<commit_before>var slidesCount = 0;
var currentSlide = 0;

var discoverCount = 0;
var currentDiscover = 0;

var slideMode = false;

function generateMenu()
{
    var menuElements = '';

    if ($('h1, h2, h3').length < 2) {
	return;
    }

    $('h1, h2, h3').each(function() {
	if ($(this).is(':visible')) {
	    html = '
'+$(this).html()+'
';
	    menuElements += html;
	}
    });

    $('.menu').html(menuElements);

    $('.menuItem').click(function() {
	var titleId = $(this).attr('rel');
	if (!slideMode) {
	    $('html,body').animate({scrollTop:$('#' + titleId).offset().top}, 300, 0);
	} else {
	    currentSlide = $('#' + titleId).closest('.slideWrapper').attr('rel');
	    scrollTo(currentSlide);
	    updateDiscovers(0);
	}
    });
}

function updateMenuPosition()
{
    var scrollTop = $('html').scrollTop();

    $('h1, h2, h3').each(function() {
	if ($(this).is(':visible')) {
	    var menuElement = $('#menu_for_' + $(this).attr('id'));

	    if ($(this).offset().top < scrollTop) {
		if (!menuElement.hasClass('menuPassed')) {
		    menuElement.addClass('menuPassed');
		}
	    } else {
		if (menuElement.hasClass('menuPassed')) {
		    menuElement.removeClass('menuPassed');
		}
	    }
	}
    });
}

function resizeSlides()
{
    var width = $(document.body).width();
    var height = $(window).height();

    if (slideMode)
    {
	$('.slideEnabled').height(height);

	$('.slideNumber').each(function() {
	    $(this).css('margin-left', width-$(this).width()-5);
	    $(this).css('margin-top', height-$(this).height()-5);
	});
    } else {
	$('.slideNumber').each(function() {
	    $(this).css('margin-left', width + $(this).width() - 20);
	    $(this).css('margin-top', 5);
	});
    }
}

function updateDiscovers()
{
    $('.discover').hide();

    for (i=0; i<currentSlide-1; i++) {
	$('#slide' + i + ' .discover').show();
    }

    updateCurrentDiscover(0);
}

function updateCurrentDiscover(end)
{
    discoverCount = $('#slide' + currentSlide + ' .discover').length;

    if (end) {
	$('#slide' + currentSlide + ' .discover').show();
	currentDiscover = discoverCount;
    } else {
	$('#slide' + currentSlide + ' .discover').hide();
        currentDiscover = 0;
    }
}

function scrollTo(slideId)
{
    $('html,body').animate({scrollTop:$('#slide' + slideId).offset().top}, 300, 0, function() {
	if (slideMode) {
	   $('body').css('background-color', $('#slide' + slideId + ' .slide').css('background-color'));
	}
    });
}

function scrollToCurrentSlide()
{
    scrollTo(currentSlide);
}

function precSlide()
{
    if (currentSlide > 0) {
	currentSlide--;
        scrollToCurrentSlide();
	updateCurrentDiscover(1);

	return 1;
    }

    return 0;
}

function nextSlide()
{
    if (currentSlide < slidesCount-1) {
        currentSlide++;
        scrollToCurrentSlide();
	updateCurrentDiscover(1);

	return 1;
    }

    return 0;
}

function precDiscover()
{
    if (currentDiscover == 0) {
	if (precSlide()) {
	   updateCurrentDiscover(1);
	}
    } else {
	currentDiscover--;
	$('#discover_' + currentSlide + '_' + currentDiscover).hide();
    }
}

function nextDiscover()
{
    if (currentDiscover == discoverCount) {
	if (nextSlide()) {
	    updateCurrentDiscover(0);
	}
    } else {
	$('#discover_' + currentSlide + '_' + currentDiscover).show();
	currentDiscover++;
    }
}

$(document).keydown(function(e){
    if (!slideMode)
    {
	return;
    }

    switch (e.keyCode) {
	case 37: // Left
	    precDiscover();
	   break;
	case 39: // Right
	    nextDiscover();
	    break;
	case 38: // Up
	    precSlide();
	break;
	case 40: // Down
	    nextSlide();
        break;
    }
});

