<commit_before>import * as PIXI from 'pixi.js';
import * as Key from './controls';
import {lerp, distance} from './helpers';
// import RouteSegment from './routesegment';

export default class Truck {
  constructor(x, y, stage, startSegment, logsOnLevel, depositsOnLevel, stats) {
    this.sprite = PIXI.Sprite.fromImage('/static/truck.svg');
    this.sprite.anchor.set(0.5);
    this.sprite.scale.set(0.1);

    this.sprite.x = x;
    this.sprite.y = y;

    this.velocity = 5.0;

    // 0.00 - 1.00, interpolation between route segment start and end
    this.pointDelta = 0;

    this.routeIndex = 0;

    this.currentSegment = startSegment;

    this.arrowSprite = PIXI.Sprite.fromImage('/static/arrow.svg');
    this.arrowSprite.anchor.set(0, 0.5);
    this.arrowSprite.scale.set(0.2);

    stage.addChild(this.arrowSprite);
    stage.addChild(this.sprite);

    // some key helpers
    this.leftWasDown = false;
    this.rightWasDown = false;

    this.previous_direction = 1;
    this.logsOnLevel = logsOnLevel;
    this.depositsOnLevel = depositsOnLevel;

    // 4x5 array matrix for logs in truck
    this.logsInTruck = [];
    for (var i = 0; i < 4; ++i) {
      this.logsInTruck[i] = [];
      for (var j = 0; j < 5; ++j) {
        this.logsInTruck[i][j] = null;
      }
    }

    //  fill priority order for log array matrix
    /*
        x/i 0  1  2  3
    y/j  ______________
      0  |  14 16 15 13
      1  |  10 12 11 9
      2  |  6  8  7  5
      3  |  x  4  3  x
      4  |  x  2  1  x
    */
    this.logContainerTraverseOrder = [[2, 4], [1, 4], [2, 3], [1, 3], [3, 2], [0, 2], [2, 2], [1, 2], [3, 1], [0, 1], [2, 1], [1, 1], [3, 0], [0, 0], [2, 0], [1, 0]];

    this.distanceMoved = 0;
    this.fuelBurned = 0;
    this.previousPoint = null;

    this.stats = stats;
  }

  // Calculates the distance truck has moved during an instance of gameplay
  calcDistance(point) {
    if(this.previousPoint === null) {
      this.previousPoint = this.currentSegment.getPositionAt(this.pointDelta);
    }

    if((this.previousPoint.x !== point.x) || (this.previousPoint.y !== point.y)) {
      this.distanceMoved += 1;
      this.calcFuelBurned();
      this.previousPoint = point;
    }
  }

  getDistanceMoved() {
    return this.distanceMoved;
  }

  // Calculates the fuel consumed by truck in one instance of gameplay
  calcFuelBurned() {
    // If there are logs in the truck increase fuel consumption by a load factor
    var loadFactor = 0;
    this.logsInTruck.forEach(x => x.forEach(y => {if(y !== null) loadFactor += 1}));

    switch(loadFactor) {
      case 0:
        this.fuelBurned += 0.001;
        break;
      case 1:
        this.fuelBurned += 0.002;
        break;
      default:
        this.fuelBurned += 0.001+0.001*loadFactor;
    }
  }

  getFuelBurned() {
    return this.fuelBurned.toFixed(2);
  }

  update(timeDelta) {
    this.move(timeDelta);
    this.checkLogs();
    this.checkDeposits();
    this.draw();
    this.calcDistance(this.currentSegment.getPositionAt(this.pointDelta));
  }

  move(timeDelta) {
    var direction = 0;

    if(Key.up.isDown) {
      this.previous_direction = 1;
      direction = 1;
    }

    if(Key.down.isDown) {
      this.previous_direction = -1;
      direction = -1;
    }

    if(Key.left.isDown) {
      this.leftWasDown = true;
      this.rightWasDown = false;
    }

    if(Key.right.isDown) {
      this.rightWasDown = true
      this.leftWasDown = false;
    }

    if(this.leftWasDown && Key.left.isUp) {
      this.leftWasDown = false;
      this.rightWasDown = false;
      ++this.routeIndex;
      var seg = this.previous_direction > 0 ? this.currentSegment.getNextNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, 1) :
        this.currentSegment.getPreviousNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, 1);
      this.routeIndex = seg['index'];
    } else if(this.rightWasDown && Key.right.isUp) {
      this.leftWasDown = false;
      this.rightWasDown = false;
      --this.routeIndex;
      seg = this.previous_direction > 0 ? this.currentSegment.getNextNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, -1) :
        this.currentSegment.getPreviousNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, -1);
      this.routeIndex = seg['index'];
    }

    // Advance on route segment based on segment length
    this.pointDelta += (direction * this.velocity * timeDelta) / this.currentSegment.getLength();

    // Switch route segment if needed
    if (this.pointDelta <= 0) {
      this.pointDelta = 0;

      if (this.currentSegment.getPreviousNode() !== null) {
        this.pointDelta = 0.99;

        var selected_segment_data = this.currentSegment.getPreviousNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite);
        this.routeIndex = selected_segment_data['index'];

        var temp_segment = selected_segment_data['seg'];

        if(this.currentSegment.startNode !== temp_segment.endNode && this.currentSegment.startNode.getSegments().length > 1) {
          var temp_node = temp_segment.startNode;
          temp_segment.startNode = temp_segment.endNode;
          temp_segment.endNode = temp_node;
        }

        if(temp_segment === this.currentSegment) {
          this.pointDelta = 0.01;
          this.currentSegment = temp_segment;
        } else {
          this.endOfSegment = false;
          this.currentSegment = temp_segment;
        }

      }

    } else if (this.pointDelta >= 1) {
      this.pointDelta = 1;

      if (this.currentSegment.getNextNode() !== null) {
        this.pointDelta = 0.01;

        selected_segment_data = this.currentSegment.getNextNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, 1);
        this.routeIndex = selected_segment_data['index'];
        var temp_segment_2 = selected_segment_data['seg'];

        if(this.currentSegment.endNode !== temp_segment_2.startNode && this.currentSegment.endNode.getSegments().length > 1) {
          var temp_node_2 = temp_segment_2.startNode;
          temp_segment_2.startNode = temp_segment_2.endNode;
          temp_segment_2.endNode = temp_node_2;
        }

        if(temp_segment_2 === this.currentSegment) {
          this.endOfSegment = true;
          this.pointDelta = 0.99;
        }
        else {
          this.endOfSegment = false;
          this.currentSegment = temp_segment_2;
        }
      }
    }
  }

  checkLogs() {
    for (var i = 0; i < this.logsOnLevel.length; ++i) {
      var log = this.logsOnLevel[i];

      // check if log is close to truck
      var distanceToLog = distance(this.sprite.position, log.getPosition());
      if (distanceToLog < 100) {
        log.setCanBePickedUp(true);
      } else {
        log.setCanBePickedUp(false);
      }

      // log close enough and it has been clicked, pick it to truck
      if (log.canBePickedUp() && log.isMarkedForPickUp()) {

        if (this.pickLog(log)) {
          // remove it from level array and from pixi stage container (parent of the log)
          this.logsOnLevel.splice(i, 1);

          // break from the for loop because we altered the logsOnLevel array
          break;
        }
      }
    }
  }

  getLogAtPriorityIndex(i) {
    var logContainerX = this.logContainerTraverseOrder[i][0];
    var logContainerY = this.logContainerTraverseOrder[i][1];

    return this.logsInTruck[logContainerX][logContainerY];
  }

  setLogAtPriorityIndex(i, log) {
    var logContainerX = this.logContainerTraverseOrder[i][0];
    var logContainerY = this.logContainerTraverseOrder[i][1];

    this.logsInTruck[logContainerX][logContainerY] = log;

    if (log != null) {

      // clear state
      log.setCanBePickedUp(false);

      // setup graphics for truck visuals
      log.removeFromParent();
      this.sprite.addChild(log.graphics);
      log.graphics.position = new PIXI.Point(0, 22.5);
      log.graphics.rotation = Math.PI/2;
    }
  }

  // returns boolean if the log was picked up
  pickLog(log) {

    // traverse the container in fill priority order to find empty position
    for (var i = 0; i < this.logContainerTraverseOrder.length; ++i) {
      var logAtPos = this.getLogAtPriorityIndex(i);
      // check if null.. aka no log at that pos
      if (!logAtPos) {
        this.setLogAtPriorityIndex(i, log);
        this.stats.updateLogs(this.logsInTruck);
        return true;
      }
    }

    // truck is full
    return false;
  }

  unloadLogTo(deposit) {
    // unload in reverse fill priority order
    for (var i = this.logContainerTraverseOrder.length - 1; i >= 0; --i) {
      var log = this.getLogAtPriorityIndex(i);
      if (log != null) {
        if (deposit.addLog(log)) {
          this.setLogAtPriorityIndex(i, null);
          this.stats.updateLogs(this.logsInTruck);
          return true;
        } else {
          return false;
        }
      }
    }
  }

  checkDeposits() {
    for (var i = 0; i < this.depositsOnLevel.length; ++i) {
      var deposit = this.depositsOnLevel[i];

      // check if deposit is close to truck
      var distanceToDeposit = distance(this.sprite.position, deposit.getPosition());
      if (distanceToDeposit < 200) {
        deposit.setCanBeUnloadedTo(true);
      } else {
        deposit.setCanBeUnloadedTo(false);
      }

      // deposit close enough and it has been clicked, unload available log
      if (deposit.canBeUnloadedTo() && deposit.isMarkedForUnload()) {

        if (this.unloadLogTo(deposit)) {
          break;
        }
      }
    }
  }

  draw() {
    var point = this.currentSegment.getPositionAt(this.pointDelta);
    this.sprite.x = point.x;
    this.sprite.y = point.y;

    this.sprite.rotation = this.currentSegment.getRotation();

    var seg = this.previous_direction > 0 ? this.currentSegment.getNextNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite) :
      this.currentSegment.getPreviousNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite);

    if(seg['seg'] !== null) {
      this.routeIndex = seg['index'];
    }
  }
}
<commit_msg>Some implementation of truck speed done. Parameters will probably change later to make it feel better.<commit_after>import * as PIXI from 'pixi.js';
import * as Key from './controls';
import {lerp, distance} from './helpers';
// import RouteSegment from './routesegment';

export default class Truck {

