<commit_before>/* ShowOff JS Logic */

var ShowOff = {};

var preso_started = false
var slidenum = 0
var slideTotal = 0
var slides
var currentSlide
var totalslides = 0
var slidesLoaded = false
var incrSteps = 0
var incrElem
var incrCurr = 0
var incrCode = false
var debugMode = false
var gotoSlidenum = 0
var shiftKeyActive = false

var loadSlidesBool
var loadSlidesPrefix

function setupPreso(load_slides, prefix) {
  if (preso_started)
  {
     alert("already started")
     return
  }
  preso_started = true

  loadSlidesBool = load_slides
  loadSlidesPrefix = prefix
  loadSlides(loadSlidesBool, loadSlidesPrefix)

  doDebugStuff()

  // bind event handlers
  document.onkeydown = keyDown
  document.onkeyup = keyUp
  /* window.onresize  = resized; */
  /* window.onscroll = scrolled; */
  /* window.onunload = unloaded; */
}

function loadSlides(load_slides, prefix) {
  //load slides offscreen, wait for images and then initialize
  if (load_slides) {
  	$("#slides").load("/slides", false, function(){
    	$("#slides img").batchImageLoad({
			loadingCompleteCallback: initializePresentation(prefix)
		})
  	})
  } else {
	$("#slides img").batchImageLoad({
		loadingCompleteCallback: initializePresentation(prefix)
	})
  }
}

function initializePresentation(prefix) {
  //center slides offscreen
  centerSlides($('#slides > .slide'))

  //copy into presentation area
  $("#preso").empty()
  $('#slides > .slide').appendTo($("#preso"))

  //populate vars
  slides = $('#preso > .slide')
  slideTotal = slides.size()

  //setup manual jquery cycle
  $('#preso').cycle({
    timeout: 0
  })

  setupMenu()
  if (slidesLoaded) {
    showSlide()
    alert('slides loaded')
  } else {
    showFirstSlide();
    slidesLoaded = true
  }
  setupSlideParamsCheck();
  sh_highlightDocument(prefix+'/js/sh_lang/', '.min.js')
}

function centerSlides(slides) {
  slides.each(function(s, slide) {
    centerSlide(slide)
  })
}

function centerSlide(slide) {
  var slide_content = $(slide).children(".content").first()
  var height = slide_content.height()
  var mar_top = (0.5 * parseFloat($(slide).height())) - (0.5 * parseFloat(height))
  if (mar_top < 0) {
    mar_top = 0
  }
  slide_content.css('margin-top', mar_top)
}

function setupMenu() {
  $('#navmenu').hide();

  var currSlide = 0
  var menu = new ListMenu()

  slides.each(function(s, elem) {
    content = $(elem).children(".content")
    shortTxt = $(content).text().substr(0, 20)
    path = $(content).attr('ref').split('/')
    currSlide += 1
    menu.addItem(path, shortTxt, currSlide)
  })

  $('#navigation').html(menu.getList())
  $('#navmenu').menu({
    content: $('#navigation').html(),
    flyOut: true
  });
}

function checkSlideParameter() {
  if (slideParam = currentSlideFromParams()) {
    slidenum = slideParam;
  }
}

function currentSlideFromParams() {
  var result;
  if (result = window.location.hash.match(/#([0-9]+)/)) {
    return result[result.length - 1] - 1;
  }
}

function setupSlideParamsCheck() {
  var check = function() {
    var currentSlide = currentSlideFromParams();
    if (slidenum != currentSlide) {
      slidenum = currentSlide;
      showSlide();
    }
    setTimeout(check, 100);
  }
  setTimeout(check, 100);
}

function gotoSlide(slideNum) {
  slidenum = parseInt(slideNum)
  if (!isNaN(slidenum)) {
    showSlide()
  }
}

function showFirstSlide() {
  slidenum = 0
  checkSlideParameter();
  showSlide()
}

function showSlide(back_step) {

  if(slidenum < 0) {
    slidenum = 0
    return
  }

  if(slidenum > (slideTotal - 1)) {
    slidenum = slideTotal - 1
    return
  }

  currentSlide = slides.eq(slidenum)

  var transition = currentSlide.attr('data-transition')
  var fullPage = currentSlide.find(".content").is('.full-page');

  if (back_step || fullPage) {
    transition = 'none'
  }

  $('#preso').cycle(slidenum, transition)

  if (fullPage) {
    $('#preso').css({'width' : '100%', 'overflow' : 'visible'});
    currentSlide.css({'width' : '100%', 'text-align' : 'center', 'overflow' : 'visible'});
  } else {
    $('#preso').css({'width' : '1020px', 'overflow' : 'hidden'});
  }

  percent = getSlidePercent()
  $("#slideInfo").text((slidenum + 1) + '/' + slideTotal + '  - ' + percent + '%')

  if(!back_step) {
    // determine if there are incremental bullets to show
    // unless we are moving backward
    determineIncremental()
  } else {
    incrCurr = 0
    incrSteps = 0
  }
  location.hash = slidenum + 1;
  $('body').addSwipeEvents().
    bind('swipeleft',  swipeLeft).
    bind('swiperight', swipeRight)
  removeResults()

  return getCurrentNotes()
}

function getSlideProgress()
{
  return (slidenum + 1) + '/' + slideTotal
}

function getCurrentNotes()
{
  return currentSlide.find("p.notes").text()
}

function getSlidePercent()
{
  return Math.ceil(((slidenum + 1) / slideTotal) * 100)
}

function determineIncremental()
{
  incrCurr = 0
  incrCode = false
  incrElem = currentSlide.find(".incremental > ul > li")
  incrSteps = incrElem.size()
  if(incrSteps == 0) {
    // also look for commandline
    incrElem = currentSlide.find(".incremental > pre > code > code")
    incrSteps = incrElem.size()
    incrCode = true
  }
  incrElem.each(function(s, elem) {
    $(elem).hide()
  })
}

function prevStep()
{
  slidenum--
  return showSlide(true) // We show the slide fully loaded
}

function nextStep()
{
  if (incrCurr >= incrSteps) {
    slidenum++
    return showSlide()
  } else {
    elem = incrElem.eq(incrCurr)
    if (incrCode && elem.hasClass('command')) {
      incrElem.eq(incrCurr).show().jTypeWriter({duration:1.0})
    } else {
      incrElem.eq(incrCurr).show()
    }
    incrCurr++
  }
}

function prevStep() {
  slidenum--
  return showSlide(true) // We show the slide fully loaded
}

function doDebugStuff()
{
  if (debugMode) {
    $('#debugInfo').show()
    debug('debug mode on')
  } else {
    $('#debugInfo').hide()
  }
}

function debug(data)
{
  $('#debugInfo').text(data)
}
//  See e.g. http://www.quirksmode.org/js/events/keys.html for keycodes
function keyDown(event)
{
    var key = event.keyCode;

    if (event.ctrlKey || event.altKey || event.metaKey)
       return true;

    debug('keyDown: ' + key)

    if (key >= 48 && key <= 57) // 0 - 9
    {
      gotoSlidenum = gotoSlidenum * 10 + (key - 48);
      return true;
    }

    if (key == 13){
        if (gotoSlidenum > 0) {
            debug('go to ' + gotoSlidenum);
            slidenum = gotoSlidenum - 1;
            showSlide(true);
            gotoSlidenum = 0;
        } else {
            debug('executeCode');
            executeCode.call($('.sh_javaScript code:visible'));
        }

    }

    if (key == 16) // shift key
    {
      shiftKeyActive = true;
    }
    if (key == 32) // space bar
    {
      if (shiftKeyActive) { prevStep() }
      else                { nextStep() }
    }
    else if (key == 68) // 'd' for debug
    {
      debugMode = !debugMode
      doDebugStuff()
    }
    else if (key == 37 || key == 33) // Left arrow or page up
    {
      prevStep()
    }
    else if (key == 39 || key == 34) // Right arrow or page down
    {
      nextStep()
    }
    else if (key == 82) // R for reload
    {
      if (confirm('really reload slides?')) {
        loadSlides(loadSlidesBool, loadSlidesPrefix)
        showSlide()
      }
    }
    else if (key == 84 || key == 67)  // T or C for table of contents
    {
      $('#navmenu').toggle().trigger('click')
    }
    else if (key == 90) // z for help
    {
      $('#help').toggle()
    }
    else if (key == 66 || key == 70) // f for footer (also "b" which is what kensington remote "stop" button sends
    {
      toggleFooter()
    }
	else if (key == 27) // esc
	{
		removeResults();
	}
    return true
}

function toggleFooter()
{
  $('#footer').toggle()
}

function keyUp(event) {
  var key = event.keyCode;
  debug('keyUp: ' + key);
  if (key == 16) // shift key
  {
    shiftKeyActive = false;
  }
}

function swipeLeft() {
  nextStep()
}

function swipeRight() {
  prevStep()
}

function ListMenu(s)
{
  this.slide = s
  this.typeName = 'ListMenu'
  this.itemLength = 0;
  this.items = new Array();
  this.addItem = function (key, text, slide) {
    if (key.length > 1) {
      thisKey = key.shift()
      if (!this.items[thisKey]) {
        this.items[thisKey] = new ListMenu(slide)
      }
      this.items[thisKey].addItem(key, text, slide)
    } else {
      thisKey = key.shift()
      this.items[thisKey] = new ListMenuItem(text, slide)
    }
  }
  this.getList = function() {
    var newMenu = $("
")
    for(var i in this.items) {
      var item = this.items[i]
      var domItem = $("
")
      if (item.typeName == 'ListMenu') {
        choice = $("" + i + "")
        domItem.append(choice)
        domItem.append(item.getList())
      }
      if (item.typeName == 'ListMenuItem') {
        choice = $("" + item.slide + '. ' + item.textName + "")
        domItem.append(choice)
      }
      newMenu.append(domItem)
    }
    return newMenu
  }
}

function ListMenuItem(t, s)
{
  this.typeName = "ListMenuItem"
  this.slide = s
  this.textName = t
}

var removeResults = function() {
  $('.results').remove();
};

var print = function(text) {
  removeResults();
  var _results = $('
').addClass('results').html($.print(text, {max_string:500}));
  $('body').append(_results);
  _results.click(removeResults);
};

function executeCode () {
    result = null;
    var codeDiv = $(this);
    codeDiv.addClass("executing");
    eval(codeDiv.text());
    setTimeout(function() { codeDiv.removeClass("executing");}, 250 );
    if (result != null) print(result);
}
$('.sh_javaScript code').live("click", executeCode);
<commit_msg>trigger custom events on showing, and jumping to next or prev slide<commit_after>/* ShowOff JS Logic */

var ShowOff = {};

var preso_started = false
var slidenum = 0
var slideTotal = 0
var slides
var currentSlide
var totalslides = 0
var slidesLoaded = false
var incrSteps = 0
var incrElem
var incrCurr = 0
var incrCode = false
var debugMode = false
var gotoSlidenum = 0
var shiftKeyActive = false

var loadSlidesBool
var loadSlidesPrefix

function setupPreso(load_slides, prefix) {
  if (preso_started)
  {
     alert("already started")
     return
  }
  preso_started = true

  loadSlidesBool = load_slides
  loadSlidesPrefix = prefix
  loadSlides(loadSlidesBool, loadSlidesPrefix)

  doDebugStuff()

  // bind event handlers
  document.onkeydown = keyDown
  document.onkeyup = keyUp
  /* window.onresize  = resized; */
  /* window.onscroll = scrolled; */
  /* window.onunload = unloaded; */
}

function loadSlides(load_slides, prefix) {
  //load slides offscreen, wait for images and then initialize
  if (load_slides) {
  	$("#slides").load("/slides", false, function(){
    	$("#slides img").batchImageLoad({
			loadingCompleteCallback: initializePresentation(prefix)
		})
  	})
  } else {
	$("#slides img").batchImageLoad({
		loadingCompleteCallback: initializePresentation(prefix)
	})
  }
}

function initializePresentation(prefix) {
  //center slides offscreen
  centerSlides($('#slides > .slide'))

  //copy into presentation area
  $("#preso").empty()
  $('#slides > .slide').appendTo($("#preso"))

  //populate vars
  slides = $('#preso > .slide')
  slideTotal = slides.size()

  //setup manual jquery cycle
  $('#preso').cycle({
    timeout: 0
  })

  setupMenu()
  if (slidesLoaded) {
    showSlide()
    alert('slides loaded')
  } else {
    showFirstSlide();
    slidesLoaded = true
  }
  setupSlideParamsCheck();
  sh_highlightDocument(prefix+'/js/sh_lang/', '.min.js')
}

function centerSlides(slides) {
  slides.each(function(s, slide) {
    centerSlide(slide)
  })
}

function centerSlide(slide) {
  var slide_content = $(slide).children(".content").first()
  var height = slide_content.height()
  var mar_top = (0.5 * parseFloat($(slide).height())) - (0.5 * parseFloat(height))
  if (mar_top < 0) {
    mar_top = 0
  }
  slide_content.css('margin-top', mar_top)
}

function setupMenu() {
  $('#navmenu').hide();

  var currSlide = 0
  var menu = new ListMenu()

  slides.each(function(s, elem) {
    content = $(elem).children(".content")
    shortTxt = $(content).text().substr(0, 20)
    path = $(content).attr('ref').split('/')
    currSlide += 1
    menu.addItem(path, shortTxt, currSlide)
  })

  $('#navigation').html(menu.getList())
  $('#navmenu').menu({
    content: $('#navigation').html(),
    flyOut: true
  });
}

function checkSlideParameter() {
  if (slideParam = currentSlideFromParams()) {
    slidenum = slideParam;
  }
}

function currentSlideFromParams() {
  var result;
  if (result = window.location.hash.match(/#([0-9]+)/)) {
    return result[result.length - 1] - 1;
  }
}

function setupSlideParamsCheck() {
  var check = function() {
    var currentSlide = currentSlideFromParams();
    if (slidenum != currentSlide) {
      slidenum = currentSlide;
      showSlide();
    }
    setTimeout(check, 100);
  }
  setTimeout(check, 100);
}

function gotoSlide(slideNum) {
  slidenum = parseInt(slideNum)
  if (!isNaN(slidenum)) {
    showSlide()
  }
}

function showFirstSlide() {
  slidenum = 0
  checkSlideParameter();
  showSlide()
}

function showSlide(back_step) {

  if(slidenum < 0) {
    slidenum = 0
    return
  }

  if(slidenum > (slideTotal - 1)) {
    slidenum = slideTotal - 1
    return
  }

  currentSlide = slides.eq(slidenum)

  var transition = currentSlide.attr('data-transition')
  var fullPage = currentSlide.find(".content").is('.full-page');

  if (back_step || fullPage) {
    transition = 'none'
  }

  $('#preso').cycle(slidenum, transition)

  if (fullPage) {
    $('#preso').css({'width' : '100%', 'overflow' : 'visible'});
    currentSlide.css({'width' : '100%', 'text-align' : 'center', 'overflow' : 'visible'});
  } else {
    $('#preso').css({'width' : '1020px', 'overflow' : 'hidden'});
  }

  percent = getSlidePercent()
  $("#slideInfo").text((slidenum + 1) + '/' + slideTotal + '  - ' + percent + '%')

  if(!back_step) {
    // determine if there are incremental bullets to show
    // unless we are moving backward
    determineIncremental()
  } else {
    incrCurr = 0
    incrSteps = 0
  }
  location.hash = slidenum + 1;
  $('body').addSwipeEvents().
    bind('swipeleft',  swipeLeft).
    bind('swiperight', swipeRight)
  removeResults()

  $(currentSlide).find(".content").trigger("showoff:show");

  return getCurrentNotes()
}

function getSlideProgress()
{
  return (slidenum + 1) + '/' + slideTotal
}

function getCurrentNotes()
{
  return currentSlide.find("p.notes").text()
}

function getSlidePercent()
{
  return Math.ceil(((slidenum + 1) / slideTotal) * 100)
}

function determineIncremental()
{
  incrCurr = 0
  incrCode = false
  incrElem = currentSlide.find(".incremental > ul > li")
  incrSteps = incrElem.size()
  if(incrSteps == 0) {
    // also look for commandline
    incrElem = currentSlide.find(".incremental > pre > code > code")
    incrSteps = incrElem.size()
    incrCode = true
  }
  incrElem.each(function(s, elem) {
    $(elem).hide()
  })
}

function prevStep()
{

  var event = jQuery.Event("showoff:prev");
  $(currentSlide).find(".content").trigger(event);
  if (event.isDefaultPrevented()) {
      return;
  }

  slidenum--
  return showSlide(true) // We show the slide fully loaded
}

function nextStep()
{
  var event = jQuery.Event("showoff:next");
  $(currentSlide).find(".content").trigger(event);
  if (event.isDefaultPrevented()) {
      return;
  }

  if (incrCurr >= incrSteps) {
    slidenum++
    return showSlide()
  } else {
    elem = incrElem.eq(incrCurr)
    if (incrCode && elem.hasClass('command')) {
      incrElem.eq(incrCurr).show().jTypeWriter({duration:1.0})
    } else {
      incrElem.eq(incrCurr).show()
    }
    incrCurr++
  }
}

function prevStep() {
  slidenum--
  return showSlide(true) // We show the slide fully loaded
}

function doDebugStuff()
{
  if (debugMode) {
    $('#debugInfo').show()
    debug('debug mode on')
  } else {
    $('#debugInfo').hide()
  }
}

function debug(data)
{
  $('#debugInfo').text(data)
}
//  See e.g. http://www.quirksmode.org/js/events/keys.html for keycodes
function keyDown(event)
{
    var key = event.keyCode;

    if (event.ctrlKey || event.altKey || event.metaKey)
       return true;

    debug('keyDown: ' + key)

    if (key >= 48 && key <= 57) // 0 - 9
    {
      gotoSlidenum = gotoSlidenum * 10 + (key - 48);
      return true;
    }

    if (key == 13){
        if (gotoSlidenum > 0) {
            debug('go to ' + gotoSlidenum);
            slidenum = gotoSlidenum - 1;
            showSlide(true);
            gotoSlidenum = 0;
        } else {
            debug('executeCode');
            executeCode.call($('.sh_javaScript code:visible'));
        }

    }

    if (key == 16) // shift key
    {
      shiftKeyActive = true;
    }
    if (key == 32) // space bar
    {
      if (shiftKeyActive) { prevStep() }
      else                { nextStep() }
    }
    else if (key == 68) // 'd' for debug
    {
      debugMode = !debugMode
      doDebugStuff()
    }
    else if (key == 37 || key == 33) // Left arrow or page up
    {
      prevStep()
    }
    else if (key == 39 || key == 34) // Right arrow or page down
    {
      nextStep()
    }
    else if (key == 82) // R for reload
    {
      if (confirm('really reload slides?')) {
        loadSlides(loadSlidesBool, loadSlidesPrefix)
        showSlide()
      }
    }
    else if (key == 84 || key == 67)  // T or C for table of contents
    {
      $('#navmenu').toggle().trigger('click')
    }
    else if (key == 90) // z for help
    {
      $('#help').toggle()
    }
    else if (key == 66 || key == 70) // f for footer (also "b" which is what kensington remote "stop" button sends
    {
      toggleFooter()
    }
	else if (key == 27) // esc
	{
		removeResults();
	}
    return true
}

function toggleFooter()
{
  $('#footer').toggle()
}

function keyUp(event) {
  var key = event.keyCode;
  debug('keyUp: ' + key);
  if (key == 16) // shift key
  {
    shiftKeyActive = false;
  }
}

function swipeLeft() {
  nextStep()
}

function swipeRight() {
  prevStep()
}

function ListMenu(s)
{
  this.slide = s
  this.typeName = 'ListMenu'
  this.itemLength = 0;
  this.items = new Array();
  this.addItem = function (key, text, slide) {
    if (key.length > 1) {
      thisKey = key.shift()
      if (!this.items[thisKey]) {
        this.items[thisKey] = new ListMenu(slide)
      }
      this.items[thisKey].addItem(key, text, slide)
    } else {
      thisKey = key.shift()
      this.items[thisKey] = new ListMenuItem(text, slide)
    }
  }
  this.getList = function() {
    var newMenu = $("
")
    for(var i in this.items) {
      var item = this.items[i]
      var domItem = $("
")
      if (item.typeName == 'ListMenu') {
        choice = $("" + i + "")
        domItem.append(choice)
        domItem.append(item.getList())
      }
      if (item.typeName == 'ListMenuItem') {
        choice = $("" + item.slide + '. ' + item.textName + "")
        domItem.append(choice)
      }
      newMenu.append(domItem)
    }
    return newMenu
  }
}

function ListMenuItem(t, s)
{
  this.typeName = "ListMenuItem"
  this.slide = s
  this.textName = t
}

var removeResults = function() {
  $('.results').remove();
};

var print = function(text) {
  removeResults();
  var _results = $('
').addClass('results').html($.print(text, {max_string:500}));
  $('body').append(_results);
  _results.click(removeResults);
};

function executeCode () {
    result = null;
    var codeDiv = $(this);
    codeDiv.addClass("executing");
    eval(codeDiv.text());
    setTimeout(function() { codeDiv.removeClass("executing");}, 250 );
    if (result != null) print(result);
}
$('.sh_javaScript code').live("click", executeCode);
<|endoftext|>


<commit_before>var querystring = Npm.require('querystring');

var generateToken = function (username) {
  console.log("got to generateToken");
  var stampedToken = Accounts._generateStampedLoginToken();
  Meteor.users.update({username: username},
                      {$push: {'services.resume.loginTokens': stampedToken}});
  return stampedToken;
}

Meteor.methods({
  getCorpCookie: function() {
    return "xxx";
  },

  findOrCreateUser: function (cookie) {
    // Since we are behind corp secure, if there
    // is an auth_user cookie, we can assume that user
    // is logged into corp.

    // Check if cookie from corp exists.
    if (!cookie) {
      // There is no cookie!
      console.log("Got to findOrCreateUser without an auth_user cookie")
      console.log("Something very wrong has happened")
      return;
    }

    // Get the username and unescape it from the cookie.
    var username = querystring.unescape(cookie);

    // Check if this user exists in Meteor.
    if (Meteor.users.findOne({username: username})) {
      return {username: username, token: generateToken(username)};
    }

    // User doesn't exist. Create and login.
    var userId = Accounts.createUser({
      username: username,
      email: username
    });

    var newUsername = Meteor.users.findOne(userId).username;
    return {username: newUsername, token: generateToken(newUsername)};
  }
});
<commit_msg>retrieve cookies<commit_after>var querystring = Npm.require('querystring');

var generateToken = function (username) {
  console.log("got to generateToken");
  var stampedToken = Accounts._generateStampedLoginToken();
  Meteor.users.update({username: username},
                      {$push: {'services.resume.loginTokens': stampedToken}});
  return stampedToken;
}

Meteor.methods({
  getCorpCookie: function() {
    var cookies = ServerCookies.retrieve(this.connection);
    console.log('', cookies);
    return cookies['auth_user'];
  },

  findOrCreateUser: function (cookie) {
    // Since we are behind corp secure, if there
    // is an auth_user cookie, we can assume that user
    // is logged into corp.

    // Check if cookie from corp exists.
    if (!cookie) {
      // There is no cookie!
      console.log("Got to findOrCreateUser without an auth_user cookie")
      console.log("Something very wrong has happened")
      return;
    }

    // Get the username and unescape it from the cookie.
    var username = querystring.unescape(cookie);

    // Check if this user exists in Meteor.
    if (Meteor.users.findOne({username: username})) {
      return {username: username, token: generateToken(username)};
    }

    // User doesn't exist. Create and login.
    var userId = Accounts.createUser({
      username: username,
      email: username
    });

    var newUsername = Meteor.users.findOne(userId).username;
    return {username: newUsername, token: generateToken(newUsername)};
  }
});
<|endoftext|>


<commit_before>// 80: Number - isNaN
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('`Number.isNaN()` determines if a value is `NaN`', function(){
  it('it is a static function on `Number`', function() {
    //// const whatType = 'method';
    const whatType = 'function';
    assert.equal(typeof Number.isNaN, whatType);
  });
  describe('returns false', () => {
    describe('for any not-Number type', () => {
      it('like null', () => {
        //// const justNull = NaN;
        const justNull = null;
        assert.equal(Number.isNaN(justNull), false);
      });
      it('like a string', () => {
        //// const aString = NaN;
        const aString = 'NaN';
        assert.equal(Number.isNaN(aString), false);
      });
      it('like an object', () => {
        //// const anObject = NaN;
        const anObject = {};
        assert.equal(Number.isNaN(anObject), false);
      });
      describe('different to the global `isNaN` function (specified way before ES6)', () => {
        it('an object gets converted to a Number before the check, and returns true therefore', () => {
          //// const fn = Number.isNaN;
          const fn = isNaN;
          assert.equal(fn({}), true);
        });
        it('a string gets converted to a Number first, and returns true therefore (even though its not `NaN`)', () => {
          //// const fn = Number.isNaN;
          const fn = isNaN;
          assert.equal(fn('just a string'), true);
        });
      });
    });
    describe('for Numbers', () => {
      it('like 0', () => {
        //// const zero = NaN;
        const zero = 0;
        assert.equal(Number.isNaN(zero), false);
      });
      it('or Infinity (+∞)', () => {
        //// const infinity = Nummmmber.POSITIVE_INFINITY;
        const infinity = Number.POSITIVE_INFINITY;
        assert.equal(Number.isNaN(infinity), false);
      });
      it('or the biggest Number (9007199254740991 (2^53−1))', () => {
        //// const max = NUMBER.MAX_SAFE_INTEGER;
        const max = Number.MAX_SAFE_INTEGER;
        assert.equal(Number.isNaN(max), false);
      });
      it('or a decimal number', () => {
        //// const pie = 3.1415926535897932;
        const pi = 3.1415926535897932;
        assert.equal(Number.isNaN(pi), false);
      });
    });
  });
  describe('returns true for', () => {
    it('exactly `NaN`', () => {
      //// const notANumber = 1;
      const notANumber = NaN;
      assert.equal(Number.isNaN(notANumber), true);
    });
    it('zero divided by zero', () => {
      //// const zeroDividedByZero = 0 / 1;
      const zeroDividedByZero = 0 / 0;
      assert.equal(Number.isNaN(zeroDividedByZero), true);
    });
  });
});
<commit_msg>Another more visible "what to do".<commit_after>// 80: Number - isNaN
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('`Number.isNaN()` determines if a value is `NaN`', function(){
  it('it is a static function on `Number`', function() {
    //// const whatType = 'method';
    const whatType = 'function';
    assert.equal(typeof Number.isNaN, whatType);
  });
  describe('returns false', () => {
    describe('for any not-Number type', () => {
      it('like null', () => {
        //// const justNull = NaN;
        const justNull = null;
        assert.equal(Number.isNaN(justNull), false);
      });
      it('like a string', () => {
        //// const aString = NaN;
        const aString = 'NaN';
        assert.equal(Number.isNaN(aString), false);
      });
      it('like an object', () => {
        //// const anObject = NaN;
        const anObject = {};
        assert.equal(Number.isNaN(anObject), false);
      });
      describe('different to the global `isNaN` function (specified way before ES6)', () => {
        it('an object gets converted to a Number before the check, and returns true therefore', () => {
          //// const fn = Number.isNaN;
          const fn = isNaN;
          assert.equal(fn({}), true);
        });
        it('a string gets converted to a Number first, and returns true therefore (even though its not `NaN`)', () => {
          //// const fn = Number.isNaN;
          const fn = isNaN;
          assert.equal(fn('just a string'), true);
        });
      });
    });
    describe('for Numbers', () => {
      it('like 0', () => {
        //// const zero = NaN;
        const zero = 0;
        assert.equal(Number.isNaN(zero), false);
      });
      it('or Infinity (+∞)', () => {
        //// const infinity = Nummmmber.POSITIVE_INFINITY;
        const infinity = Number.POSITIVE_INFINITY;
        assert.equal(Number.isNaN(infinity), false);
      });
      it('or the biggest Number (9007199254740991 (2^53−1))', () => {
        //// const max = N_u_m_b_e_r.MAX_SAFE_INTEGER;
        const max = Number.MAX_SAFE_INTEGER;
        assert.equal(Number.isNaN(max), false);
      });
      it('or a decimal number', () => {
        //// const pie = 3.1415926535897932;
        const pi = 3.1415926535897932;
        assert.equal(Number.isNaN(pi), false);
      });
    });
  });
  describe('returns true for', () => {
    it('exactly `NaN`', () => {
      //// const notANumber = 1;
      const notANumber = NaN;
      assert.equal(Number.isNaN(notANumber), true);
    });
    it('zero divided by zero', () => {
      //// const zeroDividedByZero = 0 / 1;
      const zeroDividedByZero = 0 / 0;
      assert.equal(Number.isNaN(zeroDividedByZero), true);
    });
  });
});
<|endoftext|>


<commit_before><commit_msg>Allow null thumbnail<commit_after><|endoftext|>


<commit_before>var Webtail = {
  start: function(port) {
    var self = this;
    $(function() {
      self.setupWebSocket(port);
    });
  },

  setupWebSocket: function(port) {
    var ws   = this.createWebSocket('ws://localhost:' + port);
    var self = this;
    ws.onmessage = function(e) {
      var line = $('<pre/>');
      line.text(e.data);
      line.appendTo($('body'));
    };
  },

  createWebSocket: function(url) {
    if ('WebSocket' in window) {
      return new WebSocket(url);
    } else if ('MozWebSocket' in window) {
      return new MozWebSocket(url);
    }
  }
};
<commit_msg>Refactor js code style<commit_after>var Webtail = (function() {
  return {
    start: function(port) {
      $(function() {
        setupWebSocket(port);
      });
    }
  };

  function setupWebSocket(port) {
    var ws   = createWebSocket('ws://localhost:' + port);
    var self = this;
    ws.onmessage = function(e) {
      var line = $('<pre/>');
      line.text(e.data);
      line.appendTo($('body'));
    };
  }

  function createWebSocket(url) {
    if ('WebSocket' in window) {
      return new WebSocket(url);
    } else if ('MozWebSocket' in window) {
      return new MozWebSocket(url);
    }
  }
})();
<|endoftext|>


<commit_before>'use strict';

(function($){
	$.confirm = function(params){
		if($('#confirm-dialog').length){
			$('#confirm-dialog').remove();
		}

		var markup = [
			'
' + params.msg,
			'',
			'
'
		].join('');

		$(markup).hide().appendTo('body').fadeToggle(99);
	    $("#confirm-dialog").dialog({
	      resizable: false,
	      height:120,
	      width:350,
	      modal: true,
	      buttons: {
	        "Confirm": function() {
	        	console.log(params.url);
	        	document.location.href = params.url;
	        },
	        Cancel: function() {
	          $(this).dialog("close");
	        }
	      }
	    });
	}

})(jQuery);
<commit_msg>Added support for callbacks<commit_after>'use strict';

(function($){
    $.confirm = function(params){
        if($('#confirm-dialog').length){
            $('#confirm-dialog').remove();
        }

        var markup = [
            '
' + params.msg,
            '',
            '
'
        ].join('');

        $(markup).hide().appendTo('body').fadeToggle(99);
        $("#confirm-dialog").dialog({
          resizable: false,
          height:120,
          width:350,
          modal: true,
          buttons: {
            "Confirm": function() {
                if(typeof params.url == 'function') {
                  params.url();
                  return;
                }
                document.location.href = params.url;
            },
            Cancel: function() {
              $(this).dialog("close");
            }
          }
        });
    }

})(jQuery);
<|endoftext|>


<commit_before>var mw= require('./middleware'),
    ut= require('./util'),
    _= require('underscore'),
    async= require('async'),
    multilevel= require('multilevel-http'),
    merge = require('mergesort-stream'),
    JSONStream = require('JSONStream'),
    map   =  require('map-stream');

const KS= '::';

module.exports= function (app,node)
{
    var resolveErrors= function (errors, res, wr, put)
        {
              var uerr= _.groupBy(errors,function (err)
                        {
                            if (err.statusCode == 404 || err.err.indexOf('NotFoundError') > -1)
                              return 'notfound';
                            else
                              return 'error';
                        }),
                  len= _.pluck(_.values(uerr),'length'),
                  max= _.max(len),
                  cnt= _.countBy(len,_.identity);

               if (max < wr || cnt[max]>1)
                 res.send(500,errors);
               else
                 _.keys(uerr).some(function (type)
                 {
                     var errs= uerr[type];

                     if (errs.length==max)
                     {
                       if (type=='notfound')
                         res.status(404).send(put ? 'bucket not found' : 'key not found');
                       else
                         res.status(500).send(errors);

                       return true;
                     }
                 });
        },
        compareKeys= function (key1, key2)
        {
              if (key1 > key2) return 1;
              else if (key1 < key2) return -1;
              return 0;
        },
        unique= function ()
        {
           var last;

           return map(function (data, cb)
           {
                last!==data ?
                  cb(null, data) :
                  cb();
                last= data;
           });
        };

    app.put('/dull/bucket/:bucket/data/:key', mw.binary, function (req,res)
    {
        var w= req.query.w || node.cap.w,
            nodes= node.ring.range(req.params.key,node.cap.n),
            errors= [],
            success= _.after(w,function ()
                     {
                         res.end();
                     });

        if (node.cap.n < w)
          res.status(500).send('the cluster has n='+node.cap.n+' you cannot specify a greater w. ('+w+')');
        else
        if (nodes.length < w)
          res.status(500).send('we have only '+nodes.length+' nodes active, and you specified w='+w);
        else
        async.forEach(nodes,
        function (node,done)
        {
            multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
            .batch([{ // key
                          key: ['K',req.params.key,'_'].join(KS),
                        value: req.params.key,
                         type: 'put'
                    },
                    { // value meta
                          key: ['V',req.params.key,'M'].join(KS),
                        value: {
                                   hash: ut.hash(req.binary),
                                headers: {
                                            'Content-Type': req.headers['content-type'] || 'application/octet-stream',
                                            'Content-Length': req.headers['content-length'] || req.binary.length
                                         }
                               },
                         type: 'put'
                    },
                    { // value content
                          key: ['V',req.params.key,'C'].join(KS),
                        value: req.binary,
                         type: 'put'
                    }],
            function (err,res)
            {
               if (err)
                 errors.push({ node: node, err: err, statusCode: res.statusCode });
               else
                 success();

               done();
            });
        },
        function ()
        {
           if (errors.length > (node.cap.n-w) || errors.length == nodes.length)
             resolveErrors(errors,res,w,true);
           else
             console.log('put success');
        });
    });

    app.get('/dull/bucket/:bucket/data/:key', function (req, res)
    {
        var r= req.query.r || node.cap.r,
            nodes= node.ring.range(req.params.key,node.cap.n),
            errors= [],
            values= [];

        if (node.cap.n < r)
          res.status(500).send('the cluster has n='+node.cap.n+' you cannot specify a greater r. ('+r+')');
        else
        if (nodes.length < r)
          res.status(500).send('we have only '+nodes.length+' nodes active, and you specified r='+r);
        else
        async.forEach(nodes,
        function (node,done)
        {
            var parts= [];

            multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
            .valueStream({ start: ['V',req.params.key,'C'].join(KS),
                             end: ['V',req.params.key,'M'].join(KS) })
            .on('error', function (err)
            {
                 errors.push({ node: node, err: err });
            })
            .on('data', function (data)
            {
               parts.push(data);
            })
            .on('end', function ()
            {
                values.push({ meta: JSON.parse(parts[1]), content: parts[0] });
                done();
            });
        },
        function ()
        {
           if (errors.length > (node.cap.n-r) || errors.length == nodes.length)
               resolveErrors(errors,res,r);
           else
           {
               var uval= _.groupBy(values,function (val)
                         {
                            return val.meta.hash;
                         }),
                   len= _.pluck(_.values(uval),'length'),
                   max= _.max(len),
                   cnt= _.countBy(len,_.identity);

               if (max < r)
                 res.status(500).send('We have only '+max+' replicas that agree on a value for that key, you specified r='+r);
               else
               if (cnt[max]>1)
                 res.status(500).send('Doh, we have diverging replicas for that key');
               else
                 _.keys(uval).some(function (hash)
                 {
                     var vals= uval[hash];

                     if (vals.length==max)
                     {
                       var val= vals[0];

                       _.keys(val.meta.headers).forEach(function (name)
                       {
                           res.setHeader(name,val.meta.headers[name]);
                       });

                       res.end(val.content);
                       return true;
                     }
                 });
           }
        });
    });

    app.delete('/dull/bucket/:bucket/data/:key', function (req,res)
    {
        var w= req.query.w || node.cap.w,
            nodes= node.ring.range(req.params.key,node.cap.n),
            errors= [],
            success= _.after(w,function ()
                     {
                         res.end();
                     });

        if (node.cap.n < w)
          res.status(500).send('the cluster has n='+node.cap.n+' you cannot specify a greater w. ('+w+')');
        else
        if (nodes.length < w)
          res.status(500).send('we have only '+nodes.length+' nodes active, and you specified w='+w);
        else
        async.forEach(nodes,
        function (node,done)
        {
            multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
            .batch([{ // key
                          key: ['K',req.params.key,'_'].join(KS),
                         type: 'del'
                    },
                    { // value meta
                          key: ['V',req.params.key,'M'].join(KS),
                         type: 'del'
                    },
                    { // value content
                          key: ['V',req.params.key,'C'].join(KS),
                         type: 'del'
                    }],
            function (err,res)
            {
               if (err)
                 errors.push({ node: node, err: err, statusCode: res.statusCode });
               else
                 success();

               done();
            });
        },
        function ()
        {
           if (errors.length > (node.cap.n-w) || errors.length == nodes.length)
             resolveErrors(errors,res,w);
           else
             console.log('del success');
        });

    });

    app.get('/dull/bucket/:bucket/approximateSize/:from..:to', function (req, res, next)
    {
        var size= 0;

        async.forEach(node.ring.nodes(),
        function (node,done)
        {
            multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
            .approximateSize(req.params.from,req.params.to,function (err,size)
            {
                if (!err) size+= size;
                done(err);
            });
        },
        function (err)
        {
           if (err)
             next(err);
           else
             res.send(size);
        });
    });

    app.get('/dull/bucket/:bucket/keys', function (req, res, next)
    {
        var streams= [];

        async.forEach(node.ring.nodes(),
        function (node,done)
        {
            streams.push(multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
                                   .valueStream({ start: 'K'+KS, end: ['K','\xff'].join(KS) }));
            done();
        },
        function ()
        {
           var merged= merge(compareKeys,streams);

           streams.forEach(function (stream)
           {
                stream.on('error', function (err)
                {
                    merged.emit('error', err);
                });
           });

           res.type('json');

           merged
             .pipe(unique())
             .pipe(JSONStream.stringify())
             .pipe(res);
        });
    });
};
<commit_msg>fixing binary<commit_after>var mw= require('./middleware'),
    ut= require('./util'),
    _= require('underscore'),
    async= require('async'),
    multilevel= require('multilevel-http'),
    merge = require('mergesort-stream'),
    JSONStream = require('JSONStream'),
    map   =  require('map-stream');

const KS= '::';

module.exports= function (app,node)
{
    var resolveErrors= function (errors, res, wr, put)
        {
              var uerr= _.groupBy(errors,function (err)
                        {
                            if (err.statusCode == 404 || err.err.indexOf('NotFoundError') > -1)
                              return 'notfound';
                            else
                              return 'error';
                        }),
                  len= _.pluck(_.values(uerr),'length'),
                  max= _.max(len),
                  cnt= _.countBy(len,_.identity);

               if (max < wr || cnt[max]>1)
                 res.send(500,errors);
               else
                 _.keys(uerr).some(function (type)
                 {
                     var errs= uerr[type];

                     if (errs.length==max)
                     {
                       if (type=='notfound')
                         res.status(404).send(put ? 'bucket not found' : 'key not found');
                       else
                         res.status(500).send(errors);

                       return true;
                     }
                 });
        },
        compareKeys= function (key1, key2)
        {
              if (key1 > key2) return 1;
              else if (key1 < key2) return -1;
              return 0;
        },
        unique= function ()
        {
           var last;

           return map(function (data, cb)
           {
                last!==data ?
                  cb(null, data) :
                  cb();
                last= data;
           });
        };

    app.put('/dull/bucket/:bucket/data/:key', mw.binary, function (req,res)
    {
        var w= req.query.w || node.cap.w,
            nodes= node.ring.range(req.params.key,node.cap.n),
            errors= [],
            success= _.after(w,function ()
                     {
                         res.end();
                     });

        if (node.cap.n < w)
          res.status(500).send('the cluster has n='+node.cap.n+' you cannot specify a greater w. ('+w+')');
        else
        if (nodes.length < w)
          res.status(500).send('we have only '+nodes.length+' nodes active, and you specified w='+w);
        else
        async.forEach(nodes,
        function (node,done)
        {
            multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
            .batch([{ // key
                          key: ['K',req.params.key,'_'].join(KS),
                        value: req.params.key,
                         type: 'put'
                    },
                    { // value meta
                          key: ['V',req.params.key,'M'].join(KS),
                        value: JSON.stringify
                               ({
                                   hash: ut.hash(req.binary),
                                headers: _.defaults(_.pick(req.headers,['content-type','content-length']),
                                         {
                                            'content-type': 'application/json',
                                            'content-length': req.binary.length
                                         })
                               }),
                         type: 'put'
                    },
                    { // value content
                          key: ['V',req.params.key,'C'].join(KS),
                        value: req.headers['content-type']!='application/json' ? req.binary.toString('base64') : req.binary.toString('utf8'),
                         type: 'put'
                    }],
            function (err,res)
            {
               if (err)
                 errors.push({ node: node, err: err, statusCode: res.statusCode });
               else
                 success();

               done();
            });
        },
        function ()
        {
           if (errors.length > (node.cap.n-w) || errors.length == nodes.length)
             resolveErrors(errors,res,w,true);
           else
             console.log('put success');
        });
    });

    app.get('/dull/bucket/:bucket/data/:key', function (req, res)
    {
        var r= req.query.r || node.cap.r,
            nodes= node.ring.range(req.params.key,node.cap.n),
            errors= [],
            values= [];

        if (node.cap.n < r)
          res.status(500).send('the cluster has n='+node.cap.n+' you cannot specify a greater r. ('+r+')');
        else
        if (nodes.length < r)
          res.status(500).send('we have only '+nodes.length+' nodes active, and you specified r='+r);
        else
        async.forEach(nodes,
        function (node,done)
        {
            var parts= [];

            multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
            .valueStream({ start: ['V',req.params.key,'C'].join(KS),
                             end: ['V',req.params.key,'M'].join(KS) })
            .on('error', function (err)
            {
                 errors.push({ node: node, err: err });
            })
            .on('data', function (data)
            {
               parts.push(data);
            })
            .on('end', function ()
            {
                values.push({ meta: JSON.parse(parts[1]), content: parts[0] });
                done();
            });
        },
        function ()
        {
           if (errors.length > (node.cap.n-r) || errors.length == nodes.length)
               resolveErrors(errors,res,r);
           else
           {
               var uval= _.groupBy(values,function (val)
                         {
                            return val.meta.hash;
                         }),
                   len= _.pluck(_.values(uval),'length'),
                   max= _.max(len),
                   cnt= _.countBy(len,_.identity);

               if (max < r)
                 res.status(500).send('We have only '+max+' replicas that agree on a value for that key, you specified r='+r);
               else
               if (cnt[max]>1)
                 res.status(500).send('Doh, we have diverging replicas for that key');
               else
                 _.keys(uval).some(function (hash)
                 {
                     var vals= uval[hash];

                     if (vals.length==max)
                     {
                       var val= vals[0];

                       _.keys(val.meta.headers).forEach(function (name)
                       {
                           res.setHeader(name,val.meta.headers[name]);
                       });

                       if (val.meta.headers['content-type']=='application/json')
                         res.end(val.content);
                       else
                         res.end(new Buffer(val.content,'base64'));

                       return true;
                     }
                 });
           }
        });
    });

    app.delete('/dull/bucket/:bucket/data/:key', function (req,res)
    {
        var w= req.query.w || node.cap.w,
            nodes= node.ring.range(req.params.key,node.cap.n),
            errors= [],
            success= _.after(w,function ()
                     {
                         res.end();
                     });

        if (node.cap.n < w)
          res.status(500).send('the cluster has n='+node.cap.n+' you cannot specify a greater w. ('+w+')');
        else
        if (nodes.length < w)
          res.status(500).send('we have only '+nodes.length+' nodes active, and you specified w='+w);
        else
        async.forEach(nodes,
        function (node,done)
        {
            multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
            .batch([{ // key
                          key: ['K',req.params.key,'_'].join(KS),
                         type: 'del'
                    },
                    { // value meta
                          key: ['V',req.params.key,'M'].join(KS),
                         type: 'del'
                    },
                    { // value content
                          key: ['V',req.params.key,'C'].join(KS),
                         type: 'del'
                    }],
            function (err,res)
            {
               if (err)
                 errors.push({ node: node, err: err, statusCode: res.statusCode });
               else
                 success();

               done();
            });
        },
        function ()
        {
           if (errors.length > (node.cap.n-w) || errors.length == nodes.length)
             resolveErrors(errors,res,w);
           else
             console.log('del success');
        });

    });

    app.get('/dull/bucket/:bucket/approximateSize/:from..:to', function (req, res, next)
    {
        var size= 0;

        async.forEach(node.ring.nodes(),
        function (node,done)
        {
            multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
            .approximateSize(req.params.from,req.params.to,function (err,size)
            {
                if (!err) size+= size;
                done(err);
            });
        },
        function (err)
        {
           if (err)
             next(err);
           else
             res.send(size);
        });
    });

    app.get('/dull/bucket/:bucket/keys', function (req, res, next)
    {
        var streams= [];

        async.forEach(node.ring.nodes(),
        function (node,done)
        {
            streams.push(multilevel.client('http://'+node+'/mnt/'+req.params.bucket+'/')
                                   .valueStream({ start: 'K'+KS, end: ['K','\xff'].join(KS) }));
            done();
        },
        function ()
        {
           var merged= merge(compareKeys,streams);

           streams.forEach(function (stream)
           {
                stream.on('error', function (err)
                {
                    merged.emit('error', err);
                });
           });

           res.type('json');

           merged
             .pipe(unique())
             .pipe(JSONStream.stringify())
             .pipe(res);
        });
    });
};
<|endoftext|>


<commit_before>/**
 * JS delayed hover is module that enable fires event when you
 * hover over element and move your mouse slow enough.
 *
 * Usage:
 *
 * 	var container = document.getElementById( 'testContainer' );
 *	delayedHover(
 *		container, // HTML node element to watch
 *		{
 *			checkInterval: 100, // How often mouse speed is calculated
 *			maxActivationDistance: 20, // Breakpoint for activation, onActivate callback will be fired when mouse speed is below this value
 *			onActivate: function () { // Function to call when mouse speed meets required conditions
 *				container.classList.add( 'active' );
 *			},
 *			onDeactivate: function() { // Function to call when you stop hovering element
 *				container.classList.remove( 'active' );
 *			}
 *		}
 *	);
 *
 * Copyright 2014 Wikia Inc.
 * Released under the MIT license
 * https://github.com/Wikia/js-delayed-hover
 */

(function() {
	var utils, DelayedHoverModule;

	/**
	 * Additional functions to help module to work.
	 */
	utils = {
		/**
		 * Just simple one-time-defined function that will do nothing
		 */
		noop: function() {},

		/**
		 * Returns first object extended by the properties of the second
		 * @param {Object} dst Object to be extended
		 * @param {Object} src Object with properties that should be added to the previous
		 * @return {Object} Extended object
		 */
		extend: function(dst, src) {
			var p;
			for (p in src) {
				if (src.hasOwnProperty (p)) {
					dst[p] = src[p];
				}
			}
			return dst;
		}
	};

	/**
	 * Module core
	 */
	DelayedHoverModule = function() {
		var getMoveDistance,
			mouseEnterHandler, mouseLeaveHandler, mouseMoveHandler,
			lastLocation, lastCheckedLocation, options, possiblyActivate, timeoutId;

		/**
		 * Module options
		 */
		options = {
			checkInterval: 100,
			maxActivationDistance: 20,
			onActivate: utils.noop,
			onDeactivate: utils.noop
		};

		/**
		 * Calculate distance between
		 * !Important: This is not a real distance, it's a sum of distances on both axes.
		 * This solution was chosen to increase module performance.
		 * @returns {number}
		 */
		getMoveDistance = function() {
			return Math.abs( lastCheckedLocation.x - lastLocation.x ) + Math.abs( lastCheckedLocation.y - lastLocation.y );
		}

		/**
		 * Function that checks mouse speed  activates callback when conditions are met
		 */
		possiblyActivate = function() {
			if ( lastLocation && getMoveDistance() <= options.maxActivationDistance ) {
				options.onActivate();
			} else {
				timeoutId = setTimeout( possiblyActivate, options.checkInterval );
			}

			if ( lastLocation ) {
				lastCheckedLocation = lastLocation;
			}
		};

		/**
		 * Mouse move handler
		 */
		mouseMoveHandler = function( e ) {
			lastLocation = {x: e.pageX, y: e.pageY};
		};

		mouseEnterHandler = function( e ) {
			lastCheckedLocation = {x: e.pageX, y: e.pageY};
			lastLocation = null;
			possiblyActivate();
		};

		mouseLeaveHandler = function() {
			if ( timeoutId ) {
				clearTimeout( timeoutId );
			}

			options.onDeactivate();
		};

		/**
		 * Prepare variable, hook handler
		 */
		this.init = function( elem, opts ) {
			options = utils.extend(options, opts);

			elem.addEventListener( 'click', options.onActivate );
			elem.addEventListener( 'mouseenter', mouseEnterHandler );
			elem.addEventListener( 'mouseleave', mouseLeaveHandler );
			elem.addEventListener( 'mousemove', mouseMoveHandler );

			return this;
		}
	}

	window.delayedHover = function( elem, options ) {
		var delayedHover = new DelayedHoverModule();
		return delayedHover.init( elem, options );
	};
})();
<commit_msg>Changed distance calculation method<commit_after>/**
 * JS delayed hover is module that enable fires event when you
 * hover over element and move your mouse slow enough.
 *
 * Usage:
 *
 * 	var container = document.getElementById( 'testContainer' );
 *	delayedHover(
 *		container, // HTML node element to watch
 *		{
 *			checkInterval: 100, // How often mouse speed is calculated
 *			maxActivationDistance: 20, // Breakpoint for activation, onActivate callback will be fired when mouse speed is below this value
 *			onActivate: function () { // Function to call when mouse speed meets required conditions
 *				container.classList.add( 'active' );
 *			},
 *			onDeactivate: function() { // Function to call when you stop hovering element
 *				container.classList.remove( 'active' );
 *			}
 *		}
 *	);
 *
 * Copyright 2014 Wikia Inc.
 * Released under the MIT license
 * https://github.com/Wikia/js-delayed-hover
 */

(function() {
	var utils, DelayedHoverModule;

	/**
	 * Additional functions to help module to work.
	 */
	utils = {
		/**
		 * Just simple one-time-defined function that will do nothing
		 */
		noop: function() {},

		/**
		 * Returns first object extended by the properties of the second
		 * @param {Object} dst Object to be extended
		 * @param {Object} src Object with properties that should be added to the previous
		 * @return {Object} Extended object
		 */
		extend: function( dst, src ) {
			var p;
			for ( p in src ) {
				if (src.hasOwnProperty( p )) {
					dst[p] = src[p];
				}
			}
			return dst;
		}
	};

	/**
	 * Module core
	 */
	DelayedHoverModule = function() {
		var getSquaredMoveDistance,
			mouseEnterHandler, mouseLeaveHandler, mouseMoveHandler,
			lastLocation, lastCheckedLocation, options, possiblyActivate, timeoutId;

		/**
		 * Module options
		 */
		options = {
			checkInterval: 100,
			maxActivationDistance: 20,
			onActivate: utils.noop,
			onDeactivate: utils.noop
		};

		/**
		 * Calculate squared distance between. We use squared values for better performance.
		 * We don't need squared root when comparing to squared max distance.
		 * @returns {number}
		 */
		getSquaredMoveDistance = function() {
			return ( lastCheckedLocation.x - lastLocation.x ) * ( lastCheckedLocation.x - lastLocation.x ) +
				( lastCheckedLocation.y - lastLocation.y ) * ( lastCheckedLocation.y - lastLocation.y );
		}

		/**
		 * Function that checks mouse speed  activates callback when conditions are met
		 */
		possiblyActivate = function() {
			if ( lastLocation && getSquaredMoveDistance() <= options.maxSquaredActivationDistance ) {
				options.onActivate();
			} else {
				timeoutId = setTimeout( possiblyActivate, options.checkInterval );
			}

			if ( lastLocation ) {
				lastCheckedLocation = lastLocation;
			}
		};

		/**
		 * Mouse move handler
		 */
		mouseMoveHandler = function( e ) {
			lastLocation = {x: e.pageX, y: e.pageY};
		};

		mouseEnterHandler = function( e ) {
			lastCheckedLocation = {x: e.pageX, y: e.pageY};
			lastLocation = null;
			possiblyActivate();
		};

		mouseLeaveHandler = function() {
			if ( timeoutId ) {
				clearTimeout( timeoutId );
			}

			options.onDeactivate();
		};

		/**
		 * Prepare variable, hook handler
		 */
		this.init = function( elem, opts ) {
			options = utils.extend(options, opts);
			options.maxSquaredActivationDistance = options.maxActivationDistance * options.maxActivationDistance;

			elem.addEventListener( 'click', options.onActivate );
			elem.addEventListener( 'mouseenter', mouseEnterHandler );
			elem.addEventListener( 'mouseleave', mouseLeaveHandler );
			elem.addEventListener( 'mousemove', mouseMoveHandler );

			return this;
		}
	}

	window.delayedHover = function( elem, options ) {
		var delayedHover = new DelayedHoverModule();
		return delayedHover.init( elem, options );
	};
})();
<|endoftext|>


<commit_before>Date.prototype.stdTimezoneOffset = function() {
  var jan = new Date(this.getFullYear(), 0, 1);
  var jul = new Date(this.getFullYear(), 6, 1);
  return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
};

Date.prototype.dst = function() {
  return this.getTimezoneOffset() < this.stdTimezoneOffset();
};

// assume that daylight savings time wherever server is is the same as it is for ustream
// ustream apparently uses timestamps that match whatever time it happened to be in SF, but contain no timezone or dst info
var convertUStreamDateToUTC = function(ustreamDateString){
  return new Date(ustreamDateString + " " + (new Date().dst() ? 'PDT' : 'PST'))
};

var servicesToFetch = [
  {
    serviceName: 'ustream',
    methodName: 'ustreamVideoSearchList',
    startingPage: 1,
    initialPagesGuess: 60,
    guessBias: 1,
    maxPages: parseInt(process.env.MAX_USTREAM_PAGES) || parseInt(Meteor.settings.MAX_USTREAM_PAGES) || 1000,
    asyncWaitTime: 10,
    mapFn: function (doc) {
      _.extend(doc, {
        _streamSource: 'ustream',
        username: doc.user.userName,
        creationDate: convertUStreamDateToUTC(doc.createdAt),
        lastStreamedAt: convertUStreamDateToUTC(doc.lastStreamedAt),
        currentViewers: parseInt(doc.viewersNow),
        totalViews: parseInt(doc.totalViews),
        createdAtInUStreamTime: doc.createdAt, // save this in case we need it later
        live: true
      })
      delete doc.createdAt; // this is an awful thing with no timezone info, we renamed it to make that clear
      return doc
    }
  },
  {
    serviceName: 'bambuser',
    methodName: 'bambuserVideoSearchList',
    startingPage: 0,
    initialPagesGuess: 3,
    guessBias: 0,
    maxPages: parseInt(process.env.MAX_BAMBUSER_PAGES) || parseInt(Meteor.settings.MAX_BAMBUSER_PAGES) || 1000,
    asyncWaitTime: 10,
    mapFn: function (doc) {
      _.extend(doc, {
        _streamSource: 'bambuser',
        id: doc.vid,
        creationDate: new Date(parseInt(doc.created) * 1000),
        //currentViewers: parseInt(doc.views), // no current viewers metric for bambuser
        totalViews: parseInt(doc.views_total),
        lengthSecs: doc.length,
        live: true
      });
      delete doc.length; // this only causes problems
      return doc;
    }
  }
];

var generateFetchFunction = function(serviceInfo){

  var serviceName = serviceInfo.serviceName;
  var numPagesGuess = serviceInfo.initialPagesGuess;
  var guessBias = serviceInfo.guessBias;
  var waitBetweenAsyncCalls = serviceInfo.asyncWaitTime; // ms
  var maxPages = serviceInfo.maxPages;
  var startingPage = serviceInfo.startingPage;

  return Meteor.wrapAsync(function (finalCallback) {
    var numPagesGuesses = [];

    var allStreamsLoaded = false;
    var numAsyncPages = Math.min(numPagesGuess, maxPages);

    var currentPage;

    var streamInsertCallback = function (error, result, page, cb) {
      console.log('Received ' + serviceName + ' response for page: ' + page);

      if (error) {
        allStreamsLoaded = true;
        console.log('Error returned from ' + serviceName + ' on page: ' + page);
        console.error(error);
        return cb();
      }

      if (!result.items || !result.items.length) {
        allStreamsLoaded = true;
        numPagesGuesses.push(page - 1 + guessBias);
        return cb();
      }
      Streams.batchInsert(_.map(result.items, serviceInfo.mapFn));

      console.log('Added ' + serviceName + ' streams to database for page: ' + page);
      return cb();
    };

    console.log('Current guess for number of ' + serviceName + ' pages: ' + numPagesGuess);
    console.log('Begin async ' + serviceName + ' calls')
    async.each(_.range(numAsyncPages), function (i, cb) {
        Meteor.setTimeout(function () {
          currentPage = i + startingPage;
          console.log('Async ' + serviceName + ' call for page: ' + currentPage);
          var localCurrentPage = currentPage;

          Meteor.call(serviceInfo.methodName, undefined, undefined, currentPage, function (err, result) {
            try {
              streamInsertCallback(err, result, localCurrentPage, cb);
            } catch (err) {
              console.log('Error in async ' + serviceName + ' callback page: ' + localCurrentPage)
              console.error(err)
              return cb();
            }
          });
        }, waitBetweenAsyncCalls * i)
      }, function (err) {
        console.log('Finish async ' + serviceName + ' calls');
        if (err) {
          finalCallback(err);
        } else {
          console.log('Begin sync ' + serviceName + ' calls');
          currentPage += 1;

          while (!allStreamsLoaded && currentPage < maxPages + startingPage) {
            console.log('Sync ' + serviceName + ' call for page: ' + currentPage);

            Meteor.call(serviceInfo.methodName, undefined, undefined, currentPage, function (err, result) {
              streamInsertCallback(err, result, currentPage, function (err) {
                if (err) {
                  return finalCallback(err);
                }
              })
            });
            currentPage += 1;
          }
          if (allStreamsLoaded) {
            numPagesGuess = _.min(numPagesGuesses)
          } else {
            numPagesGuess = currentPage - 1;
          }
          console.log('Finish sync ' + serviceName + ' calls');
          console.log(serviceName + ' API calls complete!');
          console.log((currentPage - 1) + ' ' + serviceName + ' pages loaded');

          console.log(serviceName + ' results loaded');
          return finalCallback();
        }
      }
    );

  })
};

var updateStreamStatus = function (deepstream) {
  var ustream;
  _.each(deepstream.streams, function (stream) {
    var streamSourceId = stream.reference.id;
    var streamSourceUsername = stream.reference.username;
    switch (stream.source) {
      case 'ustream':
        console.log('check ustream');
        if (stream = Streams.findOne({'id': streamSourceId})) {
          // TODO update views and such
          Deepstreams.update({
            _id: deepstream._id,
            'streams.reference.id': streamSourceId
          }, {$set: {'streams.$.live': true}});
        } else {
          // TODO update views and such
          Deepstreams.update({
            _id: deepstream._id,
            'streams.reference.id': streamSourceId
          }, {$set: {'streams.$.live': false}});
        }
        break;
      case 'bambuser':
        console.log('check bambuser');
        if (stream = Streams.findOne({'username': streamSourceUsername})) {
          // TODO update title and views and such. These might actually change...
          Deepstreams.update({
            _id: deepstream._id,
            'streams.reference.id': streamSourceId
          }, {$set: {'streams.$.live': true}});
        } else {
          // TODO update title and views and such
          Deepstreams.update({
            _id: deepstream._id,
            'streams.reference.id': streamSourceId
          }, {$set: {'streams.$.live': false}});
        }
        break;
      case 'youtube':
        console.log('check youtube');

        // TODO maybe only if we think youtube video is live
        Meteor.call('youtubeVideoInfo', streamSourceId, function (err, data) { // TODO this request can be done in a batch for all youtube videos we have...
          if (err) {
            throw(err);
          }
          var videos = data.items;
          var video = videos[0];
          if (video) {
            if (video.snippet.liveBroadcastContent === 'live') {
              // TODO update views and such (statistis.viewCount)
              // and current viewers liveStreamingDetails.concurrentViewers
              // TO-DO, this line below shouldn't be necessary since youtube doesn't go live again after it's dead, we think...
              Deepstreams.update({
                _id: deepstream._id,
                'streams.reference.id': streamSourceId
              }, {$set: {'streams.$.live': true}});

            } else {
              // TODO update views and such
              Deepstreams.update({
                _id: deepstream._id,
                'streams.reference.id': streamSourceId
              }, {$set: {'streams.$.live': false}});
            } // video isn't live
          } else { // video not found, so not live
            console.log('NOT FOUUUUUND')
            Deepstreams.update({
              _id: deepstream._id,
              'streams.reference.id': streamSourceId
            }, {$set: {'streams.$.live': false}});
          }
        });
        break;

    }
  });
};

var cycleStreamsCollection = function () {
  Streams.update({}, {$inc: {oneIfCurrent: 1}}, {multi: true}); // recent batch is now loaded
  Streams.remove({oneIfCurrent: {$gt: 1}}); // remove previous batch
};

var updateStreamStatuses = function () {
  Deepstreams.find({}, {fields: {streams: 1}}).forEach(updateStreamStatus);
};

var updateDeepstreamStatuses = function () {

  // TODO only check active stream when in director mode
  // TO-DO performance. restrict to published?

  var dsLive = Deepstreams.update({'streams.live': true}, {$set: {live: true}}, {multi: true});
  var dsDead = Deepstreams.update({'streams': {$not: {$elemMatch: {live: true}}}}, {$set: {live: false}}, {multi: true});

  console.log(dsLive + ' deepstreams are live');
  console.log(dsDead + ' deepstreams are dead');

};

var runJobs = function () {
  console.log('Running jobs...')
  var startTime = Date.now();
  var previousTimepoint = Date.now();

  var timeLogs = [];

  _.each(servicesToFetch, function(serviceInfo){
    generateFetchFunction(serviceInfo)();
    timeLogs.push(serviceInfo.serviceName + ' fetch time: ' + ((Date.now() - previousTimepoint)/1000) + ' seconds');
    previousTimepoint = Date.now();
  });

  cycleStreamsCollection();
  timeLogs.push('stream db cycle time: ' + ((Date.now() - previousTimepoint) / 1000) + ' seconds');
  previousTimepoint = Date.now();

  updateStreamStatuses();
  timeLogs.push('stream update time: ' + ((Date.now() - previousTimepoint) / 1000) + ' seconds');
  previousTimepoint = Date.now();

  updateDeepstreamStatuses();
  timeLogs.push('deepstream update time: ' + ((Date.now() - previousTimepoint) / 1000) + ' seconds');
  previousTimepoint = Date.now();

  _.each(timeLogs, function(str){
    console.log(str);
  });

  console.log('Total time to run jobs: ' + ((Date.now() - startTime) / 1000) + ' seconds');
};

var jobWaitInSeconds = parseInt(process.env.JOB_WAIT) || 5 * 60; // default is every 5 minutes

if (process.env.PROCESS_TYPE === 'stream_worker') { // if a worker process
  Meteor.startup(function () {
    Meteor.setTimeout(function () {
      while (true) {
        runJobs();
        Meteor._sleepForMs(jobWaitInSeconds * 1000)
      }
    });
  });
} else if (process.env.NODE_ENV === 'development') { // however, in developement, run jobs on startup
  Meteor.startup(function () {
    Meteor.setTimeout(runJobs)
  });
}
<commit_msg> check google for DST once per worker<commit_after>var isDST = false; // default in case request fails
var DSTChecked = false;

// assume that daylight savings time wherever server is is the same as it is for ustream whenever that video happened to be recorded
// ustream apparently uses timestamps that match whatever time it happened to be in SF, but contain no timezone or dst info
var convertUStreamDateToUTC = function(ustreamDateString){
  return new Date(ustreamDateString + " " + (isDST ? 'PDT' : 'PST'))
};

var checkDSTOnceOnly = function(){
  if(DSTChecked){ // only check once per worker (per day)
    return;
  }
  console.log("Checking DST Status");
  var requestParams = {
    location: "37.7833,-122.4167",
    timestamp: Date.now()/1000,
    key: Meteor.settings.GOOGLE_API_SERVER_KEY
  };

  timezoneRes = HTTP.get('https://maps.googleapis.com/maps/api/timezone/json?parameters', {
    params: requestParams
  });

  DSTChecked = true;

  if (timezoneRes.data.dstOffset){
    isDST = true;
  }
  console.log("DST Status is: " + isDST);
};

var servicesToFetch = [
  {
    serviceName: 'ustream',
    methodName: 'ustreamVideoSearchList',
    startingPage: 1,
    initialPagesGuess: 60,
    guessBias: 1,
    maxPages: parseInt(process.env.MAX_USTREAM_PAGES) || parseInt(Meteor.settings.MAX_USTREAM_PAGES) || 1000,
    asyncWaitTime: 10,
    mapFn: function (doc) {
      _.extend(doc, {
        _streamSource: 'ustream',
        username: doc.user.userName,
        creationDate: convertUStreamDateToUTC(doc.createdAt),
        lastStreamedAt: convertUStreamDateToUTC(doc.lastStreamedAt),
        currentViewers: parseInt(doc.viewersNow),
        totalViews: parseInt(doc.totalViews),
        createdAtInUStreamTime: doc.createdAt, // save this in case we need it later
        live: true
      })
      delete doc.createdAt; // this is an awful thing with no timezone info, we renamed it to make that clear
      return doc
    }
  },
  {
    serviceName: 'bambuser',
    methodName: 'bambuserVideoSearchList',
    startingPage: 0,
    initialPagesGuess: 3,
    guessBias: 0,
    maxPages: parseInt(process.env.MAX_BAMBUSER_PAGES) || parseInt(Meteor.settings.MAX_BAMBUSER_PAGES) || 1000,
    asyncWaitTime: 10,
    mapFn: function (doc) {
      _.extend(doc, {
        _streamSource: 'bambuser',
        id: doc.vid,
        creationDate: new Date(parseInt(doc.created) * 1000),
        //currentViewers: parseInt(doc.views), // no current viewers metric for bambuser
        totalViews: parseInt(doc.views_total),
        lengthSecs: doc.length,
        live: true
      });
      delete doc.length; // this only causes problems
      return doc;
    }
  }
];

var generateFetchFunction = function(serviceInfo){

  var serviceName = serviceInfo.serviceName;
  var numPagesGuess = serviceInfo.initialPagesGuess;
  var guessBias = serviceInfo.guessBias;
  var waitBetweenAsyncCalls = serviceInfo.asyncWaitTime; // ms
  var maxPages = serviceInfo.maxPages;
  var startingPage = serviceInfo.startingPage;

  return Meteor.wrapAsync(function (finalCallback) {
    var numPagesGuesses = [];

    var allStreamsLoaded = false;
    var numAsyncPages = Math.min(numPagesGuess, maxPages);

    var currentPage;

    var streamInsertCallback = function (error, result, page, cb) {
      console.log('Received ' + serviceName + ' response for page: ' + page);

      if (error) {
        allStreamsLoaded = true;
        console.log('Error returned from ' + serviceName + ' on page: ' + page);
        console.error(error);
        return cb();
      }

      if (!result.items || !result.items.length) {
        allStreamsLoaded = true;
        numPagesGuesses.push(page - 1 + guessBias);
        return cb();
      }
      Streams.batchInsert(_.map(result.items, serviceInfo.mapFn));

      console.log('Added ' + serviceName + ' streams to database for page: ' + page);
      return cb();
    };

    console.log('Current guess for number of ' + serviceName + ' pages: ' + numPagesGuess);
    console.log('Begin async ' + serviceName + ' calls')
    async.each(_.range(numAsyncPages), function (i, cb) {
        Meteor.setTimeout(function () {
          currentPage = i + startingPage;
          console.log('Async ' + serviceName + ' call for page: ' + currentPage);
          var localCurrentPage = currentPage;

          Meteor.call(serviceInfo.methodName, undefined, undefined, currentPage, function (err, result) {
            try {
              streamInsertCallback(err, result, localCurrentPage, cb);
            } catch (err) {
              console.log('Error in async ' + serviceName + ' callback page: ' + localCurrentPage)
              console.error(err)
              return cb();
            }
          });
        }, waitBetweenAsyncCalls * i)
      }, function (err) {
        console.log('Finish async ' + serviceName + ' calls');
        if (err) {
          finalCallback(err);
        } else {
          console.log('Begin sync ' + serviceName + ' calls');
          currentPage += 1;

          while (!allStreamsLoaded && currentPage < maxPages + startingPage) {
            console.log('Sync ' + serviceName + ' call for page: ' + currentPage);

            Meteor.call(serviceInfo.methodName, undefined, undefined, currentPage, function (err, result) {
              streamInsertCallback(err, result, currentPage, function (err) {
                if (err) {
                  return finalCallback(err);
                }
              })
            });
            currentPage += 1;
          }
          if (allStreamsLoaded) {
            numPagesGuess = _.min(numPagesGuesses)
          } else {
            numPagesGuess = currentPage - 1;
          }
          console.log('Finish sync ' + serviceName + ' calls');
          console.log(serviceName + ' API calls complete!');
          console.log((currentPage - 1) + ' ' + serviceName + ' pages loaded');

          console.log(serviceName + ' results loaded');
          return finalCallback();
        }
      }
    );

  })
};

var updateStreamStatus = function (deepstream) {
  var ustream;
  _.each(deepstream.streams, function (stream) {
    var streamSourceId = stream.reference.id;
    var streamSourceUsername = stream.reference.username;
    switch (stream.source) {
      case 'ustream':
        console.log('check ustream');
        if (stream = Streams.findOne({'id': streamSourceId})) {
          // TODO update views and such
          Deepstreams.update({
            _id: deepstream._id,
            'streams.reference.id': streamSourceId
          }, {$set: {'streams.$.live': true}});
        } else {
          // TODO update views and such
          Deepstreams.update({
            _id: deepstream._id,
            'streams.reference.id': streamSourceId
          }, {$set: {'streams.$.live': false}});
        }
        break;
      case 'bambuser':
        console.log('check bambuser');
        if (stream = Streams.findOne({'username': streamSourceUsername})) {
          // TODO update title and views and such. These might actually change...
          Deepstreams.update({
            _id: deepstream._id,
            'streams.reference.id': streamSourceId
          }, {$set: {'streams.$.live': true}});
        } else {
          // TODO update title and views and such
          Deepstreams.update({
            _id: deepstream._id,
            'streams.reference.id': streamSourceId
          }, {$set: {'streams.$.live': false}});
        }
        break;
      case 'youtube':
        console.log('check youtube');

        // TODO maybe only if we think youtube video is live
        Meteor.call('youtubeVideoInfo', streamSourceId, function (err, data) { // TODO this request can be done in a batch for all youtube videos we have...
          if (err) {
            throw(err);
          }
          var videos = data.items;
          var video = videos[0];
          if (video) {
            if (video.snippet.liveBroadcastContent === 'live') {
              // TODO update views and such (statistis.viewCount)
              // and current viewers liveStreamingDetails.concurrentViewers
              // TO-DO, this line below shouldn't be necessary since youtube doesn't go live again after it's dead, we think...
              Deepstreams.update({
                _id: deepstream._id,
                'streams.reference.id': streamSourceId
              }, {$set: {'streams.$.live': true}});

            } else {
              // TODO update views and such
              Deepstreams.update({
                _id: deepstream._id,
                'streams.reference.id': streamSourceId
              }, {$set: {'streams.$.live': false}});
            } // video isn't live
          } else { // video not found, so not live
            console.log('NOT FOUUUUUND')
            Deepstreams.update({
              _id: deepstream._id,
              'streams.reference.id': streamSourceId
            }, {$set: {'streams.$.live': false}});
          }
        });
        break;

    }
  });
};

var cycleStreamsCollection = function () {
  Streams.update({}, {$inc: {oneIfCurrent: 1}}, {multi: true}); // recent batch is now loaded
  Streams.remove({oneIfCurrent: {$gt: 1}}); // remove previous batch
};

var updateStreamStatuses = function () {
  Deepstreams.find({}, {fields: {streams: 1}}).forEach(updateStreamStatus);
};

var updateDeepstreamStatuses = function () {

  // TODO only check active stream when in director mode
  // TO-DO performance. restrict to published?

  var dsLive = Deepstreams.update({'streams.live': true}, {$set: {live: true}}, {multi: true});
  var dsDead = Deepstreams.update({'streams': {$not: {$elemMatch: {live: true}}}}, {$set: {live: false}}, {multi: true});

  console.log(dsLive + ' deepstreams are live');
  console.log(dsDead + ' deepstreams are dead');

};

var runJobs = function () {
  console.log('Running jobs...')
  var startTime = Date.now();
  checkDSTOnceOnly();
  var previousTimepoint = Date.now();

  var timeLogs = [];

  _.each(servicesToFetch, function(serviceInfo){
    generateFetchFunction(serviceInfo)();
    timeLogs.push(serviceInfo.serviceName + ' fetch time: ' + ((Date.now() - previousTimepoint)/1000) + ' seconds');
    previousTimepoint = Date.now();
  });

  cycleStreamsCollection();
  timeLogs.push('stream db cycle time: ' + ((Date.now() - previousTimepoint) / 1000) + ' seconds');
  previousTimepoint = Date.now();

  updateStreamStatuses();
  timeLogs.push('stream update time: ' + ((Date.now() - previousTimepoint) / 1000) + ' seconds');
  previousTimepoint = Date.now();

  updateDeepstreamStatuses();
  timeLogs.push('deepstream update time: ' + ((Date.now() - previousTimepoint) / 1000) + ' seconds');
  previousTimepoint = Date.now();

  _.each(timeLogs, function(str){
    console.log(str);
  });

  console.log('Total time to run jobs: ' + ((Date.now() - startTime) / 1000) + ' seconds');
};

var jobWaitInSeconds = parseInt(process.env.JOB_WAIT) || 5 * 60; // default is every 5 minutes

if (process.env.PROCESS_TYPE === 'stream_worker') { // if a worker process
  Meteor.startup(function () {
    Meteor.setTimeout(function () {
      while (true) {
        runJobs();
        Meteor._sleepForMs(jobWaitInSeconds * 1000)
      }
    });
  });
} else if (process.env.NODE_ENV === 'development') { // however, in developement, run jobs on startup
  Meteor.startup(function () {
    Meteor.setTimeout(runJobs)
  });
}
<|endoftext|>


<commit_before>/*global config:true, file:true, task:true, module: true */

var files = {
  0: [
    'libs/jquery-1.6.1.js',
    'libs/underscore.js'
  ],
  1: [
    'libs/jquery.scrollTo-1.4.2.js',
    'libs/jquery.hoverintent.js'
  ],
  2: [
    'src/js/core.js'
  ],
  3: [
    'src/js/models/fact.js',
    'src/js/views/ballooney_thingy.js',
    'src/js/views/balloon.js',
    'src/js/views/prepare.js'
  ],
  4: [
    'src/js/replace.js',
    'src/js/annotate.js',
    'src/js/highlight.js',
    'src/js/scrollto.js',
    'src/js/loaded_message.js',
    'src/js/search.js',
    'src/js/create.js',
    'src/js/modal.js',
    'src/js/lib/indicator.js'
  ],
  5: [
    'src/js/xdm.js'
  ],
  6: [
    'src/js/last.js'
  ]
};

var loaderFiles = {
  0: [
    'libs/easyXDM.js'
  ],
  1: [
    'src/js/loader.js'
  ]
};

module.exports = function(grunt){

  function createFactlinkConcatObject(filesObj) {
    return grunt.utils._.flatten(["<banner>", grunt.utils._(filesObj).map(function(fileGroup) {
      return fileGroup.map(function(file) {
        return "<file_strip_banner:" + file + ">";
      });
    })], true);
  }

  grunt.initConfig({
    pkg: '<json:package.json>',
    meta: {
      banner: '/*! \n' +
      ' * <%= pkg.title || pkg.name %> - v<%= pkg.version %> - \n' +
      '<%= pkg.homepage ? " * " + pkg.homepage + "\n" : "" %>' +
      ' *\n' +
      ' * Date: <%= grunt.template.today("m/d/yyyy") %>\n' +
      ' *\n' +
      ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' +
      ' */'
    },
    concat: {
      'dist/factlink.core.js': createFactlinkConcatObject(files),
      'dist/factlink.start_annotating.js': '<file_strip_banner:src/js/chrome/start_annotating.js>',
      'dist/factlink.stop_annotating.js': '<file_strip_banner:src/js/chrome/stop_annotating.js>',
      'dist/factlink.start_highlighting.js': '<file_strip_banner:src/js/chrome/start_highlighting.js>',
      'dist/factlink.stop_highlighting.js': '<file_strip_banner:src/js/chrome/stop_highlighting.js>',
      'dist/easyXDM/easyXDM.js': '<file_strip_banner:libs/easyXDM.js>',
      'dist/factlink.js': createFactlinkConcatObject(loaderFiles)
    },
    copy: {
      'dist/server/css/basic.css': 'dist/css/basic.css',

      'dist/server/images/arrow.png': 'src/images/arrow.png',
      'dist/server/images/arrows-bottom.png': 'src/images/arrows-bottom.png',
      'dist/server/images/arrows-top.png': 'src/images/arrows-top.png',
      'dist/server/images/bookmark.gif': 'src/images/bookmark.gif',
      'dist/server/images/logo-small.png': 'src/images/logo-small.png',

      'dist/images/arrow.png': 'src/images/arrow.png',
      'dist/images/arrows-bottom.png': 'src/images/arrows-bottom.png',
      'dist/images/arrows-top.png': 'src/images/arrows-top.png',
      'dist/images/bookmark.gif': 'src/images/bookmark.gif',
      'dist/images/logo-small.png': 'src/images/logo-small.png'
    },
    less: {
      basic: {
        src: 'src/css/basic.less',
        dest: 'dist/css/basic.css',
        options: {
          yuicompress: true
        }
      }
    },
    min: {
      'dist/server/factlink.core.min.js': ['<banner>', 'dist/factlink.core.js'],
      'dist/server/factlink.start_annotating.min.js': ['<banner>', 'dist/factlink.start_annotating.js'],
      'dist/server/factlink.stop_annotating.min.js': ['<banner>', 'dist/factlink.stop_annotating.js'],
      'dist/server/factlink.start_highlighting.min.js': ['<banner>', 'dist/factlink.start_highlighting.js'],
      'dist/server/factlink.stop_highlighting.min.js': ['<banner>', 'dist/factlink.stop_highlighting.js'],
      'dist/server/easyXDM/easyXDM.min.js': ['<banner>', 'dist/easyXDM/easyXDM.js'], // for the server
      'dist/easyXDM/easyXDM.min.js': ['<banner>', 'dist/easyXDM/easyXDM.js'],        // for local
      'dist/factlink.min.js': ['<banner>', 'dist/factlink.js']
    },
    qunit: {
      files: ['test/*.html']
    },
    lint: {
      files: ['grunt.js', 'src/js/**/*.js', 'test/**/*.js']
    },
    watch: {
      files: ['src/js/**/*', 'test/**/*', 'grunt.js'],
      tasks: 'lint qunit concat less copy'
    },
    jshint: {
      options: {
        // Settings
        "passfail"      : false,  // Stop on first error.
        "maxerr"        : 100,    // Maximum error before stopping.

        // Predefined globals whom JSHint will ignore.
        "browser"       : true,   // Standard browser globals e.g. `window`, `document`.

        "node"          : false,
        "rhino"         : false,
        "couch"         : false,
        "wsh"           : false,   // Windows Scripting Host.

        "jquery"        : true,
        "prototypejs"   : false,
        "mootools"      : false,
        "dojo"          : false,

        "predef"        : [  // Custom globals.
          "Factlink", "FactlinkConfig", "escape"
        ],

        // Development.
        "debug"         : false,  // Allow debugger statements e.g. browser breakpoints.
        "devel"         : true,   // Allow developments statements e.g. `console.log();`.

        // ECMAScript 5.
        "es5"           : true,   // Allow ECMAScript 5 syntax.
        "strict"        : false,  // Require `use strict` pragma  in every file.
        "globalstrict"  : false,  // Allow global "use strict" (also enables 'strict').

        // The Good Parts.
        "asi"           : false,  // Tolerate Automatic Semicolon Insertion (no semicolons).
        "laxbreak"      : true,   // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons.
        "bitwise"       : true,   // Prohibit bitwise operators (&, |, ^, etc.).
        "boss"          : true,   // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
        "curly"         : true,   // Require {} for every new block or scope.
        "eqeqeq"        : true,   // Require triple equals i.e. `===`.
        "eqnull"        : false,  // Tolerate use of `== null`.
        "evil"          : false,  // Tolerate use of `eval`.
        "expr"          : false,  // Tolerate `ExpressionStatement` as Programs.
        "forin"         : false,  // Tolerate `for in` loops without `hasOwnPrototype`.
        "immed"         : false,  // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
        "latedef"       : true,   // Prohipit variable use before definition.
        "loopfunc"      : true,   // Allow functions to be defined within loops.
        "noarg"         : true,   // Prohibit use of `arguments.caller` and `arguments.callee`.
        "regexp"        : false,  // Prohibit `.` and `[^...]` in regular expressions.
        "regexdash"     : false,  // Tolerate unescaped last dash i.e. `[-...]`.
        "scripturl"     : true,   // Tolerate script-targeted URLs.
        "shadow"        : false,  // Allows re-define variables later in code e.g. `var x=1; x=2;`.
        "supernew"      : false,  // Tolerate `new function () { ... };` and `new Object;`.
        "undef"         : true,   // Require all non-global variables be declared before they are used.

        // Personal styling preferences.
        "newcap"        : true,   // Require capitalization of all constructor functions e.g. `new F()`.
        "noempty"       : true,   // Prohibit use of empty blocks.
        "nonew"         : true,   // Prohibit use of constructors for side-effects.
        "nomen"         : false,  // Prohibit use of initial or trailing underbars in names.
        "onevar"        : false,  // Allow only one `var` statement per function.
        "plusplus"      : false,  // Prohibit use of `++` & `--`.
        "sub"           : false,  // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
        "trailing"      : true,   // Prohibit trailing whitespaces.
        "white"         : false,  // Check against strict whitespace and indentation rules.
        "indent"        : 2       // Specify indentation spacing
      }
    },
    uglify: {}
  });

  // Default task.
  grunt.registerTask('default', 'lint qunit concat min copy');
  grunt.registerTask('server', 'concat min copy');

  grunt.registerMultiTask('copy', 'copy files', function () {
    grunt.file.copy(this.data,this.target);
  });

  grunt.loadNpmTasks('grunt-less');
};
<commit_msg>Fixed location of factlink.min.js script<commit_after>/*global config:true, file:true, task:true, module: true */

var files = {
  0: [
    'libs/jquery-1.6.1.js',
    'libs/underscore.js'
  ],
  1: [
    'libs/jquery.scrollTo-1.4.2.js',
    'libs/jquery.hoverintent.js'
  ],
  2: [
    'src/js/core.js'
  ],
  3: [
    'src/js/models/fact.js',
    'src/js/views/ballooney_thingy.js',
    'src/js/views/balloon.js',
    'src/js/views/prepare.js'
  ],
  4: [
    'src/js/replace.js',
    'src/js/annotate.js',
    'src/js/highlight.js',
    'src/js/scrollto.js',
    'src/js/loaded_message.js',
    'src/js/search.js',
    'src/js/create.js',
    'src/js/modal.js',
    'src/js/lib/indicator.js'
  ],
  5: [
    'src/js/xdm.js'
  ],
  6: [
    'src/js/last.js'
  ]
};

var loaderFiles = {
  0: [
    'libs/easyXDM.js'
  ],
  1: [
    'src/js/loader.js'
  ]
};

module.exports = function(grunt){

  function createFactlinkConcatObject(filesObj) {
    return grunt.utils._.flatten(["<banner>", grunt.utils._(filesObj).map(function(fileGroup) {
      return fileGroup.map(function(file) {
        return "<file_strip_banner:" + file + ">";
      });
    })], true);
  }

  grunt.initConfig({
    pkg: '<json:package.json>',
    meta: {
      banner: '/*! \n' +
      ' * <%= pkg.title || pkg.name %> - v<%= pkg.version %> - \n' +
      '<%= pkg.homepage ? " * " + pkg.homepage + "\n" : "" %>' +
      ' *\n' +
      ' * Date: <%= grunt.template.today("m/d/yyyy") %>\n' +
      ' *\n' +
      ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' +
      ' */'
    },
    concat: {
      'dist/factlink.core.js': createFactlinkConcatObject(files),
      'dist/factlink.start_annotating.js': '<file_strip_banner:src/js/chrome/start_annotating.js>',
      'dist/factlink.stop_annotating.js': '<file_strip_banner:src/js/chrome/stop_annotating.js>',
      'dist/factlink.start_highlighting.js': '<file_strip_banner:src/js/chrome/start_highlighting.js>',
      'dist/factlink.stop_highlighting.js': '<file_strip_banner:src/js/chrome/stop_highlighting.js>',
      'dist/easyXDM/easyXDM.js': '<file_strip_banner:libs/easyXDM.js>',
      'dist/factlink.js': createFactlinkConcatObject(loaderFiles)
    },
    copy: {
      'dist/server/css/basic.css': 'dist/css/basic.css',

      'dist/server/images/arrow.png': 'src/images/arrow.png',
      'dist/server/images/arrows-bottom.png': 'src/images/arrows-bottom.png',
      'dist/server/images/arrows-top.png': 'src/images/arrows-top.png',
      'dist/server/images/bookmark.gif': 'src/images/bookmark.gif',
      'dist/server/images/logo-small.png': 'src/images/logo-small.png',

      'dist/images/arrow.png': 'src/images/arrow.png',
      'dist/images/arrows-bottom.png': 'src/images/arrows-bottom.png',
      'dist/images/arrows-top.png': 'src/images/arrows-top.png',
      'dist/images/bookmark.gif': 'src/images/bookmark.gif',
      'dist/images/logo-small.png': 'src/images/logo-small.png'
    },
    less: {
      basic: {
        src: 'src/css/basic.less',
        dest: 'dist/css/basic.css',
        options: {
          yuicompress: true
        }
      }
    },
    min: {
      'dist/server/factlink.core.min.js': ['<banner>', 'dist/factlink.core.js'],
      'dist/server/factlink.start_annotating.min.js': ['<banner>', 'dist/factlink.start_annotating.js'],
      'dist/server/factlink.stop_annotating.min.js': ['<banner>', 'dist/factlink.stop_annotating.js'],
      'dist/server/factlink.start_highlighting.min.js': ['<banner>', 'dist/factlink.start_highlighting.js'],
      'dist/server/factlink.stop_highlighting.min.js': ['<banner>', 'dist/factlink.stop_highlighting.js'],
      'dist/server/factlink.min.js': ['<banner>', 'dist/factlink.js']
      'dist/server/easyXDM/easyXDM.min.js': ['<banner>', 'dist/easyXDM/easyXDM.js'], // for the server
      'dist/easyXDM/easyXDM.min.js': ['<banner>', 'dist/easyXDM/easyXDM.js'],        // for local
    },
    qunit: {
      files: ['test/*.html']
    },
    lint: {
      files: ['grunt.js', 'src/js/**/*.js', 'test/**/*.js']
    },
    watch: {
      files: ['src/js/**/*', 'test/**/*', 'grunt.js'],
      tasks: 'lint qunit concat less copy'
    },
    jshint: {
      options: {
        // Settings
        "passfail"      : false,  // Stop on first error.
        "maxerr"        : 100,    // Maximum error before stopping.

        // Predefined globals whom JSHint will ignore.
        "browser"       : true,   // Standard browser globals e.g. `window`, `document`.

        "node"          : false,
        "rhino"         : false,
        "couch"         : false,
        "wsh"           : false,   // Windows Scripting Host.

        "jquery"        : true,
        "prototypejs"   : false,
        "mootools"      : false,
        "dojo"          : false,

        "predef"        : [  // Custom globals.
          "Factlink", "FactlinkConfig", "escape"
        ],

        // Development.
        "debug"         : false,  // Allow debugger statements e.g. browser breakpoints.
        "devel"         : true,   // Allow developments statements e.g. `console.log();`.

        // ECMAScript 5.
        "es5"           : true,   // Allow ECMAScript 5 syntax.
        "strict"        : false,  // Require `use strict` pragma  in every file.
        "globalstrict"  : false,  // Allow global "use strict" (also enables 'strict').

        // The Good Parts.
        "asi"           : false,  // Tolerate Automatic Semicolon Insertion (no semicolons).
        "laxbreak"      : true,   // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons.
        "bitwise"       : true,   // Prohibit bitwise operators (&, |, ^, etc.).
        "boss"          : true,   // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
        "curly"         : true,   // Require {} for every new block or scope.
        "eqeqeq"        : true,   // Require triple equals i.e. `===`.
        "eqnull"        : false,  // Tolerate use of `== null`.
        "evil"          : false,  // Tolerate use of `eval`.
        "expr"          : false,  // Tolerate `ExpressionStatement` as Programs.
        "forin"         : false,  // Tolerate `for in` loops without `hasOwnPrototype`.
        "immed"         : false,  // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
        "latedef"       : true,   // Prohipit variable use before definition.
        "loopfunc"      : true,   // Allow functions to be defined within loops.
        "noarg"         : true,   // Prohibit use of `arguments.caller` and `arguments.callee`.
        "regexp"        : false,  // Prohibit `.` and `[^...]` in regular expressions.
        "regexdash"     : false,  // Tolerate unescaped last dash i.e. `[-...]`.
        "scripturl"     : true,   // Tolerate script-targeted URLs.
        "shadow"        : false,  // Allows re-define variables later in code e.g. `var x=1; x=2;`.
        "supernew"      : false,  // Tolerate `new function () { ... };` and `new Object;`.
        "undef"         : true,   // Require all non-global variables be declared before they are used.

        // Personal styling preferences.
        "newcap"        : true,   // Require capitalization of all constructor functions e.g. `new F()`.
        "noempty"       : true,   // Prohibit use of empty blocks.
        "nonew"         : true,   // Prohibit use of constructors for side-effects.
        "nomen"         : false,  // Prohibit use of initial or trailing underbars in names.
        "onevar"        : false,  // Allow only one `var` statement per function.
        "plusplus"      : false,  // Prohibit use of `++` & `--`.
        "sub"           : false,  // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
        "trailing"      : true,   // Prohibit trailing whitespaces.
        "white"         : false,  // Check against strict whitespace and indentation rules.
        "indent"        : 2       // Specify indentation spacing
      }
    },
    uglify: {}
  });

  // Default task.
  grunt.registerTask('default', 'lint qunit concat min copy');
  grunt.registerTask('server', 'concat min copy');

  grunt.registerMultiTask('copy', 'copy files', function () {
    grunt.file.copy(this.data,this.target);
  });

  grunt.loadNpmTasks('grunt-less');
};
<|endoftext|>