<commit_before>var g_keyStatusIndicator = "status-indicator";

// Assistant Handlers
function onBtnAcceptClicked(evt){

	var btnAccept = $(this);

	evt.preventDefault();
	var data = evt.data;
	var token = $.cookie(g_keyToken);
	var params = {};
 	params[g_keyActivityId] = data[g_keyActivityId];
	params[g_keyToken] = token;

	$.ajax({
		type: "PUT",
		url: "/admin/accept",
		data: params,
		success: function(data, status, xhr) {
			var buttonsWrap = btnAccept.parent();
			var cell = buttonsWrap.parent();
			btnAccept.remove();
			var indicator = cell.data(g_keyStatusIndicator);
			indicator.text("Accepted");
		},
		error: function(xhr, status, err) {

		}
	});
}

function onBtnRejectClicked(evt){
	var btnReject = $(this);

	evt.preventDefault();
	var data = evt.data;
	var token = $.cookie(g_keyToken);
	var params = {};
 	params[g_keyActivityId] = data[g_keyActivityId];
	params[g_keyToken] = token;

	try{
		$.ajax({
			type: "PUT",
			url: "/admin/reject",
			data: params,
			success: function(data, status, xhr){
				var buttonsWrap = btnReject.parent();
				var cell = buttonsWrap.parent();
				btnReject.remove();
				var indicator = cell.data(g_keyStatusIndicator);
				indicator.text("Rejected");
			},
			error: function(xhr, status, err){

			}
		});
	} catch(err){

	}
}

function onBtnDeleteClicked(evt){

        var btnDelete = $(this);

        evt.preventDefault();
        var data = evt.data;
        var token = $.cookie(g_keyToken);
        var params = {};
        params[g_keyActivityId] = data[g_keyActivityId];
        params[g_keyToken] = token;

	try{
		$.ajax({
			type: "PUT",
			url: "/admin/delete",
			data: params,
			success: function(data, status, xhr){
				var buttonsWrap = btnDelete.parent();
				var cell = buttonsWrap.parent();
				btnDelete.remove();
				var indicator = cell.data(g_keyStatusIndicator);
				indicator.text("Deleted");
			},
			error: function(xhr, status, err){

			}
		});
	} catch(err){

	}
}

function listActivitiesAndRefresh() {
	var page = 1;
	listActivities(page, onListActivitiesSuccessAdmin, onListActivitiesErrorAdmin);
}

function onListActivitiesSuccessAdmin(data){
	var jsonResponse = JSON.parse(data);
        if(jsonResponse == null) return;

        var pageSt = parseInt(jsonResponse[g_keyPageSt]);
        var pageEd = parseInt(jsonResponse[g_keyPageEd]);
        var page = pageSt;

        var activitiesJson = jsonResponse[g_keyActivities];
        var length = Object.keys(activitiesJson).length;

        g_pager.screen.empty();
        var activities = [];
        for(var idx = 1; idx <= length; ++idx) {
                var activityJson = activitiesJson[idx - 1];
                var activity = new Activity(activityJson);
                activities.push(activity);
                if (page == g_pager.page) {
                        generateActivityCellForAdmin(g_pager.screen, activity);
                }

                if (idx % g_pager.nItems != 0) continue;
                g_pager.cache.putPage(page, activities);
                activities = [];
                ++page;
        }
        if (activities != null && activities.length > 0) {
                // for the last page
                g_pager.cache.putPage(page, activities);
        }

        g_pager.refreshBar();
}

function onListActivitiesErrorAdmin(error){

}

// Generators
function generateActivityCellForAdmin(par, activity){

	var arrayStatusName = ['created','pending','rejected','accepted','expired'];

        var coverImageUrl = null;

        if(activity.images != null) {
            for(var key in activity.images){
               var image = activity.images[key];
               coverImageUrl = image.url;
               break;
            }
        }

	var ret = $('
', {
		style: "display: block"
	}).appendTo(par);

	var infoWrap = $('', {
		style: "margin-left: 5pt; display: inline-block;"
	}).appendTo(ret);

	if(coverImageUrl != null){
		var coverImage = $('', {
			class: "cell-cover",
			src: coverImageUrl
		}).appendTo(infoWrap);
	}

	var cellActivityTitle = $('<plaintext>', {
		style: "color: black: font-size: 15pt",
		text: activity.title
	}).appendTo(infoWrap);

	var cellActivityContent = $('<plaintext>', {
		style: "color: black; font-size: 15pt",
		text: activity.content
	}).appendTo(infoWrap);

	var statusIndicator = $('', {
		style: "color: red; font-size: 15pt; margin-left: 5pt; display: inline-block",
		text: arrayStatusName[parseInt(activity.status)]
	}).appendTo(ret);

	ret.data(g_keyStatusIndicator, statusIndicator);

	var buttonsWrap = $('', {
		style: "margin-left: 5pt; display: inline-block"
	}).appendTo(ret);

	// this condition is temporarily hard-coded
	if(activity.status != g_statusAccepted){
            var btnAccept = $('<button>', {
		style: " width: 64pt; height: 36pt; font-size: 16pt; color: DarkSlateBlue; margin-left: 5pt; background-color: #aaaaaa;",
                text: 'Accept'
            }).appendTo(buttonsWrap);
            var dAccept = {};
            dAccept[g_keyActivityId] = activity.id;
            btnAccept.click(dAccept, onBtnAcceptClicked);
        }

	if(activity.status != g_statusRejected){
            var btnReject = $('<button>', {
		style: " width: 64pt; height: 36pt; font-size: 16pt; color: purple; margin-left: 5pt; background-color: #aaaaaa;",
                text: 'Reject'
            }).appendTo(buttonsWrap);
            var dReject = {};
            dReject[g_keyActivityId] = activity.id;
            btnReject.click(dReject, onBtnRejectClicked);
        }

	var btnDelete = $('<button>', {
		style: " width: 64pt; height: 36pt; font-size: 16pt; color: IndianRed; margin-left: 5pt; background-color: #aaaaaa;",
		text: 'Delete'
	}).appendTo(buttonsWrap);
	var dDelete = {};
	dDelete[g_keyActivityId] = activity.id;
	btnDelete.click(dDelete, onBtnDeleteClicked);

	var hr = $('
', {
		style: "height: 1pt; color: black; background-color: black"
	}).appendTo(ret);
	return ret;
}

$(document).ready(function(){

	initTopbar($("#topbar"));
	initActivityEditor($("#wrap"), null);

	g_onLoginSuccess = listActivitiesAndRefresh;
	g_onLoginError = null;
	g_onEnter = listActivitiesAndRefresh;

	var selector = createSelector($("#pager-filters"), ["pending", "accepted", "rejected"], [g_statusPending, g_statusAccepted, g_statusRejected], null, null, null, null);
	var filter = new PagerFilter(g_keyStatus, selector);
	var filters = [filter];

	var pagerCache = new PagerCache(10);

	// initialize pager widgets
	g_pager = new Pager($("#pager-screen-activities"), $("#pager-bar-activities"), g_numItemsPerPage, "/activity/list", generateActivitiesListParams, pagerCache, filters, onListActivitiesSuccessAdmin, onListActivitiesErrorAdmin);

	checkLoginStatus();
});
<commit_msg>Fixed admin page.<commit_after>var g_keyStatusIndicator = "status-indicator";

// Assistant Handlers
function onBtnAcceptClicked(evt){

	var btnAccept = $(this);

	evt.preventDefault();
	var data = evt.data;
	var token = $.cookie(g_keyToken);
	var params = {};
 	params[g_keyActivityId] = data[g_keyActivityId];
	params[g_keyToken] = token;

	$.ajax({
		type: "PUT",
		url: "/admin/accept",
		data: params,
		success: function(data, status, xhr) {
			var buttonsWrap = btnAccept.parent();
			var cell = buttonsWrap.parent();
			btnAccept.remove();
			var indicator = cell.data(g_keyStatusIndicator);
			indicator.text("Accepted");
		},
		error: function(xhr, status, err) {

		}
	});
}

function onBtnRejectClicked(evt){
	var btnReject = $(this);

	evt.preventDefault();
	var data = evt.data;
	var token = $.cookie(g_keyToken);
	var params = {};
 	params[g_keyActivityId] = data[g_keyActivityId];
	params[g_keyToken] = token;

	try{
		$.ajax({
			type: "PUT",
			url: "/admin/reject",
			data: params,
			success: function(data, status, xhr){
				var buttonsWrap = btnReject.parent();
				var cell = buttonsWrap.parent();
				btnReject.remove();
				var indicator = cell.data(g_keyStatusIndicator);
				indicator.text("Rejected");
			},
			error: function(xhr, status, err){

			}
		});
	} catch(err){

	}
}

function onBtnDeleteClicked(evt){

        var btnDelete = $(this);

        evt.preventDefault();
        var data = evt.data;
        var token = $.cookie(g_keyToken);
        var params = {};
        params[g_keyActivityId] = data[g_keyActivityId];
        params[g_keyToken] = token;

	try{
		$.ajax({
			type: "PUT",
			url: "/admin/delete",
			data: params,
			success: function(data, status, xhr){
				var buttonsWrap = btnDelete.parent();
				var cell = buttonsWrap.parent();
				btnDelete.remove();
				var indicator = cell.data(g_keyStatusIndicator);
				indicator.text("Deleted");
			},
			error: function(xhr, status, err){

			}
		});
	} catch(err){

	}
}

function listActivitiesAndRefresh() {
	var page = 1;
	listActivities(page, onListActivitiesSuccessAdmin, onListActivitiesErrorAdmin);
}

function onListActivitiesSuccessAdmin(data){
	var jsonResponse = JSON.parse(data);
        if(jsonResponse == null) return;

        var pageSt = parseInt(jsonResponse[g_keyPageSt]);
        var pageEd = parseInt(jsonResponse[g_keyPageEd]);
        var page = pageSt;

        var activitiesJson = jsonResponse[g_keyActivities];
        var length = Object.keys(activitiesJson).length;

        g_pager.screen.empty();
        var activities = [];
        for(var idx = 1; idx <= length; ++idx) {
                var activityJson = activitiesJson[idx - 1];
                var activity = new Activity(activityJson);
                activities.push(activity);
                if (page == g_pager.page) {
                        generateActivityCellForAdmin(g_pager.screen, activity);
                }

                if (idx % g_pager.nItems != 0) continue;
                g_pager.cache.putPage(page, activities);
                activities = [];
                ++page;
        }
        if (activities != null && activities.length > 0) {
                // for the last page
                g_pager.cache.putPage(page, activities);
        }

        g_pager.refreshBar();
}

function onListActivitiesErrorAdmin(error){

}