  constructor(x, y, stage, startSegment, logsOnLevel, depositsOnLevel, stats) {
    // can be lower with reverse
    Truck.MIN_VELOCITY = 1.0;
    Truck.REVERSE_VELOCITY_FACTOR = 0.5;

    this.sprite = PIXI.Sprite.fromImage('/static/truck.svg');
    this.sprite.anchor.set(0.5);
    this.sprite.scale.set(0.1);

    this.sprite.x = x;
    this.sprite.y = y;

    this.velocity = 5.0;

    // 0.00 - 1.00, interpolation between route segment start and end
    this.pointDelta = 0;

    this.routeIndex = 0;

    this.currentSegment = startSegment;

    this.arrowSprite = PIXI.Sprite.fromImage('/static/arrow.svg');
    this.arrowSprite.anchor.set(0, 0.5);
    this.arrowSprite.scale.set(0.2);

    stage.addChild(this.arrowSprite);
    stage.addChild(this.sprite);

    // some key helpers
    this.leftWasDown = false;
    this.rightWasDown = false;

    this.previous_direction = 1;
    this.logsOnLevel = logsOnLevel;
    this.depositsOnLevel = depositsOnLevel;

    // 4x5 array matrix for logs in truck
    this.logsInTruck = [];
    for (var i = 0; i < 4; ++i) {
      this.logsInTruck[i] = [];
      for (var j = 0; j < 5; ++j) {
        this.logsInTruck[i][j] = null;
      }
    }

    //  fill priority order for log array matrix
    /*
        x/i 0  1  2  3
    y/j  ______________
      0  |  14 16 15 13
      1  |  10 12 11 9
      2  |  6  8  7  5
      3  |  x  4  3  x
      4  |  x  2  1  x
    */
    this.logContainerTraverseOrder = [[2, 4], [1, 4], [2, 3], [1, 3], [3, 2], [0, 2], [2, 2], [1, 2], [3, 1], [0, 1], [2, 1], [1, 1], [3, 0], [0, 0], [2, 0], [1, 0]];

    this.distanceMoved = 0;
    this.fuelBurned = 0;
    this.previousPoint = null;

    this.stats = stats;
  }

  // Calculates the distance truck has moved during an instance of gameplay
  calcDistance(point) {
    if(this.previousPoint === null) {
      this.previousPoint = this.currentSegment.getPositionAt(this.pointDelta);
    }

    if((this.previousPoint.x !== point.x) || (this.previousPoint.y !== point.y)) {
      this.distanceMoved += 1;
      this.calcFuelBurned();
      this.previousPoint = point;
    }
  }

  getDistanceMoved() {
    return this.distanceMoved;
  }

  // Calculates the fuel consumed by truck in one instance of gameplay
  calcFuelBurned() {
    // If there are logs in the truck increase fuel consumption by a load factor
    var loadFactor = 0;
    this.logsInTruck.forEach(x => x.forEach(y => {if(y !== null) loadFactor += 1}));

    switch(loadFactor) {
      case 0:
        this.fuelBurned += 0.001;
        break;
      case 1:
        this.fuelBurned += 0.002;
        break;
      default:
        this.fuelBurned += 0.001+0.001*loadFactor;
    }
  }

  getFuelBurned() {
    return this.fuelBurned.toFixed(2);
  }

  getSpeed(reverse = false) {

      // If there are logs in the truck increase fuel consumption by a load factor
      var loadFactor = 0.0;
      this.logsInTruck.forEach(x => x.forEach(y => {if(y !== null) loadFactor += 1}));

      var velocity = this.velocity - (this.velocity - Truck.MIN_VELOCITY) * loadFactor / 20;
      return reverse ?  velocity * Truck.REVERSE_VELOCITY_FACTOR :  velocity;
  }

  update(timeDelta) {
    this.move(timeDelta);
    this.checkLogs();
    this.checkDeposits();
    this.draw();
    this.calcDistance(this.currentSegment.getPositionAt(this.pointDelta));
  }

  move(timeDelta) {
    var direction = 0;

    if(Key.up.isDown) {
      this.previous_direction = 1;
      direction = 1;
    }

    if(Key.down.isDown) {
      this.previous_direction = -1;
      direction = -1;
    }

    if(Key.left.isDown) {
      this.leftWasDown = true;
      this.rightWasDown = false;
    }

    if(Key.right.isDown) {
      this.rightWasDown = true
      this.leftWasDown = false;
    }

    // Selecting route if arrow keys were pressed
    if(this.leftWasDown && Key.left.isUp) {
      this.leftWasDown = false;
      this.rightWasDown = false;
      ++this.routeIndex;
      var seg = this.previous_direction > 0 ? this.currentSegment.getNextNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, 1) :
        this.currentSegment.getPreviousNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, 1);
      this.routeIndex = seg['index'];
    } else if(this.rightWasDown && Key.right.isUp) {
      this.leftWasDown = false;
      this.rightWasDown = false;
      --this.routeIndex;
      seg = this.previous_direction > 0 ? this.currentSegment.getNextNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, -1) :
        this.currentSegment.getPreviousNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, -1);
      this.routeIndex = seg['index'];
    }

    // Advance on route segment based on segment length
    this.pointDelta += (direction * this.getSpeed( direction != 1 ) * timeDelta) / this.currentSegment.getLength();

    // Switch route segment if needed
    if (this.pointDelta <= 0) {
      this.pointDelta = 0;

      if (this.currentSegment.getPreviousNode() !== null) {
        this.pointDelta = 0.99;

        var selected_segment_data = this.currentSegment.getPreviousNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite);
        this.routeIndex = selected_segment_data['index'];

        var temp_segment = selected_segment_data['seg'];

        if(this.currentSegment.startNode !== temp_segment.endNode && this.currentSegment.startNode.getSegments().length > 1) {
          var temp_node = temp_segment.startNode;
          temp_segment.startNode = temp_segment.endNode;
          temp_segment.endNode = temp_node;
        }

        if(temp_segment === this.currentSegment) {
          this.pointDelta = 0.01;
          this.currentSegment = temp_segment;
        } else {
          this.endOfSegment = false;
          this.currentSegment = temp_segment;
        }

      }

    } else if (this.pointDelta >= 1) {
      this.pointDelta = 1;

      if (this.currentSegment.getNextNode() !== null) {
        this.pointDelta = 0.01;

        selected_segment_data = this.currentSegment.getNextNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite, 1);
        this.routeIndex = selected_segment_data['index'];
        var temp_segment_2 = selected_segment_data['seg'];

        if(this.currentSegment.endNode !== temp_segment_2.startNode && this.currentSegment.endNode.getSegments().length > 1) {
          var temp_node_2 = temp_segment_2.startNode;
          temp_segment_2.startNode = temp_segment_2.endNode;
          temp_segment_2.endNode = temp_node_2;
        }

        if(temp_segment_2 === this.currentSegment) {
          this.endOfSegment = true;
          this.pointDelta = 0.99;
        }
        else {
          this.endOfSegment = false;
          this.currentSegment = temp_segment_2;
        }
      }
    }
  }

  checkLogs() {
    for (var i = 0; i < this.logsOnLevel.length; ++i) {
      var log = this.logsOnLevel[i];

      // check if log is close to truck
      var distanceToLog = distance(this.sprite.position, log.getPosition());
      if (distanceToLog < 100) {
        log.setCanBePickedUp(true);
      } else {
        log.setCanBePickedUp(false);
      }

      // log close enough and it has been clicked, pick it to truck
      if (log.canBePickedUp() && log.isMarkedForPickUp()) {

        if (this.pickLog(log)) {
          // remove it from level array and from pixi stage container (parent of the log)
          this.logsOnLevel.splice(i, 1);

          // break from the for loop because we altered the logsOnLevel array
          break;
        }
      }
    }
  }

  getLogAtPriorityIndex(i) {
    var logContainerX = this.logContainerTraverseOrder[i][0];
    var logContainerY = this.logContainerTraverseOrder[i][1];

    return this.logsInTruck[logContainerX][logContainerY];
  }

  setLogAtPriorityIndex(i, log) {
    var logContainerX = this.logContainerTraverseOrder[i][0];
    var logContainerY = this.logContainerTraverseOrder[i][1];

    this.logsInTruck[logContainerX][logContainerY] = log;

    if (log != null) {

      // clear state
      log.setCanBePickedUp(false);

      // setup graphics for truck visuals
      log.removeFromParent();
      this.sprite.addChild(log.graphics);
      log.graphics.position = new PIXI.Point(0, 22.5);
      log.graphics.rotation = Math.PI/2;
    }
  }

  // returns boolean if the log was picked up
  pickLog(log) {

    // traverse the container in fill priority order to find empty position
    for (var i = 0; i < this.logContainerTraverseOrder.length; ++i) {
      var logAtPos = this.getLogAtPriorityIndex(i);
      // check if null.. aka no log at that pos
      if (!logAtPos) {
        this.setLogAtPriorityIndex(i, log);
        this.stats.updateLogs(this.logsInTruck);
        return true;
      }
    }

    // truck is full
    return false;
  }

  unloadLogTo(deposit) {
    // unload in reverse fill priority order
    for (var i = this.logContainerTraverseOrder.length - 1; i >= 0; --i) {
      var log = this.getLogAtPriorityIndex(i);
      if (log != null) {
        if (deposit.addLog(log)) {
          this.setLogAtPriorityIndex(i, null);
          this.stats.updateLogs(this.logsInTruck);
          return true;
        } else {
          return false;
        }
      }
    }
  }

  checkDeposits() {
    for (var i = 0; i < this.depositsOnLevel.length; ++i) {
      var deposit = this.depositsOnLevel[i];

      // check if deposit is close to truck
      var distanceToDeposit = distance(this.sprite.position, deposit.getPosition());
      if (distanceToDeposit < 200) {
        deposit.setCanBeUnloadedTo(true);
      } else {
        deposit.setCanBeUnloadedTo(false);
      }

      // deposit close enough and it has been clicked, unload available log
      if (deposit.canBeUnloadedTo() && deposit.isMarkedForUnload()) {

        if (this.unloadLogTo(deposit)) {
          break;
        }
      }
    }
  }

  draw() {
    var point = this.currentSegment.getPositionAt(this.pointDelta);
    this.sprite.x = point.x;
    this.sprite.y = point.y;

    this.sprite.rotation = this.currentSegment.getRotation();

    var seg = this.previous_direction > 0 ? this.currentSegment.getNextNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite) :
      this.currentSegment.getPreviousNode().getSelectedSegment(this.currentSegment, this.routeIndex, this.arrowSprite);

    if(seg['seg'] !== null) {
      this.routeIndex = seg['index'];
    }
  }
}
<|endoftext|>


<commit_before>/**
 * @license
 * Code City: Server Test Runner
 *
 * Copyright 2018 Google Inc.
 * https://github.com/NeilFraser/CodeCity
 *
 * 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.
 */

/**
 * @fileoverview General-purpose test infrastructure.
 * @author cpcallen@google.com (Christopher Allen)
 */
'use strict';

const util = require('util');

///////////////////////////////////////////////////////////////////////////////

/**
 * Class that records benchmark results; much like Go's testing.B type.
 * @constructor
 */
function B() {
  this.results = {};
}

/**
 * Report a benchmark or test result.
 * @param {string} status The test result status (e.g., 'OK', 'FAIL', 'SKIP').
 * @param {string} name Name of test.
 * @param {*} opt_message Additional information to lot about result.
 */
B.prototype.result = function (status, name, opt_message) {
  console.log('%s\t%s', status, name);
  if (opt_message) {
    console.log(opt_message);
  }
  this.results[status] = this.results[status] + 1 || 1;
};

/**
 * Report a benchmark start.
 * @param {string} name Name of test.
 * @param {number} run Which run is this?  (Run 0 is warm-up run.)
 */
B.prototype.start = function (name, run) {
  var r = (run === 0) ? 'WARMUP' : ('RUN ' + run);
  console.log('%s\t%s...', r, name);
  this.startTime = Date.now();
};

