<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var actions = require('./actions')

// Keep track of events related to just IP addresses
module.exports = function (BLOCK_INTERVAL_MS, IP_RATE_LIMIT_INTERVAL_MS, IP_RATE_LIMIT_BAN_DURATION_MS, MAX_BAD_LOGINS_PER_IP, MAX_ACCOUNT_STATUS_CHECK, now) {

  now = now || Date.now

  function IpRecord() {
    this.lf = []
    this.as = []
  }

  IpRecord.parse = function (object) {
    var rec = new IpRecord()
    object = object || {}
    rec.bk = object.bk // timestamp when the account was blocked
    rec.lf = object.lf || []  // timestamps when failed login attempts occurred
    rec.as = object.as || []  // timestamps when account status check occurred
    rec.rl = object.rl  // timestamp when the account was rate-limited
    return rec
  }

  IpRecord.prototype.isOverBadLogins = function () {
    this.trimBadLogins(now())
    return this.lf.length > MAX_BAD_LOGINS_PER_IP
  }

  IpRecord.prototype.isOverAccountStatusCheck = function () {
    this.trimAccountStatus(now())
    return this.as.length > MAX_ACCOUNT_STATUS_CHECK
  }

  IpRecord.prototype.trimBadLogins = function (now) {
    if (this.lf.length === 0) { return }
    // lf is naturally ordered from oldest to newest
    // and we only need to keep up to MAX_BAD_LOGINS_PER_IP + 1
    var i = this.lf.length - 1
    var n = 0
    var login = this.lf[i]
    while (login > (now - IP_RATE_LIMIT_INTERVAL_MS) && n <= MAX_BAD_LOGINS_PER_IP) {
      login = this.lf[--i]
      n++
    }
    this.lf = this.lf.slice(i + 1)
  }

  IpRecord.prototype.trimAccountStatus = function (now) {
    if (this.as.length === 0) { return }
    // "as" is naturally ordered from oldest to newest
    // and we only need to keep up to MAX_ACCOUNT_STATUS_CHECK + 1

    var i = this.as.length - 1
    var n = 0
    var hit = this.as[i]
    while (hit > (now - IP_RATE_LIMIT_INTERVAL_MS) && n <= MAX_ACCOUNT_STATUS_CHECK) {
      hit = this.as[--i]
      n++
    }
    this.as = this.as.slice(i + 1)
  }

  IpRecord.prototype.addBadLogin = function () {
    this.trimBadLogins(now())
    this.lf.push(now())
  }

  IpRecord.prototype.addAccountStatusCheck = function () {
    this.trimAccountStatus(now())
    this.as.push(now())
  }

  IpRecord.prototype.shouldBlock = function () {
    return this.isBlocked() || this.isRateLimited()
  }

  IpRecord.prototype.isBlocked = function () {
    return !!(this.bk && (now() - this.bk < BLOCK_INTERVAL_MS))
  }

  IpRecord.prototype.isRateLimited = function () {
    return !!(this.rl && (now() - this.rl < IP_RATE_LIMIT_BAN_DURATION_MS))
  }

  IpRecord.prototype.block = function () {
    this.bk = now()
  }

  IpRecord.prototype.rateLimit = function () {
    this.rl = now()
    this.as = []
  }

  IpRecord.prototype.retryAfter = function () {
    var rateLimitAfter = Math.floor(((this.rl || 0) + IP_RATE_LIMIT_BAN_DURATION_MS - now()) / 1000)
    var banAfter = Math.floor(((this.bk || 0) + BLOCK_INTERVAL_MS - now()) / 1000)
    return Math.max(0, rateLimitAfter, banAfter)
  }

  IpRecord.prototype.update = function (action) {
    // Increment account status check and throttle if needed
    if (actions.isAccountStatusAction(action)) {
      this.addAccountStatusCheck()
      if (this.isOverAccountStatusCheck() && !this.isRateLimited()){
        this.rateLimit()
      }
    }

    // Throttle password-checking attempts if too many failed logins
    if (actions.isPasswordCheckingAction(action)) {
      if (this.isOverBadLogins() && !this.isRateLimited()) {
        this.rateLimit()
      }
    }

    return this.retryAfter()
  }

  return IpRecord
}
<commit_msg>feat(logins): Count rate-limited login attempts as failed logins.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var actions = require('./actions')

// Keep track of events related to just IP addresses
module.exports = function (BLOCK_INTERVAL_MS, IP_RATE_LIMIT_INTERVAL_MS, IP_RATE_LIMIT_BAN_DURATION_MS, MAX_BAD_LOGINS_PER_IP, MAX_ACCOUNT_STATUS_CHECK, now) {

  now = now || Date.now

  function IpRecord() {
    this.lf = []
    this.as = []
  }

  IpRecord.parse = function (object) {
    var rec = new IpRecord()
    object = object || {}
    rec.bk = object.bk // timestamp when the account was blocked
    rec.lf = object.lf || []  // timestamps when failed login attempts occurred
    rec.as = object.as || []  // timestamps when account status check occurred
    rec.rl = object.rl  // timestamp when the account was rate-limited
    return rec
  }

  IpRecord.prototype.isOverBadLogins = function () {
    this.trimBadLogins(now())
    return this.lf.length > MAX_BAD_LOGINS_PER_IP
  }

  IpRecord.prototype.isOverAccountStatusCheck = function () {
    this.trimAccountStatus(now())
    return this.as.length > MAX_ACCOUNT_STATUS_CHECK
  }

  IpRecord.prototype.trimBadLogins = function (now) {
    if (this.lf.length === 0) { return }
    // lf is naturally ordered from oldest to newest
    // and we only need to keep up to MAX_BAD_LOGINS_PER_IP + 1
    var i = this.lf.length - 1
    var n = 0
    var login = this.lf[i]
    while (login > (now - IP_RATE_LIMIT_INTERVAL_MS) && n <= MAX_BAD_LOGINS_PER_IP) {
      login = this.lf[--i]
      n++
    }
    this.lf = this.lf.slice(i + 1)
  }

  IpRecord.prototype.trimAccountStatus = function (now) {
    if (this.as.length === 0) { return }
    // "as" is naturally ordered from oldest to newest
    // and we only need to keep up to MAX_ACCOUNT_STATUS_CHECK + 1

    var i = this.as.length - 1
    var n = 0
    var hit = this.as[i]
    while (hit > (now - IP_RATE_LIMIT_INTERVAL_MS) && n <= MAX_ACCOUNT_STATUS_CHECK) {
      hit = this.as[--i]
      n++
    }
    this.as = this.as.slice(i + 1)
  }

  IpRecord.prototype.addBadLogin = function () {
    this.trimBadLogins(now())
    this.lf.push(now())
  }

  IpRecord.prototype.addAccountStatusCheck = function () {
    this.trimAccountStatus(now())
    this.as.push(now())
  }

  IpRecord.prototype.shouldBlock = function () {
    return this.isBlocked() || this.isRateLimited()
  }

  IpRecord.prototype.isBlocked = function () {
    return !!(this.bk && (now() - this.bk < BLOCK_INTERVAL_MS))
  }

  IpRecord.prototype.isRateLimited = function () {
    return !!(this.rl && (now() - this.rl < IP_RATE_LIMIT_BAN_DURATION_MS))
  }

  IpRecord.prototype.block = function () {
    this.bk = now()
  }

  IpRecord.prototype.rateLimit = function () {
    this.rl = now()
    this.as = []
  }

  IpRecord.prototype.retryAfter = function () {
    var rateLimitAfter = Math.floor(((this.rl || 0) + IP_RATE_LIMIT_BAN_DURATION_MS - now()) / 1000)
    var banAfter = Math.floor(((this.bk || 0) + BLOCK_INTERVAL_MS - now()) / 1000)
    return Math.max(0, rateLimitAfter, banAfter)
  }

  IpRecord.prototype.update = function (action) {
    // Increment account status check and throttle if needed
    if (actions.isAccountStatusAction(action)) {
      this.addAccountStatusCheck()
      if (this.isOverAccountStatusCheck() && !this.isRateLimited()){
        this.rateLimit()
      }
    }

    // Throttle password-checking attempts if too many failed logins.
    // Rate-limited login attempts still count towards your quota.
    if (actions.isPasswordCheckingAction(action)) {
      if (this.isRateLimited()) {
        this.addBadLogin()
      } else if (this.isOverBadLogins()) {
        this.addBadLogin()
        this.rateLimit()
      }
    }

    return this.retryAfter()
  }

  return IpRecord
}
<|endoftext|>


<commit_before>var currentIndex;

class KeyStroke {
	constructor(char, currentText, level) {
		this.char = char;
		this.currentText = currentText;
		// this.currentIndex = currentIndex;
		this.level = level;
	}

	scoreCorrect() {
		this.level.score++;
		currentIndex = currentIndex + 1 || 0
		this.correct = true;
	}

	scoreIncorrect() {
		this.level.score--;
		// this.currentIndex++;
		this.correct = false;
	}

	scoreBackspace() {
		this.currentIndex--;
	}

	checkIfEndOfLine() {
		if (currentIndex  == this.currentText.length) {
			this.level.nextLine(this.currentText);
			currentIndex = 0
		};
	}

	score() {
		currentIndex = currentIndex || 0
		if (currentIndex === 0 && !this.char.match(/[a-z]/i)) {
			return this;
		} else if (this.char !== this.currentText[currentIndex]) {
			this.level.bird.down();

			this.scoreIncorrect();
			return this;
		} else if (this.char === this.currentText[currentIndex]) {

			this.scoreCorrect();
			this.level.bird.up();
			this.checkIfEndOfLine();
			return this;
		}

		// if (this.char === "Backspace"){
		// 	this.level.bird.down();
		// 	this.scoreBackspace();
		// 	return this;
		// } else if (this.char !== this.currentText[this.currentIndex]) {
		// 	this.level.bird.down();
		// 	this.scoreIncorrect();
		// 	return this;
		// } else  { //(this.char === this.currentText[this.currentIndex])
		// 	this.scoreCorrect();
		// 	this.level.bird.up();
		// 	this.checkIfEndOfLine();
		// 	return this;
		// };
	}

	updateScoreCard() {
		$("#score").text(this.level.score);
	}

	prepareForNext() {
		currentIndex = currentIndex || 0
		if(this.correct && currentIndex < this.currentText.length) {
			var nextLetter = "#" + currentIndex;
			var thisLetter = "#" + (currentIndex-1);
			$(thisLetter).removeClass('my-underline').removeClass('my-grey').removeClass('my-red');
			$(nextLetter).addClass('my-underline').removeClass('my-red')
		} else if (!this.correct && currentIndex < this.currentText.length){
			var sameLetter = "#" + currentIndex;
			$(sameLetter).addClass('my-red').removeClass('my-underline').removeClass('my-grey');
			//this letter- animate highlighting glow
    }

		// if(this.correct) {
		// 	var nextLetter = "#" + this.currentIndex;
		// 	var thisLetter = "#" + (this.currentIndex-1);
		// 	$(thisLetter).removeClass('my-underline').removeClass('my-grey').removeClass('my-red');
		// 	$(nextLetter).addClass('my-underline').removeClass('my-red')
		// } else if (this.char === "Backspace") {
		// 	var deletedLetter = "#" + (this.currentIndex+2);
		// 	var nextLetter = "#" + (this.currentIndex+3);
		// 	$(deletedLetter).addClass('my-grey').addClass('my-underline');
		// 	$(nextLetter).removeClass('my-red').removeClass('my-underline');
		// } else { //!this.correct
		// 	var nextLetter = "#" + this.currentIndex;
		// 	var thisLetter = "#" + (this.currentIndex-1); // this is why the last letter is highlighted!
		// 	$(thisLetter).removeClass('my-underline').removeClass('my-grey').addClass('my-red');
		// 	$(nextLetter).addClass('my-underline')
		// };
		return this;
	}

}