// Generators
function generateActivityCellForAdmin(par, activity){

	var arrayStatusName = ['created','pending','rejected','accepted','expired'];

        var coverImageUrl = null;

        if(activity.images != null) {
            for(var key in activity.images){
               var image = activity.images[key];
               coverImageUrl = image.url;
               break;
            }
        }

	var ret = $('
', {
		style: "display: block"
	}).appendTo(par);

	var infoWrap = $('', {
		style: "margin-left: 5pt; display: inline-block;"
	}).appendTo(ret);

	if(coverImageUrl != null){
		var coverImage = $('', {
			class: "cell-cover",
			src: coverImageUrl
		}).appendTo(infoWrap);
	}

	var cellActivityTitle = $('<plaintext>', {
		style: "color: black: font-size: 15pt",
		text: activity.title
	}).appendTo(infoWrap);

	var cellActivityContent = $('<plaintext>', {
		style: "color: black; font-size: 15pt",
		text: activity.content
	}).appendTo(infoWrap);

	var statusIndicator = $('', {
		style: "color: red; font-size: 15pt; margin-left: 5pt; display: inline-block",
		text: arrayStatusName[parseInt(activity.status)]
	}).appendTo(ret);

	ret.data(g_keyStatusIndicator, statusIndicator);

	var buttonsWrap = $('', {
		style: "margin-left: 5pt; display: inline-block"
	}).appendTo(ret);

	// this condition is temporarily hard-coded
	if(activity.status != g_statusAccepted){
            var btnAccept = $('<button>', {
		style: " width: 64pt; height: 36pt; font-size: 16pt; color: DarkSlateBlue; margin-left: 5pt; background-color: #aaaaaa;",
                text: 'Accept'
            }).appendTo(buttonsWrap);
            var dAccept = {};
            dAccept[g_keyActivityId] = activity.id;
            btnAccept.click(dAccept, onBtnAcceptClicked);
        }

	if(activity.status != g_statusRejected){
            var btnReject = $('<button>', {
		style: " width: 64pt; height: 36pt; font-size: 16pt; color: purple; margin-left: 5pt; background-color: #aaaaaa;",
                text: 'Reject'
            }).appendTo(buttonsWrap);
            var dReject = {};
            dReject[g_keyActivityId] = activity.id;
            btnReject.click(dReject, onBtnRejectClicked);
        }

	var btnDelete = $('<button>', {
		style: " width: 64pt; height: 36pt; font-size: 16pt; color: IndianRed; margin-left: 5pt; background-color: #aaaaaa;",
		text: 'Delete'
	}).appendTo(buttonsWrap);
	var dDelete = {};
	dDelete[g_keyActivityId] = activity.id;
	btnDelete.click(dDelete, onBtnDeleteClicked);

	var hr = $('
', {
		style: "height: 1pt; color: black; background-color: black"
	}).appendTo(ret);
	return ret;
}

function requestAdmin() {

	var selector = createSelector($("#pager-filters"), ["pending", "accepted", "rejected"], [g_statusPending, g_statusAccepted, g_statusRejected], null, null, null, null);
	var filter = new PagerFilter(g_keyStatus, selector);
	var filters = [filter];

	var pagerCache = new PagerCache(10);

	// initialize pager widgets
	g_pager = new Pager($("#pager-screen-activities"), $("#pager-bar-activities"), g_numItemsPerPage, "/activity/list", generateActivitiesListParams, pagerCache, filters, onListActivitiesSuccessAdmin, onListActivitiesErrorAdmin);

	var onLoginSuccess = function(data) {
		listActivitiesAndRefresh();
	};

	var onLoginError = function(err) {

	};

	var onLogoutSuccess = function(data) {

	};

	var onLogoutError = null;

	g_preLoginForm = generatePreLoginForm(g_sectionLogin, onLoginSuccess, onLoginError, onLogoutSuccess, onLogoutError);

	checkLoginStatus();

}

$(document).ready(function(){

	initTopbar($("#topbar"));
	initActivityEditor($("#wrap"), null);

	requestAdmin();
});
<|endoftext|>


<commit_before>var app = angular.module('timecrunch', ['ui.router']);

app.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
  $stateProvider
    .state('home', {
      url: '/home',
      templateUrl: '/home.html',
      controller: 'DashCtrl'
    })
    .state('food', {
      url: '/food',
      templateUrl: '/food.html',
      controller: 'ListCtrl',
      resolve: {
        foodPromise: ['foods', function(foods) {
            return foods.getFood();
        }]
      }
    })
    .state('recipes', {
      url: '/recipes',
      templateUrl: '/recipes.html',
      controller: 'ListCtrl',
      resolve: {
        recipePromise: ['recipes', function(recipes) {
            return recipes.getAll();
        }]
      }
    })
    .state('recipeform', {
      url: '/recipes/form',
      templateUrl: '/templates/recipeform.html',
      controller: 'ListCtrl'
    })
    .state('recipe', {
      url: '/recipes/{id}',
      templateUrl: '/recipe.html',
      controller: 'RecipesCtrl',
      resolve: {
        recipe: ['$stateParams', 'recipes', function($stateParams, recipes) {
          return recipes.get($stateParams.id);
        }]
      }
    })
    .state('login', {
      url: '/login',
      templateUrl: '/login.html',
      controller: 'AuthCtrl',
      onEnter: ['$state', 'auth', function($state, auth) {
        if(auth.isLoggedIn()) {
          $state.go('home');
        }
      }]
    })
    .state('register', {
      url: '/register',
      templateUrl: '/register.html',
      controller: 'AuthCtrl',
      onEnter: ['$state', 'auth', function($state, auth) {
        if(auth.isLoggedIn()) {
          $state.go('home');
        }
      }]
    });

  $urlRouterProvider.otherwise('home');
}]);

// Factory for auth handling all authorization and
// user id related functions
app.factory('auth', ['$http', '$window', function($http, $window) {
  var auth = {};

  // save given token
  auth.saveToken = function(token) {
    $window.localStorage['time-crunch-token'] = token;
  };

  // get token from localStorage
  auth.getToken = function() {
    return $window.localStorage['time-crunch-token'];
  };

  // register user
  auth.register = function(user) {
    return $http.post('/register', user).then(function(data) {
      auth.saveToken(data.data.token);
    });
  };

  // login user save token
  auth.logIn = function(user) {
    return $http.post('/login', user).then(function(data) {
      auth.saveToken(data.data.token);
    });
  };

  // logout a user and delete token
  auth.logOut = function() {
    $window.localStorage.removeItem('time-crunch-token');
  };

  // check if user is logged in
  auth.isLoggedIn = function() {
    var token = auth.getToken();

    if(token) {
      var payload = JSON.parse($window.atob(token.split('.')[1]));

      return payload.exp > Date.now() / 1000;
    } else {
      return false;
    }
  };

  // returns currently logged in username
  auth.currentUser = function() {
    if(auth.isLoggedIn()) {
      var token = auth.getToken();
      var payload = JSON.parse($window.atob(token.split('.')[1]));

      return payload.username;
      }
    };

  return auth;
}]);

// Factory for foods handling all related functions
app.factory('foods', ['$http', '$state', 'auth', function($http, $state, auth) {
  var o = {
    foods: []
  };

  // Load food list for the current user
  o.getFood = function() {
    if(auth.isLoggedIn()) {
      return $http.get('/food', {
        headers: {Authorization: 'Bearer ' + auth.getToken()}
      }).then(function(data) {
        angular.copy(data.data, o.foods);
      });
    }
    $state.go('login');
  };

  // Add a food to a user's food list
  o.create = function(food) {
    return $http.post('/food', food, {
      headers: {Authorization: 'Bearer ' + auth.getToken()}
    }).then(function(data) {
      o.getFood();
    });
  };

  // Remove a food from a user's food list
  o.delete = function(food) {
    return $http.delete('/food/' + food._id).then(function(data) {
      o.getFood();
    });
  };

  return o;
}]);

// Factory for recipes handling related functions
app.factory('recipes', ['$http', 'auth', function($http, auth) {
  var o = {
    recipes: []
  };

  // Get all recipes
  o.getAll = function() {
    return $http.get('/recipes').then(function(data) {
      angular.copy(data.data, o.recipes);
    });
  };

  // Get a specific recipe
  o.get = function(id) {
    for(i = 0; i < o.recipes.length; ++i) {
      if(o.recipes[i]._id == id) {
        return o.recipes[i];
      }
    }
  };

  // Create a new recipe
  o.create = function(recipe) {
    return $http.post('/recipes', recipe, {
      headers: {Authorization: 'Bearer ' + auth.getToken()}
    }).then(function(data) {
      o.getAll();
    });
  };

  // Delete a recipe
  o.delete = function(recipe) {
    return $http.delete('/recipes/' + recipe._id).then(function(data) {
      o.getAll();
    });
  };

  return o;
}]);

// Controller for dashboard on home/index
app.controller('DashCtrl', [
  '$scope',
  'foods',
  function($scope, foods){
    $scope.foods = foods.foods;
}]);

// Controller for recipe and food lists
app.controller('ListCtrl', [
  '$scope',
  '$state',
  'auth',
  'foods',
  'recipes',
  function($scope, $state, auth, foods, recipes) {

    $scope.foods = foods.foods;
    $scope.recipes = recipes.recipes;
    $scope.ingredients = [];
    $scope.isLoggedIn = auth.isLoggedIn;

    $scope.categories = [
      "Baking",
      "Dairy",
      "Fruit",
      "Herb/Spice",
      "Meat",
      "Sauce",
      "Vegetable",
      "Other-Ingredient",
      "Other-Food",
      "Other-Produce"
    ];

    $scope.sortBy = "name";
    $scope.filterCat = "";

    $scope.filter = function() {
      return function(item) {
        if($scope.filterCat == "" || !$scope.filterCat
          || $scope.filterCat == item.category) {
          return true;
        }
        return false;
      };
    };

    // Add a new food
    $scope.addFood = function() {
      // Make sure food name is valid
      if(!$scope.name || $scope.name == '') {
        alert("Please fill in the name field");
        return;
      }
      // If sell by was left blank, set it to 2 years from now
      if(!$scope.sellBy) {
        $scope.sellBy = new Date();
        $scope.sellBy.setDate($scope.sellBy.getDate() + 730);
      }
      foods.create({
        name: $scope.name,
        sellBy: $scope.sellBy,
        amount: $scope.amount,
        units: $scope.units,
        category: $scope.category
      });
    };

    // Remove a food
    $scope.removeFood = function(food) {
      foods.delete(food);
    };

    // Add a new recipe
    $scope.addRecipe = function() {
      //Check that the recipe has a name, ingredients, and instructions
      if(!$scope.name || $scope.name == '' || !$scope.ingredients) {
        alert("Please make sure all fields are filled out");
        return;
      }

      if(!$scope.instructions && !$scope.link) {
        alert("Please provide either instructions or a link to the full recipe");
        return;
      }

      recipes.create({
        name: $scope.name,
        ingredients: $scope.ingredients,
        prepTime: $scope.prepTime,
        link: $scope.link,
        instructions: $scope.instructions
      }).then(function success() {
        // Return to the recipe list
        $state.go('recipes');
      }, function failure(error) {
        // Show error message
        $scope.error = error.data;
      });
    };

    // Add an ingredient to a recipe
    $scope.addIngredient = function() {
      // Build the ingredient string
      var ing = $scope.ing_name.concat(" - " + $scope.ing_amount);
      if($scope.ing_unit) {
        ing = ing.concat(" " + $scope.ing_unit);
      }

      // Check if the ingredient is a duplicate
      if($scope.ingredients.indexOf(ing) > -1) {
        alert("Duplicate ingredients! Please change your entry.");
      }
      else {
        ($scope.ingredients).push(ing);
      }
    };

    // Remove an ingredient from a recipe
    $scope.removeIngredient = function(ingredient) {
      if($scope.ingredients.length == 1) {
        $scope.ingredients = [];
      }
      else {
        var i = $scope.ingredients.indexOf(ingredient);
        $scope.ingredients.splice(i, 1);
      }
    };
}]);

// Controller for recipe details page
app.controller('RecipesCtrl', [
  '$scope',
  '$state',
  'recipe',
  'recipes',
  'auth',
  function($scope, $state, recipe, recipes, auth){
    $scope.recipe = recipe;
    $scope.currentUser = auth.currentUser();

    // Determines if a user is allowed to edit this
    // recipe
    $scope.canEdit = function() {
      return recipe.author == $scope.currentUser;
    }

    // Deletes the recipe
    $scope.deleteRecipe = function() {
      // Make sure user is authorized
      if($scope.canEdit()) {
        recipes.delete(recipe);
        $state.go('recipes');
      }
      else {
        // If not allowed show an alert
        alert('You cannot delete this recipe!');
      }
    }

}]);

// Controller for logging in and registering
app.controller('AuthCtrl', [
  '$scope',
  '$state',
  'auth',
  function($scope, $state, auth) {
    $scope.user = {};

    // Registers a new user
    $scope.register = function() {
      auth.register($scope.user).then(function success() {
        // Go to dashboard once logged in
        $state.go('home');
      }, function failure(error) {
        // Show error message
        $scope.error = error.data;
      });
    };

    // Starts a new login session
    $scope.logIn = function() {
      auth.logIn($scope.user).then(function success() {
        // Go to dashboard once logged in
        $state.go('home');
      }, function failure(error) {
        // Show error message
        $scope.error = error.data;
      });
    };
}]);

// Controller for dashboard on home/index
app.controller('NavCtrl', [
  '$scope',
  'auth',
  function($scope, auth){

    $scope.isLoggedIn = auth.isLoggedIn;
    $scope.currentUser = auth.currentUser;
    $scope.logOut = auth.logOut;
}]);<commit_msg>login state now using new template file<commit_after>var app = angular.module('timecrunch', ['ui.router']);

app.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
  $stateProvider
    .state('home', {
      url: '/home',
      templateUrl: '/home.html',
      controller: 'DashCtrl'
    })
    .state('food', {
      url: '/food',
      templateUrl: '/food.html',
      controller: 'ListCtrl',
      resolve: {
        foodPromise: ['foods', function(foods) {
            return foods.getFood();
        }]
      }
    })
    .state('recipes', {
      url: '/recipes',
      templateUrl: '/recipes.html',
      controller: 'ListCtrl',
      resolve: {
        recipePromise: ['recipes', function(recipes) {
            return recipes.getAll();
        }]
      }
    })
    .state('recipeform', {
      url: '/recipes/form',
      templateUrl: '/templates/recipeform.html',
      controller: 'ListCtrl'
    })
    .state('recipe', {
      url: '/recipes/{id}',
      templateUrl: '/recipe.html',
      controller: 'RecipesCtrl',
      resolve: {
        recipe: ['$stateParams', 'recipes', function($stateParams, recipes) {
          return recipes.get($stateParams.id);
        }]
      }
    })
    .state('login', {
      url: '/login',
      templateUrl: '/templates/login.html',
      controller: 'AuthCtrl',
      onEnter: ['$state', 'auth', function($state, auth) {
        if(auth.isLoggedIn()) {
          $state.go('home');
        }
      }]
    })
    .state('register', {
      url: '/register',
      templateUrl: '/register.html',
      controller: 'AuthCtrl',
      onEnter: ['$state', 'auth', function($state, auth) {
        if(auth.isLoggedIn()) {
          $state.go('home');
        }
      }]
    });

  $urlRouterProvider.otherwise('home');
}]);

// Factory for auth handling all authorization and
// user id related functions
app.factory('auth', ['$http', '$window', function($http, $window) {
  var auth = {};

  // save given token
  auth.saveToken = function(token) {
    $window.localStorage['time-crunch-token'] = token;
  };

  // get token from localStorage
  auth.getToken = function() {
    return $window.localStorage['time-crunch-token'];
  };

  // register user
  auth.register = function(user) {
    return $http.post('/register', user).then(function(data) {
      auth.saveToken(data.data.token);
    });
  };

  // login user save token
  auth.logIn = function(user) {
    return $http.post('/login', user).then(function(data) {
      auth.saveToken(data.data.token);
    });
  };

  // logout a user and delete token
  auth.logOut = function() {
    $window.localStorage.removeItem('time-crunch-token');
  };

  // check if user is logged in
  auth.isLoggedIn = function() {
    var token = auth.getToken();

    if(token) {
      var payload = JSON.parse($window.atob(token.split('.')[1]));

      return payload.exp > Date.now() / 1000;
    } else {
      return false;
    }
  };

  // returns currently logged in username
  auth.currentUser = function() {
    if(auth.isLoggedIn()) {
      var token = auth.getToken();
      var payload = JSON.parse($window.atob(token.split('.')[1]));

      return payload.username;
      }
    };

  return auth;
}]);

// Factory for foods handling all related functions
app.factory('foods', ['$http', '$state', 'auth', function($http, $state, auth) {
  var o = {
    foods: []
  };

  // Load food list for the current user
  o.getFood = function() {
    if(auth.isLoggedIn()) {
      return $http.get('/food', {
        headers: {Authorization: 'Bearer ' + auth.getToken()}
      }).then(function(data) {
        angular.copy(data.data, o.foods);
      });
    }
    $state.go('login');
  };

  // Add a food to a user's food list
  o.create = function(food) {
    return $http.post('/food', food, {
      headers: {Authorization: 'Bearer ' + auth.getToken()}
    }).then(function(data) {
      o.getFood();
    });
  };

  // Remove a food from a user's food list
  o.delete = function(food) {
    return $http.delete('/food/' + food._id).then(function(data) {
      o.getFood();
    });
  };

  return o;
}]);

// Factory for recipes handling related functions
app.factory('recipes', ['$http', 'auth', function($http, auth) {
  var o = {
    recipes: []
  };

  // Get all recipes
  o.getAll = function() {
    return $http.get('/recipes').then(function(data) {
      angular.copy(data.data, o.recipes);
    });
  };

  // Get a specific recipe
  o.get = function(id) {
    for(i = 0; i < o.recipes.length; ++i) {
      if(o.recipes[i]._id == id) {
        return o.recipes[i];
      }
    }
  };

  // Create a new recipe
  o.create = function(recipe) {
    return $http.post('/recipes', recipe, {
      headers: {Authorization: 'Bearer ' + auth.getToken()}
    }).then(function(data) {
      o.getAll();
    });
  };

  // Delete a recipe
  o.delete = function(recipe) {
    return $http.delete('/recipes/' + recipe._id).then(function(data) {
      o.getAll();
    });
  };

  return o;
}]);

// Controller for dashboard on home/index
app.controller('DashCtrl', [
  '$scope',
  'foods',
  function($scope, foods){
    $scope.foods = foods.foods;
}]);

// Controller for recipe and food lists
app.controller('ListCtrl', [
  '$scope',
  '$state',
  'auth',
  'foods',
  'recipes',
  function($scope, $state, auth, foods, recipes) {

    $scope.foods = foods.foods;
    $scope.recipes = recipes.recipes;
    $scope.ingredients = [];
    $scope.isLoggedIn = auth.isLoggedIn;

    $scope.categories = [
      "Baking",
      "Dairy",
      "Fruit",
      "Herb/Spice",
      "Meat",
      "Sauce",
      "Vegetable",
      "Other-Ingredient",
      "Other-Food",
      "Other-Produce"
    ];

    $scope.sortBy = "name";
    $scope.filterCat = "";

    $scope.filter = function() {
      return function(item) {
        if($scope.filterCat == "" || !$scope.filterCat
          || $scope.filterCat == item.category) {
          return true;
        }
        return false;
      };
    };

    // Add a new food
    $scope.addFood = function() {
      // Make sure food name is valid
      if(!$scope.name || $scope.name == '') {
        alert("Please fill in the name field");
        return;
      }
      // If sell by was left blank, set it to 2 years from now
      if(!$scope.sellBy) {
        $scope.sellBy = new Date();
        $scope.sellBy.setDate($scope.sellBy.getDate() + 730);
      }
      foods.create({
        name: $scope.name,
        sellBy: $scope.sellBy,
        amount: $scope.amount,
        units: $scope.units,
        category: $scope.category
      });
    };

    // Remove a food
    $scope.removeFood = function(food) {
      foods.delete(food);
    };

    // Add a new recipe
    $scope.addRecipe = function() {
      //Check that the recipe has a name, ingredients, and instructions
      if(!$scope.name || $scope.name == '' || !$scope.ingredients) {
        alert("Please make sure all fields are filled out");
        return;
      }

      if(!$scope.instructions && !$scope.link) {
        alert("Please provide either instructions or a link to the full recipe");
        return;
      }

      recipes.create({
        name: $scope.name,
        ingredients: $scope.ingredients,
        prepTime: $scope.prepTime,
        link: $scope.link,
        instructions: $scope.instructions
      }).then(function success() {
        // Return to the recipe list
        $state.go('recipes');
      }, function failure(error) {
        // Show error message
        $scope.error = error.data;
      });
    };

    // Add an ingredient to a recipe
    $scope.addIngredient = function() {
      // Build the ingredient string
      var ing = $scope.ing_name.concat(" - " + $scope.ing_amount);
      if($scope.ing_unit) {
        ing = ing.concat(" " + $scope.ing_unit);
      }

      // Check if the ingredient is a duplicate
      if($scope.ingredients.indexOf(ing) > -1) {
        alert("Duplicate ingredients! Please change your entry.");
      }
      else {
        ($scope.ingredients).push(ing);
      }
    };

    // Remove an ingredient from a recipe
    $scope.removeIngredient = function(ingredient) {
      if($scope.ingredients.length == 1) {
        $scope.ingredients = [];
      }
      else {
        var i = $scope.ingredients.indexOf(ingredient);
        $scope.ingredients.splice(i, 1);
      }
    };
}]);

// Controller for recipe details page
app.controller('RecipesCtrl', [
  '$scope',
  '$state',
  'recipe',
  'recipes',
  'auth',
  function($scope, $state, recipe, recipes, auth){
    $scope.recipe = recipe;
    $scope.currentUser = auth.currentUser();

    // Determines if a user is allowed to edit this
    // recipe
    $scope.canEdit = function() {
      return recipe.author == $scope.currentUser;
    }

    // Deletes the recipe
    $scope.deleteRecipe = function() {
      // Make sure user is authorized
      if($scope.canEdit()) {
        recipes.delete(recipe);
        $state.go('recipes');
      }
      else {
        // If not allowed show an alert
        alert('You cannot delete this recipe!');
      }
    }

}]);

// Controller for logging in and registering
app.controller('AuthCtrl', [
  '$scope',
  '$state',
  'auth',
  function($scope, $state, auth) {
    $scope.user = {};

    // Registers a new user
    $scope.register = function() {
      auth.register($scope.user).then(function success() {
        // Go to dashboard once logged in
        $state.go('home');
      }, function failure(error) {
        // Show error message
        $scope.error = error.data;
      });
    };

    // Starts a new login session
    $scope.logIn = function() {
      auth.logIn($scope.user).then(function success() {
        // Go to dashboard once logged in
        $state.go('home');
      }, function failure(error) {
        // Show error message
        $scope.error = error.data;
      });
    };
}]);

// Controller for dashboard on home/index
app.controller('NavCtrl', [
  '$scope',
  'auth',
  function($scope, auth){

    $scope.isLoggedIn = auth.isLoggedIn;
    $scope.currentUser = auth.currentUser;
    $scope.logOut = auth.logOut;
}]);<|endoftext|>


<commit_before>var jws = require('jws');

module.exports.decode = function (jwt) {
  var decoded = jws.decode(jwt, {json: true});
  return decoded && decoded.payload;
};

module.exports.sign = function(payload, secretOrPrivateKey, options) {
  options = options || {};

  var header = {typ: 'JWT', alg: options.algorithm || 'HS256'};

  payload.iat = Math.round(Date.now() / 1000);

  if (options.expiresInMinutes) {
    var ms = options.expiresInMinutes * 60;
    payload.exp = payload.iat + ms;
  }

  if (options.audience)
    payload.aud = options.audience;

  if (options.issuer)
    payload.iss = options.issuer;

  if (options.subject)
    payload.sub = options.subject;

  var signed = jws.sign({header: header, payload: payload, secret: secretOrPrivateKey});

  return signed;
};

module.exports.verify = function(jwtString, secretOrPublicKey, options, callback) {
  if ((typeof options === 'function') && !callback) callback = options;
  if (!options) options = {};

  var parts = jwtString.split('.');
  if (parts.length !== 3)
    return callback(new JsonWebTokenError('jwt malformed'));

  if (parts[2].trim() === '' && secretOrPublicKey)
    return callback(new JsonWebTokenError('jwt signature is required'));

  var valid;
  try {
    valid = jws.verify(jwtString, secretOrPublicKey);
  }
  catch (e) {
    return callback(e);
  }

  if (!valid)
    return callback(new JsonWebTokenError('invalid signature'));

  var payload = this.decode(jwtString);

  if (payload.exp) {
    if (Math.round(Date.now()) / 1000 >= payload.exp)
      return callback(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000)));
  }

  if (options.audience) {
    var audiences = Array.isArray(options.audience)? options.audience : [options.audience];
    if (audiences.indexOf(payload.aud) < 0)
      return callback(new JsonWebTokenError('jwt audience invalid. expected: ' + payload.aud));
  }

  if (options.issuer) {
    if (payload.iss !== options.issuer)
      return callback(new JsonWebTokenError('jwt issuer invalid. expected: ' + payload.iss));
  }

  callback(null, payload);
};

var JsonWebTokenError = module.exports.JsonWebTokenError = function (message, error) {
  Error.call(this, message);
  this.name = 'JsonWebTokenError';
  this.message = message;
  if (error) this.inner = error;
}
JsonWebTokenError.prototype = Object.create(Error.prototype);
JsonWebTokenError.prototype.constructor = JsonWebTokenError;

var TokenExpiredError = module.exports.TokenExpiredError = function (message, expiredAt) {
  JsonWebTokenError.call(this, message);
  this.name = 'TokenExpiredError';
  this.expiredAt = expiredAt;
};
TokenExpiredError.prototype = Object.create(JsonWebTokenError.prototype);
TokenExpiredError.prototype.constructor = TokenExpiredError;
<commit_msg>use math.floor instead of round fixes #17<commit_after>var jws = require('jws');

module.exports.decode = function (jwt) {
  var decoded = jws.decode(jwt, {json: true});
  return decoded && decoded.payload;
};

module.exports.sign = function(payload, secretOrPrivateKey, options) {
  options = options || {};

  var header = {typ: 'JWT', alg: options.algorithm || 'HS256'};

  payload.iat = Math.floor(Date.now() / 1000);

  if (options.expiresInMinutes) {
    var ms = options.expiresInMinutes * 60;
    payload.exp = payload.iat + ms;
  }

  if (options.audience)
    payload.aud = options.audience;

  if (options.issuer)
    payload.iss = options.issuer;

  if (options.subject)
    payload.sub = options.subject;

  var signed = jws.sign({header: header, payload: payload, secret: secretOrPrivateKey});

  return signed;
};

module.exports.verify = function(jwtString, secretOrPublicKey, options, callback) {
  if ((typeof options === 'function') && !callback) callback = options;
  if (!options) options = {};

  var parts = jwtString.split('.');
  if (parts.length !== 3)
    return callback(new JsonWebTokenError('jwt malformed'));

  if (parts[2].trim() === '' && secretOrPublicKey)
    return callback(new JsonWebTokenError('jwt signature is required'));

  var valid;
  try {
    valid = jws.verify(jwtString, secretOrPublicKey);
  }
  catch (e) {
    return callback(e);
  }

  if (!valid)
    return callback(new JsonWebTokenError('invalid signature'));

  var payload = this.decode(jwtString);

  if (payload.exp) {
    if (Math.floor(Date.now()) / 1000 >= payload.exp)
      return callback(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000)));
  }

  if (options.audience) {
    var audiences = Array.isArray(options.audience)? options.audience : [options.audience];
    if (audiences.indexOf(payload.aud) < 0)
      return callback(new JsonWebTokenError('jwt audience invalid. expected: ' + payload.aud));
  }

  if (options.issuer) {
    if (payload.iss !== options.issuer)
      return callback(new JsonWebTokenError('jwt issuer invalid. expected: ' + payload.iss));
  }

  callback(null, payload);
};

var JsonWebTokenError = module.exports.JsonWebTokenError = function (message, error) {
  Error.call(this, message);
  this.name = 'JsonWebTokenError';
  this.message = message;
  if (error) this.inner = error;
}
JsonWebTokenError.prototype = Object.create(Error.prototype);
JsonWebTokenError.prototype.constructor = JsonWebTokenError;

var TokenExpiredError = module.exports.TokenExpiredError = function (message, expiredAt) {
  JsonWebTokenError.call(this, message);
  this.name = 'TokenExpiredError';
  this.expiredAt = expiredAt;
};
TokenExpiredError.prototype = Object.create(JsonWebTokenError.prototype);
TokenExpiredError.prototype.constructor = TokenExpiredError;
<|endoftext|>


<commit_before>require('./_.array.builders');
require('./_.array.selectors');
require('./_.collections.walk');
require('./_.function.arity');
require('./_.function.combinators');
require('./_.function.dispatch');
require('./_.function.iterators');
require('./_.function.predicates');
require('./_.object.builders');
require('./_.object.selectors');
require('./_.util.existential');
require('./_.util.operators');
require('./_.util.strings');
require('./_.util.trampolines');

module.exports = require('lodash');
<commit_msg>create in own context<commit_after>var fs = require('fs');
var vm = require('vm');
var _ = require('lodash').runInContext();

var isAddOnRegEx = _.bindAll(/^_\..+/, 'test');
var context = vm.createContext({_:_});
var rightCurryVm = _.partialRight(vm.runInNewContext, context);
function simpleReadFile(filename) { return fs.readFileSync(filename); }
_(fs.readdirSync(__dirname)).filter(isAddOnRegEx.test).map(simpleReadFile).each(function (code) {
  rightCurryVm(code);
});

module.exports = _;
<|endoftext|>


<commit_before>/**
 * gulp-espower - A gulp plugin to apply espower to target files.
 *
 * https://github.com/twada/gulp-espower
 *
 * Copyright (c) 2013-2014 Takuto Wada
 * Licensed under the MIT license.
 *   https://github.com/twada/gulp-espower/blob/master/LICENSE-MIT
 */
var es = require('event-stream'),
    espowerSourceToSource = require('espower-source');

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

    function instrument(file, cb) {
        if (file.isNull()) {
            cb(null, file); // pass along
        } else if (file.isStream()) {
            cb(new Error('gulp-espower: Streaming not supported'));
        } else {
            file.contents = new Buffer(espowerSourceToSource(file.contents.toString('utf8'), file.path, opt));
            cb(null, file);
        }
    }

    return es.map(instrument);
};
<commit_msg>Rename to espowerSource<commit_after>/**
 * gulp-espower - A gulp plugin to apply espower to target files.
 *
 * https://github.com/twada/gulp-espower
 *
 * Copyright (c) 2013-2014 Takuto Wada
 * Licensed under the MIT license.
 *   https://github.com/twada/gulp-espower/blob/master/LICENSE-MIT
 */
var es = require('event-stream'),
    espowerSource = require('espower-source');

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

    function instrument(file, cb) {
        if (file.isNull()) {
            cb(null, file); // pass along
        } else if (file.isStream()) {
            cb(new Error('gulp-espower: Streaming not supported'));
        } else {
            file.contents = new Buffer(espowerSource(file.contents.toString('utf8'), file.path, opt));
            cb(null, file);
        }
    }

    return es.map(instrument);
};
<|endoftext|>


<commit_before>function str_to_color(str) {
  var total = 0,
      hex,
      leading_zeros = '000000';
  for (var i = 0; i < str.length; i++) {
    total =+ Math.pow(str.charCodeAt(i), 4);
  }

  hex = leading_zeros + total.toString(16);
  return "#" + hex.slice(-6);
}

function format_date(date) {
  return date.getDate() + "/" + (date.getMonth() + 1);
}

function is_other_day(date1, date2) {
  var day = 24 * 60 * 60 * 1000;

  return (date2 - date1) > day;
}

Raphael.fn.commit = function (x, y, radius, author) {
  var color = str_to_color(author),
      radius_growth = radius * 1.5,
      circle = this.circle(x, y, radius).animate({r: radius, fill: color, "opacity": 0.5, stroke: "none"}, 1000, "bounce"),
      author_text = this.text(x, y - 10 - radius_growth, author).hide(),
      commit_size = this.text(x, y, radius).hide()
      elements = [circle, author_text, commit_size];

  var onmouseover = function () {
    circle.animate({r: radius_growth}, 100);
    author_text.show();
    commit_size.show();
  };

  var onmouseout = function () {
    circle.animate({r: radius}, 100);
    author_text.hide();
    commit_size.hide();
  };

  for (var i = 0; i < elements.length; i++) {
    elements[i].node.onmouseover = onmouseover;
    elements[i].node.onmouseout = onmouseout;
  }
};

Raphael.fn.xy_axis = function (x, y, width, height, commits) {
  var axis_color = "#bbd1d9",
      grid_color = "#d8e4eb",
      thickness = 10,
      border = thickness * 4;
      x += border;
      width -= border * 1.5;
      height -= border * 1.5;

  this.rect(x, y, thickness, height).attr({fill: axis_color, stroke: "none"});
  this.rect(x, y + height, width, thickness).attr({fill: axis_color, stroke: "none"});

  // Fills Y Axis
  var y_values = ["100%", "", "80%", "", "60%", "", "40%", "", "20%", "", "0%"],
      num_y_values = y_values.length,
      y_offset = height / num_y_values,
      y_min = y + y_offset/2,
      y_max = y - y_offset/2 + height,
      actual_y = y_min;
  for (var i = 0; i < y_values.length; i++) {
    this.rect(x - thickness, actual_y, width + thickness * 2, 0.5).attr({fill: grid_color, stroke: "none"});
    this.text(x - thickness * 3, actual_y, y_values[i]);
    actual_y += y_offset;
  }

  // Fills X Axis
  var num_commits = Object.keys(commits).length,
      get_commit_x = function (date) {
        var hashes = Object.keys(commits),
            first_commit = commits[hashes[0]],
            last_commit = commits[hashes[hashes.length - 1]],
            first_date = new Date(first_commit.date).getTime(),
            last_date = new Date(last_commit.date).getTime();

        return (function (date) {
          var time = date.getTime(),
              offset = 50;

          return (time - first_date) * ((width - offset * 2) / (last_date - first_date)) + (x + offset);
        });
      }();

  var last_date = null;
  for (hash in commits) {
    var commit = commits[hash],
        commit_y = y_min + (height - y_offset) * (-commit.ratio + 1),
        date = new Date(commit.date);

    this.commit(get_commit_x(date), commit_y, commit.size, commit.author);

    if (is_other_day(last_date, date)) {
      date.setHours(12);
      date.setMinutes(0);
      var commit_x = get_commit_x(date)
      this.rect(commit_x, y, 0.5, height + thickness * 2).attr({fill: grid_color, stroke: "none"});
      this.text(commit_x, y + height + thickness * 3, format_date(date));

      last_date = date;
    }
  }
};

window.onload = function () {
  var paper = Raphael("canvas", 800, 600);
  paper.rect(0, 0, paper.width, paper.height, 10).attr({fill: "#fff", stroke: "none"});

  $.getJSON('/commits', function(paper) {
      return function(commits) {
        paper.xy_axis(10, 10, 800, 600, commits);
      }
  }(paper));
};

<commit_msg>extracting functions and fixing the display of labels for days where there are commits.<commit_after>function str_to_color(str) {
  var total = 0,
      hex,
      leading_zeros = '000000';
  for (var i = 0; i < str.length; i++) {
    total =+ Math.pow(str.charCodeAt(i), 4);
  }

  hex = leading_zeros + total.toString(16);
  return "#" + hex.slice(-6);
}

function format_date(date) {
  return date.getDate() + "/" + (date.getMonth() + 1);
}

function is_other_day(date1, date2) {
    return !(date1.getYear() == date2.getYear() &&
            date1.getMonth() == date2.getMonth() &&
            date1.getDate() == date2.getDate());
}

Raphael.fn.commit = function (x, y, radius, author) {
  var color = str_to_color(author),
      radius_growth = radius * 1.2,
      circle = this.circle(x, y, radius).animate({r: radius, fill: color, opacity: 0.5}, 1000, "bounce"),
      author_text = this.text(x, y - 10 - radius_growth, author).hide(),
      commit_size = this.text(x, y, radius).hide()
      elements = [circle, author_text, commit_size];

  var onmouseover = function () {
    circle.animate({r: radius_growth}, 100);
    author_text.show();
    commit_size.show();
  };

  var onmouseout = function () {
    circle.animate({r: radius}, 100);
    author_text.hide();
    commit_size.hide();
  };

  for (var i = 0; i < elements.length; i++) {
    elements[i].node.onmouseover = onmouseover;
    elements[i].node.onmouseout = onmouseout;
  }
};

Raphael.fn.xy_axis = function(commits) {
  var axis_color = "#bbd1d9",
      grid_color = "#d8e4eb",
      thickness = 10,
      width = this.width,
      height = this.height,
      border = thickness * 4,
      // Refactor these variables below
      x = 10,
      y = 10,
      paper = this,
      num_y_values = 11,
      y_offset = height / num_y_values,
      y_min = y + y_offset/2;

  x += border;
  width -= border * 1.5;
  height -= border * 1.5;

  drawAxes(this);
  drawYLabels(this);
  plotCommits(this);

  function drawAxes(paper) {
      paper.rect(x, y, thickness, height).attr({fill: axis_color, stroke: "none"});
      paper.rect(x, y + height, width, thickness).attr({fill: axis_color, stroke: "none"});
  }

  function drawYLabels(paper) {
      var y_values = ["100%", "", "80%", "", "60%", "", "40%", "", "20%", "", "0%"],
          num_y_values = y_values.length,
          y_offset = height / num_y_values,
          y_min = y + y_offset/2,
          y_max = y - y_offset/2 + height,
          actual_y = y_min;

      for (var i = 0; i < y_values.length; i++) {
          paper.rect(x - thickness, actual_y, width + thickness * 2, 0.5)
               .attr({fill: grid_color, stroke: "none"});
          paper.text(x - thickness * 3, actual_y, y_values[i]);
          actual_y += y_offset;
      }
  }

  function plotCommits(paper) {
      var num_commits = Object.keys(commits).length,
          last_date = null;

      for (hash in commits) {
          var commit = commits[hash],
              commit_y = y_min + (height - y_offset) * (-commit.ratio + 1),
              date = new Date(commit.date);

          paper.commit(get_commit_x(date), commit_y, commit.size, commit.author);

          var createLabelForNewDate = last_date == null || is_other_day(last_date, date);

          if (createLabelForNewDate) {
              date.setHours(12);
              date.setMinutes(0);
              var commit_x = get_commit_x(date);
              paper.rect(commit_x, y, 0.5, height + thickness * 2).attr({fill: grid_color, stroke: "none"});
              paper.text(commit_x, y + height + thickness * 3, format_date(date));

              last_date = date;
          }
      }
  }

  function get_commit_x(date) {
      var hashes = Object.keys(commits),
          first_commit = commits[hashes[0]],
          last_commit = commits[hashes[hashes.length - 1]],
          first_date = new Date(first_commit.date).getTime(),
          last_date = new Date(last_commit.date).getTime(),
          time = date.getTime(),
          offset = 50;

      return (time - first_date) * ((width - offset * 2) / (last_date - first_date)) + (x + offset);
  }
};

window.onload = function () {
  var paper = Raphael("canvas", 800, 600);
  paper.rect(0, 0, paper.width, paper.height).attr({fill: "#fff", stroke: "none"});

  $.getJSON('/commits', function(paper) {
      return function(commits) {
        paper.xy_axis(commits);
      }
  }(paper));
};

<|endoftext|>


<commit_before>/**
 * A Bot for Slack!
 */

/**
 * Define a function for initiating a conversation on installation
 * With custom integrations, we don't have a way to find out who installed us, so we can't message them :(
 */
var runHappening = false
,   runList = [];
// ,   q = require('q')\
//runModel = require('../model/runModel')

function onInstallation(bot, installer) {
    if (installer) {
        bot.startPrivateConversation({user: installer}, function (err, convo) {
            if (err) {
                console.log(err);
            } else {
                convo.say('I am a bot that has just joined your team');
                convo.say('You must now /invite me to a channel so that I can be of use!');
            }
        });
    }
}

/**
 * Configure the persistence options
 */

var config = {};
if (process.env.MONGOLAB_URI) {
    var BotkitStorage = require('botkit-storage-mongo');
    config = {
        storage: BotkitStorage({mongoUri: process.env.MONGOLAB_URI}),
    };
} else {
    config = {
        json_file_store: ((process.env.TOKEN)?'./db_slack_bot_ci/':'./db_slack_bot_a/'), //use a different name if an app or CI
    };
}

/**
 * Are being run as an app or a custom integration? The initialization will differ, depending
 */

if (process.env.TOKEN || process.env.SLACK_TOKEN) {
    //Treat this as a custom integration
    var customIntegration = require('./lib/custom_integrations');
    var token = (process.env.TOKEN) ? process.env.TOKEN : process.env.SLACK_TOKEN;
    var controller = customIntegration.configure(token, config, onInstallation);
} else if (process.env.CLIENT_ID && process.env.CLIENT_SECRET && process.env.PORT) {
    //Treat this as an app
    var app = require('./lib/apps');
    var controller = app.configure(process.env.PORT, process.env.CLIENT_ID, process.env.CLIENT_SECRET, config, onInstallation);
} else {
    console.log('Error: If this is a custom integration, please specify TOKEN in the environment. If this is an app, please specify CLIENTID, CLIENTSECRET, and PORT in the environment');
    process.exit(1);
}

/**
 * A demonstration for how to handle websocket events. In this case, just log when we have and have not
 * been disconnected from the websocket. In the future, it would be super awesome to be able to specify
 * a reconnect policy, and do reconnections automatically. In the meantime, we aren't going to attempt reconnects,
 * WHICH IS A B0RKED WAY TO HANDLE BEING DISCONNECTED. So we need to fix this.
 *
 * TODO: fixed b0rked reconnect behavior
 */
// Handle events related to the websocket connection to Slack
controller.on('rtm_open', function (bot) {
    console.log('** The RTM api just connected!');
});

controller.on('rtm_close', function (bot) {
    console.log('** The RTM api just closed');
    // you may want to attempt to re-open
});

/**
 * Core bot logic goes here!
 */
// BEGIN EDITING HERE!

controller.on('bot_channel_join', function (bot, message) {
    bot.reply(message, "I'm here!")
});

controller.hears('hello', 'direct_message', function (bot, message) {
    bot.reply(message, 'Hello!');
});

controller.hears('lunch run', 'direct_message, direct_mention', function(bot, message) {

        bot.startConversation(message, function(err,convo) {

            convo.say('Oooh! I LOVE Pop-a-Top!');
            convo.ask('Would you like me to see if anyone else wants something?', [{
                pattern: bot.utterances.yes,
                callback: function(response, convo){
                    convo.say('Okay! What a sweetheart you are. :heart:');
                    convo.next();
                }
            },
            {
                pattern: bot.utterances.no,
                callback: function(response, convo){
                    convo.say('Alright! Well thanks for letting me know. :grin:');
                    convo.next();
                }
            }
        ]);
    });
});

controller.hears('start', 'direct_mention', function(bot, message) {

    if (runHappening) {
        return bot.reply(message, 'Already gathering requests for a run in' + runChannel);
    }

   /* if (!runModel.getSummaryChannel()) {
        runModel.setSummaryChannel(message.channel);
    }*/
    runChannel = message.channel;

    //No other users on team
    /*if (usersModel.list().length === 0) {
        return bot.reply(message, 'Looks like everyone is right here bud... Add some people to your team and we will talk.');
    }*/

    bot.reply(message, 'Holy La Croix! <@' + message.user + '> is going for a Pop-a-Top run. Who <@here> has a request? Tell me what you want and I will let them know!');
    runHappening = true;
    console.log('runHappening =' + runHappening);

    /*//notify first user and start a conversation
    userIterator = usersModel.iterator();
    currentUser = userIterator.next();
    promptUser(bot);*/

});

controller.hears('end', 'direct_mention', function(bot, message) {
    if (!runHappening) {
        return bot.reply(message, 'Nobody is on a run right now. Start a new run with `start`');
    }

    runHappening = false;

    bot.reply(message, 'The run is now over!');
    console.log('runHappening =' + runHappening);

    bot.startConversation(message, function(err,convo){
        convo.ask('<@' + message.user + '> want to see the list?', [{
            pattern: bot.utterances.yes,
            callback: function(response, convo) {
                bot.reply(message, runList);
                // return summarizeRun(bot);
            }
        }, {
            pattern: bot.utterances.no,
            callback: function(response,convo) {
                bot.say({channel: message.channel, text: 'Okey Dokey. That was fun, see you later!'});
                runModel.clearStatuses();
                convo.next();
            }
        }]);
    });
});

controller.hears('(.*)', 'direct_mention, direct_message', function(bot, message) {
    if (runHappening) {
        gatherRequest(bot, message);
    }
});

function gatherRequest(bot, message) {
    console.log(message);
    bot.reply(message, 'Got it! Thanks ' + message.user);
    runList.push({user: message.user, request: message.text});
    console.log('Pushing request to runList');

   /* runModel.addRequest({
        request: message.text,
        user: message.user
    });
    */

}

<commit_msg>added logging for the utterance handling when ending run<commit_after>/**
 * A Bot for Slack!
 */

/**
 * Define a function for initiating a conversation on installation
 * With custom integrations, we don't have a way to find out who installed us, so we can't message them :(
 */
var runHappening = false
,   runList = [];
// ,   q = require('q')\
//runModel = require('../model/runModel')

function onInstallation(bot, installer) {
    if (installer) {
        bot.startPrivateConversation({user: installer}, function (err, convo) {
            if (err) {
                console.log(err);
            } else {
                convo.say('I am a bot that has just joined your team');
                convo.say('You must now /invite me to a channel so that I can be of use!');
            }
        });
    }
}

/**
 * Configure the persistence options
 */

var config = {};
if (process.env.MONGOLAB_URI) {
    var BotkitStorage = require('botkit-storage-mongo');
    config = {
        storage: BotkitStorage({mongoUri: process.env.MONGOLAB_URI}),
    };
} else {
    config = {
        json_file_store: ((process.env.TOKEN)?'./db_slack_bot_ci/':'./db_slack_bot_a/'), //use a different name if an app or CI
    };
}

/**
 * Are being run as an app or a custom integration? The initialization will differ, depending
 */

if (process.env.TOKEN || process.env.SLACK_TOKEN) {
    //Treat this as a custom integration
    var customIntegration = require('./lib/custom_integrations');
    var token = (process.env.TOKEN) ? process.env.TOKEN : process.env.SLACK_TOKEN;
    var controller = customIntegration.configure(token, config, onInstallation);
} else if (process.env.CLIENT_ID && process.env.CLIENT_SECRET && process.env.PORT) {
    //Treat this as an app
    var app = require('./lib/apps');
    var controller = app.configure(process.env.PORT, process.env.CLIENT_ID, process.env.CLIENT_SECRET, config, onInstallation);
} else {
    console.log('Error: If this is a custom integration, please specify TOKEN in the environment. If this is an app, please specify CLIENTID, CLIENTSECRET, and PORT in the environment');
    process.exit(1);
}

/**
 * A demonstration for how to handle websocket events. In this case, just log when we have and have not
 * been disconnected from the websocket. In the future, it would be super awesome to be able to specify
 * a reconnect policy, and do reconnections automatically. In the meantime, we aren't going to attempt reconnects,
 * WHICH IS A B0RKED WAY TO HANDLE BEING DISCONNECTED. So we need to fix this.
 *
 * TODO: fixed b0rked reconnect behavior
 */
// Handle events related to the websocket connection to Slack
controller.on('rtm_open', function (bot) {
    console.log('** The RTM api just connected!');
});

controller.on('rtm_close', function (bot) {
    console.log('** The RTM api just closed');
    // you may want to attempt to re-open
});

/**
 * Core bot logic goes here!
 */
// BEGIN EDITING HERE!

controller.on('bot_channel_join', function (bot, message) {
    bot.reply(message, "I'm here!")
});

controller.hears('hello', 'direct_message', function (bot, message) {
    bot.reply(message, 'Hello!');
});

controller.hears('lunch run', 'direct_message, direct_mention', function(bot, message) {

        bot.startConversation(message, function(err,convo) {

            convo.say('Oooh! I LOVE Pop-a-Top!');
            convo.ask('Would you like me to see if anyone else wants something?', [{
                pattern: bot.utterances.yes,
                callback: function(response, convo){
                    convo.say('Okay! What a sweetheart you are. :heart:');
                    convo.next();
                }
            },
            {
                pattern: bot.utterances.no,
                callback: function(response, convo){
                    convo.say('Alright! Well thanks for letting me know. :grin:');
                    convo.next();
                }
            }
        ]);
    });
});

controller.hears('start', 'direct_mention', function(bot, message) {

    if (runHappening) {
        return bot.reply(message, 'Already gathering requests for a run in' + runChannel);
    }

   /* if (!runModel.getSummaryChannel()) {
        runModel.setSummaryChannel(message.channel);
    }*/
    runChannel = message.channel;

    //No other users on team
    /*if (usersModel.list().length === 0) {
        return bot.reply(message, 'Looks like everyone is right here bud... Add some people to your team and we will talk.');
    }*/

    bot.reply(message, 'Holy La Croix! <@' + message.user + '> is going for a Pop-a-Top run. Who <@here> has a request? Tell me what you want and I will let them know!');
    runHappening = true;
    console.log('runHappening =' + runHappening);

    /*//notify first user and start a conversation
    userIterator = usersModel.iterator();
    currentUser = userIterator.next();
    promptUser(bot);*/

});

controller.hears('end', 'direct_mention', function(bot, message) {
    if (!runHappening) {
        return bot.reply(message, 'Nobody is on a run right now. Start a new run with `start`');
    }

    runHappening = false;

    bot.reply(message, 'The run is now over!');
    console.log('runHappening = ' + runHappening);
    console.log(runList);
    bot.startConversation(message, function(err,convo){
        convo.ask('<@' + message.user + '> want to see the list?', [{
            pattern: bot.utterances.yes,
            callback: function(response, convo) {
                bot.reply(message, runList);
                // return summarizeRun(bot);
                console.log('Heard yes, output runList');
                convo.next();
            }
        }, {
            pattern: bot.utterances.no,
            callback: function(response,convo) {
                bot.say({channel: message.channel, text: 'Okey Dokey. That was fun, see you later!'});
                // runModel.clearStatuses();
                console.log('Heard no')
                convo.next();
            }
        }]);
    });
});

controller.hears('(.*)', 'direct_mention, direct_message', function(bot, message) {
    if (runHappening) {
        gatherRequest(bot, message);
    }
});

function gatherRequest(bot, message) {
    console.log(message);
    bot.reply(message, 'Got it! Thanks ' + message.user);
    runList.push({user: message.user, request: message.text});
    console.log('Pushing request to runList');

   /* runModel.addRequest({
        request: message.text,
        user: message.user
    });
    */

}

<|endoftext|>


<commit_before>/**
 * Openframe plugin which provides a communication channel to the GPIO pins.
 */

// GPIO not available on all devices...
try {
    var gpio = require('onoff').Gpio;
} catch (e) {
    console.error(e);
}

var pjson = require('./package.json'),
    debug = require('debug')('openframe:gpio'),
    extension = module.exports = {};

/**
 * Extension initialization method.
 *
 * Called when the extension (and its dependencies) have been installed.
 *
 * @param  {object} OF An interface provided to extensions giving limitted access to the frame environment
 */
extension.init = function(OF) {
    // do your extension thing
    debug('=======>   Openframe-GPIO initialized!   <=======');
    /**
     * Extensions also have access to the global event system
     */
    var pubsub = OF.getPubsub();

    /**
     * Extensions also have access to the Swagger REST client (https://github.com/swagger-api/swagger-js)
     * See openframe.io/explorer for API docs, or openframe.io/explorer/swagger.json for the swagger definition
     * which shows the available methods as 'operationId'
     */
    var rest = OF.getRest();

    /**
     * Reference to the frame model wrapper, allowing plugin to update frame data.
     * (frame.state is the model data)
     */
    var frame = OF.getFrame();

    if (!gpio) {
        console.error('\n!!!\nGPIO Not available... is this an RPi?\n!!!\n');
        return;
    }

    var button = new gpio(17, 'in', 'both');

    var fetching = false;
    button.watch(function(err, state) {
        if (err) console.log(err);
        console.log(state);
        if (state === 1 && !fetching) {
            getRandomFromCollection();
        }
        // pubsub.publish('/openframe-gpio/17', state);
    });

    function getRandomFromCollection() {
        fetching = true;
        // get the logged-in user's primary collection
        rest.OpenframeUser.OpenframeUser_prototype_primary_collection({
            id: 'current'
        }).then(function(data) {
            var artworkList = data.collection.artwork,
                len = artworkList.length,
                randomIdx = getRandomInt(0, len-1),
                randomArtwork = artworkList(randomIdx);

            frame.state._current_artwork = randomArtwork;
            frame.save().then(function() {
                fetching = false;
            });
        });
    }

    function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min)) + min;
    }

};<commit_msg>add logging for debug<commit_after>/**
 * Openframe plugin which provides a communication channel to the GPIO pins.
 */

// GPIO not available on all devices...
try {
    var gpio = require('onoff').Gpio;
} catch (e) {
    console.error(e);
}

var pjson = require('./package.json'),
    debug = require('debug')('openframe:gpio'),
    extension = module.exports = {};

/**
 * Extension initialization method.
 *
 * Called when the extension (and its dependencies) have been installed.
 *
 * @param  {object} OF An interface provided to extensions giving limitted access to the frame environment
 */
extension.init = function(OF) {
    // do your extension thing
    debug('=======>   Openframe-GPIO initialized!   <=======');
    /**
     * Extensions also have access to the global event system
     */
    var pubsub = OF.getPubsub();

    /**
     * Extensions also have access to the Swagger REST client (https://github.com/swagger-api/swagger-js)
     * See openframe.io/explorer for API docs, or openframe.io/explorer/swagger.json for the swagger definition
     * which shows the available methods as 'operationId'
     */
    var rest = OF.getRest();

    /**
     * Reference to the frame model wrapper, allowing plugin to update frame data.
     * (frame.state is the model data)
     */
    var frame = OF.getFrame();

    if (!gpio) {
        console.error('\n!!!\nGPIO Not available... is this an RPi?\n!!!\n');
        return;
    }

    var button = new gpio(17, 'in', 'both');

    var fetching = false;
    button.watch(function(err, state) {
        if (err) console.log(err);
        console.log(state);
        if (state === 1 && !fetching) {
            getRandomFromCollection();
        }
        // pubsub.publish('/openframe-gpio/17', state);
    });

    function getRandomFromCollection() {
        fetching = true;
        // get the logged-in user's primary collection
        rest.OpenframeUser.OpenframeUser_prototype_primary_collection({
            id: 'current'
        }).then(function(data) {
            var artworkList = data.collection.artwork,
                len = artworkList.length,
                randomIdx = getRandomInt(0, len-1),
                randomArtwork = artworkList(randomIdx);

            debug(randomArtwork);
            frame.state._current_artwork = randomArtwork;
            frame.save()
                .then(function() {
                    debug('Success...');
                    fetching = false;
                })
                .catch(function(err) {
                    debug('ERROR: ', err);
                });
        });
    }

    function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min)) + min;
    }

};<|endoftext|>


<commit_before>var url = require("url");
var assert = require("assert");
var http = require("http");
var https = require("https");
var Writable = require("stream").Writable;
var debug = require("debug")("follow-redirects");

var nativeProtocols = { "http:": http, "https:": https };
var schemes = {};
var exports = module.exports = {
  maxRedirects: 21,
};
// RFC7231§4.2.1: Of the request methods defined by this specification,
// the GET, HEAD, OPTIONS, and TRACE methods are defined to be safe.
var safeMethods = { GET: true, HEAD: true, OPTIONS: true, TRACE: true };

// Create handlers that pass events from native requests
var eventHandlers = Object.create(null);
["abort", "aborted", "error", "socket"].forEach(function (event) {
  eventHandlers[event] = function (arg) {
    this._redirectable.emit(event, arg);
  };
});

// An HTTP(S) request that can be redirected
function RedirectableRequest(options, responseCallback) {
  // Initialize the request
  Writable.call(this);
  this._options = options;
  this._redirectCount = 0;
  this._bufferedWrites = [];

  // Attach a callback if passed
  if (responseCallback) {
    this.on("response", responseCallback);
  }

  // React to responses of native requests
  var self = this;
  this._onNativeResponse = function (response) {
    self._processResponse(response);
  };

  // Complete the URL object when necessary
  if (!options.pathname && options.path) {
    var searchPos = options.path.indexOf("?");
    if (searchPos < 0) {
      options.pathname = options.path;
    }
    else {
      options.pathname = options.path.substring(0, searchPos);
      options.search = options.path.substring(searchPos);
    }
  }

  // Perform the first request
  this._performRequest();
}
RedirectableRequest.prototype = Object.create(Writable.prototype);

// Executes the next native request (initial or redirect)
RedirectableRequest.prototype._performRequest = function () {
  // If specified, use the agent corresponding to the protocol
  // (HTTP and HTTPS use different types of agents)
  var protocol = this._options.protocol;
  if (this._options.agents) {
    this._options.agent = this._options.agents[schemes[protocol]];
  }

  // Create the native request
  var nativeProtocol = nativeProtocols[protocol];
  var request = this._currentRequest =
        nativeProtocol.request(this._options, this._onNativeResponse);
  this._currentUrl = url.format(this._options);

  // Set up event handlers
  request._redirectable = this;
  for (var event in eventHandlers) {
    /* istanbul ignore else */
    if (event) {
      request.on(event, eventHandlers[event]);
    }
  }

  // End a redirected request
  // (The first request must be ended explicitly with RedirectableRequest#end)
  if (this._isRedirect) {
    // If the request doesn't have en entity, end directly.
    var bufferedWrites = this._bufferedWrites;
    if (bufferedWrites.length === 0) {
      request.end();
    // Otherwise, write the request entity and end afterwards.
    }
    else {
      var i = 0;
      (function writeNext() {
        if (i < bufferedWrites.length) {
          var bufferedWrite = bufferedWrites[i++];
          request.write(bufferedWrite.data, bufferedWrite.encoding, writeNext);
        }
        else {
          request.end();
        }
      }());
    }
  }
};

// Processes a response from the current native request
RedirectableRequest.prototype._processResponse = function (response) {
  // RFC7231§6.4: The 3xx (Redirection) class of status code indicates
  // that further action needs to be taken by the user agent in order to
  // fulfill the request. If a Location header field is provided,
  // the user agent MAY automatically redirect its request to the URI
  // referenced by the Location field value,
  // even if the specific status code is not understood.
  var location = response.headers.location;
  if (location && this._options.followRedirects !== false &&
      response.statusCode >= 300 && response.statusCode < 400) {
    // RFC7231§6.4: A client SHOULD detect and intervene
    // in cyclical redirections (i.e., "infinite" redirection loops).
    if (++this._redirectCount > this._options.maxRedirects) {
      this.emit("error", new Error("Max redirects exceeded."));
      return;
    }

    // RFC7231§6.4: Automatic redirection needs to done with
    // care for methods not known to be safe […],
    // since the user might not wish to redirect an unsafe request.
    // RFC7231§6.4.7: The 307 (Temporary Redirect) status code indicates
    // that the target resource resides temporarily under a different URI
    // and the user agent MUST NOT change the request method
    // if it performs an automatic redirection to that URI.
    var header;
    var headers = this._options.headers;
    if (response.statusCode !== 307 && !(this._options.method in safeMethods)) {
      this._options.method = "GET";
      // Drop a possible entity and headers related to it
      this._bufferedWrites = [];
      for (header in headers) {
        if (/^content-/i.test(header)) {
          delete headers[header];
        }
      }
    }

    // Drop the Host header, as the redirect might lead to a different host
    if (!this._isRedirect) {
      for (header in headers) {
        if (/^host$/i.test(header)) {
          delete headers[header];
        }
      }
    }

    // Perform the redirected request
    var redirectUrl = url.resolve(this._currentUrl, location);
    debug("redirecting to", redirectUrl);
    Object.assign(this._options, url.parse(redirectUrl));
    this._isRedirect = true;
    this._performRequest();
  }
  else {
    // The response is not a redirect; return it as-is
    response.responseUrl = this._currentUrl;
    this.emit("response", response);

    // Clean up
    delete this._options;
    delete this._bufferedWrites;
  }
};

// Aborts the current native request
RedirectableRequest.prototype.abort = function () {
  this._currentRequest.abort();
};

// Flushes the headers of the current native request
RedirectableRequest.prototype.flushHeaders = function () {
  this._currentRequest.flushHeaders();
};

// Sets the noDelay option of the current native request
RedirectableRequest.prototype.setNoDelay = function (noDelay) {
  this._currentRequest.setNoDelay(noDelay);
};

// Sets the socketKeepAlive option of the current native request
RedirectableRequest.prototype.setSocketKeepAlive = function (enable, initialDelay) {
  this._currentRequest.setSocketKeepAlive(enable, initialDelay);
};

// Sets the timeout option of the current native request
RedirectableRequest.prototype.setTimeout = function (timeout, callback) {
  this._currentRequest.setTimeout(timeout, callback);
};

// Writes buffered data to the current native request
RedirectableRequest.prototype.write = function (data, encoding, callback) {
  this._currentRequest.write(data, encoding, callback);
  this._bufferedWrites.push({ data: data, encoding: encoding });
};

// Ends the current native request
RedirectableRequest.prototype.end = function (data, encoding, callback) {
  this._currentRequest.end(data, encoding, callback);
  if (data) {
    this._bufferedWrites.push({ data: data, encoding: encoding });
  }
};

// Export a redirecting wrapper for each native protocol
Object.keys(nativeProtocols).forEach(function (protocol) {
  var scheme = schemes[protocol] = protocol.substr(0, protocol.length - 1);
  var nativeProtocol = nativeProtocols[protocol];
  var wrappedProtocol = exports[scheme] = Object.create(nativeProtocol);

  // Executes an HTTP request, following redirects
  wrappedProtocol.request = function (options, callback) {
    if (typeof options === "string") {
      options = url.parse(options);
      options.maxRedirects = exports.maxRedirects;
    }
    else {
      options = Object.assign({
        maxRedirects: exports.maxRedirects,
        protocol: protocol,
      }, options);
    }
    assert.equal(options.protocol, protocol, "protocol mismatch");
    debug("options", options);

    return new RedirectableRequest(options, callback);
  };

  // Executes a GET request, following redirects
  wrappedProtocol.get = function (options, callback) {
    var request = wrappedProtocol.request(options, callback);
    request.end();
    return request;
  };
});
<commit_msg>Include timeout event.<commit_after>var url = require("url");
var assert = require("assert");
var http = require("http");
var https = require("https");
var Writable = require("stream").Writable;
var debug = require("debug")("follow-redirects");

var nativeProtocols = { "http:": http, "https:": https };
var schemes = {};
var exports = module.exports = {
  maxRedirects: 21,
};
// RFC7231§4.2.1: Of the request methods defined by this specification,
// the GET, HEAD, OPTIONS, and TRACE methods are defined to be safe.
var safeMethods = { GET: true, HEAD: true, OPTIONS: true, TRACE: true };

// Create handlers that pass events from native requests
var eventHandlers = Object.create(null);
["abort", "aborted", "error", "socket", "timeout"].forEach(function (event) {
  eventHandlers[event] = function (arg) {
    this._redirectable.emit(event, arg);
  };
});

// An HTTP(S) request that can be redirected
function RedirectableRequest(options, responseCallback) {
  // Initialize the request
  Writable.call(this);
  this._options = options;
  this._redirectCount = 0;
  this._bufferedWrites = [];

  // Attach a callback if passed
  if (responseCallback) {
    this.on("response", responseCallback);
  }

  // React to responses of native requests
  var self = this;
  this._onNativeResponse = function (response) {
    self._processResponse(response);
  };

  // Complete the URL object when necessary
  if (!options.pathname && options.path) {
    var searchPos = options.path.indexOf("?");
    if (searchPos < 0) {
      options.pathname = options.path;
    }
    else {
      options.pathname = options.path.substring(0, searchPos);
      options.search = options.path.substring(searchPos);
    }
  }

  // Perform the first request
  this._performRequest();
}
RedirectableRequest.prototype = Object.create(Writable.prototype);

// Executes the next native request (initial or redirect)
RedirectableRequest.prototype._performRequest = function () {
  // If specified, use the agent corresponding to the protocol
  // (HTTP and HTTPS use different types of agents)
  var protocol = this._options.protocol;
  if (this._options.agents) {
    this._options.agent = this._options.agents[schemes[protocol]];
  }

  // Create the native request
  var nativeProtocol = nativeProtocols[protocol];
  var request = this._currentRequest =
        nativeProtocol.request(this._options, this._onNativeResponse);
  this._currentUrl = url.format(this._options);

  // Set up event handlers
  request._redirectable = this;
  for (var event in eventHandlers) {
    /* istanbul ignore else */
    if (event) {
      request.on(event, eventHandlers[event]);
    }
  }

  // End a redirected request
  // (The first request must be ended explicitly with RedirectableRequest#end)
  if (this._isRedirect) {
    // If the request doesn't have en entity, end directly.
    var bufferedWrites = this._bufferedWrites;
    if (bufferedWrites.length === 0) {
      request.end();
    // Otherwise, write the request entity and end afterwards.
    }
    else {
      var i = 0;
      (function writeNext() {
        if (i < bufferedWrites.length) {
          var bufferedWrite = bufferedWrites[i++];
          request.write(bufferedWrite.data, bufferedWrite.encoding, writeNext);
        }
        else {
          request.end();
        }
      }());
    }
  }
};

// Processes a response from the current native request
RedirectableRequest.prototype._processResponse = function (response) {
  // RFC7231§6.4: The 3xx (Redirection) class of status code indicates
  // that further action needs to be taken by the user agent in order to
  // fulfill the request. If a Location header field is provided,
  // the user agent MAY automatically redirect its request to the URI
  // referenced by the Location field value,
  // even if the specific status code is not understood.
  var location = response.headers.location;
  if (location && this._options.followRedirects !== false &&
      response.statusCode >= 300 && response.statusCode < 400) {
    // RFC7231§6.4: A client SHOULD detect and intervene
    // in cyclical redirections (i.e., "infinite" redirection loops).
    if (++this._redirectCount > this._options.maxRedirects) {
      this.emit("error", new Error("Max redirects exceeded."));
      return;
    }

    // RFC7231§6.4: Automatic redirection needs to done with
    // care for methods not known to be safe […],
    // since the user might not wish to redirect an unsafe request.
    // RFC7231§6.4.7: The 307 (Temporary Redirect) status code indicates
    // that the target resource resides temporarily under a different URI
    // and the user agent MUST NOT change the request method
    // if it performs an automatic redirection to that URI.
    var header;
    var headers = this._options.headers;
    if (response.statusCode !== 307 && !(this._options.method in safeMethods)) {
      this._options.method = "GET";
      // Drop a possible entity and headers related to it
      this._bufferedWrites = [];
      for (header in headers) {
        if (/^content-/i.test(header)) {
          delete headers[header];
        }
      }
    }

    // Drop the Host header, as the redirect might lead to a different host
    if (!this._isRedirect) {
      for (header in headers) {
        if (/^host$/i.test(header)) {
          delete headers[header];
        }
      }
    }

    // Perform the redirected request
    var redirectUrl = url.resolve(this._currentUrl, location);
    debug("redirecting to", redirectUrl);
    Object.assign(this._options, url.parse(redirectUrl));
    this._isRedirect = true;
    this._performRequest();
  }
  else {
    // The response is not a redirect; return it as-is
    response.responseUrl = this._currentUrl;
    this.emit("response", response);

    // Clean up
    delete this._options;
    delete this._bufferedWrites;
  }
};

// Aborts the current native request
RedirectableRequest.prototype.abort = function () {
  this._currentRequest.abort();
};

// Flushes the headers of the current native request
RedirectableRequest.prototype.flushHeaders = function () {
  this._currentRequest.flushHeaders();
};

// Sets the noDelay option of the current native request
RedirectableRequest.prototype.setNoDelay = function (noDelay) {
  this._currentRequest.setNoDelay(noDelay);
};

// Sets the socketKeepAlive option of the current native request
RedirectableRequest.prototype.setSocketKeepAlive = function (enable, initialDelay) {
  this._currentRequest.setSocketKeepAlive(enable, initialDelay);
};

// Sets the timeout option of the current native request
RedirectableRequest.prototype.setTimeout = function (timeout, callback) {
  this._currentRequest.setTimeout(timeout, callback);
};

// Writes buffered data to the current native request
RedirectableRequest.prototype.write = function (data, encoding, callback) {
  this._currentRequest.write(data, encoding, callback);
  this._bufferedWrites.push({ data: data, encoding: encoding });
};

// Ends the current native request
RedirectableRequest.prototype.end = function (data, encoding, callback) {
  this._currentRequest.end(data, encoding, callback);
  if (data) {
    this._bufferedWrites.push({ data: data, encoding: encoding });
  }
};

// Export a redirecting wrapper for each native protocol
Object.keys(nativeProtocols).forEach(function (protocol) {
  var scheme = schemes[protocol] = protocol.substr(0, protocol.length - 1);
  var nativeProtocol = nativeProtocols[protocol];
  var wrappedProtocol = exports[scheme] = Object.create(nativeProtocol);

  // Executes an HTTP request, following redirects
  wrappedProtocol.request = function (options, callback) {
    if (typeof options === "string") {
      options = url.parse(options);
      options.maxRedirects = exports.maxRedirects;
    }
    else {
      options = Object.assign({
        maxRedirects: exports.maxRedirects,
        protocol: protocol,
      }, options);
    }
    assert.equal(options.protocol, protocol, "protocol mismatch");
    debug("options", options);

    return new RedirectableRequest(options, callback);
  };

  // Executes a GET request, following redirects
  wrappedProtocol.get = function (options, callback) {
    var request = wrappedProtocol.request(options, callback);
    request.end();
    return request;
  };
});
<|endoftext|>


<commit_before>$(function(){
	$('body').addClass("js-enabled");
	$('#wrapper').tabs();

	/* step link prompts */

	/* get all the sections */
	var sections = $(".tabs-panel"),
		i = sections.length,
		last = $(".tabs-panel:last").attr("id").split("-enhanced")[0],
		j,
		id,
		ul,
		navid,
		sectionTitle,
		nav;

		last = "
No thanks, just tell me how to claim
"

	while(i--){
		j = i+1;
		id = $(sections[j]).attr("id");
		navid = id+"-nav";
		nav = $("

");
		ul = $("

");

		sectionTitle = $("#"+id+" h1").html();

		if(sectionTitle != undefined){
			sectionTitle = sectionTitle.toLowerCase();
			id = id.split("-enhanced")[0];
			var next = ("
Read about "+sectionTitle+" →
");
			if(i == 2){
				$(ul).append(next)
			}
			else{
				$(ul).append(next+last)
			}

			$(sections[i]).find(".inner").append(nav);
			$("#"+navid).append(ul);

			$(".part-pagination a").live("click", function(){
			  if($(window.location.hash+"-enhanced").length != 0){
			    $(window).scrollTop( $(window.location.hash+"-enhanced").offset().top );
		    }
			});
		}
	}

});<commit_msg>Removed arrow that is nasty for screenreaders. The link is already inside a big arrow anyway<commit_after>$(function(){
	$('body').addClass("js-enabled");
	$('#wrapper').tabs();

	/* step link prompts */

	/* get all the sections */
	var sections = $(".tabs-panel"),
		i = sections.length,
		last = $(".tabs-panel:last").attr("id").split("-enhanced")[0],
		j,
		id,
		ul,
		navid,
		sectionTitle,
		nav;

		last = "
No thanks, just tell me how to claim
"

	while(i--){
		j = i+1;
		id = $(sections[j]).attr("id");
		navid = id+"-nav";
		nav = $("

");
		ul = $("

");

		sectionTitle = $("#"+id+" h1").html();

		if(sectionTitle != undefined){
			sectionTitle = sectionTitle.toLowerCase();
			id = id.split("-enhanced")[0];
			var next = ("
Read about "+sectionTitle+"
");
			if(i == 2){
				$(ul).append(next)
			}
			else{
				$(ul).append(next+last)
			}

			$(sections[i]).find(".inner").append(nav);
			$("#"+navid).append(ul);

			$(".part-pagination a").live("click", function(){
			  if($(window.location.hash+"-enhanced").length != 0){
			    $(window).scrollTop( $(window.location.hash+"-enhanced").offset().top );
		    }
			});
		}
	}

});<|endoftext|>


<commit_before>// entry point
(function() {
    window.cdb = {};
    window.cdb.config = {};
    window.cdb.core = {};
    window.cdb.geo = {};

    cdb.files = [
        "lib/jquery.min.js",
        "lib/underscore-min.js",
        "lib/backbone-min.js",

        "lib/leaflet.js",

        'core/config.js',
        'core/log.js',
        'core/view.js',

        'geo/map.js'
    ];

    /**
     * load all the javascript files. For testing, do not use in production
     */
    cdb.load = function(prefix, ready) {
        var c = 0;

        var _ready = function() {
            ++c;
            if(c == cdb.files.length) {
                if(ready)
                    ready();
            }

        };

        for(var i in cdb.files) {
            var script = document.createElement('script');
            script.src = prefix + cdb.files[i];
            script.onload = _ready;
            document.body.appendChild(script);
        }
    };
})();
<commit_msg>fixed loader<commit_after>// entry point
(function() {
    window.cdb = {};
    window.cdb.config = {};
    window.cdb.core = {};
    window.cdb.geo = {};

    cdb.files = [
        "lib/jquery.min.js",
        "lib/underscore-min.js",
        "lib/backbone-min.js",

        "lib/leaflet.js",

        'core/config.js',
        'core/log.js',
        'core/view.js',

        'geo/map.js'
    ];

    /**
     * load all the javascript files. For testing, do not use in production
     */
    cdb.load = function(prefix, ready) {
        var c = 0;

        var next = function() {
            var script = document.createElement('script');
            script.src = prefix + cdb.files[c];
            document.body.appendChild(script);
            ++c;
            if(c == cdb.files.length) {
                if(ready) {
                    script.onload = ready;
                }
            } else {
                script.onload = next;
            }
        };

        next();

    };
})();
<|endoftext|>


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

// Required modules
var fs = require('fs');
var path = require('path');
var PushBullet = require('pushbullet');
var notifier = require('node-notifier');

// Read the configuration file
var config = JSON.parse(fs.readFileSync('./settings.json'));

// Create a pushbullet instance
var pusher = new PushBullet(config.API_KEY);

// Use a random contact from the list
var contactsList = config.list;
var randomNumber = Math.floor(Math.random() * 1000) % contactsList.length;
var contact = contactsList[randomNumber];

// Push the notification to the device and OS
pusher.note(config.device, 'Call ' + contact.name, contact.message);
notifier.notify({
    title: 'Call ' + contact.name,
    message: contact.message,
    icon: path.join(__dirname, 'call.png')
});
<commit_msg>Moved the settings file to ~<commit_after>/*
 * Copyright (c) 2014 Srijan R Shetty <srijan.shetty+code@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

// Required modules
var fs = require('fs');
var path = require('path');
var PushBullet = require('pushbullet');
var notifier = require('node-notifier');

// Read the configuration file
var config = JSON.parse(fs.readFileSync('~/call-remind.json'));

// Create a pushbullet instance
var pusher = new PushBullet(config.API_KEY);

// Use a random contact from the list
var contactsList = config.list;
var randomNumber = Math.floor(Math.random() * 1000) % contactsList.length;
var contact = contactsList[randomNumber];

// Push the notification to the device and OS
pusher.note(config.device, 'Call ' + contact.name, contact.message);
notifier.notify({
    title: 'Call ' + contact.name,
    message: contact.message,
    icon: path.join(__dirname, 'call.png')
});
<|endoftext|>


<commit_before>'use strict';

module.exports = (function(){
  // Require an HTTP package to make HTTP API calls
  var rp = require('request-promise');

  var getInfo = function(str, regExp){
    if(typeof str !== 'string'){ return null; };
    if(typeof regExp !== 'object'){ return null; };

    var extractedStr = str.match(regExp);
    console.log('Info: ' + extractedStr);
    return extractedStr ? extractedStr[0] : null;
  };

  var regEx = {
    code: /\b\w+(?=<\/code>)/g,
    authToken: /\w+(?=<auth_token)/g,
    date: /([\w-:]+)(?=<\/expires-at>)/g,
    reqId: /\b\w+(?=<\/id>)/g
  };

  var plexUrl = {
    reqPin: 'https://plex.tv/pins.xml',
    /* End checkPin with '.xml' */
    checkPin: 'https://plex.tv/pins/'
  };

  var getPlexPin = function(_headers){

    /*
      This app will accomplish:
      -Request a PIN from Plex.tv
        - Needs _headers
        - Client Identifier === App name
      -Return the response from Plex.tv (Auth Token or Error)
    */

    // Verify adequate information was provided
    if(!_headers.hasOwnProperty('product' || !_headers.hasOwnProperty('version'))
      || !_headers.hasOwnProperty('identifier') || !_headers.hasOwnProperty('platform')
      || !_headers.hasOwnProperty('platformVersion') || !_headers.hasOwnProperty('device')
      || !_headers.hasOwnProperty('deviceName') || !_headers.hasOwnProperty('language')){
      throw new Error('Missing required header(s)');
    };

    var requestCB = function(body){

      var fields = {
        body: body,
        token: getInfo(body, regEx.authToken),
        code: getInfo(body, regEx.code),
        expiresIn: getInfo(body, regEx.date),
        reqId: getInfo(body, regEx.reqId)
      };
    };

    // var requiredHeaders = [
    //   'X-Plex-Product',
    //   'X-Plex-Version'
,    //   'X-Plex-Client-Identifier',
    //   'X-Plex-Platform',
    //   'X-Plex-Platform-Version',
    //   'X-Plex-Device',
    //   'X-Plex-Device-Name',
    //   'Accept-Language'
    // ];

    // We need header info such as:
    /*
      X-Plex-Product=Plex+Web
      X-Plex-Version=2.3.21
      X-Plex-Client-Identifier=r4zsj3rp4r4wjyvi
      X-Plex-Platform=Chrome
      X-Plex-Platform-Version=41.0
      X-Plex-Device=Linux
      X-Plex-Device-Name=Plex+Web+(Chrome)
      Accept-Language=en
    */

    return rp.get({ url: _url, headers: _headers });
  };

  var checkPlexPin = function(requestId){
    var authToken;

    var url = plexUrl.checkPin + requestId + '.xml';

    // Poll https://plex.tv/pins/<requestId>.xml for authToken

    // Stop poll when authToken is found

    // return promise

    return authToken;
  };

  return {
    test: true,
    requestPlexPin: getPlexPin,
    checkAuth: checkPlexPin,
    getAuthToken
  };
})();
<commit_msg>Fixed syntax error<commit_after>'use strict';

module.exports = (function(){
  // Require an HTTP package to make HTTP API calls
  var rp = require('request-promise');

  var getInfo = function(str, regExp){
    if(typeof str !== 'string'){ return null; };
    if(typeof regExp !== 'object'){ return null; };

    var extractedStr = str.match(regExp);
    console.log('Info: ' + extractedStr);
    return extractedStr ? extractedStr[0] : null;
  };

  var regEx = {
    code: /\b\w+(?=<\/code>)/g,
    authToken: /\w+(?=<auth_token)/g,
    date: /([\w-:]+)(?=<\/expires-at>)/g,
    reqId: /\b\w+(?=<\/id>)/g
  };

  var plexUrl = {
    reqPin: 'https://plex.tv/pins.xml',
    /* End checkPin with '.xml' */
    checkPin: 'https://plex.tv/pins/'
  };

  var getPlexPin = function(_headers){

    /*
      This app will accomplish:
      -Request a PIN from Plex.tv
        - Needs _headers
        - Client Identifier === App name
      -Return the response from Plex.tv (Auth Token or Error)
    */

    // Verify adequate information was provided
    if(!_headers.hasOwnProperty('product' || !_headers.hasOwnProperty('version'))
      || !_headers.hasOwnProperty('identifier') || !_headers.hasOwnProperty('platform')
      || !_headers.hasOwnProperty('platformVersion') || !_headers.hasOwnProperty('device')
      || !_headers.hasOwnProperty('deviceName') || !_headers.hasOwnProperty('language')){
      throw new Error('Missing required header(s)');
    };

    var requestCB = function(body){

      var fields = {
        body: body,
        token: getInfo(body, regEx.authToken),
        code: getInfo(body, regEx.code),
        expiresIn: getInfo(body, regEx.date),
        reqId: getInfo(body, regEx.reqId)
      };
    };

    // var requiredHeaders = [
    //   'X-Plex-Product',
    //   'X-Plex-Version',
    //   'X-Plex-Client-Identifier',
    //   'X-Plex-Platform',
    //   'X-Plex-Platform-Version',
    //   'X-Plex-Device',
    //   'X-Plex-Device-Name',
    //   'Accept-Language'
    // ];

    // We need header info such as:
    /*
      X-Plex-Product=Plex+Web
      X-Plex-Version=2.3.21
      X-Plex-Client-Identifier=r4zsj3rp4r4wjyvi
      X-Plex-Platform=Chrome
      X-Plex-Platform-Version=41.0
      X-Plex-Device=Linux
      X-Plex-Device-Name=Plex+Web+(Chrome)
      Accept-Language=en
    */

    return rp.get({ url: _url, headers: _headers });
  };

  var checkPlexPin = function(requestId){
    var authToken;

    var url = plexUrl.checkPin + requestId + '.xml';

    // Poll https://plex.tv/pins/<requestId>.xml for authToken

    // Stop poll when authToken is found

    // return promise

    return authToken;
  };

  return {
    test: true,
    requestPlexPin: getPlexPin,
    checkAuth: checkPlexPin,
    getAuthToken
  };
})();
<|endoftext|>