function initSpoilers()
{
    var spoilerId = 0;

    $('.spoiler').each(function() {
	$(this).attr('id', 'spoiler'+spoilerId);

	$(this).wrap('

');
	$('#spoilerWrapper'+spoilerId).prepend('Afficher/masquer le contenu');

	spoilerId++;
    });

    $('.spoilerLink').click(function() {
	var spoiler = $('#spoiler' + $(this).attr('rel'));

	if (spoiler.is(':visible')) {
	    spoiler.slideUp();
	} else {
	    spoiler.slideDown();
	}
    });

    $('.spoiler').hide();
}

function init()
{
    initSpoilers();

    var id = 0;
    slidesCount = $('.slide').length;

    $('.slide').each(function() {
	$(this).wrap('

');

	$('#slide' + id).prepend('
' + (id+1) + '/' + slidesCount + '
');

	var discover_id = 0;

	$(this).find('.discover').each(function() {
	    $(this).attr('id', 'discover_' + id + '_' + discover_id);
	    discover_id++;
	});

	id++;
    });

    var titleId = 0;
    $('h1, h2, h3').each(function() {
	if (!$(this).attr('id')) {
	    $(this).attr('id', 'title'+(titleId++));
	}
    });
}

function runSlideMode()
{
    $('.slideModeNormal').removeClass('slideModeEnabled');
    $('.slideModeSlide').addClass('slideModeEnabled');
    $('.slideOnly').show();
    $('.textOnly').hide();
    slideMode = true;
    $('.slideWrapper').addClass('slideEnabled');
    resizeSlides();
    updateDiscovers();
    generateMenu();
}

function runTextMode()
{
    $('body').css('background-color', 'transparent');
    $('.slideModeSlide').removeClass('slideModeEnabled');
    $('.slideModeNormal').addClass('slideModeEnabled');
    $('.discover').show();
    $('.slideOnly').hide();
    $('.textOnly').show();
    slideMode = false;
    $('.slideEnabled').height('auto');
    resizeSlides();
    $('.slideWrapper').removeClass('slideEnabled');
    generateMenu();
}

function tick()
{
    resizeSlides();
    updateMenuPosition();
}

$(document).ready(function() {
    init();
    setInterval(tick, 500);

    if (window.location.hash) {
	obj = $(window.location.hash);

	if (obj.length) {
	    currentSlide = obj.closest('.slideWrapper').attr('rel');
	}
    }

    $('.slideModeNormal').click(function() {
	runTextMode();
	scrollToCurrentSlide();
    });

    $('.slideModeSlide').click(function() {
	runSlideMode();
        scrollToCurrentSlide();
    });

    $('.slideNumber').click(function() {
	if (!slideMode) {
	    currentSlide = parseInt($(this).attr('rel'));
	    runSlideMode();
	} else {
	    runTextMode();
	}
	scrollToCurrentSlide();
    });

    runSlideMode();
    runTextMode();
    resizeSlides();
});
<commit_msg>Updating menu position on loading<commit_after>var slidesCount = 0;
var currentSlide = 0;

var discoverCount = 0;
var currentDiscover = 0;

var slideMode = false;

function generateMenu()
{
    var menuElements = '';

    if ($('h1, h2, h3').length < 2) {
	return;
    }

    $('h1, h2, h3').each(function() {
	if ($(this).is(':visible')) {
	    html = '
'+$(this).html()+'
';
	    menuElements += html;
	}
    });

    $('.menu').html(menuElements);

    $('.menuItem').click(function() {
	var titleId = $(this).attr('rel');
	if (!slideMode) {
	    $('html,body').animate({scrollTop:$('#' + titleId).offset().top}, 300, 0);
	} else {
	    currentSlide = $('#' + titleId).closest('.slideWrapper').attr('rel');
	    scrollTo(currentSlide);
	    updateDiscovers(0);
	}
    });
}

function updateMenuPosition()
{
    var scrollTop = $('html').scrollTop();

    $('h1, h2, h3').each(function() {
	if ($(this).is(':visible')) {
	    var menuElement = $('#menu_for_' + $(this).attr('id'));

	    if ($(this).offset().top < scrollTop) {
		if (!menuElement.hasClass('menuPassed')) {
		    menuElement.addClass('menuPassed');
		}
	    } else {
		if (menuElement.hasClass('menuPassed')) {
		    menuElement.removeClass('menuPassed');
		}
	    }
	}
    });
}

function resizeSlides()
{
    var width = $(document.body).width();
    var height = $(window).height();

    if (slideMode)
    {
	$('.slideEnabled').height(height);

	$('.slideNumber').each(function() {
	    $(this).css('margin-left', width-$(this).width()-5);
	    $(this).css('margin-top', height-$(this).height()-5);
	});
    } else {
	$('.slideNumber').each(function() {
	    $(this).css('margin-left', width + $(this).width() - 20);
	    $(this).css('margin-top', 5);
	});
    }
}

function updateDiscovers()
{
    $('.discover').hide();

    for (i=0; i<currentSlide-1; i++) {
	$('#slide' + i + ' .discover').show();
    }

    updateCurrentDiscover(0);
}

function updateCurrentDiscover(end)
{
    discoverCount = $('#slide' + currentSlide + ' .discover').length;

    if (end) {
	$('#slide' + currentSlide + ' .discover').show();
	currentDiscover = discoverCount;
    } else {
	$('#slide' + currentSlide + ' .discover').hide();
        currentDiscover = 0;
    }
}

function scrollTo(slideId)
{
    $('html,body').animate({scrollTop:$('#slide' + slideId).offset().top}, 300, 0, function() {
	if (slideMode) {
	   $('body').css('background-color', $('#slide' + slideId + ' .slide').css('background-color'));
	}
    });
}

function scrollToCurrentSlide()
{
    scrollTo(currentSlide);
}

function precSlide()
{
    if (currentSlide > 0) {
	currentSlide--;
        scrollToCurrentSlide();
	updateCurrentDiscover(1);

	return 1;
    }

    return 0;
}

function nextSlide()
{
    if (currentSlide < slidesCount-1) {
        currentSlide++;
        scrollToCurrentSlide();
	updateCurrentDiscover(1);

	return 1;
    }

    return 0;
}

function precDiscover()
{
    if (currentDiscover == 0) {
	if (precSlide()) {
	   updateCurrentDiscover(1);
	}
    } else {
	currentDiscover--;
	$('#discover_' + currentSlide + '_' + currentDiscover).hide();
    }
}

function nextDiscover()
{
    if (currentDiscover == discoverCount) {
	if (nextSlide()) {
	    updateCurrentDiscover(0);
	}
    } else {
	$('#discover_' + currentSlide + '_' + currentDiscover).show();
	currentDiscover++;
    }
}

$(document).keydown(function(e){
    if (!slideMode)
    {
	return;
    }

    switch (e.keyCode) {
	case 37: // Left
	    precDiscover();
	   break;
	case 39: // Right
	    nextDiscover();
	    break;
	case 38: // Up
	    precSlide();
	break;
	case 40: // Down
	    nextSlide();
        break;
    }
});

function initSpoilers()
{
    var spoilerId = 0;

    $('.spoiler').each(function() {
	$(this).attr('id', 'spoiler'+spoilerId);

	$(this).wrap('

');
	$('#spoilerWrapper'+spoilerId).prepend('Afficher/masquer le contenu');

	spoilerId++;
    });

    $('.spoilerLink').click(function() {
	var spoiler = $('#spoiler' + $(this).attr('rel'));

	if (spoiler.is(':visible')) {
	    spoiler.slideUp();
	} else {
	    spoiler.slideDown();
	}
    });

    $('.spoiler').hide();
}

function init()
{
    initSpoilers();

    var id = 0;
    slidesCount = $('.slide').length;

    $('.slide').each(function() {
	$(this).wrap('

');

	$('#slide' + id).prepend('
' + (id+1) + '/' + slidesCount + '
');

	var discover_id = 0;

	$(this).find('.discover').each(function() {
	    $(this).attr('id', 'discover_' + id + '_' + discover_id);
	    discover_id++;
	});

	id++;
    });

    var titleId = 0;
    $('h1, h2, h3').each(function() {
	if (!$(this).attr('id')) {
	    $(this).attr('id', 'title'+(titleId++));
	}
    });
}

function runSlideMode()
{
    $('.slideModeNormal').removeClass('slideModeEnabled');
    $('.slideModeSlide').addClass('slideModeEnabled');
    $('.slideOnly').show();
    $('.textOnly').hide();
    slideMode = true;
    $('.slideWrapper').addClass('slideEnabled');
    resizeSlides();
    updateDiscovers();
    generateMenu();
}

function runTextMode()
{
    $('body').css('background-color', 'transparent');
    $('.slideModeSlide').removeClass('slideModeEnabled');
    $('.slideModeNormal').addClass('slideModeEnabled');
    $('.discover').show();
    $('.slideOnly').hide();
    $('.textOnly').show();
    slideMode = false;
    $('.slideEnabled').height('auto');
    resizeSlides();
    $('.slideWrapper').removeClass('slideEnabled');
    generateMenu();
}

function tick()
{
    resizeSlides();
    updateMenuPosition();
}

$(document).ready(function() {
    init();
    setInterval(tick, 500);

    if (window.location.hash) {
	obj = $(window.location.hash);

	if (obj.length) {
	    currentSlide = obj.closest('.slideWrapper').attr('rel');
	}
    }

    $('.slideModeNormal').click(function() {
	runTextMode();
	scrollToCurrentSlide();
    });

    $('.slideModeSlide').click(function() {
	runSlideMode();
        scrollToCurrentSlide();
    });

    $('.slideNumber').click(function() {
	if (!slideMode) {
	    currentSlide = parseInt($(this).attr('rel'));
	    runSlideMode();
	} else {
	    runTextMode();
	}
	scrollToCurrentSlide();
    });

    runSlideMode();
    runTextMode();
    resizeSlides();
    updateMenuPosition();
});
<|endoftext|>


<commit_before>var request = require("request");
var mensas = require("./mensas.json")
var mensas_abig = require("./mensas_abig.json");
var parseString = require('xml2js').parseString;

var mensas = require("./mensas.json");
var mensas_abig = require("./mensas_abig.json");
var requests = 0;

// get the uni menus using the api of zfv. the format is as follows:
// http://zfv.ch/de/menus/rssMenuPlan?menuId=235&&dayOfWeek=1
// menuid is the mensa id and dayOfWeek is monday = 1 ...

function get_uni() {
  // mensas in the evening need "abend" in the name
  var menu_ids = {
    "UZH untere Mensa A": 147,
    "UZH obere Mensa B": 148,
    "UZH Lichthof": 150,
    "UZH Irchel": 180,
    "UZH Tierspital": 146,
    "UZH Zentrum Für Zahnmedizin": 151,
    "UZH Platte": 143,
    "UZH Rämi 59 (vegi)": 346,
    "ZHDK Toni-Areal": 333,
    "UZH untere Mensa A (abend)": 149,
    "UZH Irchel (abend)": 256
  };
  let weekday = new Date().getDay();

  for (var mensa in menu_ids) {
    requests++;
    url = `http://zfv.ch/de/menus/rssMenuPlan?menuId=${menu_ids[mensa]}&dayOfWeek=${weekday}`;
    (function fetchMensa(mensas, mensaName, url) {
      // console.log('getting ' + mensaName);
      request({
          followRedirect: true,
          removeRefererHeader: true,
          url: url,
          followAllRedirects: true
          //encoding: 'binary'
          //json: true
        },
        function (error, response, body) {
          if (!error && response.statusCode == 200) {
            makeObject(body, mensaName.indexOf("abend") != -1, mensaName);
          } else {
            console.error(
              "could not get uni " + mensaName + " lunch menu from internet"
            );
            console.log(error);
          }
        }
      );
    })(mensas, mensa, url);
  }
}

function makeObject(body, isDinner, mensaName) {
  var thisMensa = {
    daytime: "lunch",
    mensa: mensaName,
    meals: [],
    hours: {
      opening: [{
        from: "9:00",
        to: "18:00"
      }],
      mealtime: [{
          hardcoded: true,
          from: "lunch",
          to: "later"
        },
        {
          hardcoded: true,
          from: "dinner",
          to: "later"
        }
      ]
    },
    location: {
      id: 1,
      label: "zentrum"
    }
  };

  if (isDinner) thisMensa.daytime = "dinner";

  parseString(body, function (err, result) {
    if (result.feed.entry[0].summary[0].div[0].p) {
      var entries = result.feed.entry[0].summary[0].div[0].p.length;
      result = result.feed.entry[0].summary[0].div[0];
      var currentMeal = {};
      for (i = 0; i < entries; i++) {
        currentMeal = {
          description: [],
          prices: {}
        };
        currentMeal.label = result.h3[i]._.trim();
        if (result.h3[i].span[0]._)
          currentMeal.label = currentMeal.label + " " + result.h3[i].span[0]._.trim();
        currentMeal.description.push(result.p[i]._.trim().replace(/  +/g, ' ').replace('\n \n', '\n'));
        thisMensa.meals.push(currentMeal);
      }
    }
  });
  //console.log(thisMensa);

  if (isDinner) {
    mensas_abig[mensaName] = thisMensa;
  } else {
    mensas[mensaName] = thisMensa;
  }

  requests--;
  if (requests == 0) {
    done();
  }
}

function done() {
  //console.log(mensas);
  console.log("successfully got uni mensas");
  require("fs").writeFileSync("./mensas.json", JSON.stringify(mensas));
  require("fs").writeFileSync(
    "./mensas_abig.json",
    JSON.stringify(mensas_abig)
  );
  console.log("files written");
}
module.exports.get_uni = get_uni;
<commit_msg>used var because let not yet supported by server<commit_after>var request = require("request");
var mensas = require("./mensas.json")
var mensas_abig = require("./mensas_abig.json");
var parseString = require('xml2js').parseString;

var mensas = require("./mensas.json");
var mensas_abig = require("./mensas_abig.json");
var requests = 0;

// get the uni menus using the api of zfv. the format is as follows:
// http://zfv.ch/de/menus/rssMenuPlan?menuId=235&&dayOfWeek=1
// menuid is the mensa id and dayOfWeek is monday = 1 ...

function get_uni() {
  // mensas in the evening need "abend" in the name
  var menu_ids = {
    "UZH untere Mensa A": 147,
    "UZH obere Mensa B": 148,
    "UZH Lichthof": 150,
    "UZH Irchel": 180,
    "UZH Tierspital": 146,
    "UZH Zentrum Für Zahnmedizin": 151,
    "UZH Platte": 143,
    "UZH Rämi 59 (vegi)": 346,
    "ZHDK Toni-Areal": 333,
    "UZH untere Mensa A (abend)": 149,
    "UZH Irchel (abend)": 256
  };
  var weekday = new Date().getDay();

  for (var mensa in menu_ids) {
    requests++;
    url = `http://zfv.ch/de/menus/rssMenuPlan?menuId=${menu_ids[mensa]}&dayOfWeek=${weekday}`;
    (function fetchMensa(mensas, mensaName, url) {
      // console.log('getting ' + mensaName);
      request({
          followRedirect: true,
          removeRefererHeader: true,
          url: url,
          followAllRedirects: true
          //encoding: 'binary'
          //json: true
        },
        function (error, response, body) {
          if (!error && response.statusCode == 200) {
            makeObject(body, mensaName.indexOf("abend") != -1, mensaName);
          } else {
            console.error(
              "could not get uni " + mensaName + " lunch menu from internet"
            );
            console.log(error);
          }
        }
      );
    })(mensas, mensa, url);
  }
}

function makeObject(body, isDinner, mensaName) {
  var thisMensa = {
    daytime: "lunch",
    mensa: mensaName,
    meals: [],
    hours: {
      opening: [{
        from: "9:00",
        to: "18:00"
      }],
      mealtime: [{
          hardcoded: true,
          from: "lunch",
          to: "later"
        },
        {
          hardcoded: true,
          from: "dinner",
          to: "later"
        }
      ]
    },
    location: {
      id: 1,
      label: "zentrum"
    }
  };

  if (isDinner) thisMensa.daytime = "dinner";

  parseString(body, function (err, result) {
    if (result.feed.entry[0].summary[0].div[0].p) {
      var entries = result.feed.entry[0].summary[0].div[0].p.length;
      result = result.feed.entry[0].summary[0].div[0];
      var currentMeal = {};
      for (i = 0; i < entries; i++) {
        currentMeal = {
          description: [],
          prices: {}
        };
        currentMeal.label = result.h3[i]._.trim();
        if (result.h3[i].span[0]._)
          currentMeal.label = currentMeal.label + " " + result.h3[i].span[0]._.trim();
        currentMeal.description.push(result.p[i]._.trim().replace(/  +/g, ' ').replace('\n \n', '\n'));
        thisMensa.meals.push(currentMeal);
      }
    }
  });
  //console.log(thisMensa);

  if (isDinner) {
    mensas_abig[mensaName] = thisMensa;
  } else {
    mensas[mensaName] = thisMensa;
  }

  requests--;
  if (requests == 0) {
    done();
  }
}

function done() {
  //console.log(mensas);
  console.log("successfully got uni mensas");
  require("fs").writeFileSync("./mensas.json", JSON.stringify(mensas));
  require("fs").writeFileSync(
    "./mensas_abig.json",
    JSON.stringify(mensas_abig)
  );
  console.log("files written");
}
module.exports.get_uni = get_uni;
<|endoftext|>


<commit_before>import io from 'socket.io-client';

const socket = io.connect('http://localhost:5000');

export default socket;<commit_msg>updates url in socket connection<commit_after>import io from 'socket.io-client';

const socket = io.connect('//localhost:5000');

export default socket;<|endoftext|>


<commit_before>// TODO:
// The convention of "import X as _X; const X = _X;" is currently
// being used as a method to workaround for downstream code
// that is running via eval(). Because importing statements do not
// create a variable of the same name, the eval()'d code does not know
// about the import, and thus throws ReferenceErrors.
// Used by downstream eval
import _Conditions from './conditions.js';
const Conditions = _Conditions;
import _NetRegexes from './netregexes.js';
const NetRegexes = _NetRegexes;
import _Regexes from './regexes.js';
const Regexes = _Regexes;
import { Responses as _Responses } from './responses.js';
const Responses = _Responses;
import { Util as _Util } from './common.js';
const Util = _Util;
import _ZoneId from './zone_id.js';
const ZoneId = _ZoneId;

class UserConfig {
  constructor() {
    this.optionTemplates = {};
    this.savedConfig = null;
    this.userFileCallbacks = {};
  }
  registerOptions(overlayName, optionTemplates, userFileCallback) {
    this.optionTemplates[overlayName] = optionTemplates;
    if (userFileCallback)
      this.userFileCallbacks[overlayName] = userFileCallback;
  }

  sortUserFiles(keys) {
    // Helper data structure for subdirectories.
    const splitKeyMap = {};
    for (const key of keys)
      splitKeyMap[key] = key.toUpperCase().split(/[/\\]/);

    // Sort paths as a depth-first case-insensitive alphabetical subdirectory walk, followed by
    // all files sorted case-insensitive alphabetically once a subdir has been processed, e.g.
    //  * a/some.js
    //  * b/subdir1/z/z/z/nested_file.js
    //  * b/subdir1/file.js
    //  * b/subdir2/first.js
    //  * b/subdir2/second.js
    //  * b/some_file.js
    //  * root_file1.js
    //  * root_file2.js
    return keys.sort((a, b) => {
      const maxLen = Math.max(splitKeyMap[a].length, splitKeyMap[b].length);

      for (let idx = 0; idx < maxLen; ++idx) {
        // If both subdirectories or both files, then compare names.
        const isLastA = splitKeyMap[a].length - 1 === idx;
        const isLastB = splitKeyMap[b].length - 1 === idx;
        if (isLastA && isLastB) {
          // If both last, then this is a filename comparison.

          // First, compare filename without extension.
          const fileA = splitKeyMap[a][idx].replace(/\.[^\.]*$/, '');
          const fileB = splitKeyMap[b][idx].replace(/\.[^\.]*$/, '');
          const filenameOnlyDiff = fileA.localeCompare(fileB);
          if (filenameOnlyDiff)
            return filenameOnlyDiff;

          // Second, compare including the extension.
          // Always return something here, see note below.
          return splitKeyMap[a][idx].localeCompare(splitKeyMap[b][idx]);
        } else if (!isLastA && !isLastB) {
          // If both not last, this is a subdirectory comparison.
          const diff = splitKeyMap[a][idx].localeCompare(splitKeyMap[b][idx]);
          if (diff)
            return diff;
        }

        // At this point, if idx is the final for each, we would have returned above.
        // So, check if either a or b is at the final entry in splitKeyMap.
        // If so, then there's a mismatch in number of directories, and we know one
        // the one with a filename should be sorted last.

        if (splitKeyMap[a].length - 1 <= idx) {
          // a has fewer subdirectories, so should be sorted last.
          return 1;
        }
        if (splitKeyMap[b].length - 1 <= idx) {
          // a has more subdirectories, so should be sorted first.
          return -1;
        }
      }
      return 0;
    });
  }

  // Given a set of paths, an overlayName, and an extension, return all paths with
  // that extension that have `overlayName` either as their entire filename (no subdir)
  // or are inside a root-level subdirectory named `overlayName`/  The extension should
  // include the period separator, e.g. ".js".  All comparisons are case insensitive.
  filterUserFiles(paths, origOverlayName, origExtension) {
    const extension = origExtension.toLowerCase();
    const overlayName = origOverlayName.toLowerCase();
    return paths.filter((origPath) => {
      const path = origPath.toLowerCase();
      if (!path.endsWith(extension))
        return false;
      if (path === `${overlayName}${extension}`)
        return true;
      if (path.startsWith(`${overlayName}/`) || path.startsWith(`${overlayName}\\`))
        return true;
      return false;
    });
  }

  getUserConfigLocation(overlayName, options, callback) {
    let currentlyReloading = false;
    const reloadOnce = () => {
      if (currentlyReloading)
        return;
      currentlyReloading = true;
      window.location.reload();
    };

    window.addOverlayListener('onUserFileChanged', () => {
      reloadOnce();
    });
    window.addOverlayListener('onForceReload', () => {
      reloadOnce();
    });

    this.loadUserFiles(overlayName, options, callback);
  }

  loadUserFiles(overlayName, options, callback) {
    const readOptions = callOverlayHandler({
      call: 'cactbotLoadData',
      overlay: 'options',
    });

    const loadUser = async (e) => {
      // The basePath isn't using for anything other than cosmetic printing of full paths,
      // so replace any slashes here for uniformity.  In case anybody is using cactbot on
      // Linux (?!?), support any style of slashes elsewhere.
      const basePath = e.detail.userLocation.replace(/[/\\]*$/, '') + '\\';
      const localFiles = e.detail.localUserFiles;

      const sortedFiles = this.sortUserFiles(Object.keys(localFiles));
      const jsFiles = this.filterUserFiles(sortedFiles, overlayName, '.js');
      const cssFiles = this.filterUserFiles(sortedFiles, overlayName, '.css');

      // The plugin auto-detects the language, so set this first.
      // If options files want to override it, they can for testing.

      // Backward compatibility (language is now separated to three types.)
      if (e.detail.language) {
        options.ParserLanguage = e.detail.language;
        options.ShortLocale = e.detail.language;
        options.DisplayLanguage = e.detail.language;
      }
      // Parser Language
      if (e.detail.parserLanguage) {
        options.ParserLanguage = e.detail.parserLanguage;
        // Backward compatibility, everything "Language" should be changed to "ParserLanguage"
        options.Language = e.detail.parserLanguage;
      }
      const supportedLanguage = ['en', 'de', 'fr', 'ja', 'cn', 'ko'];
      // System Language
      if (e.detail.systemLocale) {
        options.SystemLocale = e.detail.systemLocale;
        options.ShortLocale = e.detail.systemLocale.substring(0, 2);
        if (options.ShortLocale === 'zh')
          options.ShortLocale = 'cn';
        if (!supportedLanguage.includes(options.ShortLocale))
          options.ShortLocale = options.ParserLanguage;
      }
      // User's setting Language
      options.DisplayLanguage = e.detail.displayLanguage;
      if (!supportedLanguage.includes(options.DisplayLanguage))
        options.DisplayLanguage = options.ParserLanguage || 'en';

      document.body.classList.add(`lang-${options.DisplayLanguage}`);
      this.addUnlockText(options.DisplayLanguage);

      // Handle processOptions after default language selection above,
      // but before css below which may load skin files.
      // processOptions needs to be called whether or not there are
      // any userOptions saved, as it sets up the defaults.
      const userOptions = await readOptions || {};
      this.savedConfig = userOptions.data || {};
      this.processOptions(
          options,
          this.savedConfig[overlayName] || {},
          this.optionTemplates[overlayName],
      );

      // If the overlay has a "Debug" setting, set to true via the config tool,
      // then also print out user files that have been loaded.
      const printUserFile = options.Debug ? (x) => console.log(x) : (x) => {};

      // With user files being arbitrary javascript, and having multiple files
      // in user folders, it's possible for later files to accidentally remove
      // things that previous files have added.  Warn about this, since most
      // users are not programmers.
      const warnOnVariableResetMap = {
        raidboss: [
          'Triggers',
        ],
      };
      warnOnVariableResetMap[overlayName] = warnOnVariableResetMap[overlayName] || [];

      // The values of each `warnOnVariableResetMap` field are initially set
      // after the first file, so that if there is only one file, there are
      // not any warnings.
      const variableTracker = {};

      // In cases where the user files are local but the overlay url
      // is remote, local files needed to be read by the plugin and
      // passed to Javascript for Chrome security reasons.
      if (localFiles) {
        for (const jsFile of jsFiles) {
          try {
            printUserFile(`local user file: ${basePath}${jsFile}`);
            const Options = options;

            // This is the one eval cactbot should ever need, which is for handling user files.
            // Because user files can be located anywhere on disk and there's backwards compat
            // issues, it's unlikely that these will be able to be anything but eval forever.
            //
            /* eslint-disable no-eval */
            eval(localFiles[jsFile]);
            /* eslint-enable no-eval */

            for (const field of warnOnVariableResetMap[overlayName]) {
              if (variableTracker[field] && variableTracker[field] !== options[field]) {
                // Ideally users should do something like `Options.Triggers.push([etc]);`
                // instead of `Options.Triggers = [etc];`
                console.log(`*** WARNING: ${basePath}${jsFile} overwrites Options.${field} from previous files.`);
              }
              variableTracker[field] = options[field];
            }

            if (this.userFileCallbacks[overlayName])
              this.userFileCallbacks[overlayName](jsFile, localFiles, options, basePath);
          } catch (e) {
            // Be very visible for users.
            console.log('*** ERROR IN USER FILE ***');
            console.log(e.stack);
          }
        }

        // This is a bit awkward to handle skin settings here, but
        // doing it after user config files and before user css files
        // allows user css to override skin-specific css as well.
        this.handleSkin(options.Skin);

        for (const cssFile of cssFiles) {
          printUserFile(`local user file: ${basePath}${cssFile}`);
          const userCssText = document.createElement('style');
          userCssText.innerText = localFiles[cssFile];
          document.getElementsByTagName('head')[0].appendChild(userCssText);
        }
      }

      // Post this callback so that the js and css can be executed first.
      if (callback)
        callback();

      callOverlayHandler({ call: 'cactbotRequestState' });
    };

    callOverlayHandler({
      call: 'cactbotLoadUser',
      source: location.href,
      overlayName: overlayName,
    }).then((e) => {
      // Wait for DOMContentLoaded if needed.
      if (document.readyState !== 'loading') {
        loadUser(e);
        return;
      }
      document.addEventListener('DOMContentLoaded', () => {
        loadUser(e);
      });
    });
  }

  handleSkin(skinName) {
    if (!skinName || skinName === 'default')
      return;

    let basePath = document.location.toString();
    const slashIdx = basePath.lastIndexOf('/');
    if (slashIdx !== -1)
      basePath = basePath.substr(0, slashIdx);
    if (basePath.slice(-1) !== '/')
      basePath += '/';
    const skinHref = basePath + 'skins/' + skinName + '/' + skinName + '.css';
    this.appendCSSLink(skinHref);
  }
  appendJSLink(src) {
    const userJS = document.createElement('script');
    userJS.setAttribute('type', 'text/javascript');
    userJS.setAttribute('src', src);
    userJS.setAttribute('async', false);
    document.getElementsByTagName('head')[0].appendChild(userJS);
  }
  appendCSSLink(href) {
    const userCSS = document.createElement('link');
    userCSS.setAttribute('rel', 'stylesheet');
    userCSS.setAttribute('type', 'text/css');
    userCSS.setAttribute('href', href);
    document.getElementsByTagName('head')[0].appendChild(userCSS);
  }
  processOptions(options, savedConfig, template) {
    // Take options from the template, find them in savedConfig,
    // and apply them to options. This also handles setting
    // defaults for anything in the template, even if it does not
    // exist in savedConfig.
    if (Array.isArray(template)) {
      for (let i = 0; i < template.length; ++i)
        this.processOptions(options, savedConfig, template[i]);
      return;
    }

    // Not all overlays have option templates.
    if (!template)
      return;

    const templateOptions = template.options || [];
    for (let i = 0; i < templateOptions.length; ++i) {
      const opt = templateOptions[i];

      // Grab the saved value or the default to set in options.
      const value = opt.id in savedConfig ? savedConfig[opt.id] : opt.default;

      // Options can provide custom logic to turn a value into options settings.
      // If this doesn't exist, just set the value directly.
      // Option template ids are identical to field names on Options.
      if (opt.setterFunc)
        opt.setterFunc(options, value);
      else if (opt.type === 'integer')
        options[opt.id] = parseInt(value);
      else if (opt.type === 'float')
        options[opt.id] = parseFloat(value);
      else
        options[opt.id] = value;
    }

    // For things like raidboss that build extra UI, also give them a chance
    // to handle anything that has been set on that UI.
    if (template.processExtraOptions)
      template.processExtraOptions(options, savedConfig);
  }
  addUnlockText(lang) {
    const unlockText = {
      en: '🔓 Unlocked (lock overlay before using)',
      de: '🔓 Entsperrt (Sperre das Overlay vor der Nutzung)',
      fr: '🔓 Débloqué (Bloquez l\'overlay avant utilisation)',
      ja: '🔓 ロック解除 (オーバーレイを使用する前にロックしてください)',
      cn: '🔓 已解除锁定 (你需要将此悬浮窗锁定后方可使用)',
      ko: '🔓 위치 잠금 해제됨 (사용하기 전에 위치 잠금을 설정하세요)',
    };

    const id = 'cactbot-unlocked-text';
    let textElem = document.getElementById(id);
    if (!textElem) {
      textElem = document.createElement('div');
      textElem.id = id;
      textElem.classList.add('text');
      // Set element display to none in case the page has not included defaults.css.
      textElem.style.display = 'none';
      document.body.append(textElem);
    }
    textElem.innerHTML = unlockText[lang] || unlockText['en'];
  }
}

export default new UserConfig();

if (typeof document !== 'undefined') {
  // This event comes early and is not cached, so set up event listener immediately.
  document.addEventListener('onOverlayStateUpdate', (e) => {
    const docClassList = document.documentElement.classList;
    if (e.detail.isLocked)
      docClassList.remove('resizeHandle', 'unlocked');
    else
      docClassList.add('resizeHandle', 'unlocked');
  });
}
<commit_msg>resources: fix errors when user directory is missing<commit_after>// TODO:
// The convention of "import X as _X; const X = _X;" is currently
// being used as a method to workaround for downstream code
// that is running via eval(). Because importing statements do not
// create a variable of the same name, the eval()'d code does not know
// about the import, and thus throws ReferenceErrors.
// Used by downstream eval
import _Conditions from './conditions.js';
const Conditions = _Conditions;
import _NetRegexes from './netregexes.js';
const NetRegexes = _NetRegexes;
import _Regexes from './regexes.js';
const Regexes = _Regexes;
import { Responses as _Responses } from './responses.js';
const Responses = _Responses;
import { Util as _Util } from './common.js';
const Util = _Util;
import _ZoneId from './zone_id.js';
const ZoneId = _ZoneId;

class UserConfig {
  constructor() {
    this.optionTemplates = {};
    this.savedConfig = null;
    this.userFileCallbacks = {};
  }
  registerOptions(overlayName, optionTemplates, userFileCallback) {
    this.optionTemplates[overlayName] = optionTemplates;
    if (userFileCallback)
      this.userFileCallbacks[overlayName] = userFileCallback;
  }

  sortUserFiles(keys) {
    // Helper data structure for subdirectories.
    const splitKeyMap = {};
    for (const key of keys)
      splitKeyMap[key] = key.toUpperCase().split(/[/\\]/);

    // Sort paths as a depth-first case-insensitive alphabetical subdirectory walk, followed by
    // all files sorted case-insensitive alphabetically once a subdir has been processed, e.g.
    //  * a/some.js
    //  * b/subdir1/z/z/z/nested_file.js
    //  * b/subdir1/file.js
    //  * b/subdir2/first.js
    //  * b/subdir2/second.js
    //  * b/some_file.js
    //  * root_file1.js
    //  * root_file2.js
    return keys.sort((a, b) => {
      const maxLen = Math.max(splitKeyMap[a].length, splitKeyMap[b].length);

      for (let idx = 0; idx < maxLen; ++idx) {
        // If both subdirectories or both files, then compare names.
        const isLastA = splitKeyMap[a].length - 1 === idx;
        const isLastB = splitKeyMap[b].length - 1 === idx;
        if (isLastA && isLastB) {
          // If both last, then this is a filename comparison.

          // First, compare filename without extension.
          const fileA = splitKeyMap[a][idx].replace(/\.[^\.]*$/, '');
          const fileB = splitKeyMap[b][idx].replace(/\.[^\.]*$/, '');
          const filenameOnlyDiff = fileA.localeCompare(fileB);
          if (filenameOnlyDiff)
            return filenameOnlyDiff;

          // Second, compare including the extension.
          // Always return something here, see note below.
          return splitKeyMap[a][idx].localeCompare(splitKeyMap[b][idx]);
        } else if (!isLastA && !isLastB) {
          // If both not last, this is a subdirectory comparison.
          const diff = splitKeyMap[a][idx].localeCompare(splitKeyMap[b][idx]);
          if (diff)
            return diff;
        }

        // At this point, if idx is the final for each, we would have returned above.
        // So, check if either a or b is at the final entry in splitKeyMap.
        // If so, then there's a mismatch in number of directories, and we know one
        // the one with a filename should be sorted last.

        if (splitKeyMap[a].length - 1 <= idx) {
          // a has fewer subdirectories, so should be sorted last.
          return 1;
        }
        if (splitKeyMap[b].length - 1 <= idx) {
          // a has more subdirectories, so should be sorted first.
          return -1;
        }
      }
      return 0;
    });
  }

  // Given a set of paths, an overlayName, and an extension, return all paths with
  // that extension that have `overlayName` either as their entire filename (no subdir)
  // or are inside a root-level subdirectory named `overlayName`/  The extension should
  // include the period separator, e.g. ".js".  All comparisons are case insensitive.
  filterUserFiles(paths, origOverlayName, origExtension) {
    const extension = origExtension.toLowerCase();
    const overlayName = origOverlayName.toLowerCase();
    return paths.filter((origPath) => {
      const path = origPath.toLowerCase();
      if (!path.endsWith(extension))
        return false;
      if (path === `${overlayName}${extension}`)
        return true;
      if (path.startsWith(`${overlayName}/`) || path.startsWith(`${overlayName}\\`))
        return true;
      return false;
    });
  }

  getUserConfigLocation(overlayName, options, callback) {
    let currentlyReloading = false;
    const reloadOnce = () => {
      if (currentlyReloading)
        return;
      currentlyReloading = true;
      window.location.reload();
    };

    window.addOverlayListener('onUserFileChanged', () => {
      reloadOnce();
    });
    window.addOverlayListener('onForceReload', () => {
      reloadOnce();
    });

    this.loadUserFiles(overlayName, options, callback);
  }

  loadUserFiles(overlayName, options, callback) {
    const readOptions = callOverlayHandler({
      call: 'cactbotLoadData',
      overlay: 'options',
    });

    const loadUser = async (e) => {
      // The basePath isn't using for anything other than cosmetic printing of full paths,
      // so replace any slashes here for uniformity.  In case anybody is using cactbot on
      // Linux (?!?), support any style of slashes elsewhere.
      const basePath = e.detail.userLocation.replace(/[/\\]*$/, '') + '\\';
      const localFiles = e.detail.localUserFiles;

      // The plugin auto-detects the language, so set this first.
      // If options files want to override it, they can for testing.

      // Backward compatibility (language is now separated to three types.)
      if (e.detail.language) {
        options.ParserLanguage = e.detail.language;
        options.ShortLocale = e.detail.language;
        options.DisplayLanguage = e.detail.language;
      }
      // Parser Language
      if (e.detail.parserLanguage) {
        options.ParserLanguage = e.detail.parserLanguage;
        // Backward compatibility, everything "Language" should be changed to "ParserLanguage"
        options.Language = e.detail.parserLanguage;
      }
      const supportedLanguage = ['en', 'de', 'fr', 'ja', 'cn', 'ko'];
      // System Language
      if (e.detail.systemLocale) {
        options.SystemLocale = e.detail.systemLocale;
        options.ShortLocale = e.detail.systemLocale.substring(0, 2);
        if (options.ShortLocale === 'zh')
          options.ShortLocale = 'cn';
        if (!supportedLanguage.includes(options.ShortLocale))
          options.ShortLocale = options.ParserLanguage;
      }
      // User's setting Language
      options.DisplayLanguage = e.detail.displayLanguage;
      if (!supportedLanguage.includes(options.DisplayLanguage))
        options.DisplayLanguage = options.ParserLanguage || 'en';

      document.body.classList.add(`lang-${options.DisplayLanguage}`);
      this.addUnlockText(options.DisplayLanguage);

      // Handle processOptions after default language selection above,
      // but before css below which may load skin files.
      // processOptions needs to be called whether or not there are
      // any userOptions saved, as it sets up the defaults.
      const userOptions = await readOptions || {};
      this.savedConfig = userOptions.data || {};
      this.processOptions(
          options,
          this.savedConfig[overlayName] || {},
          this.optionTemplates[overlayName],
      );

      // If the overlay has a "Debug" setting, set to true via the config tool,
      // then also print out user files that have been loaded.
      const printUserFile = options.Debug ? (x) => console.log(x) : (x) => {};

      // With user files being arbitrary javascript, and having multiple files
      // in user folders, it's possible for later files to accidentally remove
      // things that previous files have added.  Warn about this, since most
      // users are not programmers.
      const warnOnVariableResetMap = {
        raidboss: [
          'Triggers',
        ],
      };
      warnOnVariableResetMap[overlayName] = warnOnVariableResetMap[overlayName] || [];

      // The values of each `warnOnVariableResetMap` field are initially set
      // after the first file, so that if there is only one file, there are
      // not any warnings.
      const variableTracker = {};

      if (localFiles) {
        // localFiles may be null if there is no valid user directory.
        const sortedFiles = this.sortUserFiles(Object.keys(localFiles));
        const jsFiles = this.filterUserFiles(sortedFiles, overlayName, '.js');
        const cssFiles = this.filterUserFiles(sortedFiles, overlayName, '.css');

        for (const jsFile of jsFiles) {
          try {
            printUserFile(`local user file: ${basePath}${jsFile}`);
            const Options = options;

            // This is the one eval cactbot should ever need, which is for handling user files.
            // Because user files can be located anywhere on disk and there's backwards compat
            // issues, it's unlikely that these will be able to be anything but eval forever.
            //
            /* eslint-disable no-eval */
            eval(localFiles[jsFile]);
            /* eslint-enable no-eval */

            for (const field of warnOnVariableResetMap[overlayName]) {
              if (variableTracker[field] && variableTracker[field] !== options[field]) {
                // Ideally users should do something like `Options.Triggers.push([etc]);`
                // instead of `Options.Triggers = [etc];`
                console.log(`*** WARNING: ${basePath}${jsFile} overwrites Options.${field} from previous files.`);
              }
              variableTracker[field] = options[field];
            }

            if (this.userFileCallbacks[overlayName])
              this.userFileCallbacks[overlayName](jsFile, localFiles, options, basePath);
          } catch (e) {
            // Be very visible for users.
            console.log('*** ERROR IN USER FILE ***');
            console.log(e.stack);
          }
        }

        // This is a bit awkward to handle skin settings here, but
        // doing it after user config files and before user css files
        // allows user css to override skin-specific css as well.
        this.handleSkin(options.Skin);

        for (const cssFile of cssFiles) {
          printUserFile(`local user file: ${basePath}${cssFile}`);
          const userCssText = document.createElement('style');
          userCssText.innerText = localFiles[cssFile];
          document.getElementsByTagName('head')[0].appendChild(userCssText);
        }
      }

      // Post this callback so that the js and css can be executed first.
      if (callback)
        callback();

      callOverlayHandler({ call: 'cactbotRequestState' });
    };

    callOverlayHandler({
      call: 'cactbotLoadUser',
      source: location.href,
      overlayName: overlayName,
    }).then((e) => {
      // Wait for DOMContentLoaded if needed.
      if (document.readyState !== 'loading') {
        loadUser(e);
        return;
      }
      document.addEventListener('DOMContentLoaded', () => {
        loadUser(e);
      });
    });
  }

  handleSkin(skinName) {
    if (!skinName || skinName === 'default')
      return;

    let basePath = document.location.toString();
    const slashIdx = basePath.lastIndexOf('/');
    if (slashIdx !== -1)
      basePath = basePath.substr(0, slashIdx);
    if (basePath.slice(-1) !== '/')
      basePath += '/';
    const skinHref = basePath + 'skins/' + skinName + '/' + skinName + '.css';
    this.appendCSSLink(skinHref);
  }
  appendJSLink(src) {
    const userJS = document.createElement('script');
    userJS.setAttribute('type', 'text/javascript');
    userJS.setAttribute('src', src);
    userJS.setAttribute('async', false);
    document.getElementsByTagName('head')[0].appendChild(userJS);
  }
  appendCSSLink(href) {
    const userCSS = document.createElement('link');
    userCSS.setAttribute('rel', 'stylesheet');
    userCSS.setAttribute('type', 'text/css');
    userCSS.setAttribute('href', href);
    document.getElementsByTagName('head')[0].appendChild(userCSS);
  }
  processOptions(options, savedConfig, template) {
    // Take options from the template, find them in savedConfig,
    // and apply them to options. This also handles setting
    // defaults for anything in the template, even if it does not
    // exist in savedConfig.
    if (Array.isArray(template)) {
      for (let i = 0; i < template.length; ++i)
        this.processOptions(options, savedConfig, template[i]);
      return;
    }

    // Not all overlays have option templates.
    if (!template)
      return;

    const templateOptions = template.options || [];
    for (let i = 0; i < templateOptions.length; ++i) {
      const opt = templateOptions[i];

      // Grab the saved value or the default to set in options.
      const value = opt.id in savedConfig ? savedConfig[opt.id] : opt.default;

      // Options can provide custom logic to turn a value into options settings.
      // If this doesn't exist, just set the value directly.
      // Option template ids are identical to field names on Options.
      if (opt.setterFunc)
        opt.setterFunc(options, value);
      else if (opt.type === 'integer')
        options[opt.id] = parseInt(value);
      else if (opt.type === 'float')
        options[opt.id] = parseFloat(value);
      else
        options[opt.id] = value;
    }

    // For things like raidboss that build extra UI, also give them a chance
    // to handle anything that has been set on that UI.
    if (template.processExtraOptions)
      template.processExtraOptions(options, savedConfig);
  }
  addUnlockText(lang) {
    const unlockText = {
      en: '🔓 Unlocked (lock overlay before using)',
      de: '🔓 Entsperrt (Sperre das Overlay vor der Nutzung)',
      fr: '🔓 Débloqué (Bloquez l\'overlay avant utilisation)',
      ja: '🔓 ロック解除 (オーバーレイを使用する前にロックしてください)',
      cn: '🔓 已解除锁定 (你需要将此悬浮窗锁定后方可使用)',
      ko: '🔓 위치 잠금 해제됨 (사용하기 전에 위치 잠금을 설정하세요)',
    };

    const id = 'cactbot-unlocked-text';
    let textElem = document.getElementById(id);
    if (!textElem) {
      textElem = document.createElement('div');
      textElem.id = id;
      textElem.classList.add('text');
      // Set element display to none in case the page has not included defaults.css.
      textElem.style.display = 'none';
      document.body.append(textElem);
    }
    textElem.innerHTML = unlockText[lang] || unlockText['en'];
  }
}

export default new UserConfig();

if (typeof document !== 'undefined') {
  // This event comes early and is not cached, so set up event listener immediately.
  document.addEventListener('onOverlayStateUpdate', (e) => {
    const docClassList = document.documentElement.classList;
    if (e.detail.isLocked)
      docClassList.remove('resizeHandle', 'unlocked');
    else
      docClassList.add('resizeHandle', 'unlocked');
  });
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

require('proof')(1, function (step, equal) {
  var connect = require('connect'), http = require('http'), path = require('path'), app;
  step(function () {
    var on = step('on');
    app = connect()
      .use(require('../../service').create(path.join(__dirname, 'fixtures')))
      .listen(8082);
/*    on(app, 'listen');
  }, function () {
    var on = step('on');*/
    var req = http.get("http://127.0.0.1:8082/hello");
    on(req, 'response');
    on(req, 'error');
  }, function (message) {
    var on = step('on');
    message.setEncoding('utf8');
    on(message, 'data', []);
    on(message, 'end');
  }, function (data) {
    equal(data.join(''), 'Hello, World!\n', 'connect');
    app.close();
  });
});
<commit_msg>Whitespace tidy.<commit_after>#!/usr/bin/env node

require('proof')(1, function (step, equal) {
  var connect = require('connect'), http = require('http'), path = require('path'), app;
  step(function () {
    var on = step('on');
    app = connect()
      .use(require('../../service').create(path.join(__dirname, 'fixtures')))
      .listen(8082);
/*    on(app, 'listen');
  }, function () {
    var on = step('on');*/
    var req = http.get("http://127.0.0.1:8082/hello");
    on(req, 'response');
    on(req, 'error');
  }, function (message) {
    var on = step('on');
    message.setEncoding('utf8');
    on(message, 'data', []);
    on(message, 'end');
  }, function (data) {
    equal(data.join(''), 'Hello, World!\n', 'connect');
    app.close();
  });
});
<|endoftext|>


<commit_before>var express = require('express')
var clone = require("nodegit").Clone.clone;
var open = require("nodegit").Repository.open;
var proxy = express()
var git_path = "https://github.com/stevenharradine/simple-site.git"

proxy.use (function (req, res) {
  var url_folders = req.originalUrl.split ('/')
  var commit_hash = url_folders[1]
  var path = url_folders.slice(2).join('/')

  console.log (path)

// Clone a given repository into a specific folder.
//  clone(git_path, "docroot", null)
  open("docroot")//, "docroot", null)
    // Look up this known commit.
    .then(function(repo) {
      // Use a known commit sha from this repository.
      return repo.getCommit(commit_hash);
    })
    // Look up a specific file within that commit.
    .then(function(commit) {
      return commit.getEntry(path);
    })
    // Get the blob contents from the file.
    .then(function(entry) {
      // Patch the blob to contain a reference to the entry.
      return entry.getBlob().then(function(blob) {
        blob.entry = entry;
        return blob;
      });
    })
    // Display information about the blob.
    .then(function(blob) {
      res.send(String(blob));
    })
    .catch(function(err) {
    	console.log(err)

    	if (commit_hash == "master") {
		  open("docroot")//, "docroot", null)
		    // Look up this known commit.
		    .then(function(repo) {
		      // Use a known commit sha from this repository.
		      return repo.getCommit("d6e93a67642f94dd58697065fb5d24f6d7d22910");
		    })
		    // Look up a specific file within that commit.
		    .then(function(commit) {
		      return commit.getEntry(path);
		    })
		    // Get the blob contents from the file.
		    .then(function(entry) {
		      // Patch the blob to contain a reference to the entry.
		      return entry.getBlob().then(function(blob) {
		        blob.entry = entry;
		        return blob;
		      });
		    })
		    // Display information about the blob.
		    .then(function(blob) {
		      res.send(String(blob));
		    })
		    .catch(function(err) {
		    	console.log(err)

//		    	res.send(err);
		    })
    	}
      console.log(err)
//    	res.send(err);
    })
})

proxy.listen(3000)<commit_msg>added master pulled dynamicly from head not fixed point via hash<commit_after>var express = require('express')
var clone = require("nodegit").Clone.clone;
var open = require("nodegit").Repository.open;
var proxy = express()
var git_path = "https://github.com/stevenharradine/simple-site.git"

proxy.use (function (req, res) {
  var url_folders = req.originalUrl.split ('/')
  var commit_hash = url_folders[1]
  var path = url_folders.slice(2).join('/')

  console.log (path)

// Clone a given repository into a specific folder.
//  clone(git_path, "docroot", null)
  open("docroot")//, "docroot", null)
    // Look up this known commit.
    .then(function(repo) {
      // Use a known commit sha from this repository.
      return repo.getCommit(commit_hash);
    })
    // Look up a specific file within that commit.
    .then(function(commit) {
      return commit.getEntry(path);
    })
    // Get the blob contents from the file.
    .then(function(entry) {
      // Patch the blob to contain a reference to the entry.
      return entry.getBlob().then(function(blob) {
        blob.entry = entry;
        return blob;
      });
    })
    // Display information about the blob.
    .then(function(blob) {
      res.send(String(blob));
    })
    .catch(function(err) {
    	console.log(err)

    	if (commit_hash == "master") {
		  open("docroot")//, "docroot", null)
		    // Look up this known commit.
		    .then(function(repo) {
		      // Use a known commit sha from this repository.
		      return repo.getBranchCommit("master");
		    })
		    // Look up a specific file within that commit.
		    .then(function(commit) {
		      return commit.getEntry(path);
		    })
		    // Get the blob contents from the file.
		    .then(function(entry) {
		      // Patch the blob to contain a reference to the entry.
		      return entry.getBlob().then(function(blob) {
		        blob.entry = entry;
		        return blob;
		      });
		    })
		    // Display information about the blob.
		    .then(function(blob) {
		      res.send(String(blob));
		    })
		    .catch(function(err) {
		    	console.log(err)
		    })
    	}
      console.log(err)
    })
})

proxy.listen(3000)<|endoftext|>


<commit_before>var request = require("request");
var passport = require('passport');
var githubStrategy = require('passport-github').Strategy;
var q = require('q');
var GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID;
var GITHUB_CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET;
var CONTEXT_URI = process.env.CONTEXT_URI;
var mongoRepository = require('./mongoRepository.js');
var encoder = require("./encoder");

module.exports = function (app) {
    var setSession = function (req, user) {
        req.session.username = user.username;
        req.session.encodedUsername = user.encodedUsername;
        req.session.githubUsername = user.githubUser.username;
        req.session.avatarUrl = user.githubUser._json.avatar_url;
    };
    var fetchGithubUserEmails = function (accessToken) {
        var deferred = q.defer();
        var options = {
            url: "https://api.github.com/user/emails?access_token=" + accessToken,
            headers: {
                "User-Agent": "Quantified Dev Localhost"
            }
        };
        request(options, function (err, res, body) {
            if (!err) {
                deferred.resolve(JSON.parse(body));
            }
            else {
                deferred.reject(err);
            }
        });
        return deferred.promise;
    };

    var handleGithubCallback = function (req, res) {
        var githubUser = req.user.profile;
        req.session.githubAccessToken = req.user.accessToken;
        var isNewUser = function (user) {
            return !user;
        };
        var isUserRegisteredWithOneself = function (user) {
            return user && user.username;
        };
        var redirect = function (user, url) {
            res.redirect(CONTEXT_URI + url + "?username=" + user.username);
        };
        var insertGithubProfileInDb = function () {
            fetchGithubUserEmails(req.user.accessToken)
                .then(function (userEmails) {
                    for (var i in userEmails) {
                        githubUser.emails.push(userEmails[i]);
                    }
                    return {
                        githubUser: githubUser,
                        registeredOn: new Date()
                    };
                }, function (err) {
                    res.status(500).send("Could not fetch email addresses for user.");
                }).then(function (githubUserRecord) {
                    return mongoRepository.insert('users', githubUserRecord);
                }).then(function (docs) {
                    req.session.githubUsername = githubUser.username;
                    req.session.avatarUrl = githubUser._json.avatar_url;
                    redirect(githubUser, "/claimUsername");
                }, function (err) {
                    res.status(500).send("Database error");
                });
        };
        // TODO move it to separate place.
        var creditUserSignUpToApp = function () {
            var attributeUserToApp = function (appId) {
                var byAppId = {
                        "appId": appId
                    },
                    updateObject = {
                        "$push": {
                            "users": githubUser.username
                        }
                    };
                mongoRepository.update('registeredApps', byAppId, updateObject)
                    .then(function () {
                        console.log("New user " + githubUser.username + " assigned to: " + appId);
                    });
            };

            var mapUserAndAppUsingStream = function () {
                var redirectUrl = req.session.redirectUrl;
                if (redirectUrl.match("/v1/streams")) {
                    var tokenisedUrl = redirectUrl.split("/"),
                        byStreamId = {
                            "streamid": tokenisedUrl[3]
                        };
                    mongoRepository.findOne('stream', byStreamId)
                        .then(function (stream) {
                            attributeUserToApp(stream.appId);
                        }, function (err) {
                        });
                }
            };

            //main
            mapUserAndAppUsingStream();
        }; //end creditUserSignUpToApp
        var byGitHubUsername = {
            "githubUser.username": githubUser.username
        };
        mongoRepository.findOne('users', byGitHubUsername)
            .then(function (user) {
                if (isNewUser(user)) {
                    creditUserSignUpToApp();
                    insertGithubProfileInDb();
                } else if (isUserRegisteredWithOneself(user)) {
                    setSession(req, user);
                    if (req.session.redirectUrl) {
                        var redirectUrl = req.session.redirectUrl;
                        delete req.session.redirectUrl;
                        if (redirectUrl.match("/v1/streams")) {
                            var tokenisedUrl = redirectUrl.split("/");
                            tokenisedUrl[2] = "users";
                            tokenisedUrl[3] = req.session.username;
                            redirectUrl = tokenisedUrl.join("/");
                        }
                        res.cookie('_eun', req.session.encodedUsername);
                        res.redirect(redirectUrl);
                    } else {
                        redirect(user, "/dashboard");
                    }
                } else {
                    req.session.githubUsername = user.githubUser.username;
                    req.session.avatarUrl = user.githubUser._json.avatar_url;
                    redirect(githubUser, "/claimUsername");
                }
            });
    };

    var handleGithubCallbackWithIntent = function (req, res) {
        var githubUser = req.user.profile;
        var oneselfUsername = req.session.oneselfUsername;

        var encodeUsername = function (oneselfUsername) {
            var deferred = q.defer();
            deferred.resolve(encoder.encodeUsername(oneselfUsername));
            return deferred.promise;
        };

        var signupComplete = function(){
            res.redirect("/signup_complete");
        };

        var createUser = function (encUserObj) {
            var deferred = q.defer();
            fetchGithubUserEmails(req.user.accessToken)
                .then(function (userEmails) {
                    for (var i in userEmails) {
                        githubUser.emails.push(userEmails[i]);
                    }
                    return {
                        githubUser: githubUser,
                        registeredOn: new Date(),
                        username: oneselfUsername,
                        encodedUsername: encUserObj.encodedUsername,
                        salt: encUserObj.salt
                    };
                }, function (err) {
                    res.status(500).send("Could not fetch email addresses for user.");
                }).then(function (githubUserRecord) {
                    mongoRepository.insert('users', githubUserRecord);
                    deferred.resolve();
                })
            return deferred.promise;
        };

        encodeUsername(oneselfUsername)
            .then(createUser)
            .then(signupComplete);
    };

    passport.serializeUser(function (user, done) {
        done(null, user);
    });

    passport.deserializeUser(function (obj, done) {
        done(null, obj);
    });

    passport.use(new githubStrategy({
            clientID: GITHUB_CLIENT_ID,
            clientSecret: GITHUB_CLIENT_SECRET,
            callbackURL: CONTEXT_URI + "/auth/github/callback"
        },
        function (accessToken, refreshToken, profile, done) {
            var githubProfile = {
                profile: profile,
                accessToken: accessToken
            };
            return done(null, githubProfile);
        }
    ));
    app.use(passport.initialize());
    app.use(passport.session());

    app.get('/auth/github', passport.authenticate('github', {
        scope: 'user:email'
    }));

    app.get('/auth/github/1self_website', function(req, res, next) {
        req.session.redirectUrl = "/dashboard";
        passport.authenticate('github', {
            scope: 'user:email'
        })(req, res, next);
    });

    app.get('/auth/github/callback', passport.authenticate('github', {
        failureRedirect: CONTEXT_URI + '/signup'
    }), handleGithubCallbackWithIntent);
};
<commit_msg>Add check if user already exists before creating.<commit_after>var request = require("request");
var passport = require('passport');
var githubStrategy = require('passport-github').Strategy;
var q = require('q');
var GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID;
var GITHUB_CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET;
var CONTEXT_URI = process.env.CONTEXT_URI;
var mongoRepository = require('./mongoRepository.js');
var encoder = require("./encoder");

module.exports = function (app) {
    var setSession = function (req, user) {
        req.session.username = user.username;
        req.session.encodedUsername = user.encodedUsername;
        req.session.githubUsername = user.githubUser.username;
        req.session.avatarUrl = user.githubUser._json.avatar_url;
    };
    var fetchGithubUserEmails = function (accessToken) {
        var deferred = q.defer();
        var options = {
            url: "https://api.github.com/user/emails?access_token=" + accessToken,
            headers: {
                "User-Agent": "Quantified Dev Localhost"
            }
        };
        request(options, function (err, res, body) {
            if (!err) {
                deferred.resolve(JSON.parse(body));
            }
            else {
                deferred.reject(err);
            }
        });
        return deferred.promise;
    };

    var handleGithubCallback = function (req, res) {
        var githubUser = req.user.profile;
        req.session.githubAccessToken = req.user.accessToken;
        var isNewUser = function (user) {
            return !user;
        };
        var isUserRegisteredWithOneself = function (user) {
            return user && user.username;
        };
        var redirect = function (user, url) {
            res.redirect(CONTEXT_URI + url + "?username=" + user.username);
        };
        var insertGithubProfileInDb = function () {
            fetchGithubUserEmails(req.user.accessToken)
                .then(function (userEmails) {
                    for (var i in userEmails) {
                        githubUser.emails.push(userEmails[i]);
                    }
                    return {
                        githubUser: githubUser,
                        registeredOn: new Date()
                    };
                }, function (err) {
                    res.status(500).send("Could not fetch email addresses for user.");
                }).then(function (githubUserRecord) {
                    return mongoRepository.insert('users', githubUserRecord);
                }).then(function (docs) {
                    req.session.githubUsername = githubUser.username;
                    req.session.avatarUrl = githubUser._json.avatar_url;
                    redirect(githubUser, "/claimUsername");
                }, function (err) {
                    res.status(500).send("Database error");
                });
        };
        // TODO move it to separate place.
        var creditUserSignUpToApp = function () {
            var attributeUserToApp = function (appId) {
                var byAppId = {
                        "appId": appId
                    },
                    updateObject = {
                        "$push": {
                            "users": githubUser.username
                        }
                    };
                mongoRepository.update('registeredApps', byAppId, updateObject)
                    .then(function () {
                        console.log("New user " + githubUser.username + " assigned to: " + appId);
                    });
            };

            var mapUserAndAppUsingStream = function () {
                var redirectUrl = req.session.redirectUrl;
                if (redirectUrl.match("/v1/streams")) {
                    var tokenisedUrl = redirectUrl.split("/"),
                        byStreamId = {
                            "streamid": tokenisedUrl[3]
                        };
                    mongoRepository.findOne('stream', byStreamId)
                        .then(function (stream) {
                            attributeUserToApp(stream.appId);
                        }, function (err) {
                        });
                }
            };

            //main
            mapUserAndAppUsingStream();
        }; //end creditUserSignUpToApp
        var byGitHubUsername = {
            "githubUser.username": githubUser.username
        };
        mongoRepository.findOne('users', byGitHubUsername)
            .then(function (user) {
                if (isNewUser(user)) {
                    creditUserSignUpToApp();
                    insertGithubProfileInDb();
                } else if (isUserRegisteredWithOneself(user)) {
                    setSession(req, user);
                    if (req.session.redirectUrl) {
                        var redirectUrl = req.session.redirectUrl;
                        delete req.session.redirectUrl;
                        if (redirectUrl.match("/v1/streams")) {
                            var tokenisedUrl = redirectUrl.split("/");
                            tokenisedUrl[2] = "users";
                            tokenisedUrl[3] = req.session.username;
                            redirectUrl = tokenisedUrl.join("/");
                        }
                        res.cookie('_eun', req.session.encodedUsername);
                        res.redirect(redirectUrl);
                    } else {
                        redirect(user, "/dashboard");
                    }
                } else {
                    req.session.githubUsername = user.githubUser.username;
                    req.session.avatarUrl = user.githubUser._json.avatar_url;
                    redirect(githubUser, "/claimUsername");
                }
            });
    };

    var handleGithubCallbackWithIntent = function (req, res) {
        var githubUser = req.user.profile;
        var oneselfUsername = req.session.oneselfUsername;

        var isNewUser = function (user) {
            return !user;
        };

        var handleError = function(error){
            console.log(error);
            res.send(400, "Username you are tyring to use already exists");
        };

        var encodeUsername = function (oneselfUsername) {
            var deferred = q.defer();
            deferred.resolve(encoder.encodeUsername(oneselfUsername));
            return deferred.promise;
        };

        var signupComplete = function(){
            res.redirect("/signup_complete");
        };

        var findUser = function(byGitHubUsername) {
            var deferred = q.defer();
            mongoRepository.findOne('users', byGitHubUsername)
                .then(function (user) {
                    if (isNewUser(user)) {
                        deferred.resolve(byGitHubUsername["githubUser.username"]);
                    } else {
                        deferred.reject("User alredy exists");
                    }
                });
            return deferred.promise;
        }

        var createUser = function (encUserObj) {
            var deferred = q.defer();
            fetchGithubUserEmails(req.user.accessToken)
                .then(function (userEmails) {
                    for (var i in userEmails) {
                        githubUser.emails.push(userEmails[i]);
                    }
                    return {
                        githubUser: githubUser,
                        registeredOn: new Date(),
                        username: oneselfUsername,
                        encodedUsername: encUserObj.encodedUsername,
                        salt: encUserObj.salt
                    };
                }, function (err) {
                    res.status(500).send("Could not fetch email addresses for user.");
                }).then(function (githubUserRecord) {
                    mongoRepository.insert('users', githubUserRecord);
                    deferred.resolve();
                })
            return deferred.promise;
        };

        var byGitHubUsername = {
            "githubUser.username": githubUser.username
        };
        findUser(byGitHubUsername)
            .then(encodeUsername)
            .then(createUser)
            .then(signupComplete)
            .then().catch(handleError);
    };

    passport.serializeUser(function (user, done) {
        done(null, user);
    });

    passport.deserializeUser(function (obj, done) {
        done(null, obj);
    });

    passport.use(new githubStrategy({
            clientID: GITHUB_CLIENT_ID,
            clientSecret: GITHUB_CLIENT_SECRET,
            callbackURL: CONTEXT_URI + "/auth/github/callback"
        },
        function (accessToken, refreshToken, profile, done) {
            var githubProfile = {
                profile: profile,
                accessToken: accessToken
            };
            return done(null, githubProfile);
        }
    ));
    app.use(passport.initialize());
    app.use(passport.session());

    app.get('/auth/github', passport.authenticate('github', {
        scope: 'user:email'
    }));

    app.get('/auth/github/1self_website', function(req, res, next) {
        req.session.redirectUrl = "/dashboard";
        passport.authenticate('github', {
            scope: 'user:email'
        })(req, res, next);
    });

    app.get('/auth/github/callback', passport.authenticate('github', {
        failureRedirect: CONTEXT_URI + '/signup'
    }), handleGithubCallbackWithIntent);
};
<|endoftext|>


<commit_before>/*
 * grunt-hockeyapp-puck
 * https://github.com/dresources/grunt-hockeyapp-puck.git
 *
 * Copyright (c) 2015 rtregaskis
 * Licensed under the MIT license.
 */

var request = require('request'),
    fs = require('fs'),
	path = require('path');

module.exports = function(grunt) {
    'use strict';

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks

    grunt.registerMultiTask('hockeyapp_create', 'Create new app on HockeyApp via grunt', function() {
        // Merge task-specific and/or target-specific options with these defaults.
        var options = this.options({
            token: null,
			title: null,
			bundle_identifier: null,
			platform: 'iOS', //Android, Mac OS, Windows Phone, Custom
			release_type: '0',
			custom_release_type: null,
			icon:null,
			private: 'true'
        });

		// warn and exit on missing options
        if (!options['token'] || options['token'] === undefined || options['token'] === '') {
            return grunt.fatal(
                'token option is required!'
            );
        }
        if (!options['title'] || options['title'] === undefined || options['title'] === '') {
            return grunt.fatal(
                'title option is required!'
            );
        }
        if (!options['bundle_identifier'] || options['bundle_identifier'] === undefined || options['bundle_identifier'] === '') {
            return grunt.fatal(
                'bundle_identifier option is required!'
            );
        }

        // construct form data
        // NB: use read stream to access IPA file
        var formData = {
			title:options.title,
			bundle_identifier:options.bundle_identifier,
			platform:options.platform,
			release_type:options.release_type,
			private:options.private
        };

        // tidy up url
        var url = 'https://rink.hockeyapp.net/api/2/apps/new';

        // run this asynchronously
        var done = this.async();

        grunt.log.subhead('Creating a new app instance for '+options.title);
		console.log(options);
		console.log(formData);

        // fire request to server.
        request.post({
            url: url,
            formData: formData,
            headers: {
                'X-HockeyAppToken': options['token']
            }
        }, function(error, response, body) {
            if (error !== null) {
                grunt.log.error(error);
                grunt.log.error('Error creating "' + options['title'] + '"');
                done(false);
            } else {

				grunt.config('ha_app_id', JSON.parse(body)['public_identifier']);
                grunt.log.ok('Created new app "' + options['title'] + '" successfully');
                done();
            }
        });
    });

	grunt.registerMultiTask('hockeyapp_listteams', 'Lists teams of app', function(){
		var options = this.options({
			app_id:null
		});

		// warn and exit on missing options
        if (!options['app_id'] || options['app_id'] === undefined || options['app_id'] === '') {
            return grunt.fatal(
                'app_id option is required!'
            );
        }

        // tidy up url
        var url = 'https://rink.hockeyapp.net/api/2/apps/'+options.app_id+'/app_teams';

        // run this asynchronously
        var done = this.async();

        grunt.log.subhead('List teams of app');

        // fire request to server.
        request.get({
            url: url,
            headers: {
                'X-HockeyAppToken': options['token']
            }
        }, function(error, response, body) {
            if (error !== null) {
                grunt.log.error(error);
                grunt.log.error('Error listing team to app!');
                done(false);
            } else {
				body = JSON.parse(body);
                grunt.log.ok('Added team to app successfully');
				for (var i = 0; i < body.teams.length; i++){
					console.log(body.teams[i]['id'], body.teams[i]['name']);
				}
                done();
            }
        });
	});

	grunt.registerMultiTask('hockeyapp_addteam', 'Add team to app', function(){
		var options = this.options({
			app_id:null,
			team_id:null
		});

		// warn and exit on missing options
        if (!options['app_id'] || options['app_id'] === undefined || options['app_id'] === '') {
            return grunt.fatal(
                'app_id option is required!'
            );
        }
        if (!options['team_id'] || options['team_id'] === undefined || options['team_id'] === '') {
            return grunt.fatal(
                'team_id option is required!'
            );
        }

        // tidy up url
        var url = 'https://rink.hockeyapp.net/api/2/apps/'+options.app_id+'/app_teams/'+options.team_id;

        // run this asynchronously
        var done = this.async();

        grunt.log.subhead('Add app to team');

        // fire request to server.
        request.put({
            url: url,
            headers: {
                'X-HockeyAppToken': options['token']
            }
        }, function(error, response, body) {
            if (error !== null) {
                grunt.log.error(error);
                grunt.log.error('Error adding team to app!');
                done(false);
            } else {
                grunt.log.ok('Added team to app successfully');
                done();
            }
        });
	});

    grunt.registerMultiTask('hockeyapp_upload', 'Upload builds to HockeyApp via grunt', function() {
        // Merge task-specific and/or target-specific options with these defaults.
        var options = this.options({
            token: null,
            app_id: null,
            file: null,
            notes: 'Changelog',
			notes_type:1,
            notify: 2,
            status: 2,
            tags: '',
			teams:null
        });

		// warn and exit on missing options
        if (!options['token'] || options['token'] === undefined || options['token'] === '') {
            return grunt.fatal(
                'Token option is required!'
            );
        } else if (!options['app_id'] || options['app_id'] === undefined || options['app_id'] === '') {
            return grunt.fatal(
                'Application id option is required!'
            );
        } else if (!options['file'] || options['file'] === undefined || options['file'] === '') {
            return grunt.fatal(
                'File option is required!'
            );
        }

        // construct form data
        // NB: use read stream to access IPA file
        var formData = {
            ipa: fs.createReadStream(options['file']),
            status: options.status,
            notify: options.notify,
            notes: options.notes,
            notes_type: options.notes_type,
			teams: options.teams
        };

        // tidy up url
        var url = 'https://rink.hockeyapp.net/api/2/apps/' + options.app_id + '/app_versions/upload';

        // run this asynchronously
        var done = this.async();

        grunt.log.subhead('Uploading "' + options['file'] + '"');

        // fire request to server.
        request.post({
            url: url,
            formData: formData,
            headers: {
                'X-HockeyAppToken': options['token']
            }
        }, function(error, response, body) {
            if (error !== null) {
                grunt.log.error(error);
                grunt.log.error('Error uploading "' + options['file'] + '"');
                done(false);
            } else {
                grunt.log.ok('Uploaded "' + options['file'] + '" successfully');
                done();
            }
        });
    });
};
<commit_msg>listteam fixes, pass token in header. calm debug output<commit_after>/*
 * grunt-hockeyapp-puck
 * https://github.com/dresources/grunt-hockeyapp-puck.git
 *
 * Copyright (c) 2015 rtregaskis
 * Licensed under the MIT license.
 */

var request = require('request'),
    fs = require('fs'),
	path = require('path');

module.exports = function(grunt) {
    'use strict';

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks

    grunt.registerMultiTask('hockeyapp_create', 'Create new app on HockeyApp via grunt', function() {
        // Merge task-specific and/or target-specific options with these defaults.
        var options = this.options({
            token: null,
			title: null,
			bundle_identifier: null,
			platform: 'iOS', //Android, Mac OS, Windows Phone, Custom
			release_type: '0',
			custom_release_type: null,
			icon:null,
			private: 'true'
        });

		// warn and exit on missing options
        if (!options['token'] || options['token'] === undefined || options['token'] === '') {
            return grunt.fatal(
                'token option is required!'
            );
        }
        if (!options['title'] || options['title'] === undefined || options['title'] === '') {
            return grunt.fatal(
                'title option is required!'
            );
        }
        if (!options['bundle_identifier'] || options['bundle_identifier'] === undefined || options['bundle_identifier'] === '') {
            return grunt.fatal(
                'bundle_identifier option is required!'
            );
        }

        // construct form data
        // NB: use read stream to access IPA file
        var formData = {
			title:options.title,
			bundle_identifier:options.bundle_identifier,
			platform:options.platform,
			release_type:options.release_type,
			private:options.private
        };

        // tidy up url
        var url = 'https://rink.hockeyapp.net/api/2/apps/new';

        // run this asynchronously
        var done = this.async();

        grunt.log.subhead('Creating a new app instance for '+options.title);

        // fire request to server.
        request.post({
            url: url,
            formData: formData,
            headers: {
                'X-HockeyAppToken': options['token']
            }
        }, function(error, response, body) {
            if (error !== null) {
                grunt.log.error(error);
                grunt.log.error('Error creating "' + options['title'] + '"');
                done(false);
            } else {

				grunt.config('ha_app_id', JSON.parse(body)['public_identifier']);
                grunt.log.ok('Created new app "' + options['title'] + '" successfully');
                done();
            }
        });
    });

	grunt.registerMultiTask('hockeyapp_listteams', 'Lists teams of app', function(){
		var options = this.options({
            token: null,
			app_id:null
		});

		// warn and exit on missing options
        if (!options['app_id'] || options['app_id'] === undefined || options['app_id'] === '') {
            return grunt.fatal(
                'app_id option is required!'
            );
        }

        // tidy up url
        var url = 'https://rink.hockeyapp.net/api/2/apps/'+options.app_id+'/app_teams';

        // run this asynchronously
        var done = this.async();

        grunt.log.subhead('List teams of app');

        // fire request to server.
        request.get({
            url: url,
            headers: {
                'X-HockeyAppToken': options['token']
            }
        }, function(error, response, body) {
            if (error !== null) {
                grunt.log.error(error);
                grunt.log.error('Error listing team to app!');
                done(false);
            } else {
				body = JSON.parse(body);
                grunt.log.ok('Added team to app successfully');
				//for (var i = 0; i < body.teams.length; i++){
				//	console.log(body.teams[i]['id'], body.teams[i]['name']);
				//}
                done();
            }
        });
	});

	grunt.registerMultiTask('hockeyapp_addteam', 'Add team to app', function(){
		var options = this.options({
			app_id:null,
			team_id:null
		});

		// warn and exit on missing options
        if (!options['token'] || options['token'] === undefined || options['token'] === '') {
            return grunt.fatal(
                'token option is required!'
            );
        }
        if (!options['app_id'] || options['app_id'] === undefined || options['app_id'] === '') {
            return grunt.fatal(
                'app_id option is required!'
            );
        }
        if (!options['team_id'] || options['team_id'] === undefined || options['team_id'] === '') {
            return grunt.fatal(
                'team_id option is required!'
            );
        }

        // tidy up url
        var url = 'https://rink.hockeyapp.net/api/2/apps/'+options.app_id+'/app_teams/'+options.team_id;

        // run this asynchronously
        var done = this.async();

        grunt.log.subhead('Add app to team');

        // fire request to server.
        request.put({
            url: url,
            headers: {
                'X-HockeyAppToken': options['token']
            }
        }, function(error, response, body) {
            if (error !== null) {
                grunt.log.error(error);
                grunt.log.error('Error adding team to app!');
                done(false);
            } else {
                grunt.log.ok('Added team to app successfully');
                done();
            }
        });
	});

    grunt.registerMultiTask('hockeyapp_upload', 'Upload builds to HockeyApp via grunt', function() {
        // Merge task-specific and/or target-specific options with these defaults.
        var options = this.options({
            token: null,
            app_id: null,
            file: null,
            notes: 'Changelog',
			notes_type:1,
            notify: 2,
            status: 2,
            tags: '',
			teams:null
        });

		// warn and exit on missing options
        if (!options['token'] || options['token'] === undefined || options['token'] === '') {
            return grunt.fatal(
                'Token option is required!'
            );
        } else if (!options['app_id'] || options['app_id'] === undefined || options['app_id'] === '') {
            return grunt.fatal(
                'Application id option is required!'
            );
        } else if (!options['file'] || options['file'] === undefined || options['file'] === '') {
            return grunt.fatal(
                'File option is required!'
            );
        }

        // construct form data
        // NB: use read stream to access IPA file
        var formData = {
            ipa: fs.createReadStream(options['file']),
            status: options.status,
            notify: options.notify,
            notes: options.notes,
            notes_type: options.notes_type,
			teams: options.teams
        };

        // tidy up url
        var url = 'https://rink.hockeyapp.net/api/2/apps/' + options.app_id + '/app_versions/upload';

        // run this asynchronously
        var done = this.async();

        grunt.log.subhead('Uploading "' + options['file'] + '"');

        // fire request to server.
        request.post({
            url: url,
            formData: formData,
            headers: {
                'X-HockeyAppToken': options['token']
            }
        }, function(error, response, body) {
            if (error !== null) {
                grunt.log.error(error);
                grunt.log.error('Error uploading "' + options['file'] + '"');
                done(false);
            } else {
                grunt.log.ok('Uploaded "' + options['file'] + '" successfully');
                done();
            }
        });
    });
};
<|endoftext|>


<commit_before>import {map} from 'event-stream';
import gulp from 'gulp';
import {addReleaseNotesToTag} from './helpers/github-service';
import {log} from 'gulp-util';

const plugins = require('gulp-load-plugins')();

gulp.task('release-zip', () => {
  const tagName = process.env.TRAVIS_TAG;

  if (!tagName) {
    log('Skipping - because we did not cut a new release');
    return;
  }

  return gulp.src(`release/pui-${tagName}/**/*`, {base: 'release/'})
    .pipe(plugins.zip(`pui.zip`))
    .pipe(gulp.dest('.'));
});

gulp.task('release-add-release-notes', () => {
  const tagName = process.env.TRAVIS_TAG;

  if (!tagName) {
    log('Skipping - because we did not cut a new release');
    return;
  }

  return gulp.src('LATEST_CHANGES.md')
    .pipe(map(async (latestChangesFile, callback) => {
      log('Updating release notes...');
      try {
        await addReleaseNotesToTag(tagName, latestChangesFile.contents.toString());
        callback();
      }
      catch(error) {
        console.error(error);
        callback(error);
      }
    }));
});
<commit_msg>chore(release): Check that RELEASE_TOKEN is set<commit_after>import {map} from 'event-stream';
import gulp from 'gulp';
import {addReleaseNotesToTag} from './helpers/github-service';
import {log} from 'gulp-util';

const plugins = require('gulp-load-plugins')();

gulp.task('release-zip', () => {
  const tagName = process.env.TRAVIS_TAG;

  if (!tagName) {
    log('Skipping - because we did not cut a new release');
    return;
  }

  return gulp.src(`release/pui-${tagName}/**/*`, {base: 'release/'})
    .pipe(plugins.zip(`pui.zip`))
    .pipe(gulp.dest('.'));
});

gulp.task('release-add-release-notes', () => {
  const tagName = process.env.TRAVIS_TAG;

  if (!tagName) {
    log('Skipping - because we did not cut a new release');
    return;
  }

  if (!process.env.RELEASE_TOKEN) {
    log('Skipping - please set the RELEASE_TOKEN env var');
    return;
  }

  return gulp.src('LATEST_CHANGES.md')
    .pipe(map(async (latestChangesFile, callback) => {
      log(`Updating release notes for ${tagName}...`);
      try {
        await addReleaseNotesToTag(tagName, latestChangesFile.contents.toString());
        callback();
      }
      catch(error) {
        console.error(error);
        callback(error);
      }
    }));
});
<|endoftext|>