module.exports = KeyStroke;
<commit_msg>Add hacky blinking effect to letter when typed incorrectly<commit_after>var currentIndex;

class KeyStroke {
	constructor(char, currentText, level) {
		this.char = char;
		this.currentText = currentText;
		// this.currentIndex = currentIndex;
		this.level = level;
	}

	scoreCorrect() {
		this.level.score++;
		currentIndex = currentIndex + 1 || 0
		this.correct = true;
	}

	scoreIncorrect() {
		this.level.score--;
		// this.currentIndex++;
		this.correct = false;
	}

	scoreBackspace() {
		this.currentIndex--;
	}

	checkIfEndOfLine() {
		if (currentIndex  == this.currentText.length) {
			this.level.nextLine(this.currentText);
			currentIndex = 0
		};
	}

	score() {
		currentIndex = currentIndex || 0
		if (currentIndex === 0 && !this.char.match(/[a-z]/i)) {
			return this;
		} else if (this.char !== this.currentText[currentIndex]) {
			this.level.bird.down();

			this.scoreIncorrect();
			return this;
		} else if (this.char === this.currentText[currentIndex]) {

			this.scoreCorrect();
			this.level.bird.up();
			this.checkIfEndOfLine();
			return this;
		}

		// if (this.char === "Backspace"){
		// 	this.level.bird.down();
		// 	this.scoreBackspace();
		// 	return this;
		// } else if (this.char !== this.currentText[this.currentIndex]) {
		// 	this.level.bird.down();
		// 	this.scoreIncorrect();
		// 	return this;
		// } else  { //(this.char === this.currentText[this.currentIndex])
		// 	this.scoreCorrect();
		// 	this.level.bird.up();
		// 	this.checkIfEndOfLine();
		// 	return this;
		// };
	}

	updateScoreCard() {
		$("#score").text(this.level.score);
	}

	prepareForNext() {
		currentIndex = currentIndex || 0
		if(this.correct && currentIndex < this.currentText.length) {
			var nextLetter = "#" + currentIndex;
			var thisLetter = "#" + (currentIndex-1);
			$(thisLetter).removeClass('my-underline').removeClass('my-grey').removeClass('my-red');
			$(nextLetter).addClass('my-underline').removeClass('my-red')
		} else if (!this.correct && currentIndex < this.currentText.length){
			var sameLetter = "#" + currentIndex;
			$(sameLetter).addClass('my-red').removeClass('my-underline').removeClass('my-grey')
			$(sameLetter).fadeIn(100).fadeOut(80).fadeIn(80).fadeIn(80).fadeOut(80).fadeIn(80);
    }

		// if(this.correct) {
		// 	var nextLetter = "#" + this.currentIndex;
		// 	var thisLetter = "#" + (this.currentIndex-1);
		// 	$(thisLetter).removeClass('my-underline').removeClass('my-grey').removeClass('my-red');
		// 	$(nextLetter).addClass('my-underline').removeClass('my-red')
		// } else if (this.char === "Backspace") {
		// 	var deletedLetter = "#" + (this.currentIndex+2);
		// 	var nextLetter = "#" + (this.currentIndex+3);
		// 	$(deletedLetter).addClass('my-grey').addClass('my-underline');
		// 	$(nextLetter).removeClass('my-red').removeClass('my-underline');
		// } else { //!this.correct
		// 	var nextLetter = "#" + this.currentIndex;
		// 	var thisLetter = "#" + (this.currentIndex-1); // this is why the last letter is highlighted!
		// 	$(thisLetter).removeClass('my-underline').removeClass('my-grey').addClass('my-red');
		// 	$(nextLetter).addClass('my-underline')
		// };
		return this;
	}

}

module.exports = KeyStroke;
<|endoftext|>


<commit_before>/*
 * Log4stuff.js: Transport for outputting to the Log4stuff
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENCE
 *
 */

var events = require('events'),
    util = require('util'),
    http = require('http'),
    os = require('os'),
    winston = require('winston');

//
// ### function Log4stuff (options)
// #### @options {Object} Options for this instance.
// Constructor function for the Log4stuff transport object responsible
// for persisting log messages and metadata to a terminal or TTY.
//
var Log4stuff = exports.Log4stuff = function (options) {
  winston.Transport.call(this, options);
  options = options || {};

  this.applicationId = options.applicationId;

  if (this.json) {
    this.stringify = options.stringify || function (obj) {
      return JSON.stringify(obj, null, 2);
    };
  }
};

//
// Inherit from `winston.Transport`.
//
util.inherits(Log4stuff, winston.Transport);

//
// Expose the name of this Transport on the prototype
//
Log4stuff.prototype.name = 'Log4stuff';

winston.transports.Log4stuff = Log4stuff;

//
// ### function log (level, msg, [meta], callback)
// #### @level {string} Level at which to log the message.
// #### @msg {string} Message to log
// #### @meta {Object} **Optional** Additional metadata to attach
// #### @callback {function} Continuation to respond to when complete.
// Core logging method exposed to Winston. Metadata is optional.
//
Log4stuff.prototype.log = function (level, msg, meta, callback) {
  if (this.silent) {
    return callback(null, true);
  }

  var self = this;

  meta = meta || {};
  meta["log4net:HostName"] = os.hostname();

  var now = new Date();
  //Todo: Make the date/times prettier
  var dateStr = now.getFullYear() + "-"
    + (1 + now.getMonth()) + "-"
    + now.getDate() + " "
    + now.getHours() + ":"
    + now.getMinutes() + ":"
    + now.getSeconds();

  var logEvent = {
    "Logger": "winston",
    "Thread": "",
    "Timestamp": dateStr,
    "Level": level,
    "Message": msg,
    "Metadata": meta,
  };

  var json = JSON.stringify(logEvent);
  var encoded = escape(json);

  //var url = "http://localhost:58227/app/" + this.applicationId + "?logEvent=" + encoded;
  var url = "http://log4stuff.com/app/" + this.applicationId + "?logEvent=" + encoded;

  //console.log(url);

  http.get(url, function(res) {
    if(res.statusCode == 200) {
      self.emit('logged');
      callback(null, true);
    } else {
      //Remote server error
      self.emit('error', null);
      if (callback) callback(null, false);
      callback = null;
    }
  }).on('error', function(err) {
    //Local error
    self.emit('error', err);
    if (callback) callback(err, false);
    callback = null;
  });
};
<commit_msg>Updated copyright<commit_after>/*
 * Log4stuff.js: Transport for outputting to the Log4stuff
 *
 * (C) 2014 Jason Young
 * MIT LICENCE
 *
 */

var events = require('events'),
    util = require('util'),
    http = require('http'),
    os = require('os'),
    winston = require('winston');

//
// ### function Log4stuff (options)
// #### @options {Object} Options for this instance.
// Constructor function for the Log4stuff transport object responsible
// for persisting log messages and metadata to a terminal or TTY.
//
var Log4stuff = exports.Log4stuff = function (options) {
  winston.Transport.call(this, options);
  options = options || {};

  this.applicationId = options.applicationId;

  if (this.json) {
    this.stringify = options.stringify || function (obj) {
      return JSON.stringify(obj, null, 2);
    };
  }
};

//
// Inherit from `winston.Transport`.
//
util.inherits(Log4stuff, winston.Transport);

//
// Expose the name of this Transport on the prototype
//
Log4stuff.prototype.name = 'Log4stuff';

winston.transports.Log4stuff = Log4stuff;

//
// ### function log (level, msg, [meta], callback)
// #### @level {string} Level at which to log the message.
// #### @msg {string} Message to log
// #### @meta {Object} **Optional** Additional metadata to attach
// #### @callback {function} Continuation to respond to when complete.
// Core logging method exposed to Winston. Metadata is optional.
//
Log4stuff.prototype.log = function (level, msg, meta, callback) {
  if (this.silent) {
    return callback(null, true);
  }

  var self = this;

  meta = meta || {};
  meta["log4net:HostName"] = os.hostname();

  var now = new Date();
  //Todo: Make the date/times prettier
  var dateStr = now.getFullYear() + "-"
    + (1 + now.getMonth()) + "-"
    + now.getDate() + " "
    + now.getHours() + ":"
    + now.getMinutes() + ":"
    + now.getSeconds();

  var logEvent = {
    "Logger": "winston",
    "Thread": "",
    "Timestamp": dateStr,
    "Level": level,
    "Message": msg,
    "Metadata": meta,
  };

  var json = JSON.stringify(logEvent);
  var encoded = escape(json);

  //var url = "http://localhost:58227/app/" + this.applicationId + "?logEvent=" + encoded;
  var url = "http://log4stuff.com/app/" + this.applicationId + "?logEvent=" + encoded;

  //console.log(url);

  http.get(url, function(res) {
    if(res.statusCode == 200) {
      self.emit('logged');
      callback(null, true);
    } else {
      //Remote server error
      self.emit('error', null);
      if (callback) callback(null, false);
      callback = null;
    }
  }).on('error', function(err) {
    //Local error
    self.emit('error', err);
    if (callback) callback(err, false);
    callback = null;
  });
};
<|endoftext|>


<commit_before>;(function () { // closure for web browsers

if (typeof module === 'object' && module.exports) {
  module.exports = LRUCache
} else {
  // just set the global for non-node platforms.
  this.LRUCache = LRUCache
}

function hOP (obj, key) {
  return Object.prototype.hasOwnProperty.call(obj, key)
}

function naiveLength () { return 1 }

function LRUCache (options) {
  if (!(this instanceof LRUCache)) {
    return new LRUCache(options)
  }

  var max
  if (typeof options === 'number') {
    max = options
    options = { max: max }
  }

  if (!options) options = {}

  max = options.max

  var lengthCalculator = options.length || naiveLength

  if (typeof lengthCalculator !== "function") {
    lengthCalculator = naiveLength
  }

  if (!max || !(typeof max === "number") || max <= 0 ) {
    // a little bit silly.  maybe this should throw?
    max = Infinity
  }

  var allowStale = options.stale || false

  var maxAge = options.maxAge || null

  var dispose = options.dispose

  var cache = Object.create(null) // hash of items by key
    , lruList = Object.create(null) // list of items in order of use recency
    , mru = 0 // most recently used
    , lru = 0 // least recently used
    , length = 0 // number of items in the list
    , itemCount = 0

  // resize the cache when the max changes.
  Object.defineProperty(this, "max",
    { set : function (mL) {
        if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity
        max = mL
        // if it gets above double max, trim right away.
        // otherwise, do it whenever it's convenient.
        if (length > max) trim(this)
      }
    , get : function () { return max }
    , enumerable : true
    })

  // resize the cache when the lengthCalculator changes.
  Object.defineProperty(this, "lengthCalculator",
    { set : function (lC) {
        if (typeof lC !== "function") {
          lengthCalculator = naiveLength
          length = itemCount
          for (var key in cache) {
            cache[key].length = 1
          }
        } else {
          lengthCalculator = lC
          length = 0
          for (var key in cache) {
            cache[key].length = lengthCalculator(cache[key].value)
            length += cache[key].length
          }
        }

        if (length > max) trim(this)
      }
    , get : function () { return lengthCalculator }
    , enumerable : true
    })

  Object.defineProperty(this, "length",
    { get : function () { return length }
    , enumerable : true
    })

  Object.defineProperty(this, "itemCount",
    { get : function () { return itemCount }
    , enumerable : true
    })

  this.forEach = function (fn, thisp) {
    thisp = thisp || this
    var i = 0;
    for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) {
      i++
      var hit = lruList[k]
      if (maxAge && (Date.now() - hit.now > maxAge)) {
        del(this, hit)
        if (!allowStale) hit = undefined
      }
      if (hit) {
        fn.call(thisp, hit.value, hit.key, this)
      }
    }
  }

  this.keys = function () {
    var keys = new Array(itemCount)
    var i = 0
    for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) {
      var hit = lruList[k]
      keys[i++] = hit.key
    }
    return keys
  }

  this.values = function () {
    var values = new Array(itemCount)
    var i = 0
    for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) {
      var hit = lruList[k]
      values[i++] = hit.value
    }
    return values
  }

  this.reset = function () {
    if (dispose) {
      for (var k in cache) {
        dispose(k, cache[k].value)
      }
    }
    cache = Object.create(null)
    lruList = Object.create(null)
    lru = 0
    mru = 0
    length = 0
    itemCount = 0
  }

  // Provided for debugging/dev purposes only. No promises whatsoever that
  // this API stays stable.
  this.dump = function () {
    return cache
  }

  this.dumpLru = function () {
    return lruList
  }

  this.set = function (key, value) {
    if (hOP(cache, key)) {
      // dispose of the old one before overwriting
      if (dispose) dispose(key, cache[key].value)
      if (maxAge) cache[key].now = Date.now()
      cache[key].value = value
      this.get(key)
      return true
    }

    var len = lengthCalculator(value)
    var age = maxAge ? Date.now() : 0
    var hit = new Entry(key, value, mru++, len, age)

    // oversized objects fall out of cache automatically.
    if (hit.length > max) {
      if (dispose) dispose(key, value)
      return false
    }

    length += hit.length
    lruList[hit.lu] = cache[key] = hit
    itemCount ++

    if (length > max) trim(this)
    return true
  }

  this.has = function (key) {
    if (!hOP(cache, key)) return false
    var hit = cache[key]
    if (maxAge && (Date.now() - hit.now > maxAge)) {
      return false
    }
    return true
  }

  this.get = function (key) {
    return get(this, key, true)
  }

  this.peek = function (key) {
    return get(this, key, false)
  }

  this.pop = function () {
    var hit = lruList[lru]
    del(this, hit)
    return hit || null
  }

  function get (self, key, doUse) {
    var hit = cache[key]
    if (hit) {
      if (maxAge && (Date.now() - hit.now > maxAge)) {
        del(self, hit)
        if (!allowStale) hit = undefined
      } else {
        if (doUse) use(self, hit)
      }
      if (hit) hit = hit.value
    }
    return hit
  }

  function use (self, hit) {
    shiftLU(hit)
    hit.lu = mru ++
    lruList[hit.lu] = hit
  }

  this.del = function (key) {
    del(this, cache[key])
  }

  function trim (self) {
    while (lru < mru && length > max)
      del(self, lruList[lru])
  }

  function shiftLU (hit) {
    delete lruList[ hit.lu ]
    while (lru < mru && !lruList[lru]) lru ++
  }

  function del (self, hit) {
    if (hit) {
      if (dispose) dispose(hit.key, hit.value)
      length -= hit.length
      itemCount --
      delete cache[ hit.key ]
      shiftLU(hit)
    }
  }
}

// classy, since V8 prefers predictable objects.
function Entry (key, value, mru, len, age) {
  this.key = key
  this.value = value
  this.lu = mru
  this.length = len
  this.now = age
}

})()
<commit_msg>pass self to shiftLU function<commit_after>;(function () { // closure for web browsers

if (typeof module === 'object' && module.exports) {
  module.exports = LRUCache
} else {
  // just set the global for non-node platforms.
  this.LRUCache = LRUCache
}

function hOP (obj, key) {
  return Object.prototype.hasOwnProperty.call(obj, key)
}

function naiveLength () { return 1 }

function LRUCache (options) {
  if (!(this instanceof LRUCache)) {
    return new LRUCache(options)
  }

  var max
  if (typeof options === 'number') {
    max = options
    options = { max: max }
  }

  if (!options) options = {}

  max = options.max

  var lengthCalculator = options.length || naiveLength

  if (typeof lengthCalculator !== "function") {
    lengthCalculator = naiveLength
  }

  if (!max || !(typeof max === "number") || max <= 0 ) {
    // a little bit silly.  maybe this should throw?
    max = Infinity
  }

  var allowStale = options.stale || false

  var maxAge = options.maxAge || null

  var dispose = options.dispose

  var cache = Object.create(null) // hash of items by key
    , lruList = Object.create(null) // list of items in order of use recency
    , mru = 0 // most recently used
    , lru = 0 // least recently used
    , length = 0 // number of items in the list
    , itemCount = 0

  // resize the cache when the max changes.
  Object.defineProperty(this, "max",
    { set : function (mL) {
        if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity
        max = mL
        // if it gets above double max, trim right away.
        // otherwise, do it whenever it's convenient.
        if (length > max) trim(this)
      }
    , get : function () { return max }
    , enumerable : true
    })

  // resize the cache when the lengthCalculator changes.
  Object.defineProperty(this, "lengthCalculator",
    { set : function (lC) {
        if (typeof lC !== "function") {
          lengthCalculator = naiveLength
          length = itemCount
          for (var key in cache) {
            cache[key].length = 1
          }
        } else {
          lengthCalculator = lC
          length = 0
          for (var key in cache) {
            cache[key].length = lengthCalculator(cache[key].value)
            length += cache[key].length
          }
        }

        if (length > max) trim(this)
      }
    , get : function () { return lengthCalculator }
    , enumerable : true
    })

  Object.defineProperty(this, "length",
    { get : function () { return length }
    , enumerable : true
    })

  Object.defineProperty(this, "itemCount",
    { get : function () { return itemCount }
    , enumerable : true
    })

  this.forEach = function (fn, thisp) {
    thisp = thisp || this
    var i = 0;
    for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) {
      i++
      var hit = lruList[k]
      if (maxAge && (Date.now() - hit.now > maxAge)) {
        del(this, hit)
        if (!allowStale) hit = undefined
      }
      if (hit) {
        fn.call(thisp, hit.value, hit.key, this)
      }
    }
  }

  this.keys = function () {
    var keys = new Array(itemCount)
    var i = 0
    for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) {
      var hit = lruList[k]
      keys[i++] = hit.key
    }
    return keys
  }

  this.values = function () {
    var values = new Array(itemCount)
    var i = 0
    for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) {
      var hit = lruList[k]
      values[i++] = hit.value
    }
    return values
  }

  this.reset = function () {
    if (dispose) {
      for (var k in cache) {
        dispose(k, cache[k].value)
      }
    }
    cache = Object.create(null)
    lruList = Object.create(null)
    lru = 0
    mru = 0
    length = 0
    itemCount = 0
  }

  // Provided for debugging/dev purposes only. No promises whatsoever that
  // this API stays stable.
  this.dump = function () {
    return cache
  }

  this.dumpLru = function () {
    return lruList
  }

  this.set = function (key, value) {
    if (hOP(cache, key)) {
      // dispose of the old one before overwriting
      if (dispose) dispose(key, cache[key].value)
      if (maxAge) cache[key].now = Date.now()
      cache[key].value = value
      this.get(key)
      return true
    }

    var len = lengthCalculator(value)
    var age = maxAge ? Date.now() : 0
    var hit = new Entry(key, value, mru++, len, age)

    // oversized objects fall out of cache automatically.
    if (hit.length > max) {
      if (dispose) dispose(key, value)
      return false
    }

    length += hit.length
    lruList[hit.lu] = cache[key] = hit
    itemCount ++

    if (length > max) trim(this)
    return true
  }

  this.has = function (key) {
    if (!hOP(cache, key)) return false
    var hit = cache[key]
    if (maxAge && (Date.now() - hit.now > maxAge)) {
      return false
    }
    return true
  }

  this.get = function (key) {
    return get(this, key, true)
  }

  this.peek = function (key) {
    return get(this, key, false)
  }

  this.pop = function () {
    var hit = lruList[lru]
    del(this, hit)
    return hit || null
  }

  function get (self, key, doUse) {
    var hit = cache[key]
    if (hit) {
      if (maxAge && (Date.now() - hit.now > maxAge)) {
        del(self, hit)
        if (!allowStale) hit = undefined
      } else {
        if (doUse) use(self, hit)
      }
      if (hit) hit = hit.value
    }
    return hit
  }

  function use (self, hit) {
    shiftLU(self, hit)
    hit.lu = mru ++
    lruList[hit.lu] = hit
  }

  this.del = function (key) {
    del(this, cache[key])
  }

  function trim (self) {
    while (lru < mru && length > max)
      del(self, lruList[lru])
  }

  function shiftLU (self, hit) {
    delete lruList[ hit.lu ]
    while (lru < mru && !lruList[lru]) lru ++
  }

  function del (self, hit) {
    if (hit) {
      if (dispose) dispose(hit.key, hit.value)
      length -= hit.length
      itemCount --
      delete cache[ hit.key ]
      shiftLU(self, hit)
    }
  }
}

// classy, since V8 prefers predictable objects.
function Entry (key, value, mru, len, age) {
  this.key = key
  this.value = value
  this.lu = mru
  this.length = len
  this.now = age
}

})()
<|endoftext|>


<commit_before>'use strict';

var options =
{
    baseUrl: 'https://mailosaur.com/api/',
    smtpHost: 'mailosaur.io',
    apiKey: ''
}

function Mailbox(mailbox) {
    function http(opts, done) {
        var request = require('request'),
            route = opts.route.replace(':mailbox', mailbox),
            params = {
                url: options.baseUrl + route,
                method: (opts.method || 'GET'),
                auth: {
                    user: options.apiKey,
                    pass: ''
                },
                json: true
            };
        if (opts.binary) {
            params.encoding = null;
        }
        if (done) {
            request(params, function (err, headers, body) {
                if (!err) {
                    if (headers.statusCode != 200 && headers.statusCode != 204) {
                        throw new Error(headers.statusCode + ': ' + body);
                    }
                }
                done(err, body);
            });
        }
        else {
            var Promise = require("bluebird");

            return new Promise(function (resolve, reject) {
                request(params, function (err, headers, body) {
                    if (!err) {
                        if (headers.statusCode != 200 && headers.statusCode != 204) {
                            var err = new Error(headers.statusCode + ': ' + body);
                            reject(err);
                            throw err;
                        }
                    }
                    resolve(body);
                });
            });
        }
    }

    return {
        getEmails: function (searchPattern, cb) {
            var route = 'mailboxes/:mailbox/emails';
            if (typeof(searchPattern) === "string") {
                route += '/?search=' + searchPattern;
            }
            else {
                cb = searchPattern;
            }
            return http({
                route: route
            }, cb);
        },

        getEmailsByRecipient: function (recipient, cb) {
            return http({
                route: 'mailboxes/:mailbox/emails/?recipient=' + recipient
            }, cb);
        },

        getEmail: function (email, cb) {
            return http({
                route: 'emails/' + email
            }, cb);
        },

        deleteAllEmail: function (cb) {
            return http({
                route: 'mailboxes/:mailbox/empty',
                method: 'POST'
            }, cb);
        },

        deleteEmail: function (email, cb) {
            return http({
                route: 'emails/' + email + '/delete',
                method: 'POST'
            }, cb);
        },

        getAttachment: function (attachmentId, cb) {
            return http({
                route: 'attachments/' + attachmentId,
                method: 'GET',
                binary: true
            }, cb);
        },

        getRawEmail: function (rawId, cb) {
            return http({
                route: 'raw/' + rawId,
                method: 'GET',
                binary: true
            }, cb);
        },

        generateEmailAddress: function () {
            var random = Math.random().toString(36);
            return random + '.' + mailbox + '@' + options.smtpHost;
        }
    };
};

module.exports = function mailosaur(apiKey) {
    options.apiKey = apiKey;

    options.baseUrl = process.env.MAILOSAUR_BASE_URL || options.baseUrl;
    options.smtpHost = process.env.MAILOSAUR_SMTP_HOST || options.smtpHost;

    return {
        Mailbox: Mailbox
    }
};
<commit_msg>Add logging when using alternative base url<commit_after>'use strict';

var options =
{
    baseUrl: 'https://mailosaur.com/api/',
    smtpHost: 'mailosaur.io',
    apiKey: ''
}

function Mailbox(mailbox) {
    function http(opts, done) {
        var request = require('request'),
            route = opts.route.replace(':mailbox', mailbox),
            params = {
                url: options.baseUrl + route,
                method: (opts.method || 'GET'),
                auth: {
                    user: options.apiKey,
                    pass: ''
                },
                json: true
            };
        if (opts.binary) {
            params.encoding = null;
        }
        if (done) {
            request(params, function (err, headers, body) {
                if (!err) {
                    if (headers.statusCode != 200 && headers.statusCode != 204) {
                        throw new Error(headers.statusCode + ': ' + body);
                    }
                }
                done(err, body);
            });
        }
        else {
            var Promise = require("bluebird");

            return new Promise(function (resolve, reject) {
                request(params, function (err, headers, body) {
                    if (!err) {
                        if (headers.statusCode != 200 && headers.statusCode != 204) {
                            var err = new Error(headers.statusCode + ': ' + body);
                            reject(err);
                            throw err;
                        }
                    }
                    resolve(body);
                });
            });
        }
    }

    return {
        getEmails: function (searchPattern, cb) {
            var route = 'mailboxes/:mailbox/emails';
            if (typeof(searchPattern) === "string") {
                route += '/?search=' + searchPattern;
            }
            else {
                cb = searchPattern;
            }
            return http({
                route: route
            }, cb);
        },

        getEmailsByRecipient: function (recipient, cb) {
            return http({
                route: 'mailboxes/:mailbox/emails/?recipient=' + recipient
            }, cb);
        },

        getEmail: function (email, cb) {
            return http({
                route: 'emails/' + email
            }, cb);
        },

        deleteAllEmail: function (cb) {
            return http({
                route: 'mailboxes/:mailbox/empty',
                method: 'POST'
            }, cb);
        },

        deleteEmail: function (email, cb) {
            return http({
                route: 'emails/' + email + '/delete',
                method: 'POST'
            }, cb);
        },

        getAttachment: function (attachmentId, cb) {
            return http({
                route: 'attachments/' + attachmentId,
                method: 'GET',
                binary: true
            }, cb);
        },

        getRawEmail: function (rawId, cb) {
            return http({
                route: 'raw/' + rawId,
                method: 'GET',
                binary: true
            }, cb);
        },

        generateEmailAddress: function () {
            var random = Math.random().toString(36);
            return random + '.' + mailbox + '@' + options.smtpHost;
        }
    };
};

module.exports = function mailosaur(apiKey) {
    options.apiKey = apiKey;

    options.baseUrl = process.env.MAILOSAUR_BASE_URL || options.baseUrl;
    options.smtpHost = process.env.MAILOSAUR_SMTP_HOST || options.smtpHost;

    if (process.env.MAILOSAUR_BASE_URL) {
        console.log('Using', options.baseUrl, options.smtpHost);
    }

    return {
        Mailbox: Mailbox
    }
};
<|endoftext|>


<commit_before>if (MediaSource.isTypeSupported('video/webm; codecs="vp9"')) {
  log('> VP9, Profile 0, level 1 (later fields defaulted)');
}

if (MediaSource.isTypeSupported('video/webm; codecs="vp09.00.10.08"')) {
  log('> VP9, Profile 0, level 1, bit depth 8 (later fields defaulted)');
}

if (MediaSource.isTypeSupported('video/webm; codecs="vp09.01.20.08.01"')) {
  log('> VP9, Profile 0, level 1, bit depth 8, 4:2:0 chroma subsampling ' +
      '(later fields defaulted)');
}

if (MediaSource.isTypeSupported('video/webm; codecs="vp09.01.20.08.01.01.01.01.00"')) {
  log('> VP9, Profile 1, level 2, bit depth 8, ' +
      '4:2:0 chroma subsampling, REC709 color/transfer/matrix, ' +
      'luma/chroma encoded in the "legal" range.');
}

if (MediaSource.isTypeSupported('video/webm; codecs="vp09.02.10.10.01.09.16.09.01"')) {
  log('> VP9, Profile 2, level 1, 10-bit YUV content, ' +
      '4:2:0 chroma subsampling, ITU-R BT.2020 primaries, ' +
      'ST 2084 EOTF, ITU-R BT.2020 non-constant luminance color matrix, ' +
      'full-range chroma/luma encoding.');
}
<commit_msg>Address @chcunningham  feedback<commit_after>if (MediaSource.isTypeSupported('video/webm; codecs="vp9"')) {
  log('> Some VP9 profile');
}

if (MediaSource.isTypeSupported('video/webm; codecs="vp09.00.10.08"')) {
  log('> VP9, Profile 0, level 1, bit depth 8 (later fields defaulted)');
}

if (MediaSource.isTypeSupported('video/webm; codecs="vp09.01.20.08.01"')) {
  log('> VP9, Profile 1, level 2, bit depth 8, ' +
      '4:2:0 chroma subsampling colocated with (0,0) luma, ' +
      '(later fields defaulted)');
}

if (MediaSource.isTypeSupported('video/webm; codecs="vp09.01.20.08.01.01.01.01.00"')) {
  log('> VP9, Profile 1, level 2, bit depth 8, ' +
      '4:2:0 chroma subsampling colocated with (0,0) luma, ' +
      'REC709 color/transfer/matrix, ' +
      'luma/chroma encoded in the "legal" range.');
}

if (MediaSource.isTypeSupported('video/webm; codecs="vp09.02.10.10.01.09.16.09.01"')) {
  log('> VP9, Profile 2, level 1, 10-bit YUV content, ' +
      '4:2:0 colocated with luma (0,0) chroma subsampling, ' +
      'ITU-R BT.2020 primaries, ' +
      'ST 2084 EOTF, ITU-R BT.2020 non-constant luminance color matrix, ' +
      'full-range chroma/luma encoding.');
}
<|endoftext|>


<commit_before>var asyncMap = require('./async-map');

var semver = require('./semver');
var github = require('./github');
var npmWrapper = require('./npm');
var db = require('./db');
var emailWrapper = require('./email');

var running = false;

exports.start = function() {
  // Only allow one instance to run at a time
  if (running) {
    console.log("Check already running.");
    return false;
  }
  console.log("Starting check.");
  running = true;
  var retriesLeft = 2;
  checkUpdates(onDone);
  return true;

  function onDone(error) {
    if (error) {
      console.error(error);
      if (retriesLeft--) {
        return checkUpdates(onDone);
      }
      running = false;
      console.log("Giving up!");
    }
    else {
      running = false;
      console.log("Check finished.");
    }
  }
};

function checkUpdates(callback) {

  // Mapping of unique email address to list of packages
  var emails = {};

  // List of packages to monitor, indexed by user/name string
  // Each entry contains:
  //   dependencies - a map of dependency name to version
  //   devDependencies - a map of dev dependency name to version
  var packages = {};

  // This is a mapping of dependency name to dependent package
  // key is dependency name, value is direct reference to entry in packages hash
  var dependents = {};

  // First we need to load all the subscriptions
  db.readSubscriptions(onSubscriptions);

  function onSubscriptions(error, subscriptions) {
    if (error) return callback(error);

    asyncMap(subscriptions, function (subscription, callback) {
      var user = github.getUserFromUrl(subscription.repourl);
      var repo = github.getRepoFromUrl(subscription.repourl);
      var key = user + "/" + repo;

      // Record this email/package combo
      var watching = emails[subscription.email];
      if (watching) watching.push(key);
      else emails[subscription.email] = [key];

      if (packages[key]) {
        // Someone else is already watching for changes in this project
        return;
      }

      packages[key] = {};

      github.getPackageJson(user, repo, function (error, meta) {
        if (error) return callback(error);
        if (meta.dependencies) {
          packages[key].dependencies = meta.dependencies;
          Object.keys(meta.dependencies).forEach(addLink);
        }
        if (meta.devDependencies) {
          packages[key].devDependencies = meta.devDependencies;
          Object.keys(meta.devDependencies).forEach(addLink);
        }
        callback();
      });

      function addLink(name) {
        if (dependents[name]) dependents[name].push(key);
        else dependents[name] = [key];
      }

    }, onProcessed);
  }

  function onProcessed(error) {
    if (error) return callback(error);
    console.log("Checking %s unique packages with %s total unique dependencies for %s unique email addresses.",
                Object.keys(packages).length,
                Object.keys(dependents).length,
                Object.keys(emails).length);
    npmWrapper.getLatestVersions(Object.keys(dependents), onVersions);
  }

  function onVersions(error, versions) {
    if (error) return callback(error);
/*
    console.info({
      emails: emails,
      dependents: dependents,
      packages: packages,
      versions: versions
    });
*/
    // We now have emails of all the people interested in updates.
    // We also have the list of subscriptions grouped by user/name projects key.
    // We also have the latest version of any npm package that we care about.
    // We also have the dependencies and devDependencies of all subscribed packages.

    // Now the task is to loop through the packages, find dependencies and
    // devDependencies that are out of date.  Record a list of packages with
    // out of data deps.
		var newDependenciesCount = 0;
    var newPackages = {};
    var yesterday = new Date();
    yesterday.setHours(-25);
    Object.keys(packages).forEach(findDependencies);

    function findDependencies(repo) {
      if (!newPackages[repo])
        newPackages[repo] = {};
      newPackages[repo].dependencies = {};
      newPackages[repo].devDependencies = {};

      if (packages[repo].dependencies)
        Object.keys(packages[repo].dependencies).forEach(checkDepVersionFor(packages[repo].dependencies, newPackages[repo].dependencies));
      if (packages[repo].devDependencies)
        Object.keys(packages[repo].devDependencies).forEach(checkDepVersionFor(packages[repo].devDependencies, newPackages[repo].devDependencies));

      function checkDepVersionFor(dep, result) {
        return function (pack) {
          if (versions[pack].updated >= yesterday && semver.isNew(versions[pack].latest, dep[pack])) {
            result[pack] = { old: dep[pack], current: versions[pack].latest };
            newDependenciesCount++;
          }
        };
      }

			console.info('%s has %s dev and %s regular dependencies', repo, Object.keys(newPackages[repo].devDependencies).length, Object.keys(newPackages[repo].dependencies).length);
    }

    console.info('There are %s new dependencies.', newDependenciesCount);

    // Then loop through the email address and for each one, loop through it's
    // packages.  If any of them had out-of-date deps, prepare and send an email.
    // If sending an email is an async operation, you can do it in an asyncMap
    // so that you can catch errors and be notified when they are all done.
    asyncMap(emails, processEmail, onProcessedEmails);
    console.info('emails obj %s with %s keys', emails, Object.keys(emails).length);

    function processEmail(email, callback) {
      console.info('loop email %s', email);
      Object.keys(email).forEach(sendEmail);

      function sendEmail(key) {
        emails[key].forEach(function (repo) {
          var newPacks = newPackages[repo];
          var numNewPacks = Object.keys(newPacks.dependencies).length + Object.keys(newPacks.devDependencies).length;
          console.info('Email. Key: %s, repo: %s, new packages: %s', key, repo, numNewPacks);
          if (numNewPacks === 0)
            return callback();

          var repourl = github.getUrlFromUserWithRepo(repo);
          console.info('Sending email to ' + key + ' for ' + repourl + ' about potentially ' + numNewPacks + ' packages.');
          emailWrapper.send(key, repourl, newPacks, callback);
        });
      }
    }

    function onProcessedEmails(error) {
      // Once done, call the outer `callback` to release the global lock and let
      // the server log that the action is complete.
      callback(error);
    }
  }

}
<commit_msg>Fix email loop.<commit_after>var asyncMap = require('./async-map');

var semver = require('./semver');
var github = require('./github');
var npmWrapper = require('./npm');
var db = require('./db');
var emailWrapper = require('./email');

var running = false;

exports.start = function() {
  // Only allow one instance to run at a time
  if (running) {
    console.log("Check already running.");
    return false;
  }
  console.log("Starting check.");
  running = true;
  var retriesLeft = 2;
  checkUpdates(onDone);
  return true;

  function onDone(error) {
    if (error) {
      console.error(error);
      if (retriesLeft--) {
        return checkUpdates(onDone);
      }
      running = false;
      console.log("Giving up!");
    }
    else {
      running = false;
      console.log("Check finished.");
    }
  }
};

function checkUpdates(callback) {

  // Mapping of unique email address to list of packages
  var emails = {};

  // List of packages to monitor, indexed by user/name string
  // Each entry contains:
  //   dependencies - a map of dependency name to version
  //   devDependencies - a map of dev dependency name to version
  var packages = {};

  // This is a mapping of dependency name to dependent package
  // key is dependency name, value is direct reference to entry in packages hash
  var dependents = {};

  // First we need to load all the subscriptions
  db.readSubscriptions(onSubscriptions);

  function onSubscriptions(error, subscriptions) {
    if (error) return callback(error);

    asyncMap(subscriptions, function (subscription, callback) {
      var user = github.getUserFromUrl(subscription.repourl);
      var repo = github.getRepoFromUrl(subscription.repourl);
      var key = user + "/" + repo;

      // Record this email/package combo
      var watching = emails[subscription.email];
      if (watching) watching.push(key);
      else emails[subscription.email] = [key];

      if (packages[key]) {
        // Someone else is already watching for changes in this project
        return;
      }

      packages[key] = {};

      github.getPackageJson(user, repo, function (error, meta) {
        if (error) return callback(error);
        if (meta.dependencies) {
          packages[key].dependencies = meta.dependencies;
          Object.keys(meta.dependencies).forEach(addLink);
        }
        if (meta.devDependencies) {
          packages[key].devDependencies = meta.devDependencies;
          Object.keys(meta.devDependencies).forEach(addLink);
        }
        callback();
      });

      function addLink(name) {
        if (dependents[name]) dependents[name].push(key);
        else dependents[name] = [key];
      }

    }, onProcessed);
  }

  function onProcessed(error) {
    if (error) return callback(error);
    console.log("Checking %s unique packages with %s total unique dependencies for %s unique email addresses.",
                Object.keys(packages).length,
                Object.keys(dependents).length,
                Object.keys(emails).length);
    npmWrapper.getLatestVersions(Object.keys(dependents), onVersions);
  }

  function onVersions(error, versions) {
    if (error) return callback(error);
/*
    console.info({
      emails: emails,
      dependents: dependents,
      packages: packages,
      versions: versions
    });
*/
    // We now have emails of all the people interested in updates.
    // We also have the list of subscriptions grouped by user/name projects key.
    // We also have the latest version of any npm package that we care about.
    // We also have the dependencies and devDependencies of all subscribed packages.

    // Now the task is to loop through the packages, find dependencies and
    // devDependencies that are out of date.  Record a list of packages with
    // out of data deps.
		var newDependenciesCount = 0;
    var newPackages = {};
    var yesterday = new Date();
    yesterday.setHours(-25);
    Object.keys(packages).forEach(findDependencies);

    function findDependencies(repo) {
      if (!newPackages[repo])
        newPackages[repo] = {};
      newPackages[repo].dependencies = {};
      newPackages[repo].devDependencies = {};

      if (packages[repo].dependencies)
        Object.keys(packages[repo].dependencies).forEach(checkDepVersionFor(packages[repo].dependencies, newPackages[repo].dependencies));
      if (packages[repo].devDependencies)
        Object.keys(packages[repo].devDependencies).forEach(checkDepVersionFor(packages[repo].devDependencies, newPackages[repo].devDependencies));

      function checkDepVersionFor(dep, result) {
        return function (pack) {
          if (versions[pack].updated >= yesterday && semver.isNew(versions[pack].latest, dep[pack])) {
            result[pack] = { old: dep[pack], current: versions[pack].latest };
            newDependenciesCount++;
          }
        };
      }

			console.info('%s has %s dev and %s regular dependencies', repo, Object.keys(newPackages[repo].devDependencies).length, Object.keys(newPackages[repo].dependencies).length);
    }

    console.info('There are %s new dependencies.', newDependenciesCount);

    // Then loop through the email address and for each one, loop through it's
    // packages.  If any of them had out-of-date deps, prepare and send an email.
    // If sending an email is an async operation, you can do it in an asyncMap
    // so that you can catch errors and be notified when they are all done.
    console.info('emails obj %s with %s keys', emails, Object.keys(emails).length);
    asyncMap(Object.keys(emails), processEmail, onProcessedEmails);

    function processEmail(email, callback) {
      console.info('loop email %s', email);

      emails[email].forEach(function (repo) {
        var newPacks = newPackages[repo];
        var numNewPacks = Object.keys(newPacks.dependencies).length + Object.keys(newPacks.devDependencies).length;
        console.info('Email. Key: %s, repo: %s, new packages: %s', key, repo, numNewPacks);
        if (numNewPacks === 0)
          return callback();

        var repourl = github.getUrlFromUserWithRepo(repo);
        console.info('Sending email to ' + key + ' for ' + repourl + ' about potentially ' + numNewPacks + ' packages.');
        emailWrapper.send(key, repourl, newPacks, callback);
      });
    }

    function onProcessedEmails(error) {
      // Once done, call the outer `callback` to release the global lock and let
      // the server log that the action is complete.
      callback(error);
    }
  }

}
<|endoftext|>


<commit_before>'use strict';

/**
 * @license
 * (c) 2014 Cluster Labs, Inc. https://cluster.co/
 * License: MIT
 */

var crypto = require('crypto');
var fs = require('fs');
var path = require('path');

var uglify = require('uglify-js');

var SkitModule = require('./loader/SkitModule');
var loader = require('./loader/loader');
var scriptresource = require('./loader/scriptresource');
var skitutil = require('./skitutil');

var TargetEnvironment = scriptresource.TargetEnvironment;

//
// OPTIMIZER
//

function staticFilename(filename, fileContent) {
  var parts = filename.split('.');
  var md5 = crypto.createHash('md5').update(fileContent).digest('hex');
  parts[0] += '-v' + md5.substring(0, 12);
  return parts.join('.');
}

function optimizeServer(server, optimizedPackagePath, opt_options) {
  var options = opt_options || {};

  var aliasMapFilename = options.aliasMap;
  var publicStaticRoot = options.staticRoot || '';

  // COMBINE MODULES FOR PUBLIC SERVING
  var STATIC_PREFIX = '/' + server.staticPrefix;

  var moduleToStaticAliasMap = {};

  var bundleFiles = {};
  var bundles = server.loader.allBundles();
  var bundlesByFilename = {};
  bundles.forEach(function(bundle) {
    var bundleScripts = [];
    var bundleStylesheets = [];

    var jsFilename = path.join(STATIC_PREFIX, bundle.name + '.js');
    bundlesByFilename[jsFilename] = bundle;
    var cssFilename = path.join(STATIC_PREFIX, bundle.name + '.css');
    bundlesByFilename[cssFilename] = bundle;

    console.log('Building bundle "' + bundle.name + '"...');

    bundle.allStyles().forEach(function(css) {
      moduleToStaticAliasMap[css.resourcePath] = cssFilename;

      var body = css.bodyContentType().body;
      bundleStylesheets.push(body);
    });

    bundle.allScripts().forEach(function(script) {
      if (!script.includeInEnvironment(TargetEnvironment.BROWSER)) {
        return;
      }
      moduleToStaticAliasMap[script.resourcePath] = jsFilename;

      var body = script.bodyContentType().body;
      bundleScripts.push(body);
    });

    bundleFiles[cssFilename] = bundleStylesheets.join('\n');
    bundleFiles[jsFilename] = bundleScripts.join('\n');
  });

  // VERSION, UPDATE AND COPY ALL STATIC FILES

  console.log('Loading raw files that might need updated references...');

  var resolvedPackagePath = server.packagePath;
  if (resolvedPackagePath.charAt(resolvedPackagePath.length - 1) == '/') {
    resolvedPackagePath = resolvedPackagePath.substring(0, resolvedPackagePath.length - 1);
  }

  var allFiles = loader.walkSync(resolvedPackagePath);

  var filenameToContent = {};
  var staticFiles = [];
  var staticBasenames = {};

  allFiles.forEach(function(filename) {
    var basename = path.basename(filename);
    if (basename.indexOf('.') == 0) {
      return;
    }

    var relativeFilename = filename.replace(server.packagePath, '');

    var content = fs.readFileSync(filename);
    var stringContent = content + '';
    if (stringContent.indexOf('\ufffd') == -1) {
      content = stringContent;
    }

    filenameToContent[relativeFilename] = content;
    if (relativeFilename.indexOf(STATIC_PREFIX) == 0) {
      staticFiles.push(relativeFilename);
      staticBasenames[path.basename(relativeFilename)] = true;
    }
  });

  // BUILD RAW BUNDLE FILES AS IF THEY WERE REAL FILES
  // Shunt these right in here so they get versioned and written out,
  // without having to actually do that manually.
  for (var bundleFilename in bundleFiles) {
    staticFiles.push(bundleFilename);
    filenameToContent[bundleFilename] = bundleFiles[bundleFilename];
    staticBasenames[path.basename(bundleFilename)] = true;
  }
  filenameToContent[aliasMapFilename] = JSON.stringify(moduleToStaticAliasMap);

  // Minify these before doing the versioning in order to minimize the number
  // of changes that actually generate new versions of these files.
  // ie. comments / whitespace / local variable names should not create new
  // versions as long as we minify first.
  var relativeFilenames = Object.keys(filenameToContent);
  relativeFilenames.forEach(function(filename) {
    var original = filenameToContent[filename];
    if (/\.js$/.test(filename) && filename.indexOf(STATIC_PREFIX) == 0) {
      console.log('Minifying:', filename, '...');

      var uglifyOptions = {fromString: true};

      // Allow bundle to specify uglify options.
      var bundle = bundlesByFilename[filename];
      if (bundle && bundle.options) {
        if ('minify' in bundle.options && !bundle.options.minify) {
          // continue;
          return;
        }

        if (bundle.options.uglifyOptions) {
          for (var k in bundle.options.uglifyOptions) {
            uglifyOptions[k] = bundle.options.uglifyOptions[k];
          }
        }
      }

      filenameToContent[filename] = uglify.minify(original, uglifyOptions).code;
    }
  });

  console.log('Versioning static files...');

  var staticFilenamesIndex = {};
  staticFiles.forEach(function(filename) {
    var sfilename = staticFilename(filename, filenameToContent[filename]);
    // TODO(Taylor): Replace /__static__/ with https://foo/bar/.
    staticFilenamesIndex[filename] = sfilename;
  });

  console.log('Updating all references to static resources throughout the codebase...');

  var escapedBasenames = Object.keys(staticBasenames).map(function(basename) {
    return skitutil.escapeRegex(basename);
  });
  var replaceContentRegex = new RegExp(
      "(['\"(])(/?(?:[\\w.-]+/)*(?:" + escapedBasenames.join('|') + "))(\\\\?['\")])", 'g');

  var relativeFilenames = Object.keys(filenameToContent);
  relativeFilenames.forEach(function(filename) {
    var original = filenameToContent[filename];
    if (!original.replace) {
      // Buffer, probably binary object.
      return;
    }

    filenameToContent[filename] = original.replace(replaceContentRegex, function(_, quote1, match, quote2) {
      if (match.indexOf('/') != 0 && match.indexOf('://') == -1) {
        match = path.join(path.dirname(filename), match);
      }
      if (match in staticFilenamesIndex) {
        match = staticFilenamesIndex[match];

        if (publicStaticRoot) {
          match = publicStaticRoot + match.replace(STATIC_PREFIX, '');
        }
      }
      return quote1 + match + quote2;
    });
  });

  // WRITE ALL OPTIMIZED FILES TO DISK

  console.log('Writing optimized files to disk...');

  var optimizedPackagePath = path.resolve(optimizedPackagePath);
  loader.mkdirPSync(optimizedPackagePath);

  relativeFilenames.forEach(function(filename) {
    var body = filenameToContent[filename];

    var outfiles = [filename];
    if (filename in staticFilenamesIndex) {
      outfiles.push(staticFilenamesIndex[filename]);
    }

    outfiles.forEach(function(destinationFilename) {
      var absoluteFilename = path.join(optimizedPackagePath, destinationFilename);
      loader.mkdirPSync(path.dirname(absoluteFilename));

      fs.writeFileSync(absoluteFilename, body);
    });
  });

  console.log('All done!');
}

module.exports = {
  optimizeServer: optimizeServer
};<commit_msg>Also include unbundled resource files in static root when optimizing. This allows unbundled resources to be served from CDN and removed from hosting environment of production skit instance.<commit_after>'use strict';

/**
 * @license
 * (c) 2014 Cluster Labs, Inc. https://cluster.co/
 * License: MIT
 */

var crypto = require('crypto');
var fs = require('fs');
var path = require('path');

var uglify = require('uglify-js');

var SkitModule = require('./loader/SkitModule');
var loader = require('./loader/loader');
var scriptresource = require('./loader/scriptresource');
var skitutil = require('./skitutil');

var TargetEnvironment = scriptresource.TargetEnvironment;

//
// OPTIMIZER
//

function staticFilename(filename, fileContent) {
  var parts = filename.split('.');
  var md5 = crypto.createHash('md5').update(fileContent).digest('hex');
  parts[0] += '-v' + md5.substring(0, 12);
  return parts.join('.');
}

function optimizeServer(server, optimizedPackagePath, opt_options) {
  var options = opt_options || {};

  var aliasMapFilename = options.aliasMap;
  var publicStaticRoot = options.staticRoot || '';

  // COMBINE MODULES FOR PUBLIC SERVING
  var STATIC_PREFIX = '/' + server.staticPrefix;

  var moduleToStaticAliasMap = {};

  var bundleFiles = {};
  var bundles = server.loader.allBundles();
  var bundlesByFilename = {};
  bundles.forEach(function(bundle) {
    var bundleScripts = [];
    var bundleStylesheets = [];

    var jsFilename = path.join(STATIC_PREFIX, bundle.name + '.js');
    bundlesByFilename[jsFilename] = bundle;
    var cssFilename = path.join(STATIC_PREFIX, bundle.name + '.css');
    bundlesByFilename[cssFilename] = bundle;

    console.log('Building bundle "' + bundle.name + '"...');

    bundle.allStyles().forEach(function(css) {
      moduleToStaticAliasMap[css.resourcePath] = cssFilename;

      var body = css.bodyContentType().body;
      bundleStylesheets.push(body);
    });

    bundle.allScripts().forEach(function(script) {
      if (!script.includeInEnvironment(TargetEnvironment.BROWSER)) {
        return;
      }
      moduleToStaticAliasMap[script.resourcePath] = jsFilename;

      var body = script.bodyContentType().body;
      bundleScripts.push(body);
    });

    bundleFiles[cssFilename] = bundleStylesheets.join('\n');
    bundleFiles[jsFilename] = bundleScripts.join('\n');
  });

  // ADD ANY FILES NOT IN BUNDLES

  var resolvedPackagePath = server.packagePath;
  if (resolvedPackagePath.charAt(resolvedPackagePath.length - 1) == '/') {
    resolvedPackagePath = resolvedPackagePath.substring(0, resolvedPackagePath.length - 1);
  }

  var filenameToContent = {};
  var staticFiles = [];
  var staticBasenames = {};

  // VERSION, UPDATE AND COPY ALL STATIC FILES

  console.log('Loading raw files that might need updated references...');

  var allFiles = loader.walkSync(resolvedPackagePath);

  allFiles.forEach(function(filename) {
    var basename = path.basename(filename);
    if (basename.indexOf('.') == 0) {
      return;
    }

    var relativeFilename = filename.replace(server.packagePath, '');

    var content = fs.readFileSync(filename);
    var stringContent = content + '';
    if (stringContent.indexOf('\ufffd') == -1) {
      content = stringContent;
    }

    filenameToContent[relativeFilename] = content;
    if (relativeFilename.indexOf(STATIC_PREFIX) == 0) {
      staticFiles.push(relativeFilename);
      staticBasenames[path.basename(relativeFilename)] = true;
    }
  });

  // BUILD RAW BUNDLE FILES AS IF THEY WERE REAL FILES

  for (var bundleFilename in bundleFiles) {
    filenameToContent[bundleFilename] = bundleFiles[bundleFilename];
    staticFiles.push(bundleFilename);
    staticBasenames[path.basename(bundleFilename)] = true;
  }

  // BUILD UNBUNDLED RESOURCE FILES AS IF THEY WERE REAL FILES, TOO

  console.log('Loading any unbundled public resources to static root...');

  var allPublicModules = server.loader.getPublicRoot().descendants();
  allPublicModules.forEach(function(module) {
    if (!(module instanceof SkitModule)) {
      // just a parent dir.
      return;
    }

    module.buildResourceList().forEach(function(res) {
      if (moduleToStaticAliasMap[res.resourcePath]) {
        // already in a bundle.
        return;
      }
      if (res.includeInEnvironment && !res.includeInEnvironment(TargetEnvironment.BROWSER)) {
        return;
      }

      var bodyContentType = res.bodyContentType();
      var extension = '.js';
      if (bodyContentType.contentType.indexOf('/css') > 0) {
        extension = '.css';
      }
      var relativeFilename = res.resourcePath.replace(/[:\.]/g, '_') + extension;
      var newStaticFilename = path.join(STATIC_PREFIX, '__resource__', relativeFilename);

      // Add this file to output dir and minify
      filenameToContent[newStaticFilename] = bodyContentType.body;
      // Load these modules from static instead of serving them
      moduleToStaticAliasMap[res.resourcePath] = newStaticFilename;

      // Version these new static files and update any references,
      // namely in alias map JSON.
      staticFiles.push(newStaticFilename);
      staticBasenames[path.basename(newStaticFilename)] = true;
    });
  });

  filenameToContent[aliasMapFilename] = JSON.stringify(moduleToStaticAliasMap, null, '  ');

  // Minify these before doing the versioning in order to minimize the number
  // of changes that actually generate new versions of these files.
  // ie. comments / whitespace / local variable names should not create new
  // versions as long as we minify first.
  var relativeFilenames = Object.keys(filenameToContent);
  relativeFilenames.forEach(function(filename) {
    var original = filenameToContent[filename];
    if (/\.js$/.test(filename) && filename.indexOf(STATIC_PREFIX) == 0) {
      console.log('Minifying:', filename, '...');

      var uglifyOptions = {fromString: true};

      // Allow bundle to specify uglify options.
      var bundle = bundlesByFilename[filename];
      if (bundle && bundle.options) {
        if ('minify' in bundle.options && !bundle.options.minify) {
          // continue;
          return;
        }

        if (bundle.options.uglifyOptions) {
          for (var k in bundle.options.uglifyOptions) {
            uglifyOptions[k] = bundle.options.uglifyOptions[k];
          }
        }
      }

      filenameToContent[filename] = uglify.minify(original, uglifyOptions).code;
    }
  });

  console.log('Versioning static files...');

  var staticFilenamesIndex = {};
  staticFiles.forEach(function(filename) {
    var sfilename = staticFilename(filename, filenameToContent[filename]);
    // TODO(Taylor): Replace /__static__/ with https://foo/bar/.
    staticFilenamesIndex[filename] = sfilename;
  });

  console.log('Updating all references to static resources throughout the codebase...');

  var escapedBasenames = Object.keys(staticBasenames).map(function(basename) {
    return skitutil.escapeRegex(basename);
  });
  var replaceContentRegex = new RegExp(
      "(['\"(])(/?(?:[\\w.-]+/)*(?:" + escapedBasenames.join('|') + "))(\\\\?['\")])", 'g');

  var relativeFilenames = Object.keys(filenameToContent);
  relativeFilenames.forEach(function(filename) {
    var original = filenameToContent[filename];
    if (!original.replace) {
      // Buffer, probably binary object.
      return;
    }

    filenameToContent[filename] = original.replace(replaceContentRegex, function(_, quote1, match, quote2) {
      if (match.indexOf('/') != 0 && match.indexOf('://') == -1) {
        match = path.join(path.dirname(filename), match);
      }
      if (match in staticFilenamesIndex) {
        match = staticFilenamesIndex[match];

        if (publicStaticRoot) {
          match = publicStaticRoot + match.replace(STATIC_PREFIX, '');
        }
      }
      return quote1 + match + quote2;
    });
  });

  // WRITE ALL OPTIMIZED FILES TO DISK

  console.log('Writing optimized files to disk...');

  var optimizedPackagePath = path.resolve(optimizedPackagePath);
  loader.mkdirPSync(optimizedPackagePath);

  relativeFilenames.forEach(function(filename) {
    var body = filenameToContent[filename];

    var outfiles = [filename];
    if (filename in staticFilenamesIndex) {
      outfiles.push(staticFilenamesIndex[filename]);
    }

    outfiles.forEach(function(destinationFilename) {
      var absoluteFilename = path.join(optimizedPackagePath, destinationFilename);
      loader.mkdirPSync(path.dirname(absoluteFilename));

      fs.writeFileSync(absoluteFilename, body);
    });
  });

  console.log('All done!');
}

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


<commit_before>import React, { Component, PropTypes } from 'react';
import { View, Text, Image, TouchableOpacity } from 'react-native';
import styles from 'example/src/styles/SliderEntry.style';

export default class SliderEntry extends Component {

    static propTypes = {
        title: PropTypes.string.isRequired,
        subtitle: PropTypes.string,
        illustration: PropTypes.string
    };

    render () {
        const { title, subtitle, illustration } = this.props;

        return (
            <TouchableOpacity
              activeOpacity={0.9}
              style={styles.slideInnerContainer}
              >
                <View style={styles.imageContainer}>
                    <Image
                      source={{ uri: illustration }}
                      style={styles.image}
                    />
                </View>
                <View style={styles.textContainer}>
                    <Text style={styles.title} numberOfLines={2}>{ title.toUpperCase() }</Text>
                    <Text style={styles.subtitle} numberOfLines={2}>{ subtitle }</Text>
                </View>
            </TouchableOpacity>
        );
    }
}
<commit_msg>refactor(example): add 'onPress' to SliderEntry<commit_after>import React, { Component, PropTypes } from 'react';
import { View, Text, Image, TouchableOpacity } from 'react-native';
import styles from 'example/src/styles/SliderEntry.style';

export default class SliderEntry extends Component {

    static propTypes = {
        title: PropTypes.string.isRequired,
        subtitle: PropTypes.string,
        illustration: PropTypes.string
    };

    render () {
        const { title, subtitle, illustration } = this.props;

        return (
            <TouchableOpacity
              activeOpacity={0.9}
              style={styles.slideInnerContainer}
              onPress={() => { alert(`You've clicked '${title}'`); }}
              >
                <View style={styles.imageContainer}>
                    <Image
                      source={{ uri: illustration }}
                      style={styles.image}
                    />
                </View>
                <View style={styles.textContainer}>
                    <Text style={styles.title} numberOfLines={2}>{ title.toUpperCase() }</Text>
                    <Text style={styles.subtitle} numberOfLines={2}>{ subtitle }</Text>
                </View>
            </TouchableOpacity>
        );
    }
}
<|endoftext|>


<commit_before>/* Client Side JavaScript */

/* Init window */
function init() {

	var socket = io.connect('/client');

	// set cookie when receiving api key
	socket.on('joined', function (apikey) {
		$.cookie('the_magic_oulu_cookie', apikey, { expires: 365, path: '/' });
		console.log('Magic cookie set with apikey '+ apikey);
	});

	// request api key if cookie not found
	if (! $.cookie('the_magic_oulu_cookie')) {
		console.log('Requesting api key from server');
		socket.emit('create');
	};

	// receive line from IRC
	socket.on('icecap-event', function (name, data) {
		console.log("icecap-event received: '" + name + "'");
		$('#ircrows').append('
test
');
		if(name !== 'msg') return;
		$('#ircrows').append('
'+ HHmm(data.time) +' <'+ data.presence +'> '+ data.msg +'
');
	});

	// send line to IRC
	$('#sendmsgform').submit(function (event) {
		event.preventDefault();
		socket.emit('icecap.command', 'msg', { 'presence': 'jheusala2', 'msg': $('#prompt').val() } );

		// clear the text field
		$('#prompt').val('');
	});

	// set nick
	$('#loginform').submit(function (event) {
		event.preventDefault();
		socket.emit('login', $('#nick').val());
	});
}

// Convert unix-timestamp to HH:MM format
function HHmm(time) {
	var dt = new Date(time * 1000);

	var hours = dt.getHours();
	var minutes = dt.getMinutes();

	if ( minutes < 10) {
		minutes = "0"+minutes;
	};
	if ( hours < 10) {
		hours = "0"+hours;
	};
	return hours +":"+ minutes;
};

// jquery
$(document).ready(function() {
	init();
});

/* EOF */
<commit_msg>comments<commit_after>/* Client Side JavaScript */

/* Init window */
function init() {

	var socket = io.connect('/client');

	// set cookie if/when receiving api key
	socket.on('joined', function (apikey) {
		$.cookie('the_magic_oulu_cookie', apikey, { expires: 365, path: '/' });
		console.log('Magic cookie set with apikey '+ apikey);
	});

	// request api key if cookie not found
	if (! $.cookie('the_magic_oulu_cookie')) {
		console.log('Requesting api key from server');
		socket.emit('create');
	};

	// receive line from IRC
	socket.on('icecap-event', function (name, data) {
		console.log("icecap-event received: '" + name + "'");
		$('#ircrows').append('
test
');
		if(name !== 'msg') return;
		$('#ircrows').append('
'+ HHmm(data.time) +' <'+ data.presence +'> '+ data.msg +'
');
	});

	// send line to IRC
	$('#sendmsgform').submit(function (event) {
		event.preventDefault();
		socket.emit('icecap.command', 'msg', { 'presence': 'jheusala2', 'msg': $('#prompt').val() } );

		// clear the text field
		$('#prompt').val('');
	});

	// set nick
	$('#loginform').submit(function (event) {
		event.preventDefault();
		socket.emit('login', $('#nick').val());
	});
}

// Convert unix-timestamp to HH:MM format
function HHmm(time) {
	var dt = new Date(time * 1000);

	var hours = dt.getHours();
	var minutes = dt.getMinutes();

	if ( minutes < 10) {
		minutes = "0"+minutes;
	};
	if ( hours < 10) {
		hours = "0"+hours;
	};

	return hours +":"+ minutes;
};

// jquery
$(document).ready(function() {
	init();
});

/* EOF */
<|endoftext|>


<commit_before>var m = require('mithril');
var Raven = require('raven-js');
var $osf = require('js/osfHelpers');
var ShareJSDoc = require('js/pages/ShareJSDocFile.js');
require('ace-noconflict');
require('ace-mode-markdown');
require('ace-ext-language_tools');
require('addons/wiki/static/ace-markdown-snippets.js');
var Markdown = require('pagedown-ace-converter');
Markdown.getSanitizingConverter = require('pagedown-ace-sanitizer').getSanitizingConverter;
require('imports?Markdown=pagedown-ace-converter!pagedown-ace-editor');

var util = require('./util.js');

var model = {};

var FileEditor = {
    controller: function(contentUrl, shareWSUrl, editorMeta, observables) {
        var self = {};

        self.url = contentUrl;
        self.loaded = false;
        self.initialText = '';
        self.editorMeta = editorMeta;

        self.observables = observables;

        self.unthrottledStatus = self.observables.status;
        $osf.throttle(self.observables.status, 4000, {leading: false});

        self.bindAce = function(element, isInitialized, context) {
            if (isInitialized) {
                return;
            }
            model.editor = ace.edit(element.id);
            model.editor.setValue(self.initialText, -1);
            new ShareJSDoc(shareWSUrl, self.editorMeta, model.editor, self.observables);
        };

        self.reloadFile = function() {
            self.loaded = false;
            $.ajax({
                type: 'GET',
                url: self.url,
                dataType: 'text',
                beforeSend: $osf.setXHRAuthorization,
            }).done(function (parsed, status, response) {
                m.startComputation();
                self.loaded = true;
                self.initialText = response.responseText;
                if (model.editor) {
                    model.editor.setValue(self.initialText);
                }
                m.endComputation();
            }).fail(function (xhr, textStatus, error) {
                $osf.growl('Error','The file content could not be loaded.');
                Raven.captureMessage('Could not GET file contents.', {
                    url: self.url,
                    textStatus: textStatus,
                    error: error
                });
            });
        };

        self.saveFile = $osf.throttle(function() {
            if(self.changed()) {
                var oldstatus = self.observables.status();
                model.editor.setReadOnly(true);
                self.unthrottledStatus('saving');
                m.redraw();
                var request = $.ajax({
                    type: 'PUT',
                    url: self.url,
                    data: model.editor.getValue(),
                    beforeSend: $osf.setXHRAuthorization
                }).done(function () {
                    model.editor.setReadOnly(false);
                    self.unthrottledStatus(oldstatus);
                    $(document).trigger('fileviewpage:reload');
                    self.initialText = model.editor.getValue();
                    m.redraw();
                }).fail(function(xhr, textStatus, err) {
                    var message;
                    if (xhr.status === 507) {
                        message = 'Could not update file. Insufficient storage space in your Dropbox.';
                    } else {
                        message = 'The file could not be updated.';
                    }
                    model.editor.setReadOnly(false);
                    self.unthrottledStatus(oldstatus);
                    $(document).trigger('fileviewpage:reload');
                    model.editor.setValue(self.initialText);
                    $osf.growl('Error', message);
                    Raven.captureMessage('Could not PUT file content.', {
                        textStatus: textStatus,
                        url: self.url
                    });
                    m.redraw();
                });
            }
        }, 500);

        self.changed = function() {
            var file1 = self.initialText;
            var file2 = !model.editor ? '' : model.editor.getValue();

            var clean1 = typeof file1 === 'string' ?
                file1.replace(/(\r\n|\n|\r)/gm, '\n') : '';
            var clean2 = typeof file2 === 'string' ?
                file2.replace(/(\r\n|\n|\r)/gm, '\n') : '';

            return clean1 !== clean2;
        };

        self.reloadFile();

        return self;
    },
    view: function(ctrl) {
        if (!ctrl.loaded) {
            return util.Spinner;
        }
        return m('.editor-pane.panel-body', [
            m('.wiki-connected-users', m('.row', m('.col-sm-12', [
                m('.ul.list-inline', {style: {'margin-top': '10px'}}, [
                    ctrl.observables.activeUsers().map(function(user) {
                        return m('li', m('a', {href: user.url}, [
                            m('img', {
                                title: user.name,
                                src: user.gravatar,
                                'data-container': 'body',
                                'data-placement': 'top',
                                'data-toggle': 'tooltip',
                                style: {border: '1px solid black'}
                            })
                        ]));
                    })

                ])
            ]))),
            m('', {style: {'padding-top': '10px'}}, [
                m('.wmd-input.wiki-editor#editor', {config: ctrl.bindAce})
            ]),
            m('br'),
            m('[style=position:inherit]', [
                m('.row', m('.col-sm-12', [
                    m('.pull-right', [
                        m('button#fileEditorRevert.btn.btn-sm.btn-danger', {onclick: function(){ctrl.reloadFile();}}, 'Revert'),
                        ' ',
                        m('button#fileEditorSave.btn.btn-sm.btn-success', {onclick: function() {ctrl.saveFile();}}, 'Save')
                    ])
                ]))
            ])
        ]);

    }
};

module.exports = FileEditor;
<commit_msg>Delete no change checking<commit_after>var m = require('mithril');
var Raven = require('raven-js');
var $osf = require('js/osfHelpers');
var ShareJSDoc = require('js/pages/ShareJSDocFile.js');
require('ace-noconflict');
require('ace-mode-markdown');
require('ace-ext-language_tools');
require('addons/wiki/static/ace-markdown-snippets.js');
var Markdown = require('pagedown-ace-converter');
Markdown.getSanitizingConverter = require('pagedown-ace-sanitizer').getSanitizingConverter;
require('imports?Markdown=pagedown-ace-converter!pagedown-ace-editor');

var util = require('./util.js');

var model = {};

var FileEditor = {
    controller: function(contentUrl, shareWSUrl, editorMeta, observables) {
        var self = {};

        self.url = contentUrl;
        self.loaded = false;
        self.initialText = '';
        self.editorMeta = editorMeta;

        self.observables = observables;

        self.unthrottledStatus = self.observables.status;
        $osf.throttle(self.observables.status, 4000, {leading: false});

        self.bindAce = function(element, isInitialized, context) {
            if (isInitialized) {
                return;
            }
            model.editor = ace.edit(element.id);
            model.editor.setValue(self.initialText, -1);
            new ShareJSDoc(shareWSUrl, self.editorMeta, model.editor, self.observables);
        };

        self.reloadFile = function() {
            self.loaded = false;
            $.ajax({
                type: 'GET',
                url: self.url,
                dataType: 'text',
                beforeSend: $osf.setXHRAuthorization,
            }).done(function (parsed, status, response) {
                m.startComputation();
                self.loaded = true;
                self.initialText = response.responseText;
                if (model.editor) {
                    model.editor.setValue(self.initialText);
                }
                m.endComputation();
            }).fail(function (xhr, textStatus, error) {
                $osf.growl('Error','The file content could not be loaded.');
                Raven.captureMessage('Could not GET file contents.', {
                    url: self.url,
                    textStatus: textStatus,
                    error: error
                });
            });
        };

        self.saveFile = $osf.throttle(function() {
            var oldstatus = self.observables.status();
            model.editor.setReadOnly(true);
            self.unthrottledStatus('saving');
            m.redraw();
            var request = $.ajax({
                type: 'PUT',
                url: self.url,
                data: model.editor.getValue(),
                beforeSend: $osf.setXHRAuthorization
            }).done(function () {
                model.editor.setReadOnly(false);
                self.unthrottledStatus(oldstatus);
                $(document).trigger('fileviewpage:reload');
                self.initialText = model.editor.getValue();
                m.redraw();
            }).fail(function(xhr, textStatus, err) {
                var message;
                if (xhr.status === 507) {
                    message = 'Could not update file. Insufficient storage space in your Dropbox.';
                } else {
                    message = 'The file could not be updated.';
                }
                model.editor.setReadOnly(false);
                self.unthrottledStatus(oldstatus);
                $(document).trigger('fileviewpage:reload');
                model.editor.setValue(self.initialText);
                $osf.growl('Error', message);
                Raven.captureMessage('Could not PUT file content.', {
                    textStatus: textStatus,
                    url: self.url
                });
                m.redraw();
            });
        }, 500);

        self.changed = function() {
            var file1 = self.initialText;
            var file2 = !model.editor ? '' : model.editor.getValue();

            var clean1 = typeof file1 === 'string' ?
                file1.replace(/(\r\n|\n|\r)/gm, '\n') : '';
            var clean2 = typeof file2 === 'string' ?
                file2.replace(/(\r\n|\n|\r)/gm, '\n') : '';

            return clean1 !== clean2;
        };

        self.reloadFile();

        return self;
    },
    view: function(ctrl) {
        if (!ctrl.loaded) {
            return util.Spinner;
        }
        return m('.editor-pane.panel-body', [
            m('.wiki-connected-users', m('.row', m('.col-sm-12', [
                m('.ul.list-inline', {style: {'margin-top': '10px'}}, [
                    ctrl.observables.activeUsers().map(function(user) {
                        return m('li', m('a', {href: user.url}, [
                            m('img', {
                                title: user.name,
                                src: user.gravatar,
                                'data-container': 'body',
                                'data-placement': 'top',
                                'data-toggle': 'tooltip',
                                style: {border: '1px solid black'}
                            })
                        ]));
                    })

                ])
            ]))),
            m('', {style: {'padding-top': '10px'}}, [
                m('.wmd-input.wiki-editor#editor', {config: ctrl.bindAce})
            ]),
            m('br'),
            m('[style=position:inherit]', [
                m('.row', m('.col-sm-12', [
                    m('.pull-right', [
                        m('button#fileEditorRevert.btn.btn-sm.btn-danger', {onclick: function(){ctrl.reloadFile();}}, 'Revert'),
                        ' ',
                        m('button#fileEditorSave.btn.btn-sm.btn-success', {onclick: function() {ctrl.saveFile();}}, 'Save')
                    ])
                ]))
            ])
        ]);

    }
};

module.exports = FileEditor;
<|endoftext|>


<commit_before>var SignUp = require('../signUp.js');
new SignUp('#signUpScope', '/api/v1/register/');
var TweenLite = require('TweenLite');
require('EasePack');
require('vendor/youtube');

// ANIMATION FOR FRONT PAGE
$( document ).ready(function() {
    $('#logo').removeClass('off');
    $('.youtube').YouTubeModal({autoplay:1, width:640, height:480});
});

(function() {
    var width;
    var height;
    var largeHeader;
    var canvas;
    var ctx;
    var points;
    var target;
    var animateHeader = true;
    // Main
    initHeader();
    initAnimation();
    addListeners();

    function initHeader() {
        width = window.innerWidth;
        height = '800';
        target = {x: width/2, y: height/2};

        largeHeader = document.getElementById('home-hero');

        canvas = document.getElementById('demo-canvas');
        canvas.width = width - 20;
        canvas.height = height;
        ctx = canvas.getContext('2d');

        // create points
        points = [];
        for(var x = 0; x < width; x = x + width/20) {
            for(var y = 0; y < height; y = y + height/20) {
                var px = x + Math.random()*width/20;
                var py = y + Math.random()*height/20;
                var p = {x: px, originX: px, y: py, originY: py };
                points.push(p);
            }
        }

        // for each point find the 5 closest points
        for(var i = 0; i < points.length; i++) {
            var closest = [];
            var p1 = points[i];
            for(var j = 0; j < points.length; j++) {
                var p2 = points[j];
                if(p1 !== p2) {
                    var placed = false;
                    for(var k = 0; k < 5; k++) {
                        if(!placed) {
                            if(closest[k] === undefined) {
                                closest[k] = p2;
                                placed = true;
                            }
                        }
                    }
                    for(var l = 0; l < 5; l++) {
                        if(!placed) {
                            if(getDistance(p1, p2) < getDistance(p1, closest[l])) {
                                closest[l] = p2;
                                placed = true;
                            }
                        }
                    }
                }
            }
            p1.closest = closest;
        }

        // assign a circle to each point
        for(var m in points) {
            var c = new Circle(points[m], 2+Math.random()*2, 'rgba(255,255,255,0.3)');
            points[m].circle = c;
        }
    }

    // Event handling
    function addListeners() {
        setPos();
        window.addEventListener('scroll', scrollCheck);
        window.addEventListener('resize', resize);
    }

    function setPos(e) {
        target.x = window.innerWidth/2;
        target.y = 330;
    }

    function scrollCheck() {
        if(document.body.scrollTop > height) {
            animateHeader = false;
        } else {
            animateHeader = true;
        }
    }

    function resize() {
        target.x = window.innerWidth/2;
        canvas.width = window.innerWidth - 20;
    }

    // animation
    function initAnimation() {
        animate();
        for(var i in points) {
            shiftPoint(points[i]);
        }
    }

    function animate() {
        if(animateHeader) {
            ctx.clearRect(0,0,width,height);
            for(var i in points) {
                // detect points in range
                if(Math.abs(getDistance(target, points[i])) < 4000) {
                    points[i].active = 0.3;
                    points[i].circle.active = 0.6;
                } else if(Math.abs(getDistance(target, points[i])) < 20000) {
                    points[i].active = 0.1;
                    points[i].circle.active = 0.3;
                } else if(Math.abs(getDistance(target, points[i])) < 40000) {
                    points[i].active = 0.02;
                    points[i].circle.active = 0.1;
                } else {
                    points[i].active = 0;
                    points[i].circle.active = 0;
                }
                drawLines(points[i]);
                points[i].circle.draw();
            }
        }
        requestAnimationFrame(animate);
    }

    function shiftPoint(p) {
        TweenLite.to(p, 1+1*Math.random(), {x:p.originX-50+Math.random()*100,
            y: p.originY-50+Math.random()*100, ease:Circ.easeInOut,
            onComplete: function() {
                shiftPoint(p);
            }});
    }

    // Canvas manipulation
    function drawLines(p) {
        if(!p.active) {
            return;
        }
        for(var i in p.closest) {
            ctx.beginPath();
            ctx.moveTo(p.x, p.y);
            ctx.lineTo(p.closest[i].x, p.closest[i].y);
            ctx.strokeStyle = 'rgba(156,217,249,'+ p.active+')';
            ctx.stroke();
        }
    }

    function Circle(pos,rad,color) {
        var self = this;

        // constructor
        (function() {
            self.pos = pos || null;
            self.radius = rad || null;
            self.color = color || null;
        })();

        this.draw = function() {
            if(!self.active) {
                return;
            }
            ctx.beginPath();
            ctx.arc(self.pos.x, self.pos.y, self.radius, 0, 2 * Math.PI, false);
            ctx.fillStyle = 'rgba(156,217,249,'+ self.active+')';
            ctx.fill();
        };
    }

    // Util
    function getDistance(p1, p2) {
        return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2);
    }

})();<commit_msg>Update home page with new application.js from designers [skip ci]<commit_after>var SignUp = require('../signUp.js');
new SignUp('#signUpScope', '/api/v1/register/');
var TweenLite = require('TweenLite');
require('EasePack');
require('vendor/youtube');

// ANIMATION FOR FRONT PAGE

$( document ).ready(function() {
  $('#logo').removeClass('off');
  $(".youtube").YouTubeModal({autoplay:1, width:640, height:480});
});

(function(){
  if ($(window).scrollTop() > 650) {
      $('.navbar').addClass('off');
  }
  else {
      $('.navbar').removeClass('off');
  }
    setTimeout(arguments.callee, 40);
})();

var waitForFinalEvent = (function () {
  var timers = {};
  return function (callback, ms, uniqueId) {
    if (!uniqueId) {
      uniqueId = "Don't call this twice without a uniqueId";
    }
    if (timers[uniqueId]) {
      clearTimeout (timers[uniqueId]);
    }
    timers[uniqueId] = setTimeout(callback, ms);
  };
})();

(function() {

    var width, height, largeHeader, canvas, ctx, points, target, animateHeader = true;

    // Main
    initHeader();
    initAnimation();
    addListeners();

    function initHeader() {
        width = window.innerWidth;
        height = '800';
        target = {x: width/2, y: height/2};

        largeHeader = document.getElementById('home-hero');

        canvas = $('#demo-canvas')[0];
        canvas.width = width;
        canvas.height = height;
        ctx = canvas.getContext('2d');

        // create points
        points = [];
        for(var x = 0; x < width; x = x + width/20) {
            for(var y = 0; y < height; y = y + height/20) {
                var px = x + Math.random()*width/20;
                var py = y + Math.random()*height/20;
                var p = {x: px, originX: px, y: py, originY: py };
                points.push(p);
            }
        }

        // for each point find the 5 closest points
        for(var i = 0; i < points.length; i++) {
            var closest = [];
            var p1 = points[i];
            for(var j = 0; j < points.length; j++) {
                var p2 = points[j]
                if(!(p1 == p2)) {
                    var placed = false;
                    for(var k = 0; k < 5; k++) {
                        if(!placed) {
                            if(closest[k] == undefined) {
                                closest[k] = p2;
                                placed = true;
                            }
                        }
                    }

                    for(var k = 0; k < 5; k++) {
                        if(!placed) {
                            if(getDistance(p1, p2) < getDistance(p1, closest[k])) {
                                closest[k] = p2;
                                placed = true;
                            }
                        }
                    }
                }
            }
            p1.closest = closest;
        }

        // assign a circle to each point
        for(var i in points) {
            var c = new Circle(points[i], 2+Math.random()*2, 'rgba(255,255,255,0.3)');
            points[i].circle = c;
        }
    }

    // Event handling
    function addListeners() {
        setPos();
        window.addEventListener('scroll', scrollCheck);
        window.addEventListener('resize', resize);
    }

    function setPos(e) {
        target.x = window.innerWidth/2;
        target.y = 330;
    }

    function scrollCheck() {
        if(document.body.scrollTop > height) animateHeader = false;
        else animateHeader = true;
    }

    function resize() {
        if (window.innerWidth > 990) {
            waitForFinalEvent(function(){
                $('#demo-canvas').remove();
                $('#canavs-container').append('<canvas id="demo-canvas"></canvas>');
                initHeader();
                initAnimation();
            }, 300, "resize");
        }
    }

    // animation
    function initAnimation() {
        animate();
        for(var i in points) {
            shiftPoint(points[i]);
        }
    }

    function animate() {
        if(animateHeader) {
            ctx.clearRect(0,0,width,height);
            for(var i in points) {
                // detect points in range
                if(Math.abs(getDistance(target, points[i])) < 4000) {
                    points[i].active = 0.3;
                    points[i].circle.active = 0.6;
                } else if(Math.abs(getDistance(target, points[i])) < 20000) {
                    points[i].active = 0.1;
                    points[i].circle.active = 0.3;
                } else if(Math.abs(getDistance(target, points[i])) < 40000) {
                    points[i].active = 0.02;
                    points[i].circle.active = 0.1;
                } else {
                    points[i].active = 0;
                    points[i].circle.active = 0;
                }

                drawLines(points[i]);
                points[i].circle.draw();
            }
        }
        requestAnimationFrame(animate);
    }

    function shiftPoint(p) {
        TweenLite.to(p, 1+1*Math.random(), {x:p.originX-50+Math.random()*100,
            y: p.originY-50+Math.random()*100, ease:Circ.easeInOut,
            onComplete: function() {
                shiftPoint(p);
            }});
    }

    // Canvas manipulation
    function drawLines(p) {
        if(!p.active) return;
        for(var i in p.closest) {
            ctx.beginPath();
            ctx.moveTo(p.x, p.y);
            ctx.lineTo(p.closest[i].x, p.closest[i].y);
            ctx.strokeStyle = 'rgba(156,217,249,'+ p.active+')';
            ctx.stroke();
        }
    }

    function Circle(pos,rad,color) {
        var _this = this;

        // constructor
        (function() {
            _this.pos = pos || null;
            _this.radius = rad || null;
            _this.color = color || null;
        })();

        this.draw = function() {
            if(!_this.active) return;
            ctx.beginPath();
            ctx.arc(_this.pos.x, _this.pos.y, _this.radius, 0, 2 * Math.PI, false);
            ctx.fillStyle = 'rgba(156,217,249,'+ _this.active+')';
            ctx.fill();
        };
    }

    // Util
    function getDistance(p1, p2) {
        return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2);
    }

})();<|endoftext|>