/**
 * Report a benchmark end.
 * @param {string} name Name of test.
 * @param {number} run Which run is this?  (Run 0 is warm-up run.)
 */
B.prototype.end = function (name, run) {
  this.endTime = Date.now();
  var r = (run === 0) ? 'WARMUP' : ('RUN ' + run);
  console.log('%s\t%s: %d ms', r, name, this.endTime - this.startTime);
};

/**
 * Report a benchmark or test failure due to crash.
 * @param {string} name Name of test.
 * @param {*} opt_message Additional info (e.g., stack trace) to log.
 */
B.prototype.crash = function(name, opt_message) {
  this.result('CRASH', name, opt_message);
};

/**
 * Report a bench or test skip.
 * @param {string} name Name of test.
 * @param {*} opt_message Additional info to log.
 */
B.prototype.skip = function(name, opt_message) {
  this.result('SKIP', name, opt_message);
};

/**
 * Return results as string.
 * @return {string}
 */
B.prototype.toString = function() {
  var lines = ['Totals:'];
  for (var status in this.results) {
    lines.push(util.format('%s\t%d tests', status, this.results[status]));
  }
  return lines.join('\n');
};

///////////////////////////////////////////////////////////////////////////////

/**
 * Class that records test results; much like Go's testing.T type.
 * @constructor
 */
function T() {
  B.call(this);
  this.results['OK'] = 0;
  this.results['FAIL'] = 0;
}

T.prototype = Object.create(B.prototype);
T.prototype.constructor = T;

/**
 * Report a test result.
 * @param {string} status The test result status (e.g., 'OK', 'FAIL', 'SKIP').
 * @param {string} name Name of test.
 * @param {*} opt_message Additional info to log.
 */
T.prototype.result = function (status, name, opt_message) {
  status === 'OK' || console.log('%s:\t%s', status, name);
  if (opt_message) {
    console.log(opt_message);
  }
  this.results[status] = this.results[status] + 1 || 1;
};

/**
 * Report a test pass.
 * @param {string} name Name of test.
 * @param {*} opt_message Additional info to log.
 */
T.prototype.pass = function(name, opt_message) {
  this.result('OK', name, opt_message);
};

/**
 * Report a test failure.
 * @param {string} name
 * @param {*} opt_message
 */
T.prototype.fail = function(name, opt_message) {
  this.result('FAIL', name, opt_message);
};

exports.B = B;
exports.T = T;
<commit_msg>Styleguide: don't use opt_<commit_after>/**
 * @license
 * Code City: Server Test Runner
 *
 * Copyright 2018 Google Inc.
 * https://github.com/NeilFraser/CodeCity
 *
 * 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.
 */

/**
 * @fileoverview General-purpose test infrastructure.
 * @author cpcallen@google.com (Christopher Allen)
 */
'use strict';

const util = require('util');

///////////////////////////////////////////////////////////////////////////////

/**
 * Class that records benchmark results; much like Go's testing.B type.
 * @constructor
 */
function B() {
  this.results = {};
}

/**
 * Report a benchmark or test result.
 * @param {string} status The test result status (e.g., 'OK', 'FAIL', 'SKIP').
 * @param {string} name Name of test.
 * @param {string=} message Additional information to lot about result.
 */
B.prototype.result = function (status, name, message) {
  console.log('%s\t%s', status, name);
  if (message) {
    console.log(message);
  }
  this.results[status] = this.results[status] + 1 || 1;
};

/**
 * Report a benchmark start.
 * @param {string} name Name of test.
 * @param {number} run Which run is this?  (Run 0 is warm-up run.)
 */
B.prototype.start = function (name, run) {
  var r = (run === 0) ? 'WARMUP' : ('RUN ' + run);
  console.log('%s\t%s...', r, name);
  this.startTime = Date.now();
};

/**
 * Report a benchmark end.
 * @param {string} name Name of test.
 * @param {number} run Which run is this?  (Run 0 is warm-up run.)
 */
B.prototype.end = function (name, run) {
  this.endTime = Date.now();
  var r = (run === 0) ? 'WARMUP' : ('RUN ' + run);
  console.log('%s\t%s: %d ms', r, name, this.endTime - this.startTime);
};

/**
 * Report a benchmark or test failure due to crash.
 * @param {string} name Name of test.
 * @param {string=} message Additional info (e.g., stack trace) to log.
 */
B.prototype.crash = function(name, message) {
  this.result('CRASH', name, message);
};

/**
 * Report a bench or test skip.
 * @param {string} name Name of test.
 * @param {string=} message Additional info to log.
 */
B.prototype.skip = function(name, message) {
  this.result('SKIP', name, message);
};

/**
 * Return results as string.
 * @return {string}
 */
B.prototype.toString = function() {
  var lines = ['Totals:'];
  for (var status in this.results) {
    lines.push(util.format('%s\t%d tests', status, this.results[status]));
  }
  return lines.join('\n');
};

///////////////////////////////////////////////////////////////////////////////

/**
 * Class that records test results; much like Go's testing.T type.
 * @constructor
 */
function T() {
  B.call(this);
  this.results['OK'] = 0;
  this.results['FAIL'] = 0;
}

T.prototype = Object.create(B.prototype);
T.prototype.constructor = T;

/**
 * Report a test result.
 * @param {string} status The test result status (e.g., 'OK', 'FAIL', 'SKIP').
 * @param {string} name Name of test.
 * @param {string=} message Additional info to log.
 */
T.prototype.result = function (status, name, message) {
  status === 'OK' || console.log('%s:\t%s', status, name);
  if (message) {
    console.log(message);
  }
  this.results[status] = this.results[status] + 1 || 1;
};

/**
 * Report a test pass.
 * @param {string} name Name of test.
 * @param {string=} message Additional info to log.
 */
T.prototype.pass = function(name, message) {
  this.result('OK', name, message);
};

/**
 * Report a test failure.
 * @param {string} name
 * @param {string=} message
 */
T.prototype.fail = function(name, message) {
  this.result('FAIL', name, message);
};

exports.B = B;
exports.T = T;
<|endoftext|>


<commit_before>
var fs = require('fs');
var path = require('path');
var lib = require('./lib');
var Object = require('./object');

var FileSystemLoader = Object.extend({
    init: function(searchPaths) {
        if(searchPaths) {
            this.searchPaths = lib.isArray(searchPaths) ? searchPaths : [searchPaths];
        }
        else {
            this.searchPaths = [];
        }
    },

    getSource: function(name) {
        var fullpath = null;
        var paths = this.searchPaths.concat(['', __dirname]);

        for(var i=0; i<paths.length; i++) {
            var p = path.join(paths[i], name);
            if(fs.existsSync(p)) {
                fullpath = p;
                break;
            }
        }

        if(!fullpath) {
            return null;
        }

        return { src: fs.readFileSync(fullpath, 'utf-8'),
                 path: fullpath,
                 upToDate: this.upToDateFunc(fullpath) };
    },

    upToDateFunc: function(file) {
        var mtime = fs.statSync(file).mtime.toString();
        return function() {
            return fs.statSync(file).mtime.toString() == mtime;
        };
    }
});

module.exports = {
    FileSystemLoader: FileSystemLoader
};<commit_msg>check for existsSync on fs for <0.7.1 node compat<commit_after>
var fs = require('fs');
var path = require('path');
var lib = require('./lib');
var Object = require('./object');

// Node <0.7.1 compatibility
var existsSync = fs.existsSync ? fs.existsSync : path.existsSync;

var FileSystemLoader = Object.extend({
    init: function(searchPaths) {
        if(searchPaths) {
            this.searchPaths = lib.isArray(searchPaths) ? searchPaths : [searchPaths];
        }
        else {
            this.searchPaths = [];
        }
    },

    getSource: function(name) {
        var fullpath = null;
        var paths = this.searchPaths.concat(['', __dirname]);

        for(var i=0; i<paths.length; i++) {
            var p = path.join(paths[i], name);
            if(existsSync(p)) {
                fullpath = p;
                break;
            }
        }

        if(!fullpath) {
            return null;
        }

        return { src: fs.readFileSync(fullpath, 'utf-8'),
                 path: fullpath,
                 upToDate: this.upToDateFunc(fullpath) };
    },

    upToDateFunc: function(file) {
        var mtime = fs.statSync(file).mtime.toString();
        return function() {
            return fs.statSync(file).mtime.toString() == mtime;
        };
    }
});

module.exports = {
    FileSystemLoader: FileSystemLoader
};<|endoftext|>


<commit_before>#!/usr/bin/env node
// vim: set filetype=javascript:
var _ = require('underscore');
var Promise = require('promise');
var path = require('path');
var fs = require('fs');
var program = require('commander');
var http = require('http');
var connect = require('connect');
var serveStatic = require('serve-static');
var finalhandler = require('finalhandler');
var path = require('path');
var noflo = require('noflo');
var runtime = require('noflo-runtime-websocket');

program
  .option('--host <hostname>', 'Host', String, 'localhost')
  .option('--port <port>', 'Port', Number, 8080)
  .option('--secret <secret>', 'Secret string', String)
  .option('--permissions <permissions>', 'Permissions', String, 'protocol:component,protocol:runtime,protocol:graph,protocol:network,component:getsource,component:setsource')
  .option('--graph <file>', 'FBP graph file', String)
  .option('--output <file>', 'JSON graph file', String)
  .parse(process.argv);

var permissions = {};
var defaultPermissions = program.permissions.split(',');
if (program.secret) {
    permissions[program.secret] = defaultPermissions;
    defaultPermissions = [];
}
var origin = program.host + ':' + program.port;
var suffix = '%26secret%3D' + encodeURIComponent(program.secret);
program.socket = 'ws://' + origin;
program.url = 'http://' + origin + '/';
program.page = 'http://' + origin + '/index.html#runtime/endpoint?protocol%3Dwebsocket%26address%3D' +
    encodeURIComponent(program.socket) + (program.secret ? suffix : '');

var baseDir = path.join(__dirname, '..');

var serve = serveStatic(baseDir);

var server = http.createServer(function(req, res){
    var done = finalhandler(req, res);
    if (req.url == '/') {
        res.statusCode = 302;
        res.setHeader('Location', program.page);
        res.end();
    } else {
        serve(req, res, done);
    }
});

program.graph = path.resolve(process.cwd(), program.graph || 'output.json');
program.output = path.resolve(process.cwd(), program.output || program.graph.replace(/.fbp$/,'.json'));

Promise.resolve(program.graph).then(function(filename){
    return promiseResult(fs.exists, fs, program.output).then(function(exists){
        if (exists) return program.output;
        else return filename;
    });
}).then(function(filename){
    return promiseResult(fs.exists, fs, filename).then(function(exists){
        if (exists) {
            console.log("Reading graph from", filename);
            return promiseResult(noflo.graph.loadFile, noflo.graph, filename);
        } else return noflo.graph.createGraph(filename);
    });
}).then(function(graph){
    return runtime(server, {
        defaultGraph: graph,
        baseDir: baseDir,
        captureOutput: false,
        catchExceptions: true,
        permissions: permissions,
        defaultPermissions: defaultPermissions
    });
}).then(function(rt){
    return promiseResult(server.listen, server, program.port).then(function(port){
        console.log('NoFlo runtime ' + rt.version + ' listening at ' + program.socket);
        console.log('NoFlo UI is available at ' + program.url);
        console.log('Using ' + baseDir + ' for noflo-ui');
        console.log('Default permissions are ' + rt.getPermitted().join(', '));
        return rt;
    });
}).then(function(rt){
    return promiseResult(process.on, process, 'SIGINT').then(function(){
        return _.first(_.filter(_.values(rt.graph.graphs), 'nodes'));
    });
}).then(function(graph){
    if (graph && !_.isEmpty(graph.nodes)) return graph;
    return promiseResult(fs.exists, fs, program.output).then(function(exists){
        if (exists) return graph;
    });
}).then(function(graph){
    if (graph) {
        console.log("Saving graph", program.output);
        return promiseError(fs.writeFile, fs, program.output, JSON.stringify(graph, null, 2));
    }
}).then(function(){
    process.exit(0);
}).catch(function(error){
    console.log(error);
    process.exit(1);
});

function promiseError(fn, context /* arguments */) {
    var args = _.toArray(arguments).splice(2);
    return new Promise(function(resolve, reject){
        fn.apply(context, args.concat(function(err){
            if (err) reject(err);
            else resolve();
        }));
    });
}

function promiseResult(fn, context /* arguments */) {
    var args = _.toArray(arguments).splice(2);
    return new Promise(function(resolve, reject){
        fn.apply(context, args.concat(resolve));
    });
}
<commit_msg>Support for graph auto-save<commit_after>#!/usr/bin/env node
// vim: set filetype=javascript:
var _ = require('underscore');
var Promise = require('promise');
var path = require('path');
var fs = require('fs');
var program = require('commander');
var http = require('http');
var connect = require('connect');
var serveStatic = require('serve-static');
var finalhandler = require('finalhandler');
var path = require('path');
var noflo = require('noflo');
var runtime = require('noflo-runtime-websocket');

program
  .option('--host <hostname>', 'Host', String, 'localhost')
  .option('--port <port>', 'Port', Number, 8080)
  .option('--secret <secret>', 'Secret string', String)
  .option('--permissions <permissions>', 'Permissions', String, 'protocol:component,protocol:runtime,protocol:graph,protocol:network,component:getsource,component:setsource')
  .option('--graph <file>', 'FBP graph file', String)
  .option('--output <file>', 'JSON graph file', String)
  .parse(process.argv);

var permissions = {};
var defaultPermissions = program.permissions.split(',');
if (program.secret) {
    permissions[program.secret] = defaultPermissions;
    defaultPermissions = [];
}
var origin = program.host + ':' + program.port;
var suffix = '%26secret%3D' + encodeURIComponent(program.secret);
program.socket = 'ws://' + origin;
program.url = 'http://' + origin + '/';
program.page = 'http://' + origin + '/index.html#runtime/endpoint?protocol%3Dwebsocket%26address%3D' +
    encodeURIComponent(program.socket) + (program.secret ? suffix : '');

var baseDir = path.join(__dirname, '..');

var serve = serveStatic(baseDir);

var server = http.createServer(function(req, res){
    var done = finalhandler(req, res);
    if (req.url == '/') {
        res.statusCode = 302;
        res.setHeader('Location', program.page);
        res.end();
    } else {
        serve(req, res, done);
    }
});

program.graph = path.resolve(process.cwd(), program.graph || 'output.json');
program.output = path.resolve(process.cwd(), program.output || program.graph.replace(/.fbp$/,'.json'));

Promise.resolve(program.graph).then(function(filename){
    return promiseResult(fs.exists, fs, program.output).then(function(exists){
        if (exists) return program.output;
        else return filename;
    });
}).then(function(filename){
    return promiseResult(fs.exists, fs, filename).then(function(exists){
        if (exists) {
            console.log("Reading graph from", filename);
            return promiseResult(noflo.graph.loadFile, noflo.graph, filename);
        } else return noflo.graph.createGraph(filename);
    });
}).then(function(graph){
    return runtime(server, {
        defaultGraph: graph,
        baseDir: baseDir,
        captureOutput: false,
        catchExceptions: true,
        permissions: permissions,
        defaultPermissions: defaultPermissions
    });
}).then(function(rt){
    return promiseResult(server.listen, server, program.port).then(function(port){
        console.log('NoFlo runtime ' + rt.version + ' listening at ' + program.socket);
        console.log('NoFlo UI is available at ' + program.url);
        console.log('Using ' + baseDir + ' for noflo-ui');
        console.log('Default permissions are ' + rt.getPermitted().join(', '));
        return rt;
    });
}).then(function(rt){
    setInterval(saveGraph(rt), 20000);
    return promiseResult(process.on, process, 'SIGINT').then(saveGraph(rt));
}).then(function(){
    process.exit(0);
}).catch(function(error){
    console.log(error);
    process.exit(1);
});

function promiseError(fn, context /* arguments */) {
    var args = _.toArray(arguments).splice(2);
    return new Promise(function(resolve, reject){
        fn.apply(context, args.concat(function(err){
            if (err) reject(err);
            else resolve();
        }));
    });
}

function promiseResult(fn, context /* arguments */) {
    var args = _.toArray(arguments).splice(2);
    return new Promise(function(resolve, reject){
        fn.apply(context, args.concat(resolve));
    });
}

function saveGraph(rt) {
    return function() {
        var graph = _.first(_.filter(_.values(rt.graph.graphs), 'nodes'));
        promiseResult(fs.exists, fs, program.output).then(function(exists){
            if (exists) return graph;
        }).then(function(graph) {
            if (graph) {
                console.log('Saving graph',program.output);
                return promiseError(fs.writeFile, fs, program.output, JSON.stringify(graph, null, 2));
            }
        });
     };
}

<|endoftext|>


<commit_before>describe("A URL", function() {
	describe("with http", function() {
		it("should be able to extract the domain", function() {
			expect(getDomain('http://www.google.com')).toMatch('www.google.com');
			expect(getDomain('http://www.google.com/')).toMatch('www.google.com');
			expect(getDomain('http://www.google.com/kitty')).toMatch('www.google.com');
		});

		it("should be able to extract the hostname", function() {
			expect(getDomain('http://www.google.com')).toMatch('google.com');
			expect(getDomain('http://www.google.com/')).toMatch('google.com');
			expect(getDomain('http://www.google.com/kitty')).toMatch('google.com');
		});
	});

	describe("with https", function() {
		it("should be able to extract the domain", function() {
			expect(getDomain('https://www.google.com')).toMatch('www.google.com');
			expect(getDomain('https://www.google.com/')).toMatch('www.google.com');
			expect(getDomain('https://www.google.com/kitty')).toMatch('www.google.com');
		});
		it("should be able to extract the hostname", function() {
			expect(getDomain('https://www.google.com')).toMatch('google.com');
			expect(getDomain('https://www.google.com/')).toMatch('google.com');
			expect(getDomain('https://www.google.com/kitty')).toMatch('google.com');
		});
	});

	describe("that is a chrome URL", function() {
		it("should be detected with no subdirectories", function() {
			expect(isChromeURL("chrome://newtabpage"));
		});

		it("should be detected with subdirectories", function() {
			expect(isChromeURL("chrome://newtabpage/kitty/meow"));
			expect(isChromeURL("chrome://newtabpage/kitty/meow/"));
		});
	});

	describe("that is an extension URL", function() {
		var url = chrome.extension.getURL("/");

		it("should be detected with no subdirectories", function() {
			expect(isExtensionURL(url));
		});

		it("should be detected with subdirectories", function() {
			expect(isExtensionURL(url + "test"));
			expect(isExtensionURL(url + "test/"));
		});

		it("should be detected if it is the new tab page", function() {
			expect(isExtensionURL("chrome://newtab"));
			expect(isExtensionURL("chrome://newtab/"));
		})
	});
});

describe("A loop", function() {
	var answer, done;

	beforeEach(function() {
		answer = null;
		done = false;
	});

	it("should repeat the right number of times", function() {
		runs(function() {
			answer = 0;

			loop(0, 5, function(iteration, callback) {
				answer += iteration;

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done;
		}, "loop to finish", 500);

		runs(function() {
			expect(answer).toBe(10);
		});
	});

	it("should not run when the end is less than the iteration", function() {
		runs(function() {
			answer = 0;

			loop(5, -1, function(iteration, callback) {
				answer += iteration;

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done;
		}, "loop to finish", 500);

		runs(function() {
			expect(answer).toBe(0);
		});
	});
});

describe("An asynchronous loop", function() {
	var answer, done;

	beforeEach(function() {
		answer = null;
		done = false;
	});

	it("should repeat the right number of times", function() {
		runs(function() {
			answer = 0;

			async_loop(0, 5, function(iteration, callback) {
				answer += iteration;

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done;
		}, "loop to finish", 500);

		runs(function() {
			expect(answer).toBe(10);
		});
	});

	it("should not run when the end is less than the iteration", function() {
		runs(function() {
			answer = 0;

			async_loop(5, -1, function(iteration, callback) {
				answer += iteration;

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done;
		}, "loop to finish", 500);

		runs(function() {
			expect(answer).toBe(0);
		});
	});

	it("should run asynchronous operations in any order", function() {
		runs(function() {
			answer = [];

			loop(0, 5, function(iteration, callback) {
				setTimeout(function() {
					answer.push(iteration);
				}, 500 - iteration * 100);

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done && answer.length == 5;
		}, "loop to finish", 5000);

		runs(function() {
			expect(answer).toEqual([4, 3, 2, 1, 0]);
		});
	});
});

describe("An HTTP request", function() {
	var server = null;
	var success, error, response;

	beforeEach(function() {
		server = sinon.fakeServer.create();

		success = false;
		error = false;
		response = null;
	});

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

	describe("making a request that will respond 200", function() {
		beforeEach(function() {
			server.respondWith("GET", "/", [200, { "Content-Type": "text/html"}, "yay"]);

			runs(function() {
				makeHTTPRequest('/', function(res, headers) {
					response = res;

					success = true;
				}, function(status) {
					error = true;
				});

				server.respond();
			});

			waitsFor(function() {
				return success || error;
			}, "the HTTP request to finish", 500);
		});

		it("should be successful", function() {
			expect(success).toBe(true);
			expect(error).toBe(false);
		});

		it("should have the correct response", function() {
			expect(response).toEqual("yay");
		});
	});

	describe("making a request that will respond 404", function() {
		beforeEach(function() {
			server.respondWith("GET", "/", [404, { "Content-Type": "text/html"}, "yay"]);

			runs(function() {
				makeHTTPRequest('/', function(res, headers) {
					response = res;

					success = true;
				}, function(status) {
					error = true;
				});

				server.respond();
			});

			waitsFor(function() {
				return success || error;
			}, "the HTTP request to finish", 500);
		});

		it("should not be successful", function() {
			expect(success).toBe(false);
			expect(error).toBe(true);
		});

		it("should have no response", function() {
			expect(response).toBeNull();
		});
	});

	describe("making a request that will respond 301", function() {
		beforeEach(function() {
			server.respondWith("GET", "/", [301, { "Content-Type": "text/html"}, "yay"]);

			runs(function() {
				makeHTTPRequest('/', function(res, headers) {
					response = res;

					success = true;
				}, function(status) {
					error = true;
				});

				server.respond();
			});

			waitsFor(function() {
				return success || error;
			}, "the HTTP request to finish", 500);
		});

		it("should not be successful", function() {
			expect(success).toBe(false);
			expect(error).toBe(true);
		});

		it("should have no response", function() {
			expect(response).toBeNull();
		});
	});
});

describe("An array", function() {
	it("should remove an element at an arbitrary index", function() {
		var arr = [100, 200, 300, 400];

		var removed = arr.removeAtIndex(0);

		expect(removed).toEqual(100);
		expect(arr).toEqual([200, 300, 400]);
	});

	it("should insert an element at an arbitrary index", function() {
		var arr = [100, 200, 300, 400];

		arr.insertAtIndex(0, 3);

		expect(arr).toEqual([100, 200, 300, 0, 400]);
	});

	it("should swap elements", function() {
		var arr = [100, 200, 300, 400];

		var removed = arr.removeAtIndex(-1);
		arr.insertAtIndex(removed, 2);

		expect(removed).toEqual(400);
		expect(arr).toEqual([100, 200, 400, 300]);
	});
});<commit_msg>Clean up tests for array.<commit_after>describe("A URL", function() {
	describe("with http", function() {
		it("should be able to extract the domain", function() {
			expect(getDomain('http://www.google.com')).toMatch('www.google.com');
			expect(getDomain('http://www.google.com/')).toMatch('www.google.com');
			expect(getDomain('http://www.google.com/kitty')).toMatch('www.google.com');
		});

		it("should be able to extract the hostname", function() {
			expect(getDomain('http://www.google.com')).toMatch('google.com');
			expect(getDomain('http://www.google.com/')).toMatch('google.com');
			expect(getDomain('http://www.google.com/kitty')).toMatch('google.com');
		});
	});

	describe("with https", function() {
		it("should be able to extract the domain", function() {
			expect(getDomain('https://www.google.com')).toMatch('www.google.com');
			expect(getDomain('https://www.google.com/')).toMatch('www.google.com');
			expect(getDomain('https://www.google.com/kitty')).toMatch('www.google.com');
		});
		it("should be able to extract the hostname", function() {
			expect(getDomain('https://www.google.com')).toMatch('google.com');
			expect(getDomain('https://www.google.com/')).toMatch('google.com');
			expect(getDomain('https://www.google.com/kitty')).toMatch('google.com');
		});
	});

	describe("that is a chrome URL", function() {
		it("should be detected with no subdirectories", function() {
			expect(isChromeURL("chrome://newtabpage"));
		});

		it("should be detected with subdirectories", function() {
			expect(isChromeURL("chrome://newtabpage/kitty/meow"));
			expect(isChromeURL("chrome://newtabpage/kitty/meow/"));
		});
	});

	describe("that is an extension URL", function() {
		var url = chrome.extension.getURL("/");

		it("should be detected with no subdirectories", function() {
			expect(isExtensionURL(url));
		});

		it("should be detected with subdirectories", function() {
			expect(isExtensionURL(url + "test"));
			expect(isExtensionURL(url + "test/"));
		});

		it("should be detected if it is the new tab page", function() {
			expect(isExtensionURL("chrome://newtab"));
			expect(isExtensionURL("chrome://newtab/"));
		})
	});
});

describe("A loop", function() {
	var answer, done;

	beforeEach(function() {
		answer = null;
		done = false;
	});

	it("should repeat the right number of times", function() {
		runs(function() {
			answer = 0;

			loop(0, 5, function(iteration, callback) {
				answer += iteration;

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done;
		}, "loop to finish", 500);

		runs(function() {
			expect(answer).toBe(10);
		});
	});

	it("should not run when the end is less than the iteration", function() {
		runs(function() {
			answer = 0;

			loop(5, -1, function(iteration, callback) {
				answer += iteration;

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done;
		}, "loop to finish", 500);

		runs(function() {
			expect(answer).toBe(0);
		});
	});
});

describe("An asynchronous loop", function() {
	var answer, done;

	beforeEach(function() {
		answer = null;
		done = false;
	});

	it("should repeat the right number of times", function() {
		runs(function() {
			answer = 0;

			async_loop(0, 5, function(iteration, callback) {
				answer += iteration;

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done;
		}, "loop to finish", 500);

		runs(function() {
			expect(answer).toBe(10);
		});
	});

	it("should not run when the end is less than the iteration", function() {
		runs(function() {
			answer = 0;

			async_loop(5, -1, function(iteration, callback) {
				answer += iteration;

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done;
		}, "loop to finish", 500);

		runs(function() {
			expect(answer).toBe(0);
		});
	});

	it("should run asynchronous operations in any order", function() {
		runs(function() {
			answer = [];

			loop(0, 5, function(iteration, callback) {
				setTimeout(function() {
					answer.push(iteration);
				}, 500 - iteration * 100);

				callback();
			}, function() {
				done = true;
			});
		});

		waitsFor(function() {
			return done && answer.length == 5;
		}, "loop to finish", 5000);

		runs(function() {
			expect(answer).toEqual([4, 3, 2, 1, 0]);
		});
	});
});

describe("An HTTP request", function() {
	var server = null;
	var success, error, response;

	beforeEach(function() {
		server = sinon.fakeServer.create();

		success = false;
		error = false;
		response = null;
	});

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

	describe("making a request that will respond 200", function() {
		beforeEach(function() {
			server.respondWith("GET", "/", [200, { "Content-Type": "text/html"}, "yay"]);

			runs(function() {
				makeHTTPRequest('/', function(res, headers) {
					response = res;

					success = true;
				}, function(status) {
					error = true;
				});

				server.respond();
			});

			waitsFor(function() {
				return success || error;
			}, "the HTTP request to finish", 500);
		});

		it("should be successful", function() {
			expect(success).toBe(true);
			expect(error).toBe(false);
		});

		it("should have the correct response", function() {
			expect(response).toEqual("yay");
		});
	});

	describe("making a request that will respond 404", function() {
		beforeEach(function() {
			server.respondWith("GET", "/", [404, { "Content-Type": "text/html"}, "yay"]);

			runs(function() {
				makeHTTPRequest('/', function(res, headers) {
					response = res;

					success = true;
				}, function(status) {
					error = true;
				});

				server.respond();
			});

			waitsFor(function() {
				return success || error;
			}, "the HTTP request to finish", 500);
		});

		it("should not be successful", function() {
			expect(success).toBe(false);
			expect(error).toBe(true);
		});

		it("should have no response", function() {
			expect(response).toBeNull();
		});
	});

	describe("making a request that will respond 301", function() {
		beforeEach(function() {
			server.respondWith("GET", "/", [301, { "Content-Type": "text/html"}, "yay"]);

			runs(function() {
				makeHTTPRequest('/', function(res, headers) {
					response = res;

					success = true;
				}, function(status) {
					error = true;
				});

				server.respond();
			});

			waitsFor(function() {
				return success || error;
			}, "the HTTP request to finish", 500);
		});

		it("should not be successful", function() {
			expect(success).toBe(false);
			expect(error).toBe(true);
		});

		it("should have no response", function() {
			expect(response).toBeNull();
		});
	});
});

describe("An array", function() {
	var arr = [];

	beforeEach(function() {
		arr = [100, 200, 300, 400];
	});

	describe("should remove", function() {
		it("an element in the array", function() {
			var removed = arr.removeElementEqualTo(300);

			expect(removed).toEqual(300);
			expect(arr).toEqual([100, 200, 400]);
		});

		it("an element not in the array", function() {
			var removed = arr.removeElementEqualTo(800);

			expect(removed).toEqual(null);
			expect(arr).toEqual([100, 200, 300, 400]);
		});
	});

	describe("should remove the element at the index", function() {
		it("in the array", function() {
			var removed = arr.removeAtIndex(0);

			expect(removed).toEqual(100);
			expect(arr).toEqual([200, 300, 400]);
		});

		it("outside of the array (pos)", function() {
			var removed = arr.removeAtIndex(800);

			expect(removed).toEqual(null);
			expect(arr).toEqual([100, 200, 300, 400]);
		});
	});

	it("should insert an element at an arbitrary index", function() {
		arr.insertAtIndex(0, 3);

		expect(arr).toEqual([100, 200, 300, 0, 400]);
	});

	it("should swap elements", function() {
		var removed = arr.removeAtIndex(-1);
		arr.insertAtIndex(removed, 2);

		expect(removed).toEqual(400);
		expect(arr).toEqual([100, 200, 400, 300]);
	});
});<|endoftext|>


<commit_before>/** @license MIT License (c) copyright 2010-2014 original author or authors */
/** @author Brian Cavalier */
/** @author John Hann */
/** @module */

var most = require('most');

var create = most.create;
var fromPromise = most.fromPromise;

exports.fromWebSocket = fromWebSocket;
exports.toWebSocket = toWebSocket;

/**
 * Create a stream from a WebSocket.  The stream will end when the WebSocket
 * closes, and will fail if the WebSocket fails.
 * @param {WebSocket} ws WebSocket (or compatible, eg SockJS) from
 *  which to create a stream
 * @returns {Stream} stream of all the messages received by the WebSocket
 */
function fromWebSocket(ws) {
	return create(function(add, end, error) {
		return pipeFromWebSocket(ws, add, end, error);
	});
}

function pipeFromWebSocket(ws, add, end, error) {
	ws.addEventListener('open', onOpen);

	function onOpen() {
		ws.addEventListener('close', end);
		ws.addEventListener('error', error);
		ws.addEventListener('message', add);
	}

	return function() {
		ws.removeEventListener('close', end);
		ws.removeEventListener('error', error);
		ws.removeEventListener('message', add);
	};
}

/**
 * Send all events in a stream to a WebSocket
 * @param {Stream} stream Stream whose events will be sent to the WebSocket
 * @param {WebSocket} ws WebSocket (or compatible, eg SockJS) to which to
 *  send events
 * @returns {Promise} promise for the end of the stream.  If the WebSocket closes
 *  before the stream ends, the returned promise will fulfill if the WebSocket
 *  closes cleanly, or will reject if the WebSocket errors.  If the stream ends
 *  before the WebSocket closes, the returned promise will fulfill if the stream
 *  ends cleanly, or will reject if the stream errors.
 */
function toWebSocket(stream, ws) {
	return new Promise(function(resolve) {
		pipeToWebSocket(stream, ws, resolve);
	});
}

function pipeToWebSocket(stream, ws, resolve) {
	ws.addEventListener('open', function onOpen() {
		initToWebSocket(stream, ws, resolve);
	});
}

function initToWebSocket(stream, ws, resolve) {
	var endSignal = fromPromise(new Promise(function(resolve, reject) {
		ws.addEventListener('close', resolve);
		ws.addEventListener('error', reject);
	}));

	var result = stream.takeUntil(endSignal).forEach(function (x) {
		if (ws.readyState === WebSocket.OPEN) {
			ws.send(x);
		}
	});

	resolve(result);
}<commit_msg>Add optional fromWebSocket disposer. Close #1<commit_after>/** @license MIT License (c) copyright 2010-2014 original author or authors */
/** @author Brian Cavalier */
/** @author John Hann */
/** @module */

var most = require('most');

var create = most.create;
var fromPromise = most.fromPromise;

exports.fromWebSocket = fromWebSocket;
exports.toWebSocket = toWebSocket;

/**
 * Create a stream from a WebSocket.  The stream will end when the WebSocket
 * closes, and will fail if the WebSocket fails.
 * @param {WebSocket} ws WebSocket (or compatible, eg SockJS) from
 *  which to create a stream
 * @param {function():*} dispose
 * @returns {Stream} stream of all the messages received by the WebSocket
 */
function fromWebSocket(ws, dispose) {
	return create(function(add, end, error) {
		return pipeFromWebSocket(ws, dispose, add, end, error);
	});
}

function pipeFromWebSocket(ws, dispose, add, end, error) {
	ws.addEventListener('open', onOpen);

	function onOpen() {
		ws.addEventListener('close', end);
		ws.addEventListener('error', error);
		ws.addEventListener('message', add);
	}

	return function() {
		ws.removeEventListener('close', end);
		ws.removeEventListener('error', error);
		ws.removeEventListener('message', add);
		return dispose();
	};
}

/**
 * Send all events in a stream to a WebSocket
 * @param {Stream} stream Stream whose events will be sent to the WebSocket
 * @param {WebSocket} ws WebSocket (or compatible, eg SockJS) to which to
 *  send events
 * @returns {Promise} promise for the end of the stream.  If the WebSocket closes
 *  before the stream ends, the returned promise will fulfill if the WebSocket
 *  closes cleanly, or will reject if the WebSocket errors.  If the stream ends
 *  before the WebSocket closes, the returned promise will fulfill if the stream
 *  ends cleanly, or will reject if the stream errors.
 */
function toWebSocket(stream, ws) {
	return new Promise(function(resolve) {
		pipeToWebSocket(stream, ws, resolve);
	});
}

function pipeToWebSocket(stream, ws, resolve) {
	ws.addEventListener('open', function onOpen() {
		initToWebSocket(stream, ws, resolve);
	});
}

function initToWebSocket(stream, ws, resolve) {
	var endSignal = fromPromise(new Promise(function(resolve, reject) {
		ws.addEventListener('close', resolve);
		ws.addEventListener('error', reject);
	}));

	var result = stream.takeUntil(endSignal).forEach(function (x) {
		if (ws.readyState === WebSocket.OPEN) {
			ws.send(x);
		}
	});

	resolve(result);
}<|endoftext|>


<commit_before>"use strict";

function flockVector(boid, neighbourBoids, flockBehaviours){
  var boidDistances = findNeighboursInRange(boid.location,
                                            neighbourBoids,
                                            flockBehaviours.range);
  var adjustmentsToNeighbours = adjustToNeighbours(boid.location,
                                                   boidDistances,
                                                   flockBehaviours.range);
  var aggregatedAdjustment = aggregateAdjustments(adjustmentsToNeighbours,
                                                  flockBehaviours.velocity);
  return aggregatedAdjustment;
}

function findNeighboursInRange(point, boids, range, boidDistances){
  if(boidDistances === undefined){
    boidDistances = [];
  }

  if(boids.length == 0){
    return boidDistances.slice(0);
  }

  var newBoidDistances = boidDistances.slice(0);

  var distanceToBoid = distance(point, boids[0].location)

  if(distanceToBoid < range){
    newBoidDistances.push({'boid': copyBoid(boids[0]),
                           'distance': distanceToBoid});
  }

  return findNeighboursInRange(point, boids.slice(1), range, newBoidDistances);
}

function adjustToNeighbours(point, boidDistances, range, adjustments){
  if(adjustments === undefined){
    adjustments = [];
  }

  if(boidDistances.length == 0){
    return adjustments.slice(0);
  }

  var adjustment = adjustToNeighbour(point, boidDistances[0], range);
  var newAdjustments = adjustments.slice(0);
  newAdjustments.push(adjustment);
  return adjustToNeighbours(point, boidDistances.slice(1), range, newAdjustments);
}

function adjustToNeighbour(point, neighbourBoidAndDistance, range){
  var neighbour = neighbourBoidAndDistance.boid;
  var distance = neighbourBoidAndDistance.distance;

  var necessarySpace = range - distance;
  var pctOfDistReq = necessarySpace / distance;

  var xDistance = point.x - neighbour.location.x;
  var yDistance = point.y - neighbour.location.y;

  var oppositeXDistance = Math.round(xDistance * pctOfDistReq);
  var oppositeYDistance = Math.round(yDistance * pctOfDistReq);

  alert("returning " + point.x + " + " oppositeXDistance

  return {'x': point.x + oppositeXDistance,
          'y': point.y + oppositeYDistance};
}

function aggregateAdjustments(adjustments, velocity){
  var xs = reduce(sum, map(getX, adjustments));
  var ys = reduce(sum, map(getY, adjustments));

  var avgX = Math.round(xs / adjustments.length);
  var avgY = Math.round(ys / adjustments.length);

  var adjustmentDistance = distance({'x': 0, 'y': 0}, {'x': avgX, 'y': avgY});
  if(adjustmentDistance > velocity){
    return proportionateAdjustment({'x': avgX, 'y': avgY}, velocity / adjustmentDistance);
  }else{
    return {'x': avgX, 'y': avgY};
  }
}

function proportionateAdjustment(point, proportion){
  return {'x': Math.round(point.x * proportion),
          'y': Math.round(point.y * proportion)};
}

function sum(x, y){
  return x + y;
}

function getX(obj){
  return obj['x'];
}

function getY(obj){
  return obj['y'];
}
<commit_msg>Cleanup<commit_after>"use strict";

function flockVector(boid, neighbourBoids, flockBehaviours){
  var boidDistances = findNeighboursInRange(boid.location,
                                            neighbourBoids,
                                            flockBehaviours.range);
  var adjustmentsToNeighbours = adjustToNeighbours(boid.location,
                                                   boidDistances,
                                                   flockBehaviours.range);
  var aggregatedAdjustment = aggregateAdjustments(adjustmentsToNeighbours,
                                                  flockBehaviours.velocity);
  return aggregatedAdjustment;
}

function findNeighboursInRange(point, boids, range, boidDistances){
  if(boidDistances === undefined){
    boidDistances = [];
  }

  if(boids.length == 0){
    return boidDistances.slice(0);
  }

  var newBoidDistances = boidDistances.slice(0);

  var distanceToBoid = distance(point, boids[0].location)

  if(distanceToBoid < range){
    newBoidDistances.push({'boid': copyBoid(boids[0]),
                           'distance': distanceToBoid});
  }

  return findNeighboursInRange(point, boids.slice(1), range, newBoidDistances);
}

function adjustToNeighbours(point, boidDistances, range, adjustments){
  if(adjustments === undefined){
    adjustments = [];
  }

  if(boidDistances.length == 0){
    return adjustments.slice(0);
  }

  var adjustment = adjustToNeighbour(point, boidDistances[0], range);
  var newAdjustments = adjustments.slice(0);
  newAdjustments.push(adjustment);
  return adjustToNeighbours(point, boidDistances.slice(1), range, newAdjustments);
}

function adjustToNeighbour(point, neighbourBoidAndDistance, range){
  var neighbour = neighbourBoidAndDistance.boid;
  var distance = neighbourBoidAndDistance.distance;

  var necessarySpace = range - distance;
  var pctOfDistReq = necessarySpace / distance;

  var xDistance = point.x - neighbour.location.x;
  var yDistance = point.y - neighbour.location.y;

  var oppositeXDistance = Math.round(xDistance * pctOfDistReq);
  var oppositeYDistance = Math.round(yDistance * pctOfDistReq);

  return {'x': point.x + oppositeXDistance,
          'y': point.y + oppositeYDistance};
}

function aggregateAdjustments(adjustments, velocity){
  var xs = reduce(sum, map(getX, adjustments));
  var ys = reduce(sum, map(getY, adjustments));

  var avgX = Math.round(xs / adjustments.length);
  var avgY = Math.round(ys / adjustments.length);

  var adjustmentDistance = distance({'x': 0, 'y': 0}, {'x': avgX, 'y': avgY});
  if(adjustmentDistance > velocity){
    return proportionateAdjustment({'x': avgX, 'y': avgY}, velocity / adjustmentDistance);
  }else{
    return {'x': avgX, 'y': avgY};
  }
}

function proportionateAdjustment(point, proportion){
  return {'x': Math.round(point.x * proportion),
          'y': Math.round(point.y * proportion)};
}

function sum(x, y){
  return x + y;
}

function getX(obj){
  return obj['x'];
}

function getY(obj){
  return obj['y'];
}
<|endoftext|>


<commit_before>/* jshint node: true */
/* jshint esnext: true */
'use strict';

const Q = require('q');
const _ = require('lodash');
const config = require('config');

const db = require('./util/dbHelper');
const mails = require('./util/mails');
const startNumbers = require('./startNumbers');
const startBlocks = require('./startblocks');
const editUrlHelper = require('../domain/editUrlHelper');
const timeCalculator = require('../domain/timeCalculator');
const queryHelper = require('./util/queryHelper');

let participants = {
  get: {}
};

participants.get.allWithPaymentStatus = (paymentStatus) => {
  if (_.isUndefined(paymentStatus)) {
    return db.select('select * from participants where firstname != \'\' order by firstname,lastname');
  } else {
    return db.select('select * from participants where has_payed = $1 and firstname != \'\' order by firstname,lastname', [paymentStatus]);
  }
};

participants.get.registered = () => {
  return participants.get.allWithPaymentStatus(false);
};

participants.get.confirmed = () => {
  return participants.get.allWithPaymentStatus(true);
};

participants.get.blancParticipants = () => {
  return db.select('select * from participants where is_on_site_registration = true');
};

participants.get.all = () => {
  return db.select('select * from participants');
};

participants.get.forDataTables = (start, length, search, ordering) => {
  const queries = queryHelper.dataTablesQueries({
    count: 'ID',
    table: 'PARTICIPANTS',
    baseFilter: `visibility = 'yes' and has_payed = true and firstname != ''`,
    select: 'ID, START_NUMBER, FIRSTNAME, LASTNAME, TEAM',
    filterColumns: ['FIRSTNAME', 'LASTNAME', 'TEAM'],
    searchParamName: '$1',
    paging: {offset: start, length: length},
    ordering,
  });

  return db.selectForDataTables(queries, search);
};

participants.get.byId = (id) => {
  return db.select('SELECT * FROM participants WHERE id = $1', [id])
    .then(result => {
      if (_.isEmpty(result)) {
        throw new Error('No participant found');
      }
      return result;
    })
    .then(result => result[0]);
};

participants.get.byStartnumber = (number) => {
  return db.select('SELECT * FROM participants WHERE start_number = $1', [number])
    .then(result => {
      if (_.isEmpty(result)) {
        throw new Error('No participant found');
      }
      return result;
    })
    .then(result => result[0]);
};

participants.get.bySecureId = (secureid) => {
  return db.select('SELECT * FROM participants WHERE secureid = $1', [secureid])
    .then(result => {
      if (_.isEmpty(result)) {
        throw new Error('No participant found');
      }
      return result;
    })
    .then(result => result[0]);
};

participants.save = (participant) => {
  return db.insert(`INSERT INTO participants
                    (firstname, lastname, email, category, birthyear, team, visibility,discount, paymenttoken, secureid, start_number, start_block, couponcode, goal, registration_time)
                    values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) returning id`,
    [participant.firstname,
      participant.lastname,
      participant.email,
      participant.category,
      participant.birthyear,
      participant.team,
      participant.visibility,
      participant.discount,
      participant.paymentToken,
      participant.secureID,
      participant.start_number,
      participant.start_block,
      participant.couponcode,
      participant.goal,
      participant.registrationTime
    ]
  );
};

participants.saveBlancParticipants = (amount) => {

  return startNumbers.next().then(nr => {
    let startNumberList = _.range(nr, nr + amount);
    return Q.all(startNumberList.map(participants.saveBlanc));
  });
};

participants.choseStartBlock = (startNumber) => { //move this out of here TODO
  return null;
};

participants.saveBlanc = (startnumber) => {
  let participant = {
    firstname: '',
    lastname: '',
    email: '',
    category: '',
    birthyear: 0,
    team: '',
    visibility: 'yes',
    discount: 'no',
    paymentToken: 'on-site Registrierung (' + startnumber + ')',
    secureID: editUrlHelper.generateSecureID(),
    start_number: startnumber,
    start_block: participants.choseStartBlock(startnumber),
    is_on_site_registration: true,
    has_payed: false,
    goal: 'relaxed'
  };

  return db.insert(`INSERT INTO participants
                    (firstname, lastname, email, category, birthyear, team, visibility,discount, paymenttoken, secureid, start_number, start_block, is_on_site_registration, has_payed, goal)
                    values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) returning id`,
    [participant.firstname,
      participant.lastname,
      participant.email,
      participant.category,
      participant.birthyear,
      participant.team,
      participant.visibility,
      participant.discount,
      participant.paymentToken,
      participant.secureID,
      participant.start_number,
      participant.start_block,
      participant.is_on_site_registration,
      participant.has_payed,
      participant.goal
    ]
  );
};

participants.delete = (participantid) => {
  return db.delete('delete from participants where id=$1', [participantid]);
};

participants.update = (participant, secureid) => {
  return db.update(`UPDATE participants SET
                    (firstname, lastname, email, category, birthyear, team, visibility, goal) =
                    ($1, $2, $3, $4, $5, $6, $7, $8)
                    WHERE secureid = $9`,
    [participant.firstname,
      participant.lastname,
      participant.email,
      participant.category,
      participant.birthyear,
      participant.team,
      participant.visibility,
      participant.goal,
      secureid])
    .then(() => {
      participants.get.bySecureId(secureid).then(saved_participant => {
        if (saved_participant.time > 0) {
          participants.updateTimeForParticipant(saved_participant, saved_participant.time);
        }
      });
    });
};

participants.updateStartblock = (startblock,secureid) => {
  return participants.get.bySecureId(secureid)
    .then( (participant) => {
      if (participant.seconds) {
        return db.update(`UPDATE participants SET start_block = $1 WHERE secureid = $2`,[startblock,secureid])
      }
    });

}

participants.distributeIntoStartblocks = (participants, blocks) => {
  let distribution = [];

  let ambitiousParticpants = _.remove(participants, (participant) => participant.goal === 'ambitious');
  distribution.push({amount: ambitiousParticpants.length, block: {color: blocks[0].color}});

  let restOfTheParticipants = participants.length;
  let restOfTheBlocks = _.tail(blocks);
  let participantsPerBlock = _.isEmpty(restOfTheBlocks) ? restOfTheParticipants : Math.floor(restOfTheParticipants / (restOfTheBlocks.length));

  _.forEach(restOfTheBlocks, () => {
    let color = blocks[distribution.length].color
    distribution.push({ amount: participantsPerBlock, block: {color: color }});
    restOfTheParticipants = restOfTheParticipants - participantsPerBlock;
  });

  let lastBlock = distribution.length - 1;
  distribution[lastBlock].amount = _.last(distribution).amount + restOfTheParticipants;
  console.log(distribution);
  return distribution;
};

participants.assign = (dist) => {
  let offset = 0;
  let updatePromises = [];

  _.forEach(dist, (value, key) => {
    updatePromises.push(
      db.update(`update participants set start_block=${key}, start_block_color='${value.block.color}' where id in
                        (select id from participants order by goal,id limit ${value.amount} offset ${offset});`)
    );
    offset = offset + value.amount;
  });

  return Q.all(updatePromises);
};

participants.markPayed = (participantId) => {
  return db.update('update participants SET has_payed = true, confirmation_time = current_timestamp(2) WHERE id = $1', [participantId])
    .then(result => {
      if (result < 1) {
        throw new Error('Es konnte kein Teilnehmer mit ID: ' + participantId + ' gefunden werden.');
      }
      return participantId;
    });
};

participants.updateTimeForParticipant = (participant, finishtime) => {
  return startBlocks.times().then((startTimes) => {
    let seconds = timeCalculator.relativeSeconds(startTimes, finishtime, participant.start_block);
    const isTeamEvent = config.get('teamEvent');
    const fasterTimeInNonTeamEvents = !isTeamEvent &&  finishtime <= participant.time;
    const slowerTimeInTeamEvents = isTeamEvent &&  finishtime >= participant.time;

    if (_.isEmpty(participant.time) || fasterTimeInNonTeamEvents || slowerTimeInTeamEvents) {
      return db.update('update participants set time=$2,seconds=$3 where start_number=$1', [participant.start_number, finishtime, seconds])
        .then(() => {
          return seconds;
        });
    }
  });
};

participants.updateTime = (startnumber, finishtime) => {
  return participants.get.byStartnumber(startnumber)
    .then((participant) => {
      return participants.updateTimeForParticipant(participant, finishtime);
    });
};

participants.insertTime = (startnumber, timestring) => {
  return participants.updateTime(startnumber, timeCalculator.timestamp(timestring));
};

participants.getTime = (startnumber) => {
  const deferred = Q.defer();
  db.select('select seconds from participants where start_number=$1', [startnumber])
    .then((result) => {
      deferred.resolve(result[0].seconds);
    })
    .catch(deferred.reject);
  return deferred.promise;
};

participants.clearTimes = () => {
  const deferred = Q.defer();
  db.select('update participants set time = NULL, seconds = NULL')
    .then((result) => {
      deferred.resolve();
    })
    .catch(deferred.reject);
  return deferred.promise;
};

participants.rank = (startnumber) => {
  const deferred = Q.defer();
  db.select("select pos from (select seconds,start_number,rank() over (order by seconds) as pos from participants where visibility='yes') as ss where start_number=$1;", [startnumber])
    .then((result) => {
      deferred.resolve(result[0].pos);
    })
    .catch(deferred.reject);
  return deferred.promise;
};

participants.rankByCategory = (startnumber) => {
  const deferred = Q.defer();
  db.select("select pos from (select seconds,start_number,rank() over (partition by category order by seconds) as pos from participants where visibility='yes') as ss where start_number=$1;", [startnumber])
    .then((result) => {
      deferred.resolve(result[0].pos);
    })
    .catch(deferred.reject);
  return deferred.promise;
};

participants.bulkmail = () => {
  const deferred = Q.defer();

  participants.get.confirmed().then(confirmed => {
    participants.get.registered().then(unconfirmed => {
      _.forEach(confirmed, participant => {
        sendInfoMailTo(participant);
      });
      _.forEach(unconfirmed, participant => {
        sendInfoMailTo(participant);
      });
      deferred.resolve();
    });
  }).catch(deferred.reject);

  return deferred.promise;
};

participants.confirm_result = (secureId) => {
  return db.update('update participants SET confirmed_result = true WHERE secureid = $1', [secureId])
    .then(result => {
      if (result < 1) {
        throw new Error('Es konnte kein Teilnehmer mit ID: ' + secureId + ' gefunden werden.');
      }
      return secureId;
    });
};

function sendInfoMailTo(participant) {
  mails.sendStatusEmail(participant, 'Lauf gegen Rechts - Infos zum Lauf', 'views/participants/bulkmail.pug');
}

module.exports = participants;
<commit_msg>return a participant so we can render a participant<commit_after>/* jshint node: true */
/* jshint esnext: true */
'use strict';

const Q = require('q');
const _ = require('lodash');
const config = require('config');

const db = require('./util/dbHelper');
const mails = require('./util/mails');
const startNumbers = require('./startNumbers');
const startBlocks = require('./startblocks');
const editUrlHelper = require('../domain/editUrlHelper');
const timeCalculator = require('../domain/timeCalculator');
const queryHelper = require('./util/queryHelper');

let participants = {
  get: {}
};

participants.get.allWithPaymentStatus = (paymentStatus) => {
  if (_.isUndefined(paymentStatus)) {
    return db.select('select * from participants where firstname != \'\' order by firstname,lastname');
  } else {
    return db.select('select * from participants where has_payed = $1 and firstname != \'\' order by firstname,lastname', [paymentStatus]);
  }
};

participants.get.registered = () => {
  return participants.get.allWithPaymentStatus(false);
};

participants.get.confirmed = () => {
  return participants.get.allWithPaymentStatus(true);
};

participants.get.blancParticipants = () => {
  return db.select('select * from participants where is_on_site_registration = true');
};

participants.get.all = () => {
  return db.select('select * from participants');
};

participants.get.forDataTables = (start, length, search, ordering) => {
  const queries = queryHelper.dataTablesQueries({
    count: 'ID',
    table: 'PARTICIPANTS',
    baseFilter: `visibility = 'yes' and has_payed = true and firstname != ''`,
    select: 'ID, START_NUMBER, FIRSTNAME, LASTNAME, TEAM',
    filterColumns: ['FIRSTNAME', 'LASTNAME', 'TEAM'],
    searchParamName: '$1',
    paging: {offset: start, length: length},
    ordering,
  });

  return db.selectForDataTables(queries, search);
};

participants.get.byId = (id) => {
  return db.select('SELECT * FROM participants WHERE id = $1', [id])
    .then(result => {
      if (_.isEmpty(result)) {
        throw new Error('No participant found');
      }
      return result;
    })
    .then(result => result[0]);
};

participants.get.byStartnumber = (number) => {
  return db.select('SELECT * FROM participants WHERE start_number = $1', [number])
    .then(result => {
      if (_.isEmpty(result)) {
        throw new Error('No participant found');
      }
      return result;
    })
    .then(result => result[0]);
};

participants.get.bySecureId = (secureid) => {
  return db.select('SELECT * FROM participants WHERE secureid = $1', [secureid])
    .then(result => {
      if (_.isEmpty(result)) {
        throw new Error('No participant found');
      }
      return result;
    })
    .then(result => result[0]);
};

participants.save = (participant) => {
  return db.insert(`INSERT INTO participants
                    (firstname, lastname, email, category, birthyear, team, visibility,discount, paymenttoken, secureid, start_number, start_block, couponcode, goal, registration_time)
                    values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) returning id`,
    [participant.firstname,
      participant.lastname,
      participant.email,
      participant.category,
      participant.birthyear,
      participant.team,
      participant.visibility,
      participant.discount,
      participant.paymentToken,
      participant.secureID,
      participant.start_number,
      participant.start_block,
      participant.couponcode,
      participant.goal,
      participant.registrationTime
    ]
  );
};

participants.saveBlancParticipants = (amount) => {

  return startNumbers.next().then(nr => {
    let startNumberList = _.range(nr, nr + amount);
    return Q.all(startNumberList.map(participants.saveBlanc));
  });
};

participants.choseStartBlock = (startNumber) => { //move this out of here TODO
  return null;
};

participants.saveBlanc = (startnumber) => {
  let participant = {
    firstname: '',
    lastname: '',
    email: '',
    category: '',
    birthyear: 0,
    team: '',
    visibility: 'yes',
    discount: 'no',
    paymentToken: 'on-site Registrierung (' + startnumber + ')',
    secureID: editUrlHelper.generateSecureID(),
    start_number: startnumber,
    start_block: participants.choseStartBlock(startnumber),
    is_on_site_registration: true,
    has_payed: false,
    goal: 'relaxed'
  };

  return db.insert(`INSERT INTO participants
                    (firstname, lastname, email, category, birthyear, team, visibility,discount, paymenttoken, secureid, start_number, start_block, is_on_site_registration, has_payed, goal)
                    values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) returning id`,
    [participant.firstname,
      participant.lastname,
      participant.email,
      participant.category,
      participant.birthyear,
      participant.team,
      participant.visibility,
      participant.discount,
      participant.paymentToken,
      participant.secureID,
      participant.start_number,
      participant.start_block,
      participant.is_on_site_registration,
      participant.has_payed,
      participant.goal
    ]
  );
};

participants.delete = (participantid) => {
  return db.delete('delete from participants where id=$1', [participantid]);
};

participants.update = (participant, secureid) => {
  return db.update(`UPDATE participants SET
                    (firstname, lastname, email, category, birthyear, team, visibility, goal) =
                    ($1, $2, $3, $4, $5, $6, $7, $8)
                    WHERE secureid = $9`,
    [participant.firstname,
      participant.lastname,
      participant.email,
      participant.category,
      participant.birthyear,
      participant.team,
      participant.visibility,
      participant.goal,
      secureid])
    .then(() => {
      participants.get.bySecureId(secureid).then(saved_participant => {
        if (saved_participant.time > 0) {
          participants.updateTimeForParticipant(saved_participant, saved_participant.time);
        }
      });
    });
};

participants.updateStartblock = (startblock,secureid) => {
  return participants.get.bySecureId(secureid)
    .then( (participant) => {
      if (participant.seconds) {
        return db.update(`UPDATE participants SET start_block = $1 WHERE secureid = $2`,[startblock,secureid])
      }
    });

}

participants.distributeIntoStartblocks = (participants, blocks) => {
  let distribution = [];

  let ambitiousParticpants = _.remove(participants, (participant) => participant.goal === 'ambitious');
  distribution.push({amount: ambitiousParticpants.length, block: {color: blocks[0].color}});

  let restOfTheParticipants = participants.length;
  let restOfTheBlocks = _.tail(blocks);
  let participantsPerBlock = _.isEmpty(restOfTheBlocks) ? restOfTheParticipants : Math.floor(restOfTheParticipants / (restOfTheBlocks.length));

  _.forEach(restOfTheBlocks, () => {
    let color = blocks[distribution.length].color
    distribution.push({ amount: participantsPerBlock, block: {color: color }});
    restOfTheParticipants = restOfTheParticipants - participantsPerBlock;
  });

  let lastBlock = distribution.length - 1;
  distribution[lastBlock].amount = _.last(distribution).amount + restOfTheParticipants;
  console.log(distribution);
  return distribution;
};

participants.assign = (dist) => {
  let offset = 0;
  let updatePromises = [];

  _.forEach(dist, (value, key) => {
    updatePromises.push(
      db.update(`update participants set start_block=${key}, start_block_color='${value.block.color}' where id in
                        (select id from participants order by goal,id limit ${value.amount} offset ${offset});`)
    );
    offset = offset + value.amount;
  });

  return Q.all(updatePromises);
};

participants.markPayed = (participantId) => {
  return db.update('update participants SET has_payed = true, confirmation_time = current_timestamp(2) WHERE id = $1', [participantId])
    .then(result => {
      if (result < 1) {
        throw new Error('Es konnte kein Teilnehmer mit ID: ' + participantId + ' gefunden werden.');
      }
      return participantId;
    });
};

participants.updateTimeForParticipant = (participant, finishtime) => {
  return startBlocks.times().then((startTimes) => {
    let seconds = timeCalculator.relativeSeconds(startTimes, finishtime, participant.start_block);
    const isTeamEvent = config.get('teamEvent');
    const fasterTimeInNonTeamEvents = !isTeamEvent &&  finishtime <= participant.time;
    const slowerTimeInTeamEvents = isTeamEvent &&  finishtime >= participant.time;

    if (_.isEmpty(participant.time) || fasterTimeInNonTeamEvents || slowerTimeInTeamEvents) {
      return db.update('update participants set time=$2,seconds=$3 where start_number=$1', [participant.start_number, finishtime, seconds])
        .then(() => {
          return seconds;
        });
    }
  });
};

participants.updateTime = (startnumber, finishtime) => {
  return participants.get.byStartnumber(startnumber)
    .then((participant) => {
      return participants.updateTimeForParticipant(participant, finishtime);
    });
};

participants.insertTime = (startnumber, timestring) => {
  return participants.updateTime(startnumber, timeCalculator.timestamp(timestring));
};

participants.getTime = (startnumber) => {
  const deferred = Q.defer();
  db.select('select seconds from participants where start_number=$1', [startnumber])
    .then((result) => {
      deferred.resolve(result[0].seconds);
    })
    .catch(deferred.reject);
  return deferred.promise;
};

participants.clearTimes = () => {
  const deferred = Q.defer();
  db.select('update participants set time = NULL, seconds = NULL')
    .then((result) => {
      deferred.resolve();
    })
    .catch(deferred.reject);
  return deferred.promise;
};

participants.rank = (startnumber) => {
  const deferred = Q.defer();
  db.select("select pos from (select seconds,start_number,rank() over (order by seconds) as pos from participants where visibility='yes') as ss where start_number=$1;", [startnumber])
    .then((result) => {
      deferred.resolve(result[0].pos);
    })
    .catch(deferred.reject);
  return deferred.promise;
};

participants.rankByCategory = (startnumber) => {
  const deferred = Q.defer();
  db.select("select pos from (select seconds,start_number,rank() over (partition by category order by seconds) as pos from participants where visibility='yes') as ss where start_number=$1;", [startnumber])
    .then((result) => {
      deferred.resolve(result[0].pos);
    })
    .catch(deferred.reject);
  return deferred.promise;
};

participants.bulkmail = () => {
  const deferred = Q.defer();

  participants.get.confirmed().then(confirmed => {
    participants.get.registered().then(unconfirmed => {
      _.forEach(confirmed, participant => {
        sendInfoMailTo(participant);
      });
      _.forEach(unconfirmed, participant => {
        sendInfoMailTo(participant);
      });
      deferred.resolve();
    });
  }).catch(deferred.reject);

  return deferred.promise;
};

participants.confirm_result = (secureId) => {
  return db.update('update participants SET confirmed_result = true WHERE secureid = $1', [secureId])
    .then(result => {
      if (result < 1) {
        throw new Error('Es konnte kein Teilnehmer mit ID: ' + secureId + ' gefunden werden.');
      }
      return participants.get.bySecureId(secureId);
    });
};

function sendInfoMailTo(participant) {
  mails.sendStatusEmail(participant, 'Lauf gegen Rechts - Infos zum Lauf', 'views/participants/bulkmail.pug');
}

module.exports = participants;
<|endoftext|>


<commit_before>// adopted from:
//   object-visit <https://github.com/jonschlinkert/object-visit>
//   map-visit <https://github.com/jonschlinkert/map-visit>
//   collection-visit <https://github.com/jonschlinkert/collection-visit>
// Copyright (c) 2015, Jon Schlinkert -- MIT

// var forOwn = require('./forOwn')
// var forEach = require('../array/forEach')

/*
    var visit = require('visit');

    var ctx = {
      data: {},
      set: function (key, value) {
        if (typeof key === 'object') {
          visit(ctx, 'set', key);
        } else {
          ctx.data[key] = value;
        }
      }
    };

    ctx.set('a', 'a');
    ctx.set('b', 'b');
    ctx.set('c', 'c');
    ctx.set({d: {e: 'f'}});

    console.log(ctx.data);
    //=> {a: 'a', b: 'b', c: 'c', d: { e: 'f' }};
*/

function objVisit (thisArg, method, target) {
  // for (var key in target) {
  //   if (target.hasOwnProperty(key)) thisArg[method](key, target[key])
  // }
  // want to stop using for-in loops

  Object.keys(target).forEach(function (val, idx, arr) {
    if (target.hasOwnProperty(val)) thisArg[method](val, target[val])
  })

  // new code awaiting test results:
  // forOwn(target, function (val, key) {
  //   thisArg[method](val, target[val])
  // })

  return thisArg
}

function arrVisit (thisArg, method, array) {
  // new code awaiting test results:
  // forEach(array, function (val) {
  //   objVisit(thisArg, method, val)
  // })
  array.forEach(function (obj) {
    objVisit(thisArg, method, obj)
  })
}

function visit (collection, method, val) {
  if (Array.isArray(val)) arrVisit(collection, method, val)
  else objVisit(collection, method, val)

  return collection
}

module.exports = visit
<commit_msg>update object/visit.js<commit_after>// adopted from:
//   object-visit <https://github.com/jonschlinkert/object-visit>
//   map-visit <https://github.com/jonschlinkert/map-visit>
//   collection-visit <https://github.com/jonschlinkert/collection-visit>
// Copyright (c) 2015, Jon Schlinkert -- MIT

/*
    var visit = require('visit');

    var ctx = {
      data: {},
      set: function (key, value) {
        if (typeof key === 'object') {
          visit(ctx, 'set', key);
        } else {
          ctx.data[key] = value;
        }
      }
    };

    ctx.set('a', 'a');
    ctx.set('b', 'b');
    ctx.set('c', 'c');
    ctx.set({d: {e: 'f'}});

    console.log(ctx.data);
    //=> {a: 'a', b: 'b', c: 'c', d: { e: 'f' }};
*/

function objVisit (thisArg, method, target) {
  for (var key in target) {
    if (target.hasOwnProperty(key)) thisArg[method](key, target[key])
  }

  return thisArg
}

function arrVisit (thisArg, method, array) {

  array.forEach(function (obj) {
    objVisit(thisArg, method, obj)
  })
}

function visit (collection, method, val) {
  if (Array.isArray(val)) arrVisit(collection, method, val)
  else objVisit(collection, method, val)

  return collection
}

module.exports = visit
<|endoftext|>