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

  this.actorCanvas = args.actorCanvas;
  this.boardCanvas = args.boardCanvas;
  this.pelletCanvas = args.pelletCanvas;

  this.pac = new Actor({
    context: this.actorCanvas.context,
    startX: 113,
    startY: 212,
    name: "m",
    direction: "right"
  });
  this.blinky = new Ghost({
    context: this.actorCanvas.context,
    direction: "left",
    name: "b",
    startX: 112,
    startY: 116
  });
  this.inky = new Ghost({
    context: this.actorCanvas.context,
    direction: "up",
    mode: "house",
    name: "i",
    startX: 96,
    startY: 139
  });
  this.pinky = new Ghost({
    context: this.actorCanvas.context,
    direction: "right",
    mode: "exitting",
    name: "p",
    startX: 112,
    startY: 139
  });
  this.clyde = new Ghost({
    context: this.actorCanvas.context,
    direction: "down",
    mode: "house",
    name: "c",
    startX: 128,
    startY: 139
  });

  this.drawPellets();
  this.actorCanvas.renderPac(this.pac);

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

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

  setTimeout(function() {
    this.inky.setMode("exitting");
  }.bind(this), INKY_EXIT_DELAY);
  setTimeout(function() {
    this.clyde.setMode("exitting");
  }.bind(this), CLYDE_EXIT_DELAY);
}
GameController.prototype.drawPellets = function() {
  this.pelletCanvas.clearRect({
    x: 0,
    y: 0,
    w: BOARD_WIDTH,
    h: BOARD_HEIGHT
  });
  gameBoard.board.matrix.forEach(function(row, rIndex) {
    row.forEach(function(col, cIndex) {
      if(col == ".") {
        this.pelletCanvas.drawRect({
          x: (8 * cIndex) + 3,
          y: (8 * rIndex) + 27,
          w: 2,
          h: 2
        });
      }
      else if(col == "o") {
        this.pelletCanvas.drawCircle({
          x: (8 * cIndex) + 4,
          y: (8 * rIndex) + 28,
          rad: 4
        });
      }
      else if(col == "-") {
        this.pelletCanvas.drawRect({
          x: 8 * cIndex,
          y: (8 * rIndex) + 29,
          w: 8,
          h: 2
        });
      }
    });
  });
};
GameController.prototype.moveActor = function() {
  this.actorCanvas.clearRect(this.pac.getClearDimensions());
  var coords = {
    x: this.pac.x,
    y: this.pac.y
  }

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

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

  collision = gameBoard.detectCollision(coords, this.pac.direction);
  if(collision == "wall" || collision == "door") {
    clearInterval(this.pacMoveInterval);
    this.pacMoveInterval = false;
  }
  else {
    this.pac.move();
  }
  this.pac.moveTowardCenter();

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

  if(this[ghost].movementMode == "house") {
    if(this[ghost].y + 8 >= HOUSE_BOTTOM || this[ghost].y - 5 <= HOUSE_TOP) {
      this[ghost].direction = oppositeDirection(this[ghost].direction);
    }
  }
  else if(this[ghost].movementMode == "exitting") {
    this[ghost].exitHouse();
  }
  else if(this[ghost].isCentered()) {
    this[ghost].setNextDirection();
  }

  this[ghost].move();
  this.actorCanvas.renderGhost(this[ghost]);
};
GameController.prototype.handleKeyDown = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    if(this.pac.keyStates[keyPressed] === false) {
      this.pac.keyStates[keyPressed] = true;
      if(this.pacMoveInterval === false) {
        this.pacMoveInterval = setInterval(this.moveActor.bind(this), this.pac.speed);
      }
    }
  }
};
GameController.prototype.handleKeyUp = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    this.pac.handleKeyUp(keyPressed);
  }
};
<commit_msg>Replace pac.keyStates in GameController with own prop keyStates<commit_after>var GameController = function(args) {
  this.keyStates = {
    up: false,
    down: false,
    left: false,
    right: false
  }
  this.pacMoveInterval = false;

  this.actorCanvas = args.actorCanvas;
  this.boardCanvas = args.boardCanvas;
  this.pelletCanvas = args.pelletCanvas;

  this.pac = new Actor({
    context: this.actorCanvas.context,
    startX: 113,
    startY: 212,
    name: "m",
    direction: "right"
  });
  this.blinky = new Ghost({
    context: this.actorCanvas.context,
    direction: "left",
    name: "b",
    startX: 112,
    startY: 116
  });
  this.inky = new Ghost({
    context: this.actorCanvas.context,
    direction: "up",
    mode: "house",
    name: "i",
    startX: 96,
    startY: 139
  });
  this.pinky = new Ghost({
    context: this.actorCanvas.context,
    direction: "right",
    mode: "exitting",
    name: "p",
    startX: 112,
    startY: 139
  });
  this.clyde = new Ghost({
    context: this.actorCanvas.context,
    direction: "down",
    mode: "house",
    name: "c",
    startX: 128,
    startY: 139
  });

  this.drawPellets();
  this.actorCanvas.renderPac(this.pac);

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

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

  setTimeout(function() {
    this.inky.setMode("exitting");
  }.bind(this), INKY_EXIT_DELAY);
  setTimeout(function() {
    this.clyde.setMode("exitting");
  }.bind(this), CLYDE_EXIT_DELAY);
}
GameController.prototype.drawPellets = function() {
  this.pelletCanvas.clearRect({
    x: 0,
    y: 0,
    w: BOARD_WIDTH,
    h: BOARD_HEIGHT
  });
  gameBoard.board.matrix.forEach(function(row, rIndex) {
    row.forEach(function(col, cIndex) {
      if(col == ".") {
        this.pelletCanvas.drawRect({
          x: (8 * cIndex) + 3,
          y: (8 * rIndex) + 27,
          w: 2,
          h: 2
        });
      }
      else if(col == "o") {
        this.pelletCanvas.drawCircle({
          x: (8 * cIndex) + 4,
          y: (8 * rIndex) + 28,
          rad: 4
        });
      }
      else if(col == "-") {
        this.pelletCanvas.drawRect({
          x: 8 * cIndex,
          y: (8 * rIndex) + 29,
          w: 8,
          h: 2
        });
      }
    });
  });
};
GameController.prototype.moveActor = function() {
  this.actorCanvas.clearRect(this.pac.getClearDimensions());
  var coords = {
    x: this.pac.x,
    y: this.pac.y
  }

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

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

  collision = gameBoard.detectCollision(coords, this.pac.direction);
  if(collision == "wall" || collision == "door") {
    clearInterval(this.pacMoveInterval);
    this.pacMoveInterval = false;
  }
  else {
    this.pac.move();
  }
  this.pac.moveTowardCenter();

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

  if(this[ghost].movementMode == "house") {
    if(this[ghost].y + 8 >= HOUSE_BOTTOM || this[ghost].y - 5 <= HOUSE_TOP) {
      this[ghost].direction = oppositeDirection(this[ghost].direction);
    }
  }
  else if(this[ghost].movementMode == "exitting") {
    this[ghost].exitHouse();
  }
  else if(this[ghost].isCentered()) {
    this[ghost].setNextDirection();
  }

  this[ghost].move();
  this.actorCanvas.renderGhost(this[ghost]);
};
GameController.prototype.handleKeyDown = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    if(this.keyStates[keyPressed] === false) {
      this.keyStates[keyPressed] = true;
      if(this.pacMoveInterval === false) {
        this.pacMoveInterval = setInterval(this.moveActor.bind(this), this.pac.speed);
      }
    }
  }
};
GameController.prototype.handleKeyUp = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    this.keyStates[keyPressed] = false;
  }
};
<|endoftext|>


<commit_before>/**
 * Experience Sampling event page.
 *
 * This background page handles the various events for registering participants
 * and showing new surveys in response to API events.
 *
 * Participants must fill out both a consent form and a startup survey (with
 * demographics) before they can begin to answer real survey questions.
 */

/**
 * cesp namespace.
 */
var cesp = cesp || {};

cesp.openTabId = -1;

// Settings.
cesp.NOTIFICATION_TITLE = 'Take a Chrome user experience survey!';
cesp.NOTIFICATION_BODY = 'Your feedback makes Chrome better.';
cesp.NOTIFICATION_BUTTON = 'Take survey!';
cesp.NOTIFICATION_CONSENT_LINK = 'What is this?';
cesp.MAX_SURVEYS_PER_DAY = 2;
cesp.ICON_FILE = 'icons/cues_85.png';
cesp.NOTIFICATION_DEFAULT_TIMEOUT = 10;  // minutes
cesp.NOTIFICATION_TAG = 'chromeSurvey';
cesp.SURVEY_COUNT_RESET_ALARM_NAME = 'surveyCountReset';
cesp.NOTIFICATION_ALARM_NAME = 'notificationTimeout';
cesp.UNINSTALL_ALARM_NAME = 'uninstallAlarm';
cesp.READY_FOR_SURVEYS = 'readyForSurveys';
cesp.PARTICIPANT_ID_LOOKUP = 'participantId';

// SETUP

/**
 * A helper method for updating the value in local storage.
 * @param {bool} newState The desired new state for the ready for surveys flag.
 */
function setReadyForSurveysStorageValue(newState) {
  var items = {};
  items[cesp.READY_FOR_SURVEYS] = newState;
  chrome.storage.local.set(items);
}

/**
 * A helper method for updating the value in local storage.
 * @param {int} newCount The desired new survey count value.
 */
function setSurveysShownStorageValue(newCount) {
  var items = {};
  items[cesp.SURVEYS_SHOWN_TODAY] = newCount;
  chrome.storage.local.set(items);
}

/**
 * Sets up basic state for the extension. Called when extension is installed.
 * @param {object} details The details of the chrome.runtime.onInstalled event.
 */
function setupState(details) {
  // We check the event reason because onInstalled can trigger for other
  // reasons (extension or browser update).
  if (details.reason !== 'install') return;

  setReadyForSurveysStorageValue(false);
  // Automatically uninstall the extension after 120 days.
  chrome.alarms.create(cesp.UNINSTALL_ALARM_NAME, {delayInMinutes: 172800});
  // Set the count of surveys shown to 0, and reset it each day at midnight.
  setSurveysShownStorageValue(0);
  var midnight = new Date();
  midnight.setHours(0, 0, 0, 0);
  // Midnight is the last midnight, so we set the alarm for one day from it.
  chrome.alarms.create(cesp.SURVEY_THROTTLE_RESET_ALARM,
      {when: midnight.getTime() + 86400000, periodInMinutes: 1440});
  // Process the pending survey submission queue every 20 minutes.
  chrome.alarms.create(SurveySubmission.QUEUE_ALARM_NAME,
      {delayInMinutes: 1, periodInMinutes: 20});
}

/**
 * Handles the uninstall alarm.
 * @param {Alarm} alarm The alarm object from the onAlarm event.
*/
function handleUninstallAlarm(alarm) {
  if (alarm.name === cesp.UNINSTALL_ALARM_NAME)
    chrome.management.uninstallSelf();
}
chrome.alarms.onAlarm.addListener(handleUninstallAlarm);

/**
 * Resets the count of surveys shown to 0.
 * @param {Alarm} alarm The alarm object from the onAlarm event.
 */
function resetSurveyCount(alarm) {
  if (alarm.name === cesp.SURVEY_THROTTLE_RESET_ALARM)
    setSurveysShownStorageValue(0);
}
chrome.alarms.onAlarm.addListener(resetSurveyCount);

/**
 * Checks whether participant has granted consent and/or completed the
 * demographic survey. If not, get the participant started.
 */
function maybeShowConsentOrSetupSurvey() {
  var setupCallback = function(lookup) {
    if (!lookup || !lookup[constants.SETUP_KEY] ||
        lookup[constants.SETUP_KEY] === constants.SETUP_PENDING) {
      getOperatingSystem().then(function(os) {
        chrome.tabs.create(
            {'url': chrome.extension.getURL('surveys/setup.html?os=' + os)});
      });
    } else if (lookup[constants.SETUP_KEY] === constants.SETUP_COMPLETED) {
      setReadyForSurveysStorageValue(true);
    }
  };
  var consentCallback = function(lookup) {
    if (!lookup || !lookup[constants.CONSENT_KEY] ||
        lookup[constants.CONSENT_KEY] === constants.CONSENT_PENDING) {
      chrome.storage.onChanged.addListener(storageUpdated);
      getOperatingSystem().then(function(os) {
        chrome.tabs.create(
            {'url': chrome.extension.getURL('consent.html?os=' + os)});
      });
    } else if (lookup[constants.CONSENT_KEY] === constants.CONSENT_REJECTED) {
      chrome.management.uninstallSelf();
    } else if (lookup[constants.CONSENT_KEY] === constants.CONSENT_GRANTED) {
      // Someone might have filled out the consent form previously but not
      // filled out the setup survey. Check to see if that's the case.
      chrome.storage.local.get(constants.SETUP_KEY, setupCallback);
    }
  };
  chrome.storage.local.get(constants.CONSENT_KEY, consentCallback);
}

/**
 * Listens for the setup survey submission. When that happens, signals that
 * the experience sampling is now ready to begin.
 * @param {object} changes The changed portions of the database.
 * @param {string} areaName The name of the storage area.
 */
function storageUpdated(changes, areaName) {
  if (changes && changes[constants.SETUP_KEY] &&
      changes[constants.SETUP_KEY].newValue == constants.SETUP_COMPLETED) {
    setReadyForSurveysStorageValue(true);
  }
}

// Performs consent and registration checks on startup and install.
chrome.runtime.onInstalled.addListener(maybeShowConsentOrSetupSurvey);
chrome.runtime.onStartup.addListener(maybeShowConsentOrSetupSurvey);
chrome.runtime.onInstalled.addListener(setupState);

// GETTERS

/**
 * A helper method for getting (or, if necessary, setting) the participant ID.
 * @returns {Promise} A promise that resolves with the participant ID.
 */
function getParticipantId() {
  return new Promise(function(resolve, reject) {
    chrome.storage.local.get(cesp.PARTICIPANT_ID_LOOKUP, function(lookup) {
      if (lookup && lookup[cesp.PARTICIPANT_ID_LOOKUP])
        resolve(lookup[cesp.PARTICIPANT_ID_LOOKUP]);

      var charset =
          "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
      var participantId = '';
      for (var i = 0; i < 100; i++) {
        var rand = Math.floor(Math.random() * charset.length);
        participantId += charset.charAt(rand);
      }
      var items = {};
      items[cesp.PARTICIPANT_ID_LOOKUP] = participantId;
      chrome.storage.local.set(items);
      resolve(participantId);
    });
  });
}

/**
 * A helper method for getting the operating system.
 * @returns {Promise} A promise that resolves with the operating system.
 */
function getOperatingSystem() {
  return new Promise(function(resolve, reject) {
    chrome.runtime.getPlatformInfo(function(platformInfo) {
      resolve(platformInfo.os);
    });
  });
}

// SURVEY HANDLING

/**
 * Clears our existing notification(s).
 * @param {Alarm} alarm The alarm object from the onAlarm event (optional).
 */
function clearNotifications(alarm) {
  if (alarm && alarm.name !== cesp.NOTIFICATION_ALARM_NAME)
    return;
  chrome.notifications.clear(cesp.NOTIFICATION_TAG, function(unused) {});
  chrome.alarms.clear(cesp.NOTIFICATION_ALARM_NAME);
}
// Clear the notification state when the survey times out.
chrome.alarms.onAlarm.addListener(clearNotifications);

/**
 * Creates a new notification to prompt the participant to take an experience
 * sampling survey.
 * @param {object} element The browser element of interest.
 * @param {object} decision The decision the participant made.
 */
function showSurveyNotification(element, decision) {
  var eventType = constants.FindEventType(element['name']);
  switch (eventType) {
    case constants.EventType.SSL_OVERRIDABLE:
    case constants.EventType.SSL_NONOVERRIDABLE:
    case constants.EventType.MALWARE:
    case constants.EventType.PHISHING:
    case constants.EventType.EXTENSION_INSTALL:
    case constants.EventType.EXTENSION_INLINE_INSTALL:
    case constants.EventType.EXTENSION_BUNDLE:
      // Supported events.
      break;
    case constants.EventType.HARMFUL:
    case constants.EventType.SB_OTHER:
    case constants.EventType.DOWNLOAD_MALICIOUS:
    case constants.EventType.DOWNLOAD_DANGEROUS:
    case constants.EventType.DOWNLOAD_DANGER_PROMPT:
    case constants.EventType.EXTENSION_OTHER:
    case constants.EventType.UNKNOWN:
    default:
      // Unsupported events.
      return;
  }
  chrome.storage.local.get(cesp.READY_FOR_SURVEYS, function(items) {
    if (!items[cesp.READY_FOR_SURVEYS]) return;
    chrome.storage.local.get(cesp.SURVEYS_SHOWN_TODAY, function(items) {
      if (items[cesp.SURVEYS_SHOWN_TODAY] >= cesp.MAX_SURVEYS_PER_DAY) {
        return;
      }
      clearNotifications();

      var timePromptShown = new Date();
      var clickHandler = function(notificationId, buttonIndex) {
        if (buttonIndex === 1) {
          chrome.tabs.create({'url': chrome.extension.getURL('consent.html')});
        } else {
          var timePromptClicked = new Date();
          loadSurvey(element, decision, timePromptShown, timePromptClicked);
          clearNotifications();
        }
      };
      var opt = {
        type: 'basic',
        iconUrl: cesp.ICON_FILE,
        title: cesp.NOTIFICATION_TITLE,
        message: cesp.NOTIFICATION_BODY,
        eventTime: Date.now(),
        buttons: [
          {title: cesp.NOTIFICATION_BUTTON},
          {title: cesp.NOTIFICATION_CONSENT_LINK}
        ],
        isClickable: true
      };
      chrome.notifications.create(
          cesp.NOTIFICATION_TAG,
          opt,
          function(id) {
            chrome.alarms.create(
                cesp.NOTIFICATION_ALARM_NAME,
                {delayInMinutes: cesp.NOTIFICATION_DEFAULT_TIMEOUT});
          });
      chrome.notifications.onClicked.addListener(clickHandler);
      chrome.notifications.onButtonClicked.addListener(clickHandler);
      setSurveysShownStorageValue(items[cesp.SURVEYS_SHOWN_TODAY] + 1);
    });
  });
}

/**
 * Creates a new tab with the experience sampling survey page.
 * @param {object} element The browser element of interest.
 * @param {object} decision The decision the participant made.
 * @param {object} timePromptShown Date object of when the survey prompt
 *     notification was shown to the participant.
 * @param {object} timePromptClicked Date object of when the participant
 *     clicked the survey prompt notification.
 */
function loadSurvey(element, decision, timePromptShown, timePromptClicked) {
  chrome.storage.local.get(cesp.READY_FOR_SURVEYS, function(items) {
    if (!items[cesp.READY_FOR_SURVEYS]) return;
    var userDecision = decision['name'];
    if (userDecision !== constants.DecisionType.PROCEED &&
        userDecision !== constants.DecisionType.DENY) {
      return;
    }

    var surveyUrl, visitUrl;
    var eventType = constants.FindEventType(element['name']);
    switch (eventType) {
      case constants.EventType.SSL_OVERRIDABLE:
        surveyUrl = userDecision === constants.DecisionType.PROCEED ?
            constants.SurveyLocation.SSL_OVERRIDABLE_PROCEED :
            constants.SurveyLocation.SSL_OVERRIDABLE_NOPROCEED;
        visitUrl = urlHandler.GetMinimalUrl(element['destination']);
        break;
      case constants.EventType.SSL_NONOVERRIDABLE:
        surveyUrl = constants.SurveyLocation.SSL_NONOVERRIDABLE;
        visitUrl = urlHandler.GetMinimalUrl(element['destination']);
        break;
      case constants.EventType.MALWARE:
        surveyUrl = userDecision === constants.DecisionType.PROCEED ?
            constants.SurveyLocation.MALWARE_PROCEED :
            constants.SurveyLocation.MALWARE_NOPROCEED;
        visitUrl = urlHandler.GetMinimalUrl(element['destination']);
        break;
      case constants.EventType.PHISHING:
        surveyUrl = userDecision === constants.DecisionType.PROCEED ?
            constants.SurveyLocation.PHISHING_PROCEED :
            constants.SurveyLocation.PHISHING_NOPROCEED;
        visitUrl = urlHandler.GetMinimalUrl(element['destination']);
        break;
      case constants.EventType.EXTENSION_INSTALL:
      case constants.EventType.EXTENSION_INLINE_INSTALL:
      case constants.EventType.EXTENSION_BUNDLE:
        surveyUrl = userDecision === constants.DecisionType.PROCEED ?
            constants.SurveyLocation.EXTENSION_PROCEED :
            constants.SurveyLocation.EXTENSION_NOPROCEED;
        break;
      case constants.EventType.HARMFUL:
      case constants.EventType.SB_OTHER:
      case constants.EventType.DOWNLOAD_MALICIOUS:
      case constants.EventType.DOWNLOAD_DANGEROUS:
      case constants.EventType.DOWNLOAD_DANGER_PROMPT:
      case constants.EventType.EXTENSION_OTHER:
        // Don't survey about these.
        return;
      case constants.EventType.UNKNOWN:
        throw new Error('Unknown event type: ' + element['name']);
        return;
    }
    getOperatingSystem().then(function(os) {
      visitUrl = encodeURIComponent(visitUrl);
      var openUrl = 'surveys/survey.html?js=' + surveyUrl + '&url=' + visitUrl
          + '&os=' + os;
      chrome.tabs.create(
          {'url': chrome.extension.getURL(openUrl)},
          function(tab) {
            try {
              chrome.tabs.remove(cesp.openTabId);
            } catch (err) { }
            cesp.openTabId = tab.id;
      });
    });
  });
}

// Trigger the new survey prompt when the participant makes a decision about an
// experience sampling element.
chrome.experienceSamplingPrivate.onDecision.addListener(showSurveyNotification);

/**
 * Handle the submission of a completed survey.
 */
function handleCompletedSurvey(message) {
  getParticipantId().then(function(participantId) {
    var record = new SurveySubmission.SurveyRecord(
        message['survey_type'],
        participantId,
        (new Date),
        message['responses']);
    SurveySubmission.saveSurveyRecord(record);
  });
}
chrome.runtime.onMessage.addListener(handleCompletedSurvey);
<commit_msg>add blank lines back<commit_after>/**
 * Experience Sampling event page.
 *
 * This background page handles the various events for registering participants
 * and showing new surveys in response to API events.
 *
 * Participants must fill out both a consent form and a startup survey (with
 * demographics) before they can begin to answer real survey questions.
 */

/**
 * cesp namespace.
 */
var cesp = cesp || {};

cesp.openTabId = -1;

// Settings.
cesp.NOTIFICATION_TITLE = 'Take a Chrome user experience survey!';
cesp.NOTIFICATION_BODY = 'Your feedback makes Chrome better.';
cesp.NOTIFICATION_BUTTON = 'Take survey!';
cesp.NOTIFICATION_CONSENT_LINK = 'What is this?';
cesp.MAX_SURVEYS_PER_DAY = 2;
cesp.ICON_FILE = 'icons/cues_85.png';
cesp.NOTIFICATION_DEFAULT_TIMEOUT = 10;  // minutes
cesp.NOTIFICATION_TAG = 'chromeSurvey';
cesp.SURVEY_COUNT_RESET_ALARM_NAME = 'surveyCountReset';
cesp.NOTIFICATION_ALARM_NAME = 'notificationTimeout';
cesp.UNINSTALL_ALARM_NAME = 'uninstallAlarm';
cesp.READY_FOR_SURVEYS = 'readyForSurveys';
cesp.PARTICIPANT_ID_LOOKUP = 'participantId';

// SETUP

/**
 * A helper method for updating the value in local storage.
 * @param {bool} newState The desired new state for the ready for surveys flag.
 */
function setReadyForSurveysStorageValue(newState) {
  var items = {};
  items[cesp.READY_FOR_SURVEYS] = newState;
  chrome.storage.local.set(items);
}

/**
 * A helper method for updating the value in local storage.
 * @param {int} newCount The desired new survey count value.
 */
function setSurveysShownStorageValue(newCount) {
  var items = {};
  items[cesp.SURVEYS_SHOWN_TODAY] = newCount;
  chrome.storage.local.set(items);
}

/**
 * Sets up basic state for the extension. Called when extension is installed.
 * @param {object} details The details of the chrome.runtime.onInstalled event.
 */
function setupState(details) {
  // We check the event reason because onInstalled can trigger for other
  // reasons (extension or browser update).
  if (details.reason !== 'install') return;

  setReadyForSurveysStorageValue(false);
  // Automatically uninstall the extension after 120 days.
  chrome.alarms.create(cesp.UNINSTALL_ALARM_NAME, {delayInMinutes: 172800});
  // Set the count of surveys shown to 0, and reset it each day at midnight.
  setSurveysShownStorageValue(0);
  var midnight = new Date();
  midnight.setHours(0, 0, 0, 0);
  // Midnight is the last midnight, so we set the alarm for one day from it.
  chrome.alarms.create(cesp.SURVEY_THROTTLE_RESET_ALARM,
      {when: midnight.getTime() + 86400000, periodInMinutes: 1440});
  // Process the pending survey submission queue every 20 minutes.
  chrome.alarms.create(SurveySubmission.QUEUE_ALARM_NAME,
      {delayInMinutes: 1, periodInMinutes: 20});
}

/**
 * Handles the uninstall alarm.
 * @param {Alarm} alarm The alarm object from the onAlarm event.
*/
function handleUninstallAlarm(alarm) {
  if (alarm.name === cesp.UNINSTALL_ALARM_NAME)
    chrome.management.uninstallSelf();
}
chrome.alarms.onAlarm.addListener(handleUninstallAlarm);

/**
 * Resets the count of surveys shown to 0.
 * @param {Alarm} alarm The alarm object from the onAlarm event.
 */
function resetSurveyCount(alarm) {
  if (alarm.name === cesp.SURVEY_THROTTLE_RESET_ALARM)
    setSurveysShownStorageValue(0);
}
chrome.alarms.onAlarm.addListener(resetSurveyCount);

/**
 * Checks whether participant has granted consent and/or completed the
 * demographic survey. If not, get the participant started.
 */
function maybeShowConsentOrSetupSurvey() {
  var setupCallback = function(lookup) {
    if (!lookup || !lookup[constants.SETUP_KEY] ||
        lookup[constants.SETUP_KEY] === constants.SETUP_PENDING) {
      getOperatingSystem().then(function(os) {
        chrome.tabs.create(
            {'url': chrome.extension.getURL('surveys/setup.html?os=' + os)});
      });
    } else if (lookup[constants.SETUP_KEY] === constants.SETUP_COMPLETED) {
      setReadyForSurveysStorageValue(true);
    }
  };
  var consentCallback = function(lookup) {
    if (!lookup || !lookup[constants.CONSENT_KEY] ||
        lookup[constants.CONSENT_KEY] === constants.CONSENT_PENDING) {
      chrome.storage.onChanged.addListener(storageUpdated);
      getOperatingSystem().then(function(os) {
        chrome.tabs.create(
            {'url': chrome.extension.getURL('consent.html?os=' + os)});
      });
    } else if (lookup[constants.CONSENT_KEY] === constants.CONSENT_REJECTED) {
      chrome.management.uninstallSelf();
    } else if (lookup[constants.CONSENT_KEY] === constants.CONSENT_GRANTED) {
      // Someone might have filled out the consent form previously but not
      // filled out the setup survey. Check to see if that's the case.
      chrome.storage.local.get(constants.SETUP_KEY, setupCallback);
    }
  };
  chrome.storage.local.get(constants.CONSENT_KEY, consentCallback);
}

/**
 * Listens for the setup survey submission. When that happens, signals that
 * the experience sampling is now ready to begin.
 * @param {object} changes The changed portions of the database.
 * @param {string} areaName The name of the storage area.
 */
function storageUpdated(changes, areaName) {
  if (changes && changes[constants.SETUP_KEY] &&
      changes[constants.SETUP_KEY].newValue == constants.SETUP_COMPLETED) {
    setReadyForSurveysStorageValue(true);
  }
}

// Performs consent and registration checks on startup and install.
chrome.runtime.onInstalled.addListener(maybeShowConsentOrSetupSurvey);
chrome.runtime.onStartup.addListener(maybeShowConsentOrSetupSurvey);
chrome.runtime.onInstalled.addListener(setupState);

// GETTERS

/**
 * A helper method for getting (or, if necessary, setting) the participant ID.
 * @returns {Promise} A promise that resolves with the participant ID.
 */
function getParticipantId() {
  return new Promise(function(resolve, reject) {
    chrome.storage.local.get(cesp.PARTICIPANT_ID_LOOKUP, function(lookup) {
      if (lookup && lookup[cesp.PARTICIPANT_ID_LOOKUP])
        resolve(lookup[cesp.PARTICIPANT_ID_LOOKUP]);

      var charset =
          "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
      var participantId = '';
      for (var i = 0; i < 100; i++) {
        var rand = Math.floor(Math.random() * charset.length);
        participantId += charset.charAt(rand);
      }
      var items = {};
      items[cesp.PARTICIPANT_ID_LOOKUP] = participantId;
      chrome.storage.local.set(items);
      resolve(participantId);
    });
  });
}

/**
 * A helper method for getting the operating system.
 * @returns {Promise} A promise that resolves with the operating system.
 */
function getOperatingSystem() {
  return new Promise(function(resolve, reject) {
    chrome.runtime.getPlatformInfo(function(platformInfo) {
      resolve(platformInfo.os);
    });
  });
}

// SURVEY HANDLING

/**
 * Clears our existing notification(s).
 * @param {Alarm} alarm The alarm object from the onAlarm event (optional).
 */
function clearNotifications(alarm) {
  if (alarm && alarm.name !== cesp.NOTIFICATION_ALARM_NAME)
    return;
  chrome.notifications.clear(cesp.NOTIFICATION_TAG, function(unused) {});
  chrome.alarms.clear(cesp.NOTIFICATION_ALARM_NAME);
}
// Clear the notification state when the survey times out.
chrome.alarms.onAlarm.addListener(clearNotifications);

/**
 * Creates a new notification to prompt the participant to take an experience
 * sampling survey.
 * @param {object} element The browser element of interest.
 * @param {object} decision The decision the participant made.
 */
function showSurveyNotification(element, decision) {
  var eventType = constants.FindEventType(element['name']);
  switch (eventType) {
    case constants.EventType.SSL_OVERRIDABLE:
    case constants.EventType.SSL_NONOVERRIDABLE:
    case constants.EventType.MALWARE:
    case constants.EventType.PHISHING:
    case constants.EventType.EXTENSION_INSTALL:
    case constants.EventType.EXTENSION_INLINE_INSTALL:
    case constants.EventType.EXTENSION_BUNDLE:
      // Supported events.
      break;
    case constants.EventType.HARMFUL:
    case constants.EventType.SB_OTHER:
    case constants.EventType.DOWNLOAD_MALICIOUS:
    case constants.EventType.DOWNLOAD_DANGEROUS:
    case constants.EventType.DOWNLOAD_DANGER_PROMPT:
    case constants.EventType.EXTENSION_OTHER:
    case constants.EventType.UNKNOWN:
    default:
      // Unsupported events.
      return;
  }
  chrome.storage.local.get(cesp.READY_FOR_SURVEYS, function(items) {
    if (!items[cesp.READY_FOR_SURVEYS]) return;

    chrome.storage.local.get(cesp.SURVEYS_SHOWN_TODAY, function(items) {
      if (items[cesp.SURVEYS_SHOWN_TODAY] >= cesp.MAX_SURVEYS_PER_DAY) {
        return;
      }

      clearNotifications();

      var timePromptShown = new Date();
      var clickHandler = function(notificationId, buttonIndex) {
        if (buttonIndex === 1) {
          chrome.tabs.create({'url': chrome.extension.getURL('consent.html')});
        } else {
          var timePromptClicked = new Date();
          loadSurvey(element, decision, timePromptShown, timePromptClicked);
          clearNotifications();
        }
      };
      var opt = {
        type: 'basic',
        iconUrl: cesp.ICON_FILE,
        title: cesp.NOTIFICATION_TITLE,
        message: cesp.NOTIFICATION_BODY,
        eventTime: Date.now(),
        buttons: [
          {title: cesp.NOTIFICATION_BUTTON},
          {title: cesp.NOTIFICATION_CONSENT_LINK}
        ],
        isClickable: true
      };
      chrome.notifications.create(
          cesp.NOTIFICATION_TAG,
          opt,
          function(id) {
            chrome.alarms.create(
                cesp.NOTIFICATION_ALARM_NAME,
                {delayInMinutes: cesp.NOTIFICATION_DEFAULT_TIMEOUT});
          });
      chrome.notifications.onClicked.addListener(clickHandler);
      chrome.notifications.onButtonClicked.addListener(clickHandler);
      setSurveysShownStorageValue(items[cesp.SURVEYS_SHOWN_TODAY] + 1);
    });
  });
}

/**
 * Creates a new tab with the experience sampling survey page.
 * @param {object} element The browser element of interest.
 * @param {object} decision The decision the participant made.
 * @param {object} timePromptShown Date object of when the survey prompt
 *     notification was shown to the participant.
 * @param {object} timePromptClicked Date object of when the participant
 *     clicked the survey prompt notification.
 */
function loadSurvey(element, decision, timePromptShown, timePromptClicked) {
  chrome.storage.local.get(cesp.READY_FOR_SURVEYS, function(items) {
    if (!items[cesp.READY_FOR_SURVEYS]) return;
    var userDecision = decision['name'];
    if (userDecision !== constants.DecisionType.PROCEED &&
        userDecision !== constants.DecisionType.DENY) {
      return;
    }

    var surveyUrl, visitUrl;
    var eventType = constants.FindEventType(element['name']);
    switch (eventType) {
      case constants.EventType.SSL_OVERRIDABLE:
        surveyUrl = userDecision === constants.DecisionType.PROCEED ?
            constants.SurveyLocation.SSL_OVERRIDABLE_PROCEED :
            constants.SurveyLocation.SSL_OVERRIDABLE_NOPROCEED;
        visitUrl = urlHandler.GetMinimalUrl(element['destination']);
        break;
      case constants.EventType.SSL_NONOVERRIDABLE:
        surveyUrl = constants.SurveyLocation.SSL_NONOVERRIDABLE;
        visitUrl = urlHandler.GetMinimalUrl(element['destination']);
        break;
      case constants.EventType.MALWARE:
        surveyUrl = userDecision === constants.DecisionType.PROCEED ?
            constants.SurveyLocation.MALWARE_PROCEED :
            constants.SurveyLocation.MALWARE_NOPROCEED;
        visitUrl = urlHandler.GetMinimalUrl(element['destination']);
        break;
      case constants.EventType.PHISHING:
        surveyUrl = userDecision === constants.DecisionType.PROCEED ?
            constants.SurveyLocation.PHISHING_PROCEED :
            constants.SurveyLocation.PHISHING_NOPROCEED;
        visitUrl = urlHandler.GetMinimalUrl(element['destination']);
        break;
      case constants.EventType.EXTENSION_INSTALL:
      case constants.EventType.EXTENSION_INLINE_INSTALL:
      case constants.EventType.EXTENSION_BUNDLE:
        surveyUrl = userDecision === constants.DecisionType.PROCEED ?
            constants.SurveyLocation.EXTENSION_PROCEED :
            constants.SurveyLocation.EXTENSION_NOPROCEED;
        break;
      case constants.EventType.HARMFUL:
      case constants.EventType.SB_OTHER:
      case constants.EventType.DOWNLOAD_MALICIOUS:
      case constants.EventType.DOWNLOAD_DANGEROUS:
      case constants.EventType.DOWNLOAD_DANGER_PROMPT:
      case constants.EventType.EXTENSION_OTHER:
        // Don't survey about these.
        return;
      case constants.EventType.UNKNOWN:
        throw new Error('Unknown event type: ' + element['name']);
        return;
    }
    getOperatingSystem().then(function(os) {
      visitUrl = encodeURIComponent(visitUrl);
      var openUrl = 'surveys/survey.html?js=' + surveyUrl + '&url=' + visitUrl
          + '&os=' + os;
      chrome.tabs.create(
          {'url': chrome.extension.getURL(openUrl)},
          function(tab) {
            try {
              chrome.tabs.remove(cesp.openTabId);
            } catch (err) { }
            cesp.openTabId = tab.id;
      });
    });
  });
}

// Trigger the new survey prompt when the participant makes a decision about an
// experience sampling element.
chrome.experienceSamplingPrivate.onDecision.addListener(showSurveyNotification);

/**
 * Handle the submission of a completed survey.
 */
function handleCompletedSurvey(message) {
  getParticipantId().then(function(participantId) {
    var record = new SurveySubmission.SurveyRecord(
        message['survey_type'],
        participantId,
        (new Date),
        message['responses']);
    SurveySubmission.saveSurveyRecord(record);
  });
}
chrome.runtime.onMessage.addListener(handleCompletedSurvey);
<|endoftext|>


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

  this.actorCanvas = args.actorCanvas;
  this.boardCanvas = args.boardCanvas;
  this.pelletCanvas = args.pelletCanvas;

  this.pac = new Actor({
    context: this.actorCanvas.context,
    startX: 113,
    startY: 212,
    name: "m",
    direction: "right"
  });
  this.blinky = new Ghost({
    context: this.actorCanvas.context,
    direction: "left",
    name: "b",
    startX: 112,
    startY: 116
  });
  this.inky = new Ghost({
    context: this.actorCanvas.context,
    direction: "up",
    mode: "house",
    name: "i",
    startX: 96,
    startY: 139
  });
  this.pinky = new Ghost({
    context: this.actorCanvas.context,
    direction: "right",
    mode: "exitting",
    name: "p",
    startX: 112,
    startY: 139
  });
  this.clyde = new Ghost({
    context: this.actorCanvas.context,
    direction: "down",
    mode: "house",
    name: "c",
    startX: 128,
    startY: 139
  });

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

  this.drawPellets();
  this.boardCanvas.finalizePerPixelRender();
  drawBorders(this.boardCanvas.context);

  this.actorCanvas.renderPac(this.pac);

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

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

  setTimeout(function() {
    this.inky.setMode("exitting");
  }.bind(this), INKY_EXIT_DELAY);
  setTimeout(function() {
    this.clyde.setMode("exitting");
  }.bind(this), CLYDE_EXIT_DELAY);
}
GameController.prototype.drawPellets = function() {
  this.pelletCanvas.clearRect({
    x: 0,
    y: 0,
    w: BOARD_WIDTH,
    h: BOARD_HEIGHT
  });
  this.gameBoard.board.matrix.forEach(function(row, rIndex) {
    row.forEach(function(col, cIndex) {
      if(col == ".") {
        this.pelletCanvas.drawRect({
          x: (8 * cIndex) + 3,
          y: (8 * rIndex) + 27,
          w: 2,
          h: 2
        });
      }
      else if(col == "o") {
        this.pelletCanvas.drawCircle({
          x: (8 * cIndex) + 4,
          y: (8 * rIndex) + 28,
          rad: 4
        });
      }
      else if(col == "-") {
        this.pelletCanvas.drawRect({
          x: 8 * cIndex,
          y: (8 * rIndex) + 29,
          w: 8,
          h: 2
        });
      }
    }.bind(this));
  }.bind(this));
};
GameController.prototype.moveActor = function() {
  this.actorCanvas.clearRect(this.pac.getClearDimensions());
  var coords = {
    x: this.pac.x,
    y: this.pac.y
  }

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

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

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

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

  if(this[ghost].movementMode == "house") {
    if(this[ghost].y + 8 >= HOUSE_BOTTOM || this[ghost].y - 5 <= HOUSE_TOP) {
      this[ghost].direction = oppositeDirection(this[ghost].direction);
    }
  }
  else if(this[ghost].movementMode == "exitting") {
    this[ghost].exitHouse();
    if(this[ghost].movementMode == "scatter") {
      this.setNextDirection(ghost);
    }
  }
  else if(this[ghost].isCentered()) {
    this.setNextDirection(ghost);
  }

  this[ghost].move();
  this.actorCanvas.renderGhost(this[ghost]);
};
GameController.prototype.handleKeyDown = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    if(this.keyStates[keyPressed] === false) {
      this.keyStates[keyPressed] = true;
      if(this.pacMoveInterval === false) {
        this.pacMoveInterval = setInterval(this.moveActor.bind(this), this.pac.speed);
      }
    }
  }
};
GameController.prototype.handleKeyUp = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    this.keyStates[keyPressed] = false;
  }
};
GameController.prototype.setNextDirection = function(ghost) {
  var currentTile = this.gameBoard.convertToTile({
    x: this[ghost].x,
    y: this[ghost].y
  });
  var adjacentTiles = this.gameBoard.getAdjacentTiles({
    x: this[ghost].x,
    y: this[ghost].y
  });
  adjacentTiles[oppositeDirection(this[ghost].direction)] = undefined;

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

  if(nextTile.x < currentTile.x) {
    this[ghost].direction = "left";
  }
  else if(nextTile.x > currentTile.x) {
    this[ghost].direction = "right";
  }
  else if(nextTile.y < currentTile.y) {
    this[ghost].direction = "up";
  }
  else if(nextTile.y > currentTile.y) {
    this[ghost].direction = "down";
  }
};
<commit_msg>Update GameController.moveActor to update actorBoard whenever pac moves<commit_after>var GameController = function(args) {
  this.keyStates = {
    up: false,
    down: false,
    left: false,
    right: false
  }
  this.pacMoveInterval = false;

  this.actorCanvas = args.actorCanvas;
  this.boardCanvas = args.boardCanvas;
  this.pelletCanvas = args.pelletCanvas;

  this.pac = new Actor({
    context: this.actorCanvas.context,
    startX: 113,
    startY: 212,
    name: "m",
    direction: "right"
  });
  this.blinky = new Ghost({
    context: this.actorCanvas.context,
    direction: "left",
    name: "b",
    startX: 112,
    startY: 116
  });
  this.inky = new Ghost({
    context: this.actorCanvas.context,
    direction: "up",
    mode: "house",
    name: "i",
    startX: 96,
    startY: 139
  });
  this.pinky = new Ghost({
    context: this.actorCanvas.context,
    direction: "right",
    mode: "exitting",
    name: "p",
    startX: 112,
    startY: 139
  });
  this.clyde = new Ghost({
    context: this.actorCanvas.context,
    direction: "down",
    mode: "house",
    name: "c",
    startX: 128,
    startY: 139
  });

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

  this.drawPellets();
  this.boardCanvas.finalizePerPixelRender();
  drawBorders(this.boardCanvas.context);

  this.actorCanvas.renderPac(this.pac);

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

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

  setTimeout(function() {
    this.inky.setMode("exitting");
  }.bind(this), INKY_EXIT_DELAY);
  setTimeout(function() {
    this.clyde.setMode("exitting");
  }.bind(this), CLYDE_EXIT_DELAY);
}
GameController.prototype.drawPellets = function() {
  this.pelletCanvas.clearRect({
    x: 0,
    y: 0,
    w: BOARD_WIDTH,
    h: BOARD_HEIGHT
  });
  this.gameBoard.board.matrix.forEach(function(row, rIndex) {
    row.forEach(function(col, cIndex) {
      if(col == ".") {
        this.pelletCanvas.drawRect({
          x: (8 * cIndex) + 3,
          y: (8 * rIndex) + 27,
          w: 2,
          h: 2
        });
      }
      else if(col == "o") {
        this.pelletCanvas.drawCircle({
          x: (8 * cIndex) + 4,
          y: (8 * rIndex) + 28,
          rad: 4
        });
      }
      else if(col == "-") {
        this.pelletCanvas.drawRect({
          x: 8 * cIndex,
          y: (8 * rIndex) + 29,
          w: 8,
          h: 2
        });
      }
    }.bind(this));
  }.bind(this));
};
GameController.prototype.moveActor = function() {
  this.actorCanvas.clearRect(this.pac.getClearDimensions());
  var coords = {
    x: this.pac.x,
    y: this.pac.y
  }

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

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

  collision = this.gameBoard.predictCollision(coords, this.pac.direction);
  if(collision == "wall" || collision == "door") {
    clearInterval(this.pacMoveInterval);
    this.pacMoveInterval = false;
  }
  else {
    var coords = this.actorBoard.find("m");
    this.actorBoard.setCell({
      x: coords.x,
      y: coords.y,
      value: " "
    });
    this.pac.move();
    coords = this.actorBoard.convertToTile({
      x: this.pac.x,
      y: this.pac.y
    });
    this.actorBoard.setCell({
      x: coords.x,
      y: coords.y,
      value: "m"
    });
  }
  this.pac.moveTowardCenter();

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

  if(this[ghost].movementMode == "house") {
    if(this[ghost].y + 8 >= HOUSE_BOTTOM || this[ghost].y - 5 <= HOUSE_TOP) {
      this[ghost].direction = oppositeDirection(this[ghost].direction);
    }
  }
  else if(this[ghost].movementMode == "exitting") {
    this[ghost].exitHouse();
    if(this[ghost].movementMode == "scatter") {
      this.setNextDirection(ghost);
    }
  }
  else if(this[ghost].isCentered()) {
    this.setNextDirection(ghost);
  }

  this[ghost].move();
  this.actorCanvas.renderGhost(this[ghost]);
};
GameController.prototype.handleKeyDown = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    if(this.keyStates[keyPressed] === false) {
      this.keyStates[keyPressed] = true;
      if(this.pacMoveInterval === false) {
        this.pacMoveInterval = setInterval(this.moveActor.bind(this), this.pac.speed);
      }
    }
  }
};
GameController.prototype.handleKeyUp = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    this.keyStates[keyPressed] = false;
  }
};
GameController.prototype.setNextDirection = function(ghost) {
  var currentTile = this.gameBoard.convertToTile({
    x: this[ghost].x,
    y: this[ghost].y
  });
  var adjacentTiles = this.gameBoard.getAdjacentTiles({
    x: this[ghost].x,
    y: this[ghost].y
  });
  adjacentTiles[oppositeDirection(this[ghost].direction)] = undefined;

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

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


<commit_before>function runGame (game, render, getInput) {
  'use strict';
  var socket = io.connect (document.URL);

  socket.on ('connect', function () {
    var inputId = null;
    var latestInput = game.defaultInput ();
    var storedInputs = [];

    socket.on ('message', function (data) {
      if (data.error) {
        alert (data.error);
        return;
      }
      if (data.notifyInputId) {
        inputId = data.notifyInputId;
        return;
      }

      var newInputTime = data.pastTime + data.knownInputs.length - 1;

      var readInput = getInput ();

      if (readInput) {
        latestInput = readInput;
        socket.json.send ({
          input: readInput,
          time: newInputTime
        });
      }

      storedInputs.unshift ({
        input: latestInput,
        time: newInputTime
      });

      var frame = {};
      frame.state = data.pastState;
      frame.time = data.pastTime;
      while (data.knownInputs.length) {
        var frameInputs = data.knownInputs.pop();
        for (var i = 0; i < storedInputs.length; ++i) {
          if (storedInputs[i].time === frame.time) {
            frameInputs[inputId] = storedInputs[i].input;
            break;
          }
        }
        frame.state = game.step (frameInputs, frame.state);
        frame.time++;
      }

      render (frame.state);

      // TODO Replace magic number with science number
      if (storedInputs.length > 50) storedInputs.pop ();
    });
  });
}

<commit_msg>Added renderLag option<commit_after>function runGame (game, render, getInput, renderLag) {
  'use strict';
  var socket = io.connect (document.URL);

  if (typeof renderLag === 'undefined') renderLag = 0;

  socket.on ('connect', function () {
    var inputId = null;
    var latestInput = game.defaultInput ();
    var storedInputs = [];

    socket.on ('message', function (data) {
      if (data.error) {
        alert (data.error);
        return;
      }
      if (data.notifyInputId) {
        inputId = data.notifyInputId;
        return;
      }

      var newInputTime = data.pastTime + data.knownInputs.length - 1;

      var readInput = getInput ();

      if (readInput) {
        latestInput = readInput;
        socket.json.send ({
          input: readInput,
          time: newInputTime
        });
      }

      storedInputs.unshift ({
        input: latestInput,
        time: newInputTime
      });

      var frame = {};
      frame.state = data.pastState;
      frame.time = data.pastTime;
      while (data.knownInputs.length > renderLag) {
        var frameInputs = data.knownInputs.pop();
        for (var i = 0; i < storedInputs.length; ++i) {
          if (storedInputs[i].time === frame.time) {
            frameInputs[inputId] = storedInputs[i].input;
            break;
          }
        }
        frame.state = game.step (frameInputs, frame.state);
        frame.time++;
      }

      render (frame.state);

      // TODO Replace magic number with science number
      if (storedInputs.length > 50) storedInputs.pop ();
    });
  });
}

<|endoftext|>


<commit_before>/**
 * From https://en.wikipedia.org/wiki/User:Nageh/mathJax/config/TeX-AMS-texvc_HTML.js
 */

MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
  var VERSION = "1.0";

  var MML = MathJax.ElementJax.mml;

  /*
   *  Get an RGB color (a triplet of values between 0 and 255)
   */
  MathJax.Extension["TeX/color"].get_RGB = function (rgb) {
    rgb = rgb.split(/,/); var RGB = "#";
    if (rgb.length !== 3) {this.TEX.Error("RGB colors require 3 decimal numbers")}
    for (var i = 0; i < 3; i++) {
      if (!rgb[i].match(/^(\d{1,3})$/)) {this.TEX.Error("Invalid decimal number")}
      var n = parseInt(rgb[i], 10);
      if (n < 0 || n > 255) {this.TEX.Error("RGB values must be between 0 and 255")}
      n = n.toString(16); if (n.length < 2) {n = "0"+n}
      RGB += n;
    }
    return RGB;
  }

  MathJax.Hub.Insert(MathJax.InputJax.TeX.Definitions,{

    mathchar0mi: {
      // Lowercase Greek letters
      thetasym:     '03B8',  // theta
      koppa:        '03DF',
      stigma:       '03DB',
      coppa:        '03D9',  // archaic koppa

      // Ord symbols
      C:            ['0043',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      cnums:        ['0043',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      Complex:      ['0043',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      N:            ['004E',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      natnums:      ['004E',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      R:            ['0052',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      reals:        ['0052',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      Reals:        ['0052',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      Z:            ['005A',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      sect:         '00A7',  // S
      P:            '00B6',
      alef:         ['2135',{mathvariant: MML.VARIANT.NORMAL}],  // aleph
      alefsym:      ['2135',{mathvariant: MML.VARIANT.NORMAL}],  // aleph
      weierp:       ['2118',{mathvariant: MML.VARIANT.NORMAL}],  // wp
      real:         ['211C',{mathvariant: MML.VARIANT.NORMAL}],  // Re
      part:         ['2202',{mathvariant: MML.VARIANT.NORMAL}],  // partial
      infin:        ['221E',{mathvariant: MML.VARIANT.NORMAL}],  // infty
      empty:        ['2205',{mathvariant: MML.VARIANT.NORMAL}],  // emptyset
      O:            ['2205',{mathvariant: MML.VARIANT.NORMAL}],  // emptyset (but should probably be Swedish O)
      ang:          ['2220',{mathvariant: MML.VARIANT.NORMAL}],  // angle
      exist:        ['2203',{mathvariant: MML.VARIANT.NORMAL}],  // exists
      clubs:        ['2663',{mathvariant: MML.VARIANT.NORMAL}],  // clubsuit
      diamonds:     ['2662',{mathvariant: MML.VARIANT.NORMAL}],  // diamondsuit
      hearts:       ['2661',{mathvariant: MML.VARIANT.NORMAL}],  // heartsuit
      spades:       ['2660',{mathvariant: MML.VARIANT.NORMAL}],  // spadesuit
      textvisiblespace: '2423'
    },

    mathchar0mo: {
      // Binary operators
      and:          '2227',  // land
      or:           '2228',  // lor
      bull:         '2219',  // bullet
      plusmn:       '00B1',  // pm
      sdot:         '22C5',  // cdot

      // Binary relations
      sup:          '2283',  // supset
      sub:          '2282',  // subset
      supe:         '2287',  // supseteq
      sube:         '2286',  // subseteq
      isin:         '2208',  // in

      hAar:               '21D4',  // Leftrightarrow [sic]
      hArr:               '21D4',  // Leftrightarrow
      Harr:               '21D4',  // Leftrightarrow
      Lrarr:              '21D4',  // Leftrightarrow
      lrArr:              '21D4',  // Leftrightarrow
      lArr:               '21D0',  // Leftarrow
      Larr:               '21D0',  // Leftarrow
      rArr:               '21D2',  // Rightarrow
      Rarr:               '21D2',  // Rightarrow
      harr:               '2194',  // leftrightarrow
      lrarr:              '2194',  // leftrightarrow
      larr:               '2190',  // leftarrow
      gets:               '2190',  // leftarrow
      rarr:               '2192',   // rightarrow

      // big ops
      oiint:              ['222F',{texClass: MML.TEXCLASS.OP}],  // not part of texvc but nice to have
      oiiint:             ['2230',{texClass: MML.TEXCLASS.OP}]
    },

    mathchar7: {
      // Uppercase Greek letters
      Alpha:        '0391',
      Beta:         '0392',
      Epsilon:      '0395',
      Zeta:         '0396',
      Eta:          '0397',
      Iota:         '0399',
      Kappa:        '039A',
      Mu:           '039C',
      Nu:           '039D',
      Omicron:      '039F',
      Rho:          '03A1',
      Tau:          '03A4',
      Chi:          '03A7',

      Koppa:        '03DE',
      Stigma:       '03DA',
      Coppa:        '03D8'  // archaic Koppa
    },

    delimiter: {
      '\\uarr':           '2191',  // uparrow
      '\\darr':           '2193',  // downarrow
      '\\Uarr':           '21D1',  // Uparrow
      '\\uArr':           '21D1',  // Uparrow
      '\\Darr':           '21D3',  // Downarrow
      '\\dArr':           '21D3',  // Downarrow
      '\\rang':           '27E9',  // rangle
      '\\lang':           '27E8'   // langle
    },

    macros: {
      sgn:                'NamedFn',
      arccot:             'NamedFn',
      arcsec:             'NamedFn',
      arccsc:             'NamedFn',
      bold:               ['Macro','\\boldsymbol'],  // boldsymbol
      href:               'NamedFn', // disable dangerous command
      style:              'NamedFn', // disable dangerous command
      pagecolor:          ['Macro','',1]  // ignore \pagecolor{}
    }

  });
});

MathJax.Hub.Startup.signal.Post("TeX texvc Ready");

MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/texvc.js");
<commit_msg>MathJax: Remove our RGB extension again, added in MathJax 2.1<commit_after>/**
 * From https://en.wikipedia.org/wiki/User:Nageh/mathJax/config/TeX-AMS-texvc_HTML.js
 */

MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
  var VERSION = "1.0";

  var MML = MathJax.ElementJax.mml;

  MathJax.Hub.Insert(MathJax.InputJax.TeX.Definitions,{

    mathchar0mi: {
      // Lowercase Greek letters
      thetasym:     '03B8',  // theta
      koppa:        '03DF',
      stigma:       '03DB',
      coppa:        '03D9',  // archaic koppa

      // Ord symbols
      C:            ['0043',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      cnums:        ['0043',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      Complex:      ['0043',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      N:            ['004E',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      natnums:      ['004E',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      R:            ['0052',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      reals:        ['0052',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      Reals:        ['0052',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      Z:            ['005A',{mathvariant: MML.VARIANT.DOUBLESTRUCK}],
      sect:         '00A7',  // S
      P:            '00B6',
      alef:         ['2135',{mathvariant: MML.VARIANT.NORMAL}],  // aleph
      alefsym:      ['2135',{mathvariant: MML.VARIANT.NORMAL}],  // aleph
      weierp:       ['2118',{mathvariant: MML.VARIANT.NORMAL}],  // wp
      real:         ['211C',{mathvariant: MML.VARIANT.NORMAL}],  // Re
      part:         ['2202',{mathvariant: MML.VARIANT.NORMAL}],  // partial
      infin:        ['221E',{mathvariant: MML.VARIANT.NORMAL}],  // infty
      empty:        ['2205',{mathvariant: MML.VARIANT.NORMAL}],  // emptyset
      O:            ['2205',{mathvariant: MML.VARIANT.NORMAL}],  // emptyset (but should probably be Swedish O)
      ang:          ['2220',{mathvariant: MML.VARIANT.NORMAL}],  // angle
      exist:        ['2203',{mathvariant: MML.VARIANT.NORMAL}],  // exists
      clubs:        ['2663',{mathvariant: MML.VARIANT.NORMAL}],  // clubsuit
      diamonds:     ['2662',{mathvariant: MML.VARIANT.NORMAL}],  // diamondsuit
      hearts:       ['2661',{mathvariant: MML.VARIANT.NORMAL}],  // heartsuit
      spades:       ['2660',{mathvariant: MML.VARIANT.NORMAL}],  // spadesuit
      textvisiblespace: '2423'
    },

    mathchar0mo: {
      // Binary operators
      and:          '2227',  // land
      or:           '2228',  // lor
      bull:         '2219',  // bullet
      plusmn:       '00B1',  // pm
      sdot:         '22C5',  // cdot

      // Binary relations
      sup:          '2283',  // supset
      sub:          '2282',  // subset
      supe:         '2287',  // supseteq
      sube:         '2286',  // subseteq
      isin:         '2208',  // in

      hAar:               '21D4',  // Leftrightarrow [sic]
      hArr:               '21D4',  // Leftrightarrow
      Harr:               '21D4',  // Leftrightarrow
      Lrarr:              '21D4',  // Leftrightarrow
      lrArr:              '21D4',  // Leftrightarrow
      lArr:               '21D0',  // Leftarrow
      Larr:               '21D0',  // Leftarrow
      rArr:               '21D2',  // Rightarrow
      Rarr:               '21D2',  // Rightarrow
      harr:               '2194',  // leftrightarrow
      lrarr:              '2194',  // leftrightarrow
      larr:               '2190',  // leftarrow
      gets:               '2190',  // leftarrow
      rarr:               '2192',   // rightarrow

      // big ops
      oiint:              ['222F',{texClass: MML.TEXCLASS.OP}],  // not part of texvc but nice to have
      oiiint:             ['2230',{texClass: MML.TEXCLASS.OP}]
    },

    mathchar7: {
      // Uppercase Greek letters
      Alpha:        '0391',
      Beta:         '0392',
      Epsilon:      '0395',
      Zeta:         '0396',
      Eta:          '0397',
      Iota:         '0399',
      Kappa:        '039A',
      Mu:           '039C',
      Nu:           '039D',
      Omicron:      '039F',
      Rho:          '03A1',
      Tau:          '03A4',
      Chi:          '03A7',

      Koppa:        '03DE',
      Stigma:       '03DA',
      Coppa:        '03D8'  // archaic Koppa
    },

    delimiter: {
      '\\uarr':           '2191',  // uparrow
      '\\darr':           '2193',  // downarrow
      '\\Uarr':           '21D1',  // Uparrow
      '\\uArr':           '21D1',  // Uparrow
      '\\Darr':           '21D3',  // Downarrow
      '\\dArr':           '21D3',  // Downarrow
      '\\rang':           '27E9',  // rangle
      '\\lang':           '27E8'   // langle
    },

    macros: {
      sgn:                'NamedFn',
      arccot:             'NamedFn',
      arcsec:             'NamedFn',
      arccsc:             'NamedFn',
      bold:               ['Macro','\\boldsymbol'],  // boldsymbol
      href:               'NamedFn', // disable dangerous command
      style:              'NamedFn', // disable dangerous command
      pagecolor:          ['Macro','',1]  // ignore \pagecolor{}
    }

  });
});

MathJax.Hub.Startup.signal.Post("TeX texvc Ready");

MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/texvc.js");
<|endoftext|>


<commit_before>let jsroot = require("jsroot");
let fs = require("fs");

console.log('JSROOT version', jsroot.version);

// one could specify rendering engine via options
// r3d_img is normal webgl, create svg:image (default)
// r3d_svg uses SVGRenderer, can produce large output

jsroot.httpRequest("https://root.cern/js/files/geom/simple_alice.json.gz", 'object')
      .then(obj => jsroot.MakeSVG({ object: obj, width: 1200, height: 800 /*, option: "r3d_svg" */ }))
      .then(svg => { fs.writeFileSync("alice_geom.svg", svg); console.log(`Create alice_geom.svg size ${svg.length}`); });
<commit_msg>Update geomsvg.js<commit_after>let jsroot = require("jsroot");
let fs = require("fs");

console.log('JSROOT version', jsroot.version);

// one could specify rendering engine via options
// r3d_img is normal webgl, create svg:image (default)
// r3d_svg uses SVGRenderer, can produce large output

jsroot.httpRequest("https://root.cern/js/files/geom/simple_alice.json.gz", 'object')
      .then(obj => jsroot.makeSVG({ object: obj, width: 1200, height: 800 /*, option: "r3d_svg" */ }))
      .then(svg => { fs.writeFileSync("alice_geom.svg", svg); console.log(`Create alice_geom.svg size ${svg.length}`); });
<|endoftext|>


<commit_before>var sys = require("sys")
  , express = require('express')
  , nowjs = require("now")
  , port = parseInt(process.env.VCAP_APP_PORT || process.env.PORT || 8080)
  , Backbone = require('backbone-nowjs');

// express to make life easier
var app = express.createServer();
app.register('.html', require('ejs'));
app.set('views', __dirname + '/views');
app.set('view engine', 'html');
app.set('view options', {layout: false});

app.use(express.static(__dirname + '/'));
app.use(express.static(__dirname + '/node_modules/backbone-nowjs/'));

app.get('/', function(req, res) {
  res.render('index.html');
});

app.listen(port);

var everyone = nowjs.initialize(app);
var todos = new Backbone.Backend();

/*
var Procedures = Backbone.Backend.extend({
  byPatientId: function (model, options, callback) {
    var results = [];
    for (var i = 0, l = this.col.length; i < l; i++) {
      if (this.col[i].patientId == options.id) {
        results.push(this.col[i]);
      }
    }
    callback(results);
  }
});

var procedures = new Procedures();
procedures.create({id:1, type:"outpatient", patientId: 1});
procedures.create({id:2, type:"outpatient", patientId: 1});
*/

Backbone.nowjsConnector.connect(everyone, {todos: todos});
<commit_msg>more cleanup<commit_after>var sys = require("sys")
  , express = require('express')
  , nowjs = require("now")
  , port = parseInt(process.env.VCAP_APP_PORT || process.env.PORT || 8080)
  , Backbone = require('backbone-nowjs');

// express to make life easier
var app = express.createServer();
app.register('.html', require('ejs'));
app.set('views', __dirname + '/views');
app.set('view engine', 'html');
app.set('view options', {layout: false});

app.use(express.static(__dirname + '/'));
app.use(express.static(__dirname + '/node_modules/backbone-nowjs/'));

app.get('/', function(req, res) {
  res.render('index.html');
});

app.listen(port);

var everyone = nowjs.initialize(app);
var todos = new Backbone.Backend();

Backbone.nowjsConnector.connect(everyone, {todos: todos});
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const player = require('./player');

/*
 * Play video file.
 */

if (process.argv.length !== 3) {
    console.log('missing video file parameter');
    return;
}

const file = process.argv[2];

player.playVideo({
    src: path.join(process.cwd(), file),
    opts: 'amino_dump_format=1',
    gfxOpts: {
        //cbx
        //resolution: '1080p@25'
        resolution: '1080p@30'
        //resolution: '1080p@60'
    }
}, (err, video) => {
    //empty
});<commit_msg>60 Hz<commit_after>'use strict';

const path = require('path');
const player = require('./player');

/*
 * Play video file.
 */

if (process.argv.length !== 3) {
    console.log('missing video file parameter');
    return;
}

const file = process.argv[2];

player.playVideo({
    src: path.join(process.cwd(), file),
    opts: 'amino_dump_format=1',
    gfxOpts: {
        //cbx
        //resolution: '1080p@25'
        //resolution: '1080p@30'
        resolution: '1080p@60'
    }
}, (err, video) => {
    //empty
});<|endoftext|>


<commit_before>const HomebrewModel = require('./homebrew.model.js').model;
const router = require('express').Router();
const Moment = require('moment');
//const render = require('vitreum/steps/render');
const templateFn = require('../client/template.js');
const zlib = require('zlib');

process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin';
process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3';

const mw = {
	adminOnly : (req, res, next)=>{
		if(!req.get('authorization')){
			return res
				.set('WWW-Authenticate', 'Basic realm="Authorization Required"')
				.status(401)
				.send('Authorization Required');
		}
		const [username, password] = new Buffer(req.get('authorization').split(' ').pop(), 'base64')
			.toString('ascii')
			.split(':');
		if(process.env.ADMIN_USER === username && process.env.ADMIN_PASS === password){
			return next();
		}
		return res.status(401).send('Access denied');
	}
};

/* Search for brews that are older than 3 days and that are shorter than a tweet */
const junkBrewQuery = HomebrewModel.find({
	'$where'  : 'this.text.length < 140',
	createdAt : {
		$lt : Moment().subtract(30, 'days').toDate()
	}
}).limit(100).maxTime(60000);

/* Search for brews that aren't compressed (missing the compressed text field) */
const uncompressedBrewQuery = HomebrewModel.find({
	'textBin' : null
}).lean().limit(1000).select('_id');

router.get('/admin/cleanup', mw.adminOnly, (req, res)=>{
	junkBrewQuery.exec((err, objs)=>{
		if(err) return res.status(500).send(err);
		return res.json({ count: objs.length });
	});
});
/* Removes all empty brews that are older than 3 days and that are shorter than a tweet */
router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{
	junkBrewQuery.remove().exec((err, objs)=>{
		if(err) return res.status(500).send(err);
		return res.json({ count: objs.length });
	});
});

/* Searches for matching edit or share id, also attempts to partial match */
router.get('/admin/lookup/:id', mw.adminOnly, (req, res, next)=>{
	HomebrewModel.findOne({ $or : [
		{ editId: { '$regex': req.params.id, '$options': 'i' } },
		{ shareId: { '$regex': req.params.id, '$options': 'i' } },
	] }).exec((err, brew)=>{
		return res.json(brew);
	});
});

/* Find 50 brews that aren't compressed yet */
router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{
	uncompressedBrewQuery.exec((err, objs)=>{
		if(err) return res.status(500).send(err);
		objs = objs.map((obj)=>{return obj._id;});
		return res.json({ count: objs.length, ids: objs });
	});
});

/* Compresses the "text" field of a brew to binary */
router.put('/admin/compress/:id', (req, res)=>{
	HomebrewModel.get({ _id: req.params.id })
		.then((brew)=>{
			brew.textBin = zlib.deflateRawSync(brew.text);	// Compress brew text to binary before saving
			brew.text = undefined;							// Delete the non-binary text field since it's not needed anymore

			brew.save((err, obj)=>{
				if(err) throw err;
				return res.status(200).send(obj);
			});
		})
		.catch((err)=>{
			console.log(err);
			return res.status(500).send('Error while saving');
		});
});

router.get('/admin/stats', mw.adminOnly, (req, res)=>{
	HomebrewModel.count({}, (err, count)=>{
		return res.json({
			totalBrews : count
		});
	});
});

router.get('/admin', mw.adminOnly, (req, res)=>{
	templateFn('admin', {
		url : req.originalUrl
	})
		.then((page)=>res.send(page))
		.catch((err)=>res.sendStatus(500));
});

module.exports = router;
<commit_msg>Update admin.api.js<commit_after>const HomebrewModel = require('./homebrew.model.js').model;
const router = require('express').Router();
const Moment = require('moment');
//const render = require('vitreum/steps/render');
const templateFn = require('../client/template.js');
const zlib = require('zlib');

process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin';
process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3';

const mw = {
	adminOnly : (req, res, next)=>{
		if(!req.get('authorization')){
			return res
				.set('WWW-Authenticate', 'Basic realm="Authorization Required"')
				.status(401)
				.send('Authorization Required');
		}
		const [username, password] = new Buffer(req.get('authorization').split(' ').pop(), 'base64')
			.toString('ascii')
			.split(':');
		if(process.env.ADMIN_USER === username && process.env.ADMIN_PASS === password){
			return next();
		}
		return res.status(401).send('Access denied');
	}
};

/* Search for brews that are older than 3 days and that are shorter than a tweet */
const junkBrewQuery = HomebrewModel.find({
	'$where'  : 'this.text.length < 140',
	createdAt : {
		$lt : Moment().subtract(30, 'days').toDate()
	}
}).limit(100).maxTime(60000);

/* Search for brews that aren't compressed (missing the compressed text field) */
const uncompressedBrewQuery = HomebrewModel.find({
	'text' :  { '$exists' : true }
}).lean().limit(1000).select('_id');

router.get('/admin/cleanup', mw.adminOnly, (req, res)=>{
	junkBrewQuery.exec((err, objs)=>{
		if(err) return res.status(500).send(err);
		return res.json({ count: objs.length });
	});
});
/* Removes all empty brews that are older than 3 days and that are shorter than a tweet */
router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{
	junkBrewQuery.remove().exec((err, objs)=>{
		if(err) return res.status(500).send(err);
		return res.json({ count: objs.length });
	});
});

/* Searches for matching edit or share id, also attempts to partial match */
router.get('/admin/lookup/:id', mw.adminOnly, (req, res, next)=>{
	HomebrewModel.findOne({ $or : [
		{ editId: { '$regex': req.params.id, '$options': 'i' } },
		{ shareId: { '$regex': req.params.id, '$options': 'i' } },
	] }).exec((err, brew)=>{
		return res.json(brew);
	});
});

/* Find 50 brews that aren't compressed yet */
router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{
	uncompressedBrewQuery.exec((err, objs)=>{
		if(err) return res.status(500).send(err);
		objs = objs.map((obj)=>{return obj._id;});
		return res.json({ count: objs.length, ids: objs });
	});
});

/* Compresses the "text" field of a brew to binary */
router.put('/admin/compress/:id', (req, res)=>{
	HomebrewModel.get({ _id: req.params.id })
		.then((brew)=>{
			brew.textBin = zlib.deflateRawSync(brew.text);	// Compress brew text to binary before saving
			brew.text = undefined;							// Delete the non-binary text field since it's not needed anymore

			brew.save((err, obj)=>{
				if(err) throw err;
				return res.status(200).send(obj);
			});
		})
		.catch((err)=>{
			console.log(err);
			return res.status(500).send('Error while saving');
		});
});

router.get('/admin/stats', mw.adminOnly, (req, res)=>{
	HomebrewModel.count({}, (err, count)=>{
		return res.json({
			totalBrews : count
		});
	});
});

router.get('/admin', mw.adminOnly, (req, res)=>{
	templateFn('admin', {
		url : req.originalUrl
	})
		.then((page)=>res.send(page))
		.catch((err)=>res.sendStatus(500));
});

module.exports = router;
<|endoftext|>


<commit_before>import express from 'express'
// import Datastore from '@google-cloud/datastore'
import config from '../config'

console.log(config)

console.log(config.GCLOUD_PROJECT)
// const ds = Datastore({
//   projectId: config.get('GCLOUD_PROJECT')
// });

const app = express()

app.get('/', (req, res) => {
  console.info(req.method + ' ' + req.originalUrl)
  res.status(200).send('Soul Distance Server')
})
app.get('/UTC', (req, res) => {
  console.info(`${req.method} ${req.originalUrl}`)
  res.status(200).send(new Date().getTime())
})

app.post('/location/:deviceId', (req, res) => {
  console.info(`${req.method} ${req.originalUrl}`)
  console.info(`latitude:${req.body.latitude} longitude:${req.body.longitude}`)
  res.status(200).end()
})

app.get('/distance', (req, res) => {
  console.info(`${req.method} ${req.originalUrl}`)
  console.info(`local:${req.query.local} remote:${req.query.remote}`)
  res.status(200).json({
    localUpdateUTC: 0,
    remoteUpdateUTC: 0,
    distance: 'Todo'
  })
})

const port=process.env.PORT||80
app.listen(port, () => {
  console.info(`Soul Distance Server listening on port ${port}!`)
})
<commit_msg>standard<commit_after>import express from 'express'
// import Datastore from '@google-cloud/datastore'
import config from '../config'

console.log(config)

console.log(config.GCLOUD_PROJECT)
// const ds = Datastore({
//   projectId: config.get('GCLOUD_PROJECT')
// });

const app = express()

app.get('/', (req, res) => {
  console.info(req.method + ' ' + req.originalUrl)
  res.status(200).send('Soul Distance Server')
})
app.get('/UTC', (req, res) => {
  console.info(`${req.method} ${req.originalUrl}`)
  res.status(200).send(new Date().getTime())
})

app.post('/location/:deviceId', (req, res) => {
  console.info(`${req.method} ${req.originalUrl}`)
  console.info(`latitude:${req.body.latitude} longitude:${req.body.longitude}`)
  res.status(200).end()
})

app.get('/distance', (req, res) => {
  console.info(`${req.method} ${req.originalUrl}`)
  console.info(`local:${req.query.local} remote:${req.query.remote}`)
  res.status(200).json({
    localUpdateUTC: 0,
    remoteUpdateUTC: 0,
    distance: 'Todo'
  })
})

const port = process.env.PORT || 80
app.listen(port, () => {
  console.info(`Soul Distance Server listening on port ${port}!`)
})
<|endoftext|>


<commit_before>
/* todo: use json-rpc (http://www.jsonrpc.org/specification) with websockets notification schema:
 * --> {"jsonrpc": "2.0", "method": "postCreated", "params": [{"message": "blah blah"]}
 */<commit_msg>update json-rpc todo item<commit_after>
/* todo: use json-rpc notification schema (http://www.jsonrpc.org/specification#notification) with websockets to notify connected clients of server-side updates:
 * server --> client : {"jsonrpc": "2.0", "method": "postCreated", "params": [{"id": "123", "from": "John Doe", "message": "blah blah..."]}
 */<|endoftext|>


<commit_before>var Promise = require('bluebird')
var _ = require('lodash')

module.exports = function (context) {
  var Job = context.models.Job,
      Project = context.models.Project,
      items = [];

  return new Promise(function (resolve, reject) {
    Project.find({}, 'name branches.name').exec(function(err, projects) {
      if (err) { reject(err); }

      var command = {
        map: map,
        reduce: reduce,
        finalize: finalize,
        query: {"project": {$in: _.map(projects, 'name')}},
        sort: { 'finished': 1 },
        out: { inline: 1 }
      }

      Job.mapReduce(command, function(err, results) {
        if (err) { reject(err); }
        return resolve(_.map(results,'value'));
      });
    });
  })
}

function map() {
  emit(this.project, {
    branch: this.ref.branch,
    finished: this.finished,
    data: {
      test_exitcode: this.test_exitcode,
      deploy_exitcode: this.deploy_exitcode,
      plugin_data: this.plugin_data
    }
  });
}

function reduce(project, values) {
  var branches = [],
      jobs = {};

  for(var i = 0; i < values.length; i++) {
    if (! jobs[values[i].branch]) { jobs[values[i].branch] = []; }
    jobs[values[i].branch].push(values[i]);
  }

  for (var key in jobs) {
    print(jobs[key]);
    branches.push({
      name: key,
      status: jobs[key].sort(function(x,y) {
        return x.finished == y.finished;
      })[jobs[key].length - 1].data
    });
  }

  return {
    project: project,
    branches: branches
  }
}

function finalize(key, reduced) {
  var result = [];
  for(var i = 0; i < reduced.length; i++) {
    result.push(reduced[i].value);
  }
  return reduced;
}
<commit_msg>don't consider archived jobs<commit_after>var Promise = require('bluebird')
var _ = require('lodash')

module.exports = function (context) {
  var Job = context.models.Job,
      Project = context.models.Project,
      items = [];

  return new Promise(function (resolve, reject) {
    Project.find({}, 'name branches.name').exec(function(err, projects) {
      if (err) { reject(err); }

      var command = {
        map: map,
        reduce: reduce,
        finalize: finalize,
        query: {
          "project": {$in: _.map(projects, 'name')},
          "archived": {$exists: false}
        },
        sort: { 'finished': 1 },
        out: { inline: 1 }
      }

      Job.mapReduce(command, function(err, results) {
        if (err) { reject(err); }
        return resolve(_.map(results,'value'));
      });
    });
  })
}

function map() {
  emit(this.project, {
    branch: this.ref.branch,
    finished: this.finished,
    data: {
      test_exitcode: this.test_exitcode,
      deploy_exitcode: this.deploy_exitcode,
      plugin_data: this.plugin_data
    }
  });
}

function reduce(project, values) {
  var branches = [],
      jobs = {};

  for(var i = 0; i < values.length; i++) {
    if (! jobs[values[i].branch]) { jobs[values[i].branch] = []; }
    jobs[values[i].branch].push(values[i]);
  }

  for (var key in jobs) {
    print(jobs[key]);
    branches.push({
      name: key,
      status: jobs[key].sort(function(x,y) {
        return x.finished == y.finished;
      })[jobs[key].length - 1].data
    });
  }

  return {
    project: project,
    branches: branches
  }
}

function finalize(key, reduced) {
  var result = [];
  for(var i = 0; i < reduced.length; i++) {
    result.push(reduced[i].value);
  }
  return result;
}
<|endoftext|>