<commit_before>var getIndex = require('./utils/getIndex');

module.exports = function() {
  this.Given(/^I submit the form$/, function(callback) {
    return driver.findElement(by.css('button[type="submit"]')).click().then(function() {
      callback();
    });
  });

  /**
   * Fill in a text input or textarea with some text
   * @param string Matches either the inputs name attribute or its label text
   * @param string The text to input
   */
  this.Given(/^I fill in "([^"]*)" with "([^"]*)"$/, function(arg1, arg2, callback) {
    var action = function(_by) {
      driver.findElements(_by).then(function(inputs) {
        var input = inputs[inputs.length - 1];

        //input.isDisplayed().then(function() {
          input.clear().then(function() {
            input.sendKeys(arg2).then(function() {
              callback();
            });
          });
        //}).addErrback(function(e) {
          //action(_by);
        //});
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    };

    // replace parameter value
    if (arg2.indexOf('%') !== -1) {
      arg2 = parameters[arg2.replace(/%/g, '')];
    }

    if (arg1.match(/^#.*/)) { // find by id if hash is found
      arg1 = arg1.replace('#', '');
      action(by.id(arg1));
    } else if (arg1.match(/^\..*/)) { // find by css if . is found
      action(by.css(arg1));
    } else if (/[A-Z]/.test(arg1[0])) { // find by label if first letter of arg1 is capitalized
      driver.findElement(by.xpath('//label[text()="' + arg1 + '"]')).then(function(label) {
        label.getAttribute('for').then(function(id) {
          action(by.id(id));
        });
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    } else {  // find by name attribute
      action(by.xpath('//[name="' + arg1 + '"]'));
    }
  });

  this.Given(/^I select "([^"]*)" from "([^"]*)"$/, function(arg1, arg2, callback) {
    var option,
        opts;

    var action = function(opts) {
      opts.then(function(elems) {
        elems.forEach(function(v, i) {
          v.getText().then(function(text) {
            if (text === arg1) {
              option = v;
              v.click().then(function() {
                callback();
              });
            }
          });
        });
      });
    };

    if (arg2.match(/\..*/)) { // find by class
      action(browser.findElements(by.css(arg2 + ' option')));
    } else if (/[A-Z]/.test(arg2[0])) { // find by label if first letter of arg1 is capitalized
      driver.findElements(by.xpath('//label[text()="' + arg2 + '"]')).then(function(labels) {
        labels[labels.length - 1].getAttribute('for').then(function(id) {
          action(browser.findElements(by.css('#' + id + ' option')));
        });
      });
    } else { //find by select name
      action(browser.findElements(by.css('select[name="' + arg2 + '"] option')));
    }
  });

  this.Given(/^I select "([^"]*)" and "([^"]*)" from "([^"]*)"$/, function(arg1, arg2, arg3, callback) {
    var selectCount = 0,
        opts;

    if (arg3.match(/\..*/)) { // find by class
      opts = browser.findElements(by.css(arg3 + ' option'));
    } else { //find by select name
      opts = browser.findElements(by.css('select[name="' + arg3 + '"] option'));
    }

    opts.then(function(elems) {
      elems.forEach(function(v, i) {
        v.getText().then(function(text) {
          if (text === arg1 || text === arg2) {
            v.click().then(function() {
              selectCount++;
              if (selectCount === 2) {
                callback();
              }
            });
          }
        });
      });
    });
  });

  this.Given(/^I check "([^"]*)"$/, function(arg1, callback) {
    var action = function(_by) {
      browser.findElement(_by).then(function(el) {
        el.click().then(function() {
          callback();
        }).addErrback(function(e) {
          callback.fail(e.message);
        });
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    };

    if (arg1.match(/^#.*/)) { // find by id
      arg1 = arg1.replace('#', '');
      action(by.id(arg1));
    } else if (arg1.match(/\..*/)) { // find by class
      action(by.css(arg1));
    } else { // find by link text
      action(by.linkText(arg1));
    }
  });

  this.Given(/^I check the "([^"]*)" "([^"]*)"$/, function(arg1, arg2, callback) {
    var action = function(_by) {
      browser.findElements(_by).then(function(elems) {
        elems[getIndex(arg1)].click().then(function() {
          callback();
        }).addErrback(function(e) {
          callback.fail(e.message);
        });
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    };

    action(by.css(arg2));
  });

  this.Then(/^I fill in the "([^"]*)" "([^"]*)" input with "([^"]*)"$/, function(arg1, arg2, arg3, callback) {
    browser.findElements(by.css(arg2)).then(function(elems) {
      elems[getIndex(arg1)].then(function(el) {
        el.clear(function() {
          el.sendKeys(arg3).then(function() {
            callback();
          });
        });
      });
    });
  });

  /**
   * Simulate a file upload
   * @param string   arg1 Matches either the inputs name attribute or its label text
   * @param string   arg1 The text to input
   * @param function callback
   */
  this.Given(/^I upload "([^"]*)" with "([^"]*)"$/, function(arg1, arg2, callback) {
    var action = function(input) {
      input.sendKeys(arg2).then(function() {
        callback();
      });
    };

    if (arg2.indexOf('%') !== -1) {
      arg2 = parameters[arg2.replace(/%/g, '')];
    }

    if (arg1.indexOf('#') !== -1) {
      arg1 = arg1.replace('#', '');
      driver.findElement(by.id(arg1)).then(function(input) {
        action(input);
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    } else {
      driver.findElement(by.xpath('//input[name="' + arg1 + '"]')).then(function(input) {
        action(input);
      }).addErrback(function(e) {
        driver.findElement(by.xpath('//label[text()="' + arg1 + '"]')).then(function(label) {
          label.getAttribute('for').then(function(id) {
            browser.findElement(by.id(id)).then(function(input) {
              action(input);
            });
          });
        }).addErrback(function(e) {
          callback.fail(e.message);
        });
      });
    }
  });

  this.Given(/^I choose "([^"]*)" from "([^"]*)"$/, function(arg1, arg2, callback) {
    browser.findElement(by.css('select[name="' + arg2 + '"]')).then(function(elem) {
      elem.getAttribute('id').then(function(id) {
        browser.findElement(by.id(id + '_chosen')).then(function(chosenContainer) {
          chosenContainer.click().then(function() {
            browser.findElement(by.xpath('//li[text()="' + arg1 + '"]')).then(function(option) {
              option.click().then(function() {
                callback();
              });
            });
          });
        });
      });
    });
  });

  this.Given(/^I choose "([^"]*)" and "([^"]*)" from "([^"]*)"$/, function(arg1, arg2, arg3, callback) {
    browser.findElement(by.css('select[name="' + arg3 + '"]')).then(function(elem) {
      elem.getAttribute('id').then(function(id) {
        browser.findElement(by.id(id + '_chosen')).then(function(chosenContainer) {
          chosenContainer.click().then(function() {
            browser.findElement(by.xpath('//li[text()="' + arg1 + '"]')).then(function(option) {
              option.click().then(function() {
                chosenContainer.click().then(function() {
                  browser.findElement(by.xpath('//li[text()="' + arg2 + '"]')).then(function(option) {
                    option.click().then(function() {
                      callback();
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  });
};
<commit_msg>fix xpath selector<commit_after>var getIndex = require('./utils/getIndex');

module.exports = function() {
  this.Given(/^I submit the form$/, function(callback) {
    return driver.findElement(by.css('button[type="submit"]')).click().then(function() {
      callback();
    });
  });

  /**
   * Fill in a text input or textarea with some text
   * @param string Matches either the inputs name attribute or its label text
   * @param string The text to input
   */
  this.Given(/^I fill in "([^"]*)" with "([^"]*)"$/, function(arg1, arg2, callback) {
    var action = function(_by) {
      driver.findElements(_by).then(function(inputs) {
        var input = inputs[inputs.length - 1];

        //input.isDisplayed().then(function() {
          input.clear().then(function() {
            input.sendKeys(arg2).then(function() {
              callback();
            });
          });
        //}).addErrback(function(e) {
          //action(_by);
        //});
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    };

    // replace parameter value
    if (arg2.indexOf('%') !== -1) {
      arg2 = parameters[arg2.replace(/%/g, '')];
    }

    if (arg1.match(/^#.*/)) { // find by id if hash is found
      arg1 = arg1.replace('#', '');
      action(by.id(arg1));
    } else if (arg1.match(/^\..*/)) { // find by css if . is found
      action(by.css(arg1));
    } else if (/[A-Z]/.test(arg1[0])) { // find by label if first letter of arg1 is capitalized
      driver.findElement(by.xpath('//label[text()="' + arg1 + '"]')).then(function(label) {
        label.getAttribute('for').then(function(id) {
          action(by.id(id));
        });
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    } else {  // find by name attribute
      action(by.xpath('//*[name="' + arg1 + '"]'));
    }
  });

  this.Given(/^I select "([^"]*)" from "([^"]*)"$/, function(arg1, arg2, callback) {
    var option,
        opts;

    var action = function(opts) {
      opts.then(function(elems) {
        elems.forEach(function(v, i) {
          v.getText().then(function(text) {
            if (text === arg1) {
              option = v;
              v.click().then(function() {
                callback();
              });
            }
          });
        });
      });
    };

    if (arg2.match(/\..*/)) { // find by class
      action(browser.findElements(by.css(arg2 + ' option')));
    } else if (/[A-Z]/.test(arg2[0])) { // find by label if first letter of arg1 is capitalized
      driver.findElements(by.xpath('//label[text()="' + arg2 + '"]')).then(function(labels) {
        labels[labels.length - 1].getAttribute('for').then(function(id) {
          action(browser.findElements(by.css('#' + id + ' option')));
        });
      });
    } else { //find by select name
      action(browser.findElements(by.css('select[name="' + arg2 + '"] option')));
    }
  });

  this.Given(/^I select "([^"]*)" and "([^"]*)" from "([^"]*)"$/, function(arg1, arg2, arg3, callback) {
    var selectCount = 0,
        opts;

    if (arg3.match(/\..*/)) { // find by class
      opts = browser.findElements(by.css(arg3 + ' option'));
    } else { //find by select name
      opts = browser.findElements(by.css('select[name="' + arg3 + '"] option'));
    }

    opts.then(function(elems) {
      elems.forEach(function(v, i) {
        v.getText().then(function(text) {
          if (text === arg1 || text === arg2) {
            v.click().then(function() {
              selectCount++;
              if (selectCount === 2) {
                callback();
              }
            });
          }
        });
      });
    });
  });

  this.Given(/^I check "([^"]*)"$/, function(arg1, callback) {
    var action = function(_by) {
      browser.findElement(_by).then(function(el) {
        el.click().then(function() {
          callback();
        }).addErrback(function(e) {
          callback.fail(e.message);
        });
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    };

    if (arg1.match(/^#.*/)) { // find by id
      arg1 = arg1.replace('#', '');
      action(by.id(arg1));
    } else if (arg1.match(/\..*/)) { // find by class
      action(by.css(arg1));
    } else { // find by link text
      action(by.linkText(arg1));
    }
  });

  this.Given(/^I check the "([^"]*)" "([^"]*)"$/, function(arg1, arg2, callback) {
    var action = function(_by) {
      browser.findElements(_by).then(function(elems) {
        elems[getIndex(arg1)].click().then(function() {
          callback();
        }).addErrback(function(e) {
          callback.fail(e.message);
        });
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    };

    action(by.css(arg2));
  });

  this.Then(/^I fill in the "([^"]*)" "([^"]*)" input with "([^"]*)"$/, function(arg1, arg2, arg3, callback) {
    browser.findElements(by.css(arg2)).then(function(elems) {
      elems[getIndex(arg1)].then(function(el) {
        el.clear(function() {
          el.sendKeys(arg3).then(function() {
            callback();
          });
        });
      });
    });
  });

  /**
   * Simulate a file upload
   * @param string   arg1 Matches either the inputs name attribute or its label text
   * @param string   arg1 The text to input
   * @param function callback
   */
  this.Given(/^I upload "([^"]*)" with "([^"]*)"$/, function(arg1, arg2, callback) {
    var action = function(input) {
      input.sendKeys(arg2).then(function() {
        callback();
      });
    };

    if (arg2.indexOf('%') !== -1) {
      arg2 = parameters[arg2.replace(/%/g, '')];
    }

    if (arg1.indexOf('#') !== -1) {
      arg1 = arg1.replace('#', '');
      driver.findElement(by.id(arg1)).then(function(input) {
        action(input);
      }).addErrback(function(e) {
        callback.fail(e.message);
      });
    } else {
      driver.findElement(by.xpath('//input[name="' + arg1 + '"]')).then(function(input) {
        action(input);
      }).addErrback(function(e) {
        driver.findElement(by.xpath('//label[text()="' + arg1 + '"]')).then(function(label) {
          label.getAttribute('for').then(function(id) {
            browser.findElement(by.id(id)).then(function(input) {
              action(input);
            });
          });
        }).addErrback(function(e) {
          callback.fail(e.message);
        });
      });
    }
  });

  this.Given(/^I choose "([^"]*)" from "([^"]*)"$/, function(arg1, arg2, callback) {
    browser.findElement(by.css('select[name="' + arg2 + '"]')).then(function(elem) {
      elem.getAttribute('id').then(function(id) {
        browser.findElement(by.id(id + '_chosen')).then(function(chosenContainer) {
          chosenContainer.click().then(function() {
            browser.findElement(by.xpath('//li[text()="' + arg1 + '"]')).then(function(option) {
              option.click().then(function() {
                callback();
              });
            });
          });
        });
      });
    });
  });

  this.Given(/^I choose "([^"]*)" and "([^"]*)" from "([^"]*)"$/, function(arg1, arg2, arg3, callback) {
    browser.findElement(by.css('select[name="' + arg3 + '"]')).then(function(elem) {
      elem.getAttribute('id').then(function(id) {
        browser.findElement(by.id(id + '_chosen')).then(function(chosenContainer) {
          chosenContainer.click().then(function() {
            browser.findElement(by.xpath('//li[text()="' + arg1 + '"]')).then(function(option) {
              option.click().then(function() {
                chosenContainer.click().then(function() {
                  browser.findElement(by.xpath('//li[text()="' + arg2 + '"]')).then(function(option) {
                    option.click().then(function() {
                      callback();
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  });
};
<|endoftext|>


<commit_before>var events = require('events');
var moment = require('moment-timezone');
var Q = require('q');
var util = require('util');
var utils = require('./utils');

module.exports = Game;

function Game(game) {
  if (!(this instanceof Game)) { return new Game(game); }

  events.EventEmitter.call(this);

  this.urlRoot = 'http://www.mlb.com/gdcross' + game.game_data_directory;

  // Assuming the start is always given in eastern time
  var startString = game.time_date + game.ampm;
  var eastern = moment.tz(startString, 'YYYY/MM/DD h:mma', 'America/New_York');
  this.startTime = eastern.tz(moment.tz.guess());

  this.disp = game.away_name_abbrev + ' @ ' + game.home_name_abbrev + ' - ';
  this.disp += this.startTime.format('h:mm A');
  if (game.status) {
    var status = game.status.status;
    if (status !== 'Preview' && status !== 'Pre-Game') {
      this.disp += ' - ' + status;
      if (status === 'In Progress') {
        this.disp += ' ' + game.status.inning_state + ' ' + game.status.inning;
      }
    }
  }

  this.players = {};
}

util.inherits(Game, events.EventEmitter);

Game.prototype.start = function() {
  utils.getXml(this.urlRoot + '/players.xml')
    .then(parsePlayers.bind(undefined, this))
    .then(loop.bind(undefined, this));
};

var timeouts = {
  preview: untilStart,
  preGame: untilStart,
  warmup: 30000,
  delayed: 30000,
  delayedStart: 30000,
  inProgress: 10000,
  replay: 10000,
  review: 10000,
  managerChallenge: 10000,
};

var inningState = {};

function untilStart(self) {
  var until = self.startTime.diff(moment());
  return until < 0 ? 30000 : until;
}

function loop(self) {
  Q.all([
    utils.getXml(self.urlRoot + '/inning/inning_all.xml'),
    utils.getXml(self.urlRoot + '/plays.xml'),
  ])
  .spread(function(events, plays) {
    var status = utils.camelCase(plays.status);

    if (status === 'inProgress') {
      if (inningState.num !== plays.inning ||
          inningState.side !== plays.inning_state) {
        inningState = {num: plays.inning, side: plays.inning_state};
        self.emit('inning', inningState);
      }
    } else {
      self.emit(status);
    }

    var timeout = timeouts[status];
    if (timeout) {
      if (typeof timeout === 'function') {
        timeout = timeout(self);
      }
      setTimeout(loop, timeout, self);
    }
  })
  .done();
}

function parsePlayers(self, game) {
  game.team.forEach(function (team) {
    team.player.forEach(function (player) {
      self.players[player.id] = player;
    });
  });
}
<commit_msg>Store team info<commit_after>var events = require('events');
var moment = require('moment-timezone');
var Q = require('q');
var util = require('util');
var utils = require('./utils');

module.exports = Game;

function Game(game) {
  if (!(this instanceof Game)) { return new Game(game); }

  events.EventEmitter.call(this);

  this.teams = {
    away: {
      id: game.away_team_id,
      city: game.away_team_city,
      name: game.away_team_name,
      code: game.away_code,
      abbrev: game.away_name_abbrev,
      home_away: 'away',
    },
    home: {
      id: game.home_team_id,
      city: game.home_team_city,
      name: game.home_team_name,
      code: game.home_code,
      abbrev: game.home_name_abbrev,
      home_away: 'home',
    }
  };

  this.urlRoot = 'http://www.mlb.com/gdcross' + game.game_data_directory;

  // Assuming the start is always given in eastern time
  var startString = game.time_date + game.ampm;
  var eastern = moment.tz(startString, 'YYYY/MM/DD h:mma', 'America/New_York');
  this.startTime = eastern.tz(moment.tz.guess());

  this.disp = this.teams.away.abbrev + ' @ ' + this.teams.home.abbrev + ' - ';
  this.disp += this.startTime.format('h:mm A');
  if (game.status) {
    var status = game.status.status;
    if (status !== 'Preview' && status !== 'Pre-Game') {
      this.disp += ' - ' + status;
      if (status === 'In Progress') {
        this.disp += ' ' + game.status.inning_state + ' ' + game.status.inning;
      }
    }
  }

  this.players = {};
}

util.inherits(Game, events.EventEmitter);

Game.prototype.start = function() {
  utils.getXml(this.urlRoot + '/players.xml')
    .then(parsePlayers.bind(undefined, this))
    .then(loop.bind(undefined, this));
};

var timeouts = {
  preview: untilStart,
  preGame: untilStart,
  warmup: 30000,
  delayed: 30000,
  delayedStart: 30000,
  inProgress: 10000,
  replay: 10000,
  review: 10000,
  managerChallenge: 10000,
};

var inningState = {};

function untilStart(self) {
  var until = self.startTime.diff(moment());
  return until < 0 ? 30000 : until;
}

function loop(self) {
  Q.all([
    utils.getXml(self.urlRoot + '/inning/inning_all.xml'),
    utils.getXml(self.urlRoot + '/plays.xml'),
  ])
  .spread(function(events, plays) {
    var status = utils.camelCase(plays.status);

    if (status === 'inProgress') {
      if (inningState.num !== plays.inning ||
          inningState.side !== plays.inning_state) {
        inningState = {num: plays.inning, side: plays.inning_state};
        self.emit('inning', inningState);
      }
    } else {
      self.emit(status);
    }

    var timeout = timeouts[status];
    if (timeout) {
      if (typeof timeout === 'function') {
        timeout = timeout(self);
      }
      setTimeout(loop, timeout, self);
    }
  })
  .done();
}

function parsePlayers(self, game) {
  game.team.forEach(function (team) {
    team.player.forEach(function (player) {
      self.players[player.id] = player;
    });
  });
}
<|endoftext|>


<commit_before>const Player = require('./player');
const $      = require('jquery');

function boardDetails() {
  var canvas    = document.getElementById('game');
  var gameBoard = canvas.getContext("2d");
  var width     = $(canvas).width();
  var height    = $(canvas).height();

  return { gameBoard: gameBoard, width: width, height: height };
}

function createBoard() {
  var board = boardDetails();
  board.gameBoard.fillStyle = "black";
  board.gameBoard.fillRect(0, 0, board.width, board.height);

  return board.gameBoard;
}

function Game() {
  this.board = createBoard();
  this.oneKeys = {
    left:  "65",
    up:    "87",
    right: "68",
    down:  "83"
  };
  this.twoKeys = {
    left:  "37",
    up:    "38",
    right: "39",
    down:  "40"
  };
  this.end = false;
}

Game.prototype.createPlayers = function() {
  this.playerOne = new Player("red", { x: 10, y: 30 }, "right", this.oneKeys);
  this.playerTwo = new Player("blue", { x: 110, y: 30 }, "left", this.twoKeys);
};

Game.prototype.start = function () {
  this.createPlayers();
  this.gameLoopInterval = setInterval(this.movePlayers.bind(this), 30);
};

Game.prototype.movePlayers = function() {
  this.playerOne.move(this);
  this.playerTwo.move(this);
};

Game.prototype.detectCollision = function(position) {
  var border             = this.borderCollision(position);
  var playerOneCollision = this.playerCollision(position, this.playerOne);
  var playerTwoCollision = this.playerCollision(position, this.playerTwo);

  if (border || playerOneCollision || playerTwoCollision) {
    this.end = true;
    this.displayEndMessage();
  }
};

Game.prototype.borderCollision = function(position) {
  return position.x == -1 || position.x == 1200 / 10 || position.y == -1 || position.y == 600 / 10
};

Game.prototype.playerCollision = function(position, player) {
  for (var i = 0; i < player.trail.length; i++) {
    if (position.x === player.trail[i].x && position.y === player.trail[i].y) {
      return true;
    }
  }
};

Game.prototype.displayEndMessage = function() {
  clearInterval(this.gameLoopInterval);
  document.getElementById("end").style.display = 'inline';
};

module.exports = Game;
<commit_msg>refactor Game.createBoard function<commit_after>const Player = require('./player');
const $      = require('jquery');

function Game() {
  this.oneKeys = {
    left:  "65",
    up:    "87",
    right: "68",
    down:  "83"
  };
  this.twoKeys = {
    left:  "37",
    up:    "38",
    right: "39",
    down:  "40"
  };
  this.end = false;
}

Game.prototype.createBoard = function() {
  var canvas = document.getElementById('game');
  this.board = canvas.getContext("2d");
  var width  = $(canvas).width();
  var height = $(canvas).height();

  this.board.fillStyle = "black";
  this.board.fillRect(0, 0, width, height);
};

Game.prototype.createPlayers = function() {
  this.playerOne = new Player("red", { x: 10, y: 30 }, "right", this.oneKeys);
  this.playerTwo = new Player("blue", { x: 110, y: 30 }, "left", this.twoKeys);
};

Game.prototype.start = function () {
  this.createBoard();
  this.createPlayers();
  this.gameLoopInterval = setInterval(this.movePlayers.bind(this), 30);
};

Game.prototype.movePlayers = function() {
  this.playerOne.move(this);
  this.playerTwo.move(this);
};

Game.prototype.detectCollision = function(position) {
  var border             = this.borderCollision(position);
  var playerOneCollision = this.playerCollision(position, this.playerOne);
  var playerTwoCollision = this.playerCollision(position, this.playerTwo);

  if (border || playerOneCollision || playerTwoCollision) {
    this.end = true;
    this.displayEndMessage();
  }
};

Game.prototype.borderCollision = function(position) {
  return position.x == -1 || position.x == 1200 / 10 || position.y == -1 || position.y == 600 / 10
};

Game.prototype.playerCollision = function(position, player) {
  for (var i = 0; i < player.trail.length; i++) {
    if (position.x === player.trail[i].x && position.y === player.trail[i].y) {
      return true;
    }
  }
};

Game.prototype.displayEndMessage = function() {
  clearInterval(this.gameLoopInterval);
  document.getElementById("end").style.display = 'inline';
};

module.exports = Game;
<|endoftext|>


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

var path = require("path");

var cfEnv = require("cf-env");
var cfCore = cfEnv.getCore();

var VCAP_APPLICATION = JSON.parse(process.env.VCAP_APPLICATION);
var VCAP_SERVICES = JSON.parse(process.env.VCAP_SERVICES);

var settings = module.exports = {
    uiPort: process.env.VCAP_APP_PORT || 1880,
    mqttReconnectTime: 15000,
    serialReconnectTime: 15000,
    debugMaxLength: 1000,

    // Add the bluemix-specific nodes in
    nodesDir: path.join(__dirname,"nodes"),

    // Blacklist the non-bluemix friendly nodes
    nodesExcludes:['66-mongodb.js','75-exec.js','35-arduino.js','36-rpi-gpio.js','25-serial.js','28-tail.js','50-file.js','31-tcpin.js','32-udp.js'],

    // Move the admin UI
    httpAdminRoot: '/red',

    // You can protect the user interface with a userid and password by using the following property
    // the password must be an md5 hash  eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
    //httpAdminAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"},

    // Serve up the welcome page
    httpStatic: path.join(__dirname,"public"),

    functionGlobalContext: { },

    storageModule: require("./couchstorage")
}

settings.couchAppname = VCAP_APPLICATION['application_name'];

var storageServiceName = process.env.NODE_RED_STORAGE_NAME || settings.couchAppname+":cloudantNoSQLDB";
settings.couchUrl = cfEnv.getService(storageServiceName).credentials.url;
<commit_msg>Enabled autoInstallModules<commit_after>/**
 * Copyright 2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var path = require("path");

var cfEnv = require("cf-env");
var cfCore = cfEnv.getCore();

var VCAP_APPLICATION = JSON.parse(process.env.VCAP_APPLICATION);
var VCAP_SERVICES = JSON.parse(process.env.VCAP_SERVICES);

var settings = module.exports = {
    uiPort: process.env.VCAP_APP_PORT || 1880,
    mqttReconnectTime: 15000,
    serialReconnectTime: 15000,
    debugMaxLength: 1000,

    // Add the bluemix-specific nodes in
    nodesDir: path.join(__dirname,"nodes"),

    // Blacklist the non-bluemix friendly nodes
    nodesExcludes:['66-mongodb.js','75-exec.js','35-arduino.js','36-rpi-gpio.js','25-serial.js','28-tail.js','50-file.js','31-tcpin.js','32-udp.js'],

    // Enable module reinstalls on start-up; this ensures modules installed
    // post-deploy are restored after a restage
    autoInstallModules: true,

    // Move the admin UI
    httpAdminRoot: '/red',

    // You can protect the user interface with a userid and password by using the following property
    // the password must be an md5 hash  eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
    //httpAdminAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"},

    // Serve up the welcome page
    httpStatic: path.join(__dirname,"public"),

    functionGlobalContext: { },

    storageModule: require("./couchstorage")
}

settings.couchAppname = VCAP_APPLICATION['application_name'];

var storageServiceName = process.env.NODE_RED_STORAGE_NAME || settings.couchAppname+":cloudantNoSQLDB";
settings.couchUrl = cfEnv.getService(storageServiceName).credentials.url;
<|endoftext|>


<commit_before>$(function() {

    // 人气切换效果
    $('.shortItem').hover(function(){
        $('.longItem').hide();
        $('.shortItem').show();
        $(this).hide();
        $(this).next().show();
    });

    // 倒计时渲染函数
    var render = function(min, sec, msec, obj) {
        var html = '
揭晓倒计时:
';
        html += '
' + min + '
';
        html += '
:
';
        html += '
' + sec + '
';
        html += '
:
';
        html += '
' + msec + '
';
        obj.html(html);
    }

    // 倒计时渲染结果
    var renderDiv = function(id, data) {
        $('#win' + id + ' .item-body').remove();
        $('#win' + id + ' .item-footer').remove();
        var html = '
';
        html += '
';
        html += '';
        html += '
';
        html += '
';
        html += '
';
        html += '
';
        html += '    ';
        html += '
';
        html += '
';
        html += '
获奖者：'+data.nickname+'
';
        html += '
来自：'+data.area+'
';
        html += '
';
        html += '
';
        html += '
';
        html += '
当前乐淘:'+data.count+'人次
';
        html += '
揭晓时间：'+data.opentime+'
';
        html += '
';
        html += '

';
        html += '

';
        html += '幸运乐淘码:'+data.code+'
';
        html += '查看详情
';

        $('#win' + id + ' .item-head').after(html);
    }

    // 倒计时效果
    $('.countdown').each(function() {
        var obj = $(this);
        var t = obj.attr('endtime');
        var id = obj.attr('phaseId');

        var timer = setInterval(function() {
            var endtime = new Date(t);
            var nowtime = new Date();
            var second = parseInt((endtime.getTime()-nowtime.getTime())/1000);
            var min = parseInt((second/60)%60);
            var sec = parseInt(second%60);
            var msec = nowtime.getMilliseconds();

            if(min < 10) {
                min = '0' + min.toString();
            }

            if(sec < 10) {
                sec = '0' + sec.toString();
            }

            msec = (msec/10).toFixed(0);
            if(msec < 10) {
                msec = '0' + msec.toString();
            } else if(msec == 100) {
                msec = 10;
            }

            if(second <= 0) {
                clearInterval(timer);
                // 切换计算中
                obj.hide();
                obj.parent().next().show();

                var loadTimer = setInterval(function() {
                   // 获取揭晓结果
                   $.ajax({
                        url: RESULT_URL,
                        type: 'get',
                        data: {id:id},
                        dataType:'json',
                        success: function(data) {
                            if(data.status == 'fail') {
                                clearInterval(loadTimer);
                            } else {
                                if(typeof(data.data) != 'undefined') {
                                    renderDiv(id, data.data);
                                    clearInterval(loadTimer);
                                }
                            }
                        }
                   });
                }, 3000);
            } else {
                render(min, sec, msec, obj);
            }

        }, 40);
    });
});
<commit_msg>修改倒计时后样式不一致<commit_after>$(function() {

    // 人气切换效果
    $('.shortItem').hover(function(){
        $('.longItem').hide();
        $('.shortItem').show();
        $(this).hide();
        $(this).next().show();
    });

    // 倒计时渲染函数
    var render = function(min, sec, msec, obj) {
        var html = '
揭晓倒计时:
';
        html += '
' + min + '
';
        html += '
:
';
        html += '
' + sec + '
';
        html += '
:
';
        html += '
' + msec + '
';
        obj.html(html);
    }

    // 倒计时渲染结果
    var renderDiv = function(id, data) {
        $('#win' + id + ' .item-body').remove();
        $('#win' + id + ' .item-footer').remove();
        var html = '
';
        html += '
';
        html += '';
        html += '
';
        html += '
';
        html += '
';
        html += '
';
        html += '    ';
        html += '
';
        html += '
';
        html += '
获奖者：'+data.nickname+'
';
        html += '
来自：'+data.area+'
';
        html += '
';
        html += '
';
        html += '
';
        html += '
当前乐淘:'+data.count+'人次
';
        html += '
揭晓时间：'+data.opentime+'
';
        html += '
';
        html += '

';
        html += '

';
        html += '幸运乐淘码:<s class="r">'+data.code+'</>
';
        html += '查看详情
';

        $('#win' + id).removeClass('active');
        $('#win' + id + ' .item-head').after(html);
    }

    // 倒计时效果
    $('.countdown').each(function() {
        var obj = $(this);
        var t = obj.attr('endtime');
        var id = obj.attr('phaseId');

        var timer = setInterval(function() {
            var endtime = new Date(t);
            var nowtime = new Date();
            var second = parseInt((endtime.getTime()-nowtime.getTime())/1000);
            var min = parseInt((second/60)%60);
            var sec = parseInt(second%60);
            var msec = nowtime.getMilliseconds();

            if(min < 10) {
                min = '0' + min.toString();
            }

            if(sec < 10) {
                sec = '0' + sec.toString();
            }

            msec = (msec/10).toFixed(0);
            if(msec < 10) {
                msec = '0' + msec.toString();
            } else if(msec == 100) {
                msec = 10;
            }

            if(second <= 0) {
                clearInterval(timer);
                // 切换计算中
                obj.hide();
                obj.parent().next().show();

                var loadTimer = setInterval(function() {
                   // 获取揭晓结果
                   $.ajax({
                        url: RESULT_URL,
                        type: 'get',
                        data: {id:id},
                        dataType:'json',
                        success: function(data) {
                            if(data.status == 'fail') {
                                clearInterval(loadTimer);
                            } else {
                                if(typeof(data.data) != 'undefined') {
                                    renderDiv(id, data.data);
                                    clearInterval(loadTimer);
                                }
                            }
                        }
                   });
                }, 3000);
            } else {
                render(min, sec, msec, obj);
            }

        }, 40);
    });
});
<|endoftext|>


<commit_before>// MIT License
// Copyright (C) 2012 EdgeCase
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

var _ = require('underscore');

var Glue = function(target) {
  this.target = target;
  this.resetListeners();
};

Glue.version = '0.5.3'

Glue.eventBus = {}

Glue.prototype.resetListeners = function() {
  this.listeners = {specific: {}, generic: {}};
};

Glue.deepClone = function(obj) {
  return JSON.parse(JSON.stringify(obj));
};

Glue.normalizeKey = function(key) {
  return key.replace(/\s/g, '');
};

Glue.permutateKey = function (key) {
  var keys = [],
      segments = key.split('.');

  _.each(segments, function(segment, i) {
    var k        = _.first(segments, i+1).join('.'),
        regIndex = /\d*(?=\]$)/;

    if (k.match(regIndex)) {
      keys.push({
        specific: k,
        generic:   k.replace(regIndex, ''),
        index:        parseInt(k.match(regIndex)[0])
      });
    }
  });

  return keys;
};

Glue.keysAndOperations = function(ko) {
  if (arguments.length === 0) return [[], []];

  var k = Glue.normalizeKey(ko).split(':'),
      keys = _.isEmpty(k[0]) ? [''] : k[0].split(','),
      operations = _.isEmpty(k[1]) ? [] : k[1].split(',');

  return [keys, operations];
};

// Usage:
// glue.addListener([key(s):operation(s)], [context], callback)

Glue.prototype.addListener = function() {
  var self = this,
      a    = arguments;

  if (a.length === 1) {
    add('*', a[0], this.target);
  } else if (a.length === 2) {
    _.isString(a[0]) ? add(a[0], a[1], this.target) : add('*', a[1], a[0]);
  } else {
    add(a[0], a[2], a[1]);
  }

  function add(k, callback, context) {
    var ko         = Glue.keysAndOperations(k),
        keys       = _.isEqual(ko[0], ['']) ? ['*'] : ko[0],
        operations = ko[1];

    _.each(keys, function(key) {
      var type = key.match(/\[\]$/) ? 'generic' : 'specific';

      self.listeners[type][key] = self.listeners[type][key] || [];

      self.listeners[type][key].push({
        callback: callback, operations: operations, context: context
      });
    });
  }
};

// Usage:
// glue.removeListener((key(s):operation(s)), [context]);
Glue.prototype.removeListener = function() {
  var self = this,
      a    = arguments;

  if(a.length === 0) {
    remove('');
  } else if (a.length === 1) {
    _.isString(a[0]) ? remove(Glue.normalizeKey(a[0])) : remove('', a[0]);
  } else if (a.length === 2) {
    remove(Glue.normalizeKey(a[0]), a[1]);
  }

  function remove(k, context) {
    var ko         = Glue.keysAndOperations(k),
        operations = ko[1],
        keys;

    if (_.isEqual(ko[0], [''])) {
      keys = _.union(_.keys(self.listeners.specific), _.keys(self.listeners.generic));
    } else {
      keys = ko[0];
    }

    _.each(keys, function(key) {
      var type = key.match(/\[\]$/) ? 'generic' : 'specific';

      if(!_.isEmpty(operations)) {
        _.each(self.listeners[type][key], function(listener) {
          listener.operations = _.difference(listener.operations, operations);
        });
      }

      self.listeners[type][key] = _.reject(self.listeners[type][key], function(listener) {
        if (!_.isEmpty(operations) && context) {
          return _.isEmpty(listener.operations) && listener.context === context;
        } else if (context) {
          return listener.context === context;
        } else if (!_.isEmpty(operations)) {
          return _.isEmpty(listener.operations);
        } else {
          return true;
        }
      });

      if (_.isEmpty(self.listeners[type][key])) delete self.listeners[type][key];
    });
  };
};

// Not in the public API.
Glue.prototype.notify = function(operation, key, oldTargetClone, reverse) {
  var self               = this,
      currentTargetClone = Glue.deepClone(this.target);

  _.each(this.listeners.specific, function(listeners, k) {
    var currentValue      = self.get(k),
        currentValueClone = self.get(k, currentTargetClone),
        oldValueClone     = self.get(k, oldTargetClone);

      _.each(listeners, function(listener) {
        invoke(operation, listener, currentValue, currentValueClone, oldValueClone);
     });
  });

  invokeGeneric();

  function invokeGeneric() {
    var keysAndIndices = Glue.permutateKey(key);

    _.each(keysAndIndices, function(keyAndIndex) {
      _.each(self.listeners.generic[keyAndIndex.generic], function(listener) {
        var currentValue      = self.get(keyAndIndex.specific),
            currentValueClone = self.get(keyAndIndex.specific, currentTargetClone),
            oldValueClone     = self.get(keyAndIndex.specific, oldTargetClone);

        invoke(operation, listener, currentValue, currentValueClone, oldValueClone, keyAndIndex.index);
      });
    });

    var affectedGenericChildren = {},
        keyMatcher       = new RegExp("^" + key.replace('[', '\\\[').replace(']', '\\\]'));

    _.each(self.listeners.generic, function(listeners, k) {
      if (k.match(keyMatcher)) affectedGenericChildren[k] = listeners;
    });

    _.each(affectedGenericChildren, function(listeners, k) {
      var base              = k.replace(/\[[^\[]*\]$/, ''),
          currentArray      = self.get(base),
          currentArrayClone = self.get(base, currentTargetClone),
          oldArrayClone     = self.get(base, oldTargetClone),
          maxRange;

      if (oldArrayClone.length > currentArrayClone.length) {
        maxRange = oldArrayClone.length;
      } else {
        maxRange = currentArrayClone.length;
      }

      var range = reverse ? _.range(0, maxRange).reverse() : _.range(0, maxRange);

      _.each(range, function(index) {
        var currentValue      = currentArray[index],
            currentValueClone = currentArrayClone[index],
            oldValueClone     = oldArrayClone[index];

        _.each(listeners, function(listener) {
          invoke(operation, listener, currentValue, currentValueClone, oldValueClone, index);
        });
      });
    });
  };

  function invoke(operation, listener, currentValue, oldValueClone, currentValueClone, index) {
    if (!_.isEqual(currentValueClone, oldValueClone)) {
      var message = {
        operation: operation,
        value: currentValue
      };

      if (!_.isUndefined(index)) message.index = index;

      if (!_.isEmpty(listener.operations)) {
        if (_.include(listener.operations, operation)) callListener(listener, message);
      } else {
        callListener(listener, message);
      }
    }
  };

  function callListener(listener, message) {
    listener.callback.call(listener.context, message);
  };
};

// Not in the public API. It is more performant to access
// values directly through glue.target. However, one should never
// modify the values of a target object obtain directly from
// glue.target.
//
// Usage:
// glue.get([key], [obj]);

Glue.prototype.get = function(key, obj) {
  if (key === '' || key === '*') return obj || this.target;

  var returnVal,
      target = obj || this.target;

  key = Glue.normalizeKey(key);
  key = (_.isArray(target) ? "target" : "target.") + key;

  try {
    returnVal = eval(key);
  } catch(e) {
    returnVal = undefined;
  }
  return returnVal;
};

// Usage:
// glue.set(key, value);
Glue.prototype.set = function(key, value) {
  var oldTargetClone = Glue.deepClone(this.target)
    , lastDot     = key.lastIndexOf(".")
    , lastBracket = key.lastIndexOf("[")
    , index       = lastBracket > lastDot ? lastBracket : lastDot
    , keySuffix   = key.substring(index+1).replace(/\]/g, '');

  var base = this.get(key.substring(0, index));
  base[keySuffix] = value;

  this.notify('set', key, oldTargetClone);

  return this;
};

// Usage
// glue.remove([key]);

Glue.prototype.remove = function(key){
  var oldTargetClone = Glue.deepClone(this.target)
      match = key.match(/\[(\d+)\]$/);

  if (match) {
    var index           = match[1]
      , suffixLastIndex = key.lastIndexOf(match[0]);

    if (suffixLastIndex === 0) {
      removed = this.target.splice(index, 1)[0];
    } else {
      removed = this.get(key.substr(0, suffixLastIndex)).splice(index, 1)[0];
    }
  } else {
    key = key.split('.');

    if (key.length > 1) {
      var top = key.pop();
      removed = this.get(key.join('.'))[top];
      delete this.get(key.join('.'))[top];
    } else {
      removed = this.target[key[0]];
      delete this.target[key[0]];
    }

    key = key.join('.');
  }

  this.notify("remove", key, oldTargetClone);

  return removed;
};

// Usage
// topic.push([key], value);
Glue.prototype.push = function() {
  var oldTargetClone = Glue.deepClone(this.target),
      self = this,
      a = arguments;

  if (a.length === 1) {
    push('', this.target, a[0]);
  } else {
    push(a[0], self.get(a[0]), a[1]);
  }

  function push(key, collection, item) {
    collection.push(item);
    self.notify("push", key, oldTargetClone);
  };

  return this;
};

// Usage
// glue.pop([key]);
Glue.prototype.pop = function(key){
  var oldTargetClone = Glue.deepClone(this.target),
      key = key || '',
      collection = this.get(key),
      value = collection.pop();

  this.notify("pop", key, oldTargetClone);

  return value;
};

// Usage
// glue.insert([key], index, value);
Glue.prototype.insert = function() {
  var oldTargetClone = Glue.deepClone(this.target),
      key = key || '',
      i = 0, a = arguments;

  var key   = a.length < 3 ?  '' : a[i++],
      index = a[i++],
      value = a[i++];

  this.get(key).splice(index, 0, value);
  this.notify('insert', key, oldTargetClone);

  return this;
};

// Usage
// glue.filter([key], filterBy);

Glue.prototype.filter = function() {
  var oldTargetClone = Glue.deepClone(this.target),
      self     = this,
      i        = 0,
      a        = arguments,
      removed  = [],
      indices,

      key      = a.length < 2 ?  '' : a[i++],
      filterBy = a[i++];

  var collection = key === '' ? this.target : self.get(key);

  indices = _.without(_.map(collection, function(value, index) {
    if (!filterBy(value)) return index;
  }), undefined).reverse();

  _.each(indices, function(index) {
    self.get(key).splice(index, 1)[0];
  });

  self.notify("filter", key, oldTargetClone, true);

  return this.get(Glue.baseKey(key));
};

Glue.baseKey = function(key) {
  return key.replace(/\[[^\[]*\]$/, '');
};

Glue.prototype.baseKeyAndSuffix = function(key) {
  var lastDot     = key.lastIndexOf(".")
    , lastBracket = key.lastIndexOf("[")
    , index       = lastBracket > lastDot ? lastBracket : lastDot
    , keySuffix   = key.substring(index+1).replace(/\]/g, '');

  return [this.get(key.substring(0, index)), keySuffix];
};

// Usage
// glue.sort([key], sortBy);

Glue.prototype.sortBy = function() {
  var oldTargetClone = Glue.deepClone(this.target),
      self = this,
      i = 0, a = arguments,
      key    = a.length < 2 ?  '' : a[i++],
      sortBy = a[i++];

  collectionWithIndex = _.map(this.get(key), function(val, index) {
    return [val, index];
  });

  var sortedWithIndex = _.sortBy(collectionWithIndex, function(elem) {
    return sortBy(elem[0]);
  });

  var sorted = _.map(sortedWithIndex, function(elem) { return elem[0] });

  if (key === '') {
    this.target = sorted;
  } else {
    bs = this.baseKeyAndSuffix(key);
    bs[0][bs[1]] = sorted;
  };

  var indices = _.map(sortedWithIndex, function(elem) {
    return elem[1];
  });

  this.notify("filter", key, oldTargetClone, true);

  return sorted;
};

// Usage
// glue.swap(loc1, loc2);
Glue.prototype.swap = function(loc1, loc2) {
  var oldTargetClone = Glue.deepClone(this.target),
      self = this,
      value1 = this.get(loc1),
      value2 = this.get(loc2),
      bs1 = this.baseKeyAndSuffix(loc1),
      bs2 = this.baseKeyAndSuffix(loc2);

  bs1[0][bs1[1]] = value2;
  bs2[0][bs2[1]] = value1;

  _.each(_.uniq(_.union(Glue.baseKey(loc1), Glue.baseKey(loc2))), function(key) {
    self.notify("swap", key, oldTargetClone);
  });

  return this;
};

module.exports = Glue;
<commit_msg>Adding an event bus for all glue instances<commit_after>// MIT License
// Copyright (C) 2012 EdgeCase
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

var _ = require('underscore');

var Glue = function(target) {
  this.target = target;
  this.resetListeners();
  this.objID = Glue.nextObjectID();
};

Glue.version = '0.6.0';

Glue._objID = 0;

Glue.nextObjectID = function() {
  return ++Glue._objID;
};

Glue.events = {};

Glue.prototype.addObserver = function(event, callback){
  if (!_.has(Glue.events, event)) Glue.events[event] = [];

  Glue.events[event].push({
    objID: this.objID,
    callback: callback
  });
};

Glue.prototype.removeObserver = function(event, callback) {
  if (_.has(Glue.events, event)) {
    Glue.events[event] = _.filter(Glue.events[event], function(e) {
      var toFilter = false;

      if (callback) toFilter = e.callback === callback;
      toFilter = e.objID === this.objID;

      return toFilter;
    });
  }
};

Glue.prototype.broadcast = function(event) {
  if (_.has(Glue.events, event)) {
    _.each(Glue.events[event], function(e) {
      e.callback(_.rest(_.toArray(arguments)));
    });
  }
};

Glue.prototype.resetListeners = function() {
  this.listeners = {specific: {}, generic: {}};
};

Glue.deepClone = function(obj) {
  return JSON.parse(JSON.stringify(obj));
};

Glue.normalizeKey = function(key) {
  return key.replace(/\s/g, '');
};

Glue.permutateKey = function (key) {
  var keys = [],
      segments = key.split('.');

  _.each(segments, function(segment, i) {
    var k        = _.first(segments, i+1).join('.'),
        regIndex = /\d*(?=\]$)/;

    if (k.match(regIndex)) {
      keys.push({
        specific: k,
        generic:   k.replace(regIndex, ''),
        index:        parseInt(k.match(regIndex)[0])
      });
    }
  });

  return keys;
};

Glue.keysAndOperations = function(ko) {
  if (arguments.length === 0) return [[], []];

  var k = Glue.normalizeKey(ko).split(':'),
      keys = _.isEmpty(k[0]) ? [''] : k[0].split(','),
      operations = _.isEmpty(k[1]) ? [] : k[1].split(',');

  return [keys, operations];
};

// Usage:
// glue.addListener([key(s):operation(s)], [context], callback)

Glue.prototype.addListener = function() {
  var self = this,
      a    = arguments;

  if (a.length === 1) {
    add('*', a[0], this.target);
  } else if (a.length === 2) {
    _.isString(a[0]) ? add(a[0], a[1], this.target) : add('*', a[1], a[0]);
  } else {
    add(a[0], a[2], a[1]);
  }

  function add(k, callback, context) {
    var ko         = Glue.keysAndOperations(k),
        keys       = _.isEqual(ko[0], ['']) ? ['*'] : ko[0],
        operations = ko[1];

    _.each(keys, function(key) {
      var type = key.match(/\[\]$/) ? 'generic' : 'specific';

      self.listeners[type][key] = self.listeners[type][key] || [];

      self.listeners[type][key].push({
        callback: callback, operations: operations, context: context
      });
    });
  }
};

// Usage:
// glue.removeListener((key(s):operation(s)), [context]);
Glue.prototype.removeListener = function() {
  var self = this,
      a    = arguments;

  if(a.length === 0) {
    remove('');
  } else if (a.length === 1) {
    _.isString(a[0]) ? remove(Glue.normalizeKey(a[0])) : remove('', a[0]);
  } else if (a.length === 2) {
    remove(Glue.normalizeKey(a[0]), a[1]);
  }

  function remove(k, context) {
    var ko         = Glue.keysAndOperations(k),
        operations = ko[1],
        keys;

    if (_.isEqual(ko[0], [''])) {
      keys = _.union(_.keys(self.listeners.specific), _.keys(self.listeners.generic));
    } else {
      keys = ko[0];
    }

    _.each(keys, function(key) {
      var type = key.match(/\[\]$/) ? 'generic' : 'specific';

      if(!_.isEmpty(operations)) {
        _.each(self.listeners[type][key], function(listener) {
          listener.operations = _.difference(listener.operations, operations);
        });
      }

      self.listeners[type][key] = _.reject(self.listeners[type][key], function(listener) {
        if (!_.isEmpty(operations) && context) {
          return _.isEmpty(listener.operations) && listener.context === context;
        } else if (context) {
          return listener.context === context;
        } else if (!_.isEmpty(operations)) {
          return _.isEmpty(listener.operations);
        } else {
          return true;
        }
      });

      if (_.isEmpty(self.listeners[type][key])) delete self.listeners[type][key];
    });
  };
};

// Not in the public API.
Glue.prototype.notify = function(operation, key, oldTargetClone, reverse) {
  var self               = this,
      currentTargetClone = Glue.deepClone(this.target);

  _.each(this.listeners.specific, function(listeners, k) {
    var currentValue      = self.get(k),
        currentValueClone = self.get(k, currentTargetClone),
        oldValueClone     = self.get(k, oldTargetClone);

      _.each(listeners, function(listener) {
        invoke(operation, listener, currentValue, currentValueClone, oldValueClone);
     });
  });

  invokeGeneric();

  function invokeGeneric() {
    var keysAndIndices = Glue.permutateKey(key);

    _.each(keysAndIndices, function(keyAndIndex) {
      _.each(self.listeners.generic[keyAndIndex.generic], function(listener) {
        var currentValue      = self.get(keyAndIndex.specific),
            currentValueClone = self.get(keyAndIndex.specific, currentTargetClone),
            oldValueClone     = self.get(keyAndIndex.specific, oldTargetClone);

        invoke(operation, listener, currentValue, currentValueClone, oldValueClone, keyAndIndex.index);
      });
    });

    var affectedGenericChildren = {},
        keyMatcher       = new RegExp("^" + key.replace('[', '\\\[').replace(']', '\\\]'));

    _.each(self.listeners.generic, function(listeners, k) {
      if (k.match(keyMatcher)) affectedGenericChildren[k] = listeners;
    });

    _.each(affectedGenericChildren, function(listeners, k) {
      var base              = k.replace(/\[[^\[]*\]$/, ''),
          currentArray      = self.get(base),
          currentArrayClone = self.get(base, currentTargetClone),
          oldArrayClone     = self.get(base, oldTargetClone),
          maxRange;

      if (oldArrayClone.length > currentArrayClone.length) {
        maxRange = oldArrayClone.length;
      } else {
        maxRange = currentArrayClone.length;
      }

      var range = reverse ? _.range(0, maxRange).reverse() : _.range(0, maxRange);

      _.each(range, function(index) {
        var currentValue      = currentArray[index],
            currentValueClone = currentArrayClone[index],
            oldValueClone     = oldArrayClone[index];

        _.each(listeners, function(listener) {
          invoke(operation, listener, currentValue, currentValueClone, oldValueClone, index);
        });
      });
    });
  };

  function invoke(operation, listener, currentValue, oldValueClone, currentValueClone, index) {
    if (!_.isEqual(currentValueClone, oldValueClone)) {
      var message = {
        operation: operation,
        value: currentValue
      };

      if (!_.isUndefined(index)) message.index = index;

      if (!_.isEmpty(listener.operations)) {
        if (_.include(listener.operations, operation)) callListener(listener, message);
      } else {
        callListener(listener, message);
      }
    }
  };

  function callListener(listener, message) {
    listener.callback.call(listener.context, message);
  };
};

// Not in the public API. It is more performant to access
// values directly through glue.target. However, one should never
// modify the values of a target object obtain directly from
// glue.target.
//
// Usage:
// glue.get([key], [obj]);

Glue.prototype.get = function(key, obj) {
  if (key === '' || key === '*') return obj || this.target;

  var returnVal,
      target = obj || this.target;

  key = Glue.normalizeKey(key);
  key = (_.isArray(target) ? "target" : "target.") + key;

  try {
    returnVal = eval(key);
  } catch(e) {
    returnVal = undefined;
  }
  return returnVal;
};

// Usage:
// glue.set(key, value);
Glue.prototype.set = function(key, value) {
  var oldTargetClone = Glue.deepClone(this.target)
    , lastDot     = key.lastIndexOf(".")
    , lastBracket = key.lastIndexOf("[")
    , index       = lastBracket > lastDot ? lastBracket : lastDot
    , keySuffix   = key.substring(index+1).replace(/\]/g, '');

  var base = this.get(key.substring(0, index));
  base[keySuffix] = value;

  this.notify('set', key, oldTargetClone);

  return this;
};

// Usage
// glue.remove([key]);

Glue.prototype.remove = function(key){
  var oldTargetClone = Glue.deepClone(this.target)
      match = key.match(/\[(\d+)\]$/);

  if (match) {
    var index           = match[1]
      , suffixLastIndex = key.lastIndexOf(match[0]);

    if (suffixLastIndex === 0) {
      removed = this.target.splice(index, 1)[0];
    } else {
      removed = this.get(key.substr(0, suffixLastIndex)).splice(index, 1)[0];
    }
  } else {
    key = key.split('.');

    if (key.length > 1) {
      var top = key.pop();
      removed = this.get(key.join('.'))[top];
      delete this.get(key.join('.'))[top];
    } else {
      removed = this.target[key[0]];
      delete this.target[key[0]];
    }

    key = key.join('.');
  }

  this.notify("remove", key, oldTargetClone);

  return removed;
};

// Usage
// topic.push([key], value);
Glue.prototype.push = function() {
  var oldTargetClone = Glue.deepClone(this.target),
      self = this,
      a = arguments;

  if (a.length === 1) {
    push('', this.target, a[0]);
  } else {
    push(a[0], self.get(a[0]), a[1]);
  }

  function push(key, collection, item) {
    collection.push(item);
    self.notify("push", key, oldTargetClone);
  };

  return this;
};

// Usage
// glue.pop([key]);
Glue.prototype.pop = function(key){
  var oldTargetClone = Glue.deepClone(this.target),
      key = key || '',
      collection = this.get(key),
      value = collection.pop();

  this.notify("pop", key, oldTargetClone);

  return value;
};

// Usage
// glue.insert([key], index, value);
Glue.prototype.insert = function() {
  var oldTargetClone = Glue.deepClone(this.target),
      key = key || '',
      i = 0, a = arguments;

  var key   = a.length < 3 ?  '' : a[i++],
      index = a[i++],
      value = a[i++];

  this.get(key).splice(index, 0, value);
  this.notify('insert', key, oldTargetClone);

  return this;
};

// Usage
// glue.filter([key], filterBy);

Glue.prototype.filter = function() {
  var oldTargetClone = Glue.deepClone(this.target),
      self     = this,
      i        = 0,
      a        = arguments,
      removed  = [],
      indices,

      key      = a.length < 2 ?  '' : a[i++],
      filterBy = a[i++];

  var collection = key === '' ? this.target : self.get(key);

  indices = _.without(_.map(collection, function(value, index) {
    if (!filterBy(value)) return index;
  }), undefined).reverse();

  _.each(indices, function(index) {
    self.get(key).splice(index, 1)[0];
  });

  self.notify("filter", key, oldTargetClone, true);

  return this.get(Glue.baseKey(key));
};

Glue.baseKey = function(key) {
  return key.replace(/\[[^\[]*\]$/, '');
};

Glue.prototype.baseKeyAndSuffix = function(key) {
  var lastDot     = key.lastIndexOf(".")
    , lastBracket = key.lastIndexOf("[")
    , index       = lastBracket > lastDot ? lastBracket : lastDot
    , keySuffix   = key.substring(index+1).replace(/\]/g, '');

  return [this.get(key.substring(0, index)), keySuffix];
};

// Usage
// glue.sort([key], sortBy);

Glue.prototype.sortBy = function() {
  var oldTargetClone = Glue.deepClone(this.target),
      self = this,
      i = 0, a = arguments,
      key    = a.length < 2 ?  '' : a[i++],
      sortBy = a[i++];

  collectionWithIndex = _.map(this.get(key), function(val, index) {
    return [val, index];
  });

  var sortedWithIndex = _.sortBy(collectionWithIndex, function(elem) {
    return sortBy(elem[0]);
  });

  var sorted = _.map(sortedWithIndex, function(elem) { return elem[0] });

  if (key === '') {
    this.target = sorted;
  } else {
    bs = this.baseKeyAndSuffix(key);
    bs[0][bs[1]] = sorted;
  };

  var indices = _.map(sortedWithIndex, function(elem) {
    return elem[1];
  });

  this.notify("filter", key, oldTargetClone, true);

  return sorted;
};

// Usage
// glue.swap(loc1, loc2);
Glue.prototype.swap = function(loc1, loc2) {
  var oldTargetClone = Glue.deepClone(this.target),
      self = this,
      value1 = this.get(loc1),
      value2 = this.get(loc2),
      bs1 = this.baseKeyAndSuffix(loc1),
      bs2 = this.baseKeyAndSuffix(loc2);

  bs1[0][bs1[1]] = value2;
  bs2[0][bs2[1]] = value1;

  _.each(_.uniq(_.union(Glue.baseKey(loc1), Glue.baseKey(loc2))), function(key) {
    self.notify("swap", key, oldTargetClone);
  });

  return this;
};

module.exports = Glue;
<|endoftext|>


<commit_before>let vcGameLoop = Vue.component("game-loop", {
    template: `

{{ title }}

Number of players: {{ playerCount }}

            <game-round :game-id="gameId" @finished="endRound()" v-if="gameState === 'round'"></game-round>
            <round-result :game-id="gameId" v-if="gameState === 'post-round'"></round-result>
            <game-result :game-id="gameId" v-if="gameState === 'post-game'"></game-result>

    `,
    props: ['gameId'],
    data: function(){
        return {
            numRounds: 0,
            isHost: false,
            gameState: "",
            playerCount: 0,
            title: ""
        }
    },
    mounted: function(){
        this.gameRef = firebaseData.games.child(`${this.gameId}`);
        this.gameStateRef = this.gameRef.child("state");
        this.gameDetailsRef = this.gameRef.child("details");
        this.playersRef = this.gameRef.child('players');
        this.roundsRef = this.gameRef.child("rounds");
        this.roundIndexRef = this.roundsRef.child("index");
        this.currentRoundRef = this.roundsRef.child("current");

        this.gameDetailsRef.once("value", (data)=>{
            let details = data.val();
            if(!details){
                return router.push("home");
            }
            this.title = details.title;
            this.numRounds = details.numRounds;
        });

        this.gameStateRef.on("value", (data)=>{
            this.gameState = data.val() || "";
            console.log(this.gameState);
            if(this.gameState === "pre-round"){
                this.roundIndexRef.once("value", (data)=>{
                    let roundIndex = data.val() || -1;
                    roundIndex++;
                    this.roundIndexRef.set(roundIndex);
                });
            }
        });

        this.playersRef.on("value", (data)=>{
            let players = data.val();
            if(!players) return;
            let playerIds = Object.keys(players);
            this.playerCount = playerIds.length;
            this.isHost = players[user.uid].host;
            if(this.isHost){
                if(playerIds.length !== 2) return;
                if(this.gameState === ""){
                    this.currentRoundRef.child("prompterId").once("value", (data)=>{
                        let prompterId = data.val();
                        if(!prompterId){
                            prompterId = playerIds[Math.floor(Math.random() * 2) + 0];
                            this.currentRoundRef.child("prompterId").set(prompterId);
                        }
                    });
                }
                if(this.gameState === "" || this.gameState === "post-round"){
                    let readyCount = 0;
                    playerIds.forEach((key)=>{
                        if(players[key].ready) readyCount++;
                    });
                    if(readyCount == 2){
                        playerIds.forEach((key)=>{
                            this.playersRef.child(`${key}/ready`).set(false);
                        });
                        this.roundsRef.once("value", (data)=>{
                            let rounds = data.val();
                            let roundIndex = rounds.index || 0;
                            let prompterId = rounds.current.prompterId == playerIds[0]
                                ? playerIds[1]
                                : playerIds[0];
                            this.roundsRef.child(roundIndex).set(rounds.current);
                            roundIndex += 1;
                            this.roundsRef.child("index").set(roundIndex);
                            this.roundsRef.child("current").set({prompterId});
                            if(roundIndex > this.numRounds){
                                this.gameStateRef.set("post-game");
                            }else{
                                this.gameStateRef.set("pre-round");
                            }
                        });
                    }
                }
            }
        });

    },
    methods: {
        startGame(){
            if(this.isHost) this.gameStateRef.set("pre-round");
        },
        startRound(){
            this.gameStateRef.set("round");
        },
        endRound(){
            if(this.isHost){
                this.gameStateRef.set("post-round");
            }
        }
    }
});<commit_msg>closing game when two players join<commit_after>let vcGameLoop = Vue.component("game-loop", {
    template: `

{{ title }}

Number of players: {{ playerCount }}

            <game-round :game-id="gameId" @finished="endRound()" v-if="gameState === 'round'"></game-round>
            <round-result :game-id="gameId" v-if="gameState === 'post-round'"></round-result>
            <game-result :game-id="gameId" v-if="gameState === 'post-game'"></game-result>

    `,
    props: ['gameId'],
    data: function(){
        return {
            numRounds: 0,
            isHost: false,
            gameState: "",
            playerCount: 0,
            title: ""
        }
    },
    mounted: function(){
        this.gameRef = firebaseData.games.child(`${this.gameId}`);
        this.gameStateRef = this.gameRef.child("state");
        this.gameDetailsRef = this.gameRef.child("details");
        this.playersRef = this.gameRef.child('players');
        this.roundsRef = this.gameRef.child("rounds");
        this.roundIndexRef = this.roundsRef.child("index");
        this.currentRoundRef = this.roundsRef.child("current");

        this.gameDetailsRef.once("value", (data)=>{
            let details = data.val();
            if(!details){
                return router.push("home");
            }
            this.title = details.title;
            this.numRounds = details.numRounds;
        });

        this.gameStateRef.on("value", (data)=>{
            this.gameState = data.val() || "";
            console.log(this.gameState);
            if(this.gameState === "pre-round"){
                this.roundIndexRef.once("value", (data)=>{
                    let roundIndex = data.val() || -1;
                    roundIndex++;
                    this.roundIndexRef.set(roundIndex);
                });
            }
        });

        this.playersRef.on("value", (data)=>{
            let players = data.val();
            if(!players) return;
            let playerIds = Object.keys(players);
            this.playerCount = playerIds.length;
            if(this.playerCount === 2){
                this.gameRef.child("open").set("false");
            }
            this.isHost = players[user.uid].host;
            if(this.isHost){
                if(playerIds.length !== 2) return;
                if(this.gameState === ""){
                    this.currentRoundRef.child("prompterId").once("value", (data)=>{
                        let prompterId = data.val();
                        if(!prompterId){
                            prompterId = playerIds[Math.floor(Math.random() * 2) + 0];
                            this.currentRoundRef.child("prompterId").set(prompterId);
                        }
                    });
                }
                if(this.gameState === "" || this.gameState === "post-round"){
                    let readyCount = 0;
                    playerIds.forEach((key)=>{
                        if(players[key].ready) readyCount++;
                    });
                    if(readyCount == 2){
                        playerIds.forEach((key)=>{
                            this.playersRef.child(`${key}/ready`).set(false);
                        });
                        this.roundsRef.once("value", (data)=>{
                            let rounds = data.val();
                            let roundIndex = rounds.index || 0;
                            let prompterId = rounds.current.prompterId == playerIds[0]
                                ? playerIds[1]
                                : playerIds[0];
                            this.roundsRef.child(roundIndex).set(rounds.current);
                            roundIndex += 1;
                            this.roundsRef.child("index").set(roundIndex);
                            this.roundsRef.child("current").set({prompterId});
                            if(roundIndex > this.numRounds){
                                this.gameStateRef.set("post-game");
                            }else{
                                this.gameStateRef.set("pre-round");
                            }
                        });
                    }
                }
            }
        });

    },
    methods: {
        startGame(){
            if(this.isHost) this.gameStateRef.set("pre-round");
        },
        startRound(){
            this.gameStateRef.set("round");
        },
        endRound(){
            if(this.isHost){
                this.gameStateRef.set("post-round");
            }
        }
    }
});<|endoftext|>


<commit_before>const _ = require('lodash');
const moment = require('moment');
const debug = require('debug')('lib:glue');
const reportDuplicate = require('debug')('lib:glue:duplicate!');
const nconf = require('nconf');
const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'));

const mongo = require('./mongo');
const params = require('./params');

/* these functions are used in:
 *  bin/importfreshsample
 * because it download a random timeline and import in the local db
 *
 * and `parsers/unique` (via lib/parse), because when a requested ID is not found,
 * is downloaded with the function glue.retrive
 *
 * the api is /api/v1/glue/$password/$samplesize
 */

function importer(content) {
    const htmlCleanFields = [ 'savingTime', 'id', 'userId',
        'impressionId', 'timelineId', 'html' ];

    var timeline = content[2];
    timeline.startTime = new Date(content[2].startTime);
    var impressions = _.map(content[0], function(i) {
        i.impressionTime = new Date(i.impressionTime);
        return i;
    });
    var htmls = _.map(content[1], function(h) {
        var clean = _.pick(h, htmlCleanFields);
        clean.savingTime = new Date(clean.savingTime);
        return clean;
    });

    if(!_.size(htmls) || !_.size(impressions)) {
        debug("Found an empty timeline! (%s) nothing to save.",
            content[2].id);
        return [ null, [], [] ];
    }
    debug("Ready with a timeline with %d impressions and %d htmls",
        _.size(impressions), _.size(htmls));

    /* because one writing operation might fail for
     * duplicated Id the operation are separated */
    return [ timeline, impressions, htmls ];
}

function writeTimeline(blob) {
    if(blob[0] && _.get(blob[0], 'id')) {
        return mongo
            .writeOne(nconf.get('schema').timelines, blob[0])
            .catch(duplicatedError)
            .return(blob);
    } else
        throw new Error("Nothing to do here");
}

function writeImpressions(blob) {
    var counter = 0;
    return Promise.map(blob[1], function(impression) {
        return mongo
            .writeOne(nconf.get('schema').impressions, impression)
            .tap(function() { counter++; })
            .catch(duplicatedError);
    }, { concurrency: 1} )
    .tap(function() {
        if(_.size(blob[1])) {
            if(!counter)
                reportDuplicate("timeline already saved");
            else
                debug("Written %d impressions", counter);
        }
    })
    .return(blob);
}

function writeHtmls(blob) {
    return Promise.map(blob[2], function(html) {
        _.unset(html, 'processed');
        /* this hack and updateSupporter, are necessary to make run the test with bin/parserv.js */
        html.savingTime = new Date();
        return mongo
            .writeOne(nconf.get('schema').htmls, html)
            .catch(duplicatedError);
    }, { concurrency: 1} )
    .return(blob);
}

function duplicatedError(error) {
    if(error.code !== 11000) {
        debug("unexpected error?\n%s", error.message);
        console.log(error.stack);
        process.exit(0);
    }
}

function updateSupporter(blob) {
    if(blob[0]) {
        var userId = blob[0].userId;
        return mongo
            .readOne(nconf.get('schema').supporters, { userId: userId })
            .then(function(found) {
                if(!found) found = { userId };
                return _.set(found, 'lastActivity', new Date());
            })
            .then(function(updated) {
                return mongo
                    .upsertOne(nconf.get('schema').supporters, { userId: updated.userId }, updated);
            });
    };
};

function retrive(htmlfilter) {
    const url = ( nconf.get('server') || 'https://testing.tracking.exposed' ) + '/api/v2/debug/html/' + htmlfilter.id;
    debug("Remotely retrive the HTML content (%s)", url);
    return request
        .getAsync(url)
        .then(function(res) {
            return res.body;
        })
        .then(JSON.parse)
        .then(function(x) {
            debug("Importing the HTML %s (%s | %s) impressionOrder %d",
                x.impression.htmlId,
                moment.duration(moment(x.impression.impressionTime) - moment()).humanize(),
                x.timeline.geoip,
                x.impression.impressionOrder
            );
            return [ x.timeline, [ x.impression ] , [ x.html ] ];
        });
};

function writers(blob) {
    debug("Ready to write %d total bytes", _.size(JSON.stringify(blob)));
    return writeTimeline(blob)
        .tap(writeImpressions)
        .tap(updateSupporter)
        .then(writeHtmls)
        .catch(function(error) {
            debug("Impossible to write: %s", error.message);
        });
};

module.exports = {
    importer: importer,
    writers: writers,
    retrive: retrive
};
<commit_msg>aligned glue.js to API v2<commit_after>const _ = require('lodash');
const moment = require('moment');
const debug = require('debug')('lib:glue');
const reportDuplicate = require('debug')('lib:glue:duplicate!');
const nconf = require('nconf');
const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'));

const mongo = require('./mongo');
const params = require('./params');

/* these functions are used in:
 *  bin/importfreshsample
 * because it download a random timeline and import in the local db
 *
 * and `parsers/unique` (via lib/parse), because when a requested ID is not found,
 * is downloaded with the function glue.retrive
 *
 * the api is /api/v1/glue/$password/$samplesize
 */

function importer(content) {
    const htmlCleanFields = [ 'savingTime', 'id', 'userId',
        'impressionId', 'timelineId', 'html' ];

    var timeline = content[2];
    timeline.startTime = new Date(content[2].startTime);
    var impressions = _.map(content[0], function(i) {
        i.impressionTime = new Date(i.impressionTime);
        return i;
    });
    var htmls = _.map(content[1], function(h) {
        var clean = _.pick(h, htmlCleanFields);
        clean.savingTime = new Date(clean.savingTime);
        return clean;
    });

    if(!_.size(htmls) || !_.size(impressions)) {
        debug("Found an empty timeline! (%s) nothing to save.",
            content[2].id);
        return [ null, [], [] ];
    }
    debug("Ready with a timeline with %d impressions and %d htmls",
        _.size(impressions), _.size(htmls));

    /* because one writing operation might fail for
     * duplicated Id the operation are separated */
    return [ timeline, impressions, htmls ];
}

function writeTimeline(blob) {
    if(blob[0] && _.get(blob[0], 'id')) {
        return mongo
            .writeOne(nconf.get('schema').timelines, blob[0])
            .catch(duplicatedError)
            .return(blob);
    } else
        throw new Error("Nothing to do here");
}

function writeImpressions(blob) {
    var counter = 0;
    return Promise.map(blob[1], function(impression) {
        return mongo
            .writeOne(nconf.get('schema').impressions, impression)
            .tap(function() { counter++; })
            .catch(duplicatedError);
    }, { concurrency: 1} )
    .tap(function() {
        if(_.size(blob[1])) {
            if(!counter)
                reportDuplicate("timeline already saved");
            else
                debug("Written %d impressions", counter);
        }
    })
    .return(blob);
}

function writeHtmls(blob) {
    return Promise.map(blob[2], function(html) {
        _.unset(html, 'processed');
        /* this hack and updateSupporter, are necessary to make run the test with bin/parserv.js */
        html.savingTime = new Date();
        return mongo
            .writeOne(nconf.get('schema').htmls, html)
            .catch(duplicatedError);
    }, { concurrency: 1} )
    .return(blob);
}

function duplicatedError(error) {
    if(error.code !== 11000) {
        debug("unexpected error?\n%s", error.message);
        console.log(error.stack);
        process.exit(0);
    }
}

function updateSupporter(blob) {
    if(blob[0]) {
        var userId = blob[0].userId;
        return mongo
            .readOne(nconf.get('schema').supporters, { userId: userId })
            .then(function(found) {
                if(!found) found = { userId };
                return _.set(found, 'lastActivity', new Date());
            })
            .then(function(updated) {
                return mongo
                    .upsertOne(nconf.get('schema').supporters, { userId: updated.userId }, updated);
            });
    };
};

function retrive(htmlfilter) {
    const url = ( nconf.get('server') || 'https://facebook.tracking.exposed' ) + '/api/v2/debug/html/' + htmlfilter.id;
    debug("Remotely retrive the HTML content (%s)", url);
    return request
        .getAsync(url)
        .then(function(res) {
            return res.body;
        })
        .then(JSON.parse)
        .then(function(x) {
            debug("Importing the HTML %s (%s | %s) impressionOrder %d",
                x.impression.htmlId,
                moment.duration(moment(x.impression.impressionTime) - moment()).humanize(),
                x.timeline.geoip,
                x.impression.impressionOrder
            );
            return [ x.timeline, [ x.impression ] , [ x.html ] ];
        });
};

function writers(blob) {
    debug("Ready to write %d total bytes", _.size(JSON.stringify(blob)));
    return writeTimeline(blob)
        .tap(writeImpressions)
        .tap(updateSupporter)
        .then(writeHtmls)
        .catch(function(error) {
            debug("Impossible to write: %s", error.message);
        });
};

module.exports = {
    importer: importer,
    writers: writers,
    retrive: retrive
};
<|endoftext|>


<commit_before>/**
 * Alphagov Locator jQuery plugin
 * @name locator-0.1.js
 * @author Matt Patterson
 * @version 0.1
 * @date March 23, 2011
 * @category jQuery plugin
 */
(function($) {
  /**
   * $ is an alias to jQuery object
   */
  $.fn.locator = function(settings) {
    var locator_form = this,
        ask_ui = locator_form.find('.ask_location'),
        locating_ui = locator_form.find('.finding_location'),
        found_ui = locator_form.find('.found_location'),
        all_ui = ask_ui.add(locating_ui).add(found_ui),
        geolocate_ui;

    /* Helper functions */
    var setup_geolocation_api_ui = function() {
      return $('
or locate me automatically
').appendTo(ask_ui);
    }
    var show_ui = function(ui_to_show) {
      all_ui.addClass('hidden');
      ui_to_show.removeClass('hidden');
    }
    var update_geo_labels = function(geo_data) {
      found_ui.find('h3').text(geo_data.locality);
      found_ui.find('a').text('Not in ' + geo_data.locality + '?');
    }
    var dispatch_location = function(response_data) {
      if (response_data.current_location.lat != '0.0') {
        update_geo_labels(response_data.current_location);
        show_ui(found_ui);
        $(document).trigger('location-changed', response_data);
      } else {
        if (ask_ui.find('.error-response').length == 0) {
          ask_ui.prepend('

');
        }
        ask_ui.find('.error-response').text("Sorry, we couldn't find a match for that postcode. Please check you entered it correctly.  If the postcode was correct, try the Automatically Locate Me button.");
        show_ui(ask_ui);
      }
    }

    /* Locator setup */
    found_ui.find('a').click(function (e) {
      locator_form.find('input[name=lat]').val('');
      locator_form.find('input[name=lon]').val('');
      found_ui.find('h3').text('');
      show_ui(ask_ui);
      $(document).trigger('location-removed');
      e.preventDefault();
    });
    if (navigator.geolocation) {
      var geolocate_ui = setup_geolocation_api_ui();
      geolocate_ui.bind('location-started', function () {
        show_ui(locating_ui);
      });
      geolocate_ui.bind('location-failed', function () {
        $(this).text('We were not able to locate you.');
        show_ui(ask_ui);
      });
      geolocate_ui.bind('location-completed', function (event, details) {
        locator_form.find('input[name=lat]').val(details.lat);
        locator_form.find('input[name=lon]').val(details.lon);
        locator_form.trigger('submit');
      });
      geolocate_ui.find('a').click(function (e) {
        var parent_element = $(this).closest('.locate-me');

        geolocate_ui.trigger('location-started');
        browserSupportFlag = true;
        navigator.geolocation.getCurrentPosition(
          function(position) {
            var new_location = {lat: position.coords.latitude, lon: position.coords.longitude};
            geolocate_ui.trigger('location-completed', new_location)
          },
          function() {
            geolocate_ui.trigger('location-failed')
          }
        );

        e.preventDefault();
        // return false;
      });
    }
    locator_form.submit(function(e) {
      $.getJSON(this.action, $(this).serialize(), dispatch_location);
      show_ui(locating_ui);
      e.preventDefault();
    });
  }
})(jQuery);

$(function() {
  $('#large-locator-form').locator();
});
<commit_msg>POST to /locator.json rather than GET<commit_after>/**
 * Alphagov Locator jQuery plugin
 * @name locator-0.1.js
 * @author Matt Patterson
 * @version 0.1
 * @date March 23, 2011
 * @category jQuery plugin
 */
(function($) {
  /**
   * $ is an alias to jQuery object
   */
  $.fn.locator = function(settings) {
    var locator_form = this,
        ask_ui = locator_form.find('.ask_location'),
        locating_ui = locator_form.find('.finding_location'),
        found_ui = locator_form.find('.found_location'),
        all_ui = ask_ui.add(locating_ui).add(found_ui),
        geolocate_ui;

    /* Helper functions */
    var setup_geolocation_api_ui = function() {
      return $('
or locate me automatically
').appendTo(ask_ui);
    }
    var show_ui = function(ui_to_show) {
      all_ui.addClass('hidden');
      ui_to_show.removeClass('hidden');
    }
    var update_geo_labels = function(geo_data) {
      found_ui.find('h3').text(geo_data.locality);
      found_ui.find('a').text('Not in ' + geo_data.locality + '?');
    }
    var dispatch_location = function(response_data) {
      if (response_data.current_location.lat != '0.0') {
        update_geo_labels(response_data.current_location);
        show_ui(found_ui);
        $(document).trigger('location-changed', response_data);
      } else {
        if (ask_ui.find('.error-response').length == 0) {
          ask_ui.prepend('

');
        }
        ask_ui.find('.error-response').text("Sorry, we couldn't find a match for that postcode. Please check you entered it correctly.  If the postcode was correct, try the Automatically Locate Me button.");
        show_ui(ask_ui);
      }
    }

    /* Locator setup */
    found_ui.find('a').click(function (e) {
      locator_form.find('input[name=lat]').val('');
      locator_form.find('input[name=lon]').val('');
      found_ui.find('h3').text('');
      show_ui(ask_ui);
      $(document).trigger('location-removed');
      e.preventDefault();
    });
    if (navigator.geolocation) {
      var geolocate_ui = setup_geolocation_api_ui();
      geolocate_ui.bind('location-started', function () {
        show_ui(locating_ui);
      });
      geolocate_ui.bind('location-failed', function () {
        $(this).text('We were not able to locate you.');
        show_ui(ask_ui);
      });
      geolocate_ui.bind('location-completed', function (event, details) {
        locator_form.find('input[name=lat]').val(details.lat);
        locator_form.find('input[name=lon]').val(details.lon);
        locator_form.trigger('submit');
      });
      geolocate_ui.find('a').click(function (e) {
        var parent_element = $(this).closest('.locate-me');

        geolocate_ui.trigger('location-started');
        browserSupportFlag = true;
        navigator.geolocation.getCurrentPosition(
          function(position) {
            var new_location = {lat: position.coords.latitude, lon: position.coords.longitude};
            geolocate_ui.trigger('location-completed', new_location)
          },
          function() {
            geolocate_ui.trigger('location-failed')
          }
        );

        e.preventDefault();
        // return false;
      });
    }
    locator_form.submit(function(e) {
      $.post(this.action, $(this).serialize(), dispatch_location, 'json');
      show_ui(locating_ui);
      e.preventDefault();
    });
  }
})(jQuery);

$(function() {
  $('#large-locator-form').locator();
});
<|endoftext|>


<commit_before>var hive		= exports = module.exports = {};
var _			= require('underscore');
hive.Model 	    = require('./model');
hive.File	    = require('./file');
hive.Dir	    = require('./dir');
hive.Query	    = require('./query');
hive.Http	    = require('./http');
hive.Controller = require('./controller');
hive.log 	    = require('./util/console').log;
hive.config     = {
	template: 'haml',
	debug: true
};

var fs = require('fs');
require('./util/cli');

hive.init = function(path) {

	// load config
	var config = new hive.File({path: path + '/config.json'});
	config.bind('success', function() {
		var data = config.get('data');
		if(data) {
			var json = JSON.parse(data, false);
			hive.config = _.extend(hive.config, json);
		}
		if(hive.config.debug) {
			console.log('Config:');
			console.log(hive.config);
		}
		init(path);
	});
	config.bind('error', function() {
		init(path);
	});
	config.fetch();

}

//Start the magic
function init(path) {

	hive.sync = require('./sync');

	cli.clear();
	cli.color('cyan')
	.write(hiveART)
	.color('white');
	try {
		load('views',       path, null, true);
		load('models',      path);
		load('queries',     path);
		load('controllers', path);
	} catch(e) { return; }
	cli
	.write('[')
	.color('green')
	.write('All Hive files loaded!')
	.color('white')
	.write(']\r\n\r\n');
	hive.app.listen(hive.config.port || 3000);
	cli
	.write('[')
	.color('green')
	.write('Hive listening at http://localhost:3000')
	.color('white')
	.write(']\r\n\r\n');
}

//Load all files of type at path
function load(type, path, target, refOnly) {
	target = target || hive;
	target[type] = {};
	var files,
		path = path + '/' + type;
	try {
		files = fs.readdirSync(path);
		files.forEach(function(file) {
			var name = file.replace('.js', '').replace('.haml', ''),
				isDir = name == file;
			try {
				if(isDir) {
					load(file, path, target[type], refOnly);
				} else {
					refOnly
						?
						target[type][name] = {}
						:
						target[type][name] = require(path + '/' + file);
					target[type][name]._name = name;
				}
			} catch(e) {
				cli.clear()
				.color('red')
				.write('\r\nError\r\n')
				.color('white')
				.write('An error has occured while loading Hive ')
				.color('cyan')
				.write(type)
				.color('white')
				.write('\r\n')
				.write('Hive could not load ')
				.color('red')
				.write(file)
				.color('white')
				.write(' located at \r\n')
				.color('yellow')
				.write(path + '/' + file)
				.color('red')
				.write('\r\n\r\nReason\r\n')
				.color('white');
				hive.log(e.stack.toString());
				cli
				.confirm('\r\nDo you want to open this file in Textmate? y/n', function(answer) {
					if(answer) cli.exec('mate ' + path + '/' + file);
				});
				throw 'Init failed';
				return false;
			}
			cli.write('[')
			.color('cyan')
			.write(type)
			.color('white')
			.write(']')
			.fwd(20 - type.length)
			.write('Loaded ')
			.color('green')
			.write(name)
			.color('white')
			.write('!\r\n');
		});
	} catch(e) {
		if(e == 'Init failed') throw 'Init failed'
	}
}

var hiveART = ''
+ ' _   _         \r\n'
+ '| |_|_|_ _ ___ \r\n'
+ '|   | | | | -_|\r\n'
+ '|_|_|_|\\_/|___|\r\n'
+ '\r\n'

<commit_msg>Added host, port config<commit_after>var hive		= exports = module.exports = {};
var _			= require('underscore');
hive.Model 	    = require('./model');
hive.File	    = require('./file');
hive.Dir	    = require('./dir');
hive.Query	    = require('./query');
hive.Http	    = require('./http');
hive.Controller = require('./controller');
hive.log 	    = require('./util/console').log;
hive.config     = {
	template: 'haml',
	debug: true,
	port: 3000,
	host: 'localhost'
};

var fs = require('fs');
require('./util/cli');

hive.init = function(path) {

	// load config
	var config = new hive.File({path: path + '/config.json'});
	config.bind('success', function() {
		var data = config.get('data');
		if(data) {
			var json = JSON.parse(data, false);
			hive.config = _.extend(hive.config, json);
		}
		if(hive.config.debug) {
			console.log('Config:');
			console.log(hive.config);
		}
		init(path);
	});
	config.bind('error', function() {
		init(path);
	});
	config.fetch();

}

//Start the magic
function init(path) {

	hive.sync = require('./sync');

	cli.clear();
	cli.color('cyan')
	.write(hiveART)
	.color('white');
	try {
		load('views',       path, null, true);
		load('models',      path);
		load('queries',     path);
		load('controllers', path);
	} catch(e) { return; }
	cli
	.write('[')
	.color('green')
	.write('All Hive files loaded!')
	.color('white')
	.write(']\r\n\r\n');
	hive.app.listen(hive.config.port);
	cli
	.write('[')
	.color('cyan')
	.write('Hive is listening at ')
	.color('green')
	.write('http://' + hive.config.host + ':' + hive.config.port)
	.color('white')
	.write(']\r\n\r\n');
}

//Load all files of type at path
function load(type, path, target, refOnly) {
	target = target || hive;
	target[type] = {};
	var files,
		path = path + '/' + type;
	try {
		files = fs.readdirSync(path);
		files.forEach(function(file) {
			var name = file.replace('.js', '').replace('.haml', ''),
				isDir = name == file;
			try {
				if(isDir) {
					load(file, path, target[type], refOnly);
				} else {
					refOnly
						?
						target[type][name] = {}
						:
						target[type][name] = require(path + '/' + file);
					target[type][name]._name = name;
				}
			} catch(e) {
				cli.clear()
				.color('red')
				.write('\r\nError\r\n')
				.color('white')
				.write('An error has occured while loading Hive ')
				.color('cyan')
				.write(type)
				.color('white')
				.write('\r\n')
				.write('Hive could not load ')
				.color('red')
				.write(file)
				.color('white')
				.write(' located at \r\n')
				.color('yellow')
				.write(path + '/' + file)
				.color('red')
				.write('\r\n\r\nReason\r\n')
				.color('white');
				hive.log(e.stack.toString());
				cli
				.confirm('\r\nDo you want to open this file in Textmate? y/n', function(answer) {
					if(answer) cli.exec('mate ' + path + '/' + file);
				});
				throw 'Init failed';
				return false;
			}
			cli.write('[')
			.color('cyan')
			.write(type)
			.color('white')
			.write(']')
			.fwd(20 - type.length)
			.write('Loaded ')
			.color('green')
			.write(name)
			.color('white')
			.write('!\r\n');
		});
	} catch(e) {
		if(e == 'Init failed') throw 'Init failed'
	}
}

var hiveART = ''
+ ' _   _         \r\n'
+ '| |_|_|_ _ ___ \r\n'
+ '|   | | | | -_|\r\n'
+ '|_|_|_|\\_/|___|\r\n'
+ '\r\n'

<|endoftext|>


<commit_before>describe("About Mutability", function() {

  it("should expect object properties to be public and mutable", function () {
    var aPerson = {firstname: "John", lastname: "Smith" };
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe(FILL_ME_IN);
  });

  it("should understand that constructed properties are public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    var aPerson = new Person ("John", "Smith");
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe(FILL_ME_IN);
  });

  it("should expect prototype properties to be public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    Person.prototype.getFullName = function () {
      return this.firstname + " " + this.lastname;
    };

    var aPerson = new Person ("John", "Smith");
    expect(aPerson.getFullName()).toBe(FILL_ME_IN);

    aPerson.getFullName = function () {
      return this.lastname + ", " + this.firstname;
    };

    expect(aPerson.getFullName()).toBe(FILL_ME_IN);
  });

  it("should know that variables inside a constructor and constructor args are private", function () {
    function Person(firstname, lastname)
    {
      var fullName = firstname + " " + lastname;

      this.getFirstName = function () { return firstname; };
      this.getLastName = function () { return lastname; };
      this.getFullName = function () { return fullName; };
    }
    var aPerson = new Person ("John", "Smith");

    aPerson.firstname = "Penny";
    aPerson.lastname = "Andrews";
    aPerson.fullName = "Penny Andrews";

    expect(aPerson.getFirstName()).toBe(FILL_ME_IN);
    expect(aPerson.getLastName()).toBe(FILL_ME_IN);
    expect(aPerson.getFullName()).toBe(FILL_ME_IN);

    aPerson.getFullName = function () {
      return aPerson.lastname + ", " + aPerson.firstname;
    };

    expect(aPerson.getFullName()).toBe(FILL_ME_IN);
  });

});
<commit_msg>COMPLETE: AboutMutability<commit_after>describe("About Mutability", function() {

  it("should expect object properties to be public and mutable", function () {
    var aPerson = {firstname: "John", lastname: "Smith" };
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe("Alan");
  });

  it("should understand that constructed properties are public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    var aPerson = new Person ("John", "Smith");
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe("Alan");
  });

  it("should expect prototype properties to be public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    Person.prototype.getFullName = function () {
      return this.firstname + " " + this.lastname;
    };

    var aPerson = new Person ("John", "Smith");
    expect(aPerson.getFullName()).toBe("John Smith");

    aPerson.getFullName = function () {
      return this.lastname + ", " + this.firstname;
    };

    expect(aPerson.getFullName()).toBe("Smith, John");
  });

  it("should know that variables inside a constructor and constructor args are private", function () {
    function Person(firstname, lastname)
    {
      var fullName = firstname + " " + lastname;

      this.getFirstName = function () { return firstname; };
      this.getLastName = function () { return lastname; };
      this.getFullName = function () { return fullName; };
    }
    var aPerson = new Person ("John", "Smith");

    aPerson.firstname = "Penny";
    aPerson.lastname = "Andrews";
    aPerson.fullName = "Penny Andrews";

    expect(aPerson.getFirstName()).toBe("John");
    expect(aPerson.getLastName()).toBe("Smith");
    expect(aPerson.getFullName()).toBe("John Smith");

    aPerson.getFullName = function () {
      return aPerson.lastname + ", " + aPerson.firstname;
    };

    expect(aPerson.getFullName()).toBe("Andrews, Penny");
  });

});
<|endoftext|>