<commit_before>'use strict';

angular.module('BeerPallsApp').
controller('BeerHubCtrl', function ($scope, $http, $routeParams, $filter) {

  $scope.user = $routeParams.user;

  var initArray = function(arraySize){
    var array = [];
    while(arraySize--) {
      array.push([]);
    }
    return array;
  };

  var filter = function(message){
    return /^feat.+|^chore.+|^style.+|^fix.+|^test.+/.test(message);
  };

  $scope.period = {};
  $scope.commits = [];
  var lastYearArr = initArray(366);
  var yearArr = initArray(12);
  var weekArr = initArray(7);
  var dayArr = initArray(24);
  var weekhoursArr = [initArray(24), initArray(24), initArray(24), initArray(24), initArray(24), initArray(24), initArray(24)];

  $scope.analytics = {
    'yearArr': yearArr,
    'weekArr': weekArr,
    'dayArr': dayArr,
    'weekhoursArr': weekhoursArr,
    'lastYearArr': lastYearArr,
    'year': {},
    'month': {},
    'week': {}
  };

  $http.get('https://api.github.com/repos/' + $scope.user + '/beerhub/commits', {})
  .success(function(commits){
    _.pluck(commits, 'commit').forEach(function(commit){
      if (!filter(commit.message)){
        var date = new Date(commit.author.date);

        var c = {
          'date': commit.author.date,
          'message': commit.message,
          'author': commit.author.name,
          'email': commit.author.email
        };

        var hour = date.getHours();
        var day = date.getDay();
        var month = date.getMonth();

        $scope.analytics['yearArr'][month].push(c);
        $scope.analytics['weekArr'][day].push(c);
        $scope.analytics['dayArr'][hour].push(c);
        $scope.analytics['weekhoursArr'][day][hour].push(c);

        var now = new Date();
        var oneYearAgo = new Date();
        var oneMonthAgo = new Date();
        var oneWeekAgo = new Date();
        oneYearAgo.setYear(now.getFullYear() - 1);
        oneMonthAgo.setMonth(now.getMonth() - 1);
        oneWeekAgo.setDate(now.getDate() - 7);
        oneYearAgo.setHours(0,0,0);
        oneMonthAgo.setHours(0,0,0);
        oneWeekAgo.setHours(0,0,0);
        $scope.firstDay = oneYearAgo.getDay();

        var index = Math.floor((date - oneYearAgo) / (24 * 60 * 60 * 1000));
        if (index >= 0) {
          $scope.analytics['lastYearArr'][index].push(c);
          if ($scope.analytics['year'][c.message] > 0) {
            $scope.analytics['year'][c.message]++;
          }
          else {
            $scope.analytics['year'][c.message] = 1;
          }
        }

        if (oneMonthAgo <= new Date(c.date)) {
          if ($scope.analytics['month'][c.message] > 0) {
            $scope.analytics['month'][c.message]++;
          }
          else {
            $scope.analytics['month'][c.message] = 1;
          }
        }
        if (oneWeekAgo <= new Date(c.date)) {
          if ($scope.analytics['week'][c.message] > 0) {
            $scope.analytics['week'][c.message]++
          }
          else {
            $scope.analytics['week'][c.message] = 1;
          }

        }
        $scope.commits.push(c);
      }
    });

    $scope.maxLastYear = getMax($scope.analytics.lastYearArr);
    $scope.maxYear = getMax($scope.analytics.yearArr);
    $scope.maxWeek = getMax($scope.analytics.weekArr);
    $scope.maxDay = getMax($scope.analytics.dayArr);
    $scope.maxWeekHours = getMaxDouble($scope.analytics.weekhoursArr);

    getStreaks($scope.analytics.lastYearArr);

    $scope.period.name = 'week';
    $scope.contributionBeers = getDayBeerArray($scope.analytics[$scope.period.name]);

  });

  $scope.totalContributions = 0;

  var getStreaks = function(lastYearArr){
    var total = 0;

    var longestStreak = {
      'startIndex': undefined,
      'endIndex': undefined,
      'days': 0
    };

    var streakInterval = 0;

    var i;
    for (i=0; i<lastYearArr.length; i++){
      var beers = lastYearArr[i].length;

      if (beers > 0) {
        streakInterval++;
        total += beers;
      }
      else {
        if (streakInterval > longestStreak.days) {
          longestStreak['startIndex'] = i - streakInterval;
          longestStreak['endIndex'] = i - 1;
          longestStreak['days'] = streakInterval;
        }
        streakInterval = 0;
      }
    }

    if (streakInterval > longestStreak.days) {
      longestStreak['startIndex'] = i - streakInterval;
      longestStreak['endIndex'] = i - 1;
      longestStreak['days'] = streakInterval;
    }

    $scope.totalContributions = total;
    $scope.longestStreak = longestStreak;

    var currentStreak = {
      'startIndex': undefined,
      'endIndex': undefined,
      'days': 0
    };

    streakInterval = 0;
    for (i=lastYearArr.length - 1; i>=0; i--){
      var beers = lastYearArr[i].length;
      if (beers > 0) {
        streakInterval++;
        currentStreak['startIndex'] = i;
        currentStreak['endIndex'] = i + streakInterval - 1;
        currentStreak['days'] = streakInterval;
      }
      else if (i === lastYearArr.length - 1){
        continue;
      }
      else {
        break;
      }
    }

    $scope.currentStreak = currentStreak;
  };

  var getMax = function(arr){
    var max = 0;
    arr.forEach(function(item){
      if (max < item.length){
        max = item.length;
      }
    });
    return max;
  };

  var getMaxDouble = function(week){
    var max = 0;
    week.forEach(function(day){
      day.forEach(function(hour){
        if (max < hour.length){
          max = hour.length;
        }
      });
    });
    return max;
  };

  $scope.dayHours = [];
  $scope.hours = [];
  $scope.days = [];
  $scope.months = [];

  for (var dh=0; dh<24;dh++){
    $scope.dayHours.push(dh);
  }

  for (var h=0; h<24;h++){
    $scope.hours.push(h);
  }

  for (var d=0; d<7;d++){
    $scope.days.push(d);
  }

  for (var m=0; m<12;m++){
    $scope.months.push(m);
  }

  $scope.strings = {
    "DAY": {
      "0": "Sunday",
      "1": "Monday",
      "2": "Tuesday",
      "3": "Wednesday",
      "4": "Thursday",
      "5": "Friday",
      "6": "Saturday"
    },
    "MONTH": {
      "0": "January",
      "1": "February",
      "2": "March",
      "3": "April",
      "4": "May",
      "5": "June",
      "6": "July",
      "7": "August",
      "8": "September",
      "9": "October",
      "10": "November",
      "11": "December"
    },
    "SHORTDAY": {
      "0": "Sun",
      "1": "Mon",
      "2": "Tue",
      "3": "Wed",
      "4": "Thu",
      "5": "Fri",
      "6": "Sat"
    },
    "SHORTMONTH": {
      "0": "Jan",
      "1": "Feb",
      "2": "Mar",
      "3": "Apr",
      "4": "May",
      "5": "Jun",
      "6": "Jul",
      "7": "Aug",
      "8": "Sep",
      "9": "Oct",
      "10": "Nov",
      "11": "Dec"
    }
  };

  $scope.getContributionClass = function(contributions, max){
    if (contributions === 0) {
      return 'contributions-none';
    }
    else if (contributions / max <= 0.25) {
      return 'contributions-low';
    }
    else if (contributions / max <= 0.50) {
      return 'contributions-medium';
    }
    else if (contributions / max <= 0.75) {
      return 'contributions-high';
    }
    else if (contributions / max <= 1.00) {
      return 'contributions-most';
    }
  };

  $scope.getContributionPosition = function(day, week){
    var style = {
      'top': day * 15 + 'px',
      'left': 80 + Math.floor(week) * 15 + 'px'
    };
    return style;
  };

  $scope.getContributionDayClass = function(day){
    return 'contributions-day-' + day;
  };

  $scope.getContributionWeekClass = function(week){
    return 'contributions-week-' + Math.floor(week);
  };

  $scope.getContributionDate = function(index, lastYearArr){
    var diffdays = lastYearArr.length - index - 1;
    var now = new Date();
    var contributionDate = new Date();
    contributionDate.setDate(now.getDate() - diffdays);
    contributionDate.setHours(0,0,0);
    return contributionDate;
  };

  $scope.getTooltip = function(contributions, contributionDate){
    var html = '';
    if (contributions === 0) {
      html += 'No contributions';
    }
    else if (contributions === 1) {
      html += '' + contributions + ' contribution';
    }
    else if (contributions > 1) {
      html += '' + contributions + ' contributions';
    }

    if (contributionDate) {
      html += ' on ' + $filter('date')(contributionDate, 'longDate');
    }

    return html;
  };

  var getDayBeerCount = function(beers){
    var dayBeers = {};
    beers.forEach(function(beer){
      if (dayBeers[beer.message] > 0) {
        dayBeers[beer.message]++
      }
      else {
        dayBeers[beer.message] = 1;
      }
    });
    return dayBeers;
  };

  var getDayBeerArray = function(beerCount){
    var beers = [];
    if (beerCount) {
      Object.keys(beerCount).forEach(function(beer){
        var beer = {
          'name': beer,
          'count': beerCount[beer]
        };
        beers.push(beer);
      });
    }
    return beers;
  };

  $scope.browseBeers = function(beers, date){
    $scope.contributionBeers = getDayBeerArray(getDayBeerCount(beers));
    $scope.period.date = date;
    $scope.period.name = undefined;
  };

  $scope.getTotalBeers = function(beers){
    var total = 0;
    for (var i=0; beers && i<beers.length; i++){
      total += beers[i].count;
    }
    return total;
  };

  $scope.changePeriod = function(period) {
    $scope.period.date = undefined;
    $scope.period.name = period;
    $scope.contributionBeers = getDayBeerArray($scope.analytics[period]);
  };

});<commit_msg>feat: add `merge` into commit filter regexp<commit_after>'use strict';

angular.module('BeerPallsApp').
controller('BeerHubCtrl', function ($scope, $http, $routeParams, $filter) {

  $scope.user = $routeParams.user;

  var initArray = function(arraySize){
    var array = [];
    while(arraySize--) {
      array.push([]);
    }
    return array;
  };

  var filter = function(message){
    return /^feat.*:.+|^chore.*:.+|^style.*:.+|^fix.*:.+|^test.*:.+|^merge.+/i.test(message);
  };

  $scope.period = {};
  $scope.commits = [];
  var lastYearArr = initArray(366);
  var yearArr = initArray(12);
  var weekArr = initArray(7);
  var dayArr = initArray(24);
  var weekhoursArr = [initArray(24), initArray(24), initArray(24), initArray(24), initArray(24), initArray(24), initArray(24)];

  $scope.analytics = {
    'yearArr': yearArr,
    'weekArr': weekArr,
    'dayArr': dayArr,
    'weekhoursArr': weekhoursArr,
    'lastYearArr': lastYearArr,
    'year': {},
    'month': {},
    'week': {}
  };

  $http.get('https://api.github.com/repos/' + $scope.user + '/beerhub/commits', {})
  .success(function(commits){
    _.pluck(commits, 'commit').forEach(function(commit){
      if (!filter(commit.message)){
        var date = new Date(commit.author.date);

        var c = {
          'date': commit.author.date,
          'message': commit.message,
          'author': commit.author.name,
          'email': commit.author.email
        };

        var hour = date.getHours();
        var day = date.getDay();
        var month = date.getMonth();

        $scope.analytics['yearArr'][month].push(c);
        $scope.analytics['weekArr'][day].push(c);
        $scope.analytics['dayArr'][hour].push(c);
        $scope.analytics['weekhoursArr'][day][hour].push(c);

        var now = new Date();
        var oneYearAgo = new Date();
        var oneMonthAgo = new Date();
        var oneWeekAgo = new Date();
        oneYearAgo.setYear(now.getFullYear() - 1);
        oneMonthAgo.setMonth(now.getMonth() - 1);
        oneWeekAgo.setDate(now.getDate() - 7);
        oneYearAgo.setHours(0,0,0);
        oneMonthAgo.setHours(0,0,0);
        oneWeekAgo.setHours(0,0,0);
        $scope.firstDay = oneYearAgo.getDay();

        var index = Math.floor((date - oneYearAgo) / (24 * 60 * 60 * 1000));
        if (index >= 0) {
          $scope.analytics['lastYearArr'][index].push(c);
          if ($scope.analytics['year'][c.message] > 0) {
            $scope.analytics['year'][c.message]++;
          }
          else {
            $scope.analytics['year'][c.message] = 1;
          }
        }

        if (oneMonthAgo <= new Date(c.date)) {
          if ($scope.analytics['month'][c.message] > 0) {
            $scope.analytics['month'][c.message]++;
          }
          else {
            $scope.analytics['month'][c.message] = 1;
          }
        }
        if (oneWeekAgo <= new Date(c.date)) {
          if ($scope.analytics['week'][c.message] > 0) {
            $scope.analytics['week'][c.message]++
          }
          else {
            $scope.analytics['week'][c.message] = 1;
          }

        }
        $scope.commits.push(c);
      }
    });

    $scope.maxLastYear = getMax($scope.analytics.lastYearArr);
    $scope.maxYear = getMax($scope.analytics.yearArr);
    $scope.maxWeek = getMax($scope.analytics.weekArr);
    $scope.maxDay = getMax($scope.analytics.dayArr);
    $scope.maxWeekHours = getMaxDouble($scope.analytics.weekhoursArr);

    getStreaks($scope.analytics.lastYearArr);

    $scope.period.name = 'week';
    $scope.contributionBeers = getDayBeerArray($scope.analytics[$scope.period.name]);

  });

  $scope.totalContributions = 0;

  var getStreaks = function(lastYearArr){
    var total = 0;

    var longestStreak = {
      'startIndex': undefined,
      'endIndex': undefined,
      'days': 0
    };

    var streakInterval = 0;

    var i;
    for (i=0; i<lastYearArr.length; i++){
      var beers = lastYearArr[i].length;

      if (beers > 0) {
        streakInterval++;
        total += beers;
      }
      else {
        if (streakInterval > longestStreak.days) {
          longestStreak['startIndex'] = i - streakInterval;
          longestStreak['endIndex'] = i - 1;
          longestStreak['days'] = streakInterval;
        }
        streakInterval = 0;
      }
    }

    if (streakInterval > longestStreak.days) {
      longestStreak['startIndex'] = i - streakInterval;
      longestStreak['endIndex'] = i - 1;
      longestStreak['days'] = streakInterval;
    }

    $scope.totalContributions = total;
    $scope.longestStreak = longestStreak;

    var currentStreak = {
      'startIndex': undefined,
      'endIndex': undefined,
      'days': 0
    };

    streakInterval = 0;
    for (i=lastYearArr.length - 1; i>=0; i--){
      var beers = lastYearArr[i].length;
      if (beers > 0) {
        streakInterval++;
        currentStreak['startIndex'] = i;
        currentStreak['endIndex'] = i + streakInterval - 1;
        currentStreak['days'] = streakInterval;
      }
      else if (i === lastYearArr.length - 1){
        continue;
      }
      else {
        break;
      }
    }

    $scope.currentStreak = currentStreak;
  };

  var getMax = function(arr){
    var max = 0;
    arr.forEach(function(item){
      if (max < item.length){
        max = item.length;
      }
    });
    return max;
  };

  var getMaxDouble = function(week){
    var max = 0;
    week.forEach(function(day){
      day.forEach(function(hour){
        if (max < hour.length){
          max = hour.length;
        }
      });
    });
    return max;
  };

  $scope.dayHours = [];
  $scope.hours = [];
  $scope.days = [];
  $scope.months = [];

  for (var dh=0; dh<24;dh++){
    $scope.dayHours.push(dh);
  }

  for (var h=0; h<24;h++){
    $scope.hours.push(h);
  }

  for (var d=0; d<7;d++){
    $scope.days.push(d);
  }

  for (var m=0; m<12;m++){
    $scope.months.push(m);
  }

  $scope.strings = {
    "DAY": {
      "0": "Sunday",
      "1": "Monday",
      "2": "Tuesday",
      "3": "Wednesday",
      "4": "Thursday",
      "5": "Friday",
      "6": "Saturday"
    },
    "MONTH": {
      "0": "January",
      "1": "February",
      "2": "March",
      "3": "April",
      "4": "May",
      "5": "June",
      "6": "July",
      "7": "August",
      "8": "September",
      "9": "October",
      "10": "November",
      "11": "December"
    },
    "SHORTDAY": {
      "0": "Sun",
      "1": "Mon",
      "2": "Tue",
      "3": "Wed",
      "4": "Thu",
      "5": "Fri",
      "6": "Sat"
    },
    "SHORTMONTH": {
      "0": "Jan",
      "1": "Feb",
      "2": "Mar",
      "3": "Apr",
      "4": "May",
      "5": "Jun",
      "6": "Jul",
      "7": "Aug",
      "8": "Sep",
      "9": "Oct",
      "10": "Nov",
      "11": "Dec"
    }
  };

  $scope.getContributionClass = function(contributions, max){
    if (contributions === 0) {
      return 'contributions-none';
    }
    else if (contributions / max <= 0.25) {
      return 'contributions-low';
    }
    else if (contributions / max <= 0.50) {
      return 'contributions-medium';
    }
    else if (contributions / max <= 0.75) {
      return 'contributions-high';
    }
    else if (contributions / max <= 1.00) {
      return 'contributions-most';
    }
  };

  $scope.getContributionPosition = function(day, week){
    var style = {
      'top': day * 15 + 'px',
      'left': 80 + Math.floor(week) * 15 + 'px'
    };
    return style;
  };

  $scope.getContributionDayClass = function(day){
    return 'contributions-day-' + day;
  };

  $scope.getContributionWeekClass = function(week){
    return 'contributions-week-' + Math.floor(week);
  };

  $scope.getContributionDate = function(index, lastYearArr){
    var diffdays = lastYearArr.length - index - 1;
    var now = new Date();
    var contributionDate = new Date();
    contributionDate.setDate(now.getDate() - diffdays);
    contributionDate.setHours(0,0,0);
    return contributionDate;
  };

  $scope.getTooltip = function(contributions, contributionDate){
    var html = '';
    if (contributions === 0) {
      html += 'No contributions';
    }
    else if (contributions === 1) {
      html += '' + contributions + ' contribution';
    }
    else if (contributions > 1) {
      html += '' + contributions + ' contributions';
    }

    if (contributionDate) {
      html += ' on ' + $filter('date')(contributionDate, 'longDate');
    }

    return html;
  };

  var getDayBeerCount = function(beers){
    var dayBeers = {};
    beers.forEach(function(beer){
      if (dayBeers[beer.message] > 0) {
        dayBeers[beer.message]++
      }
      else {
        dayBeers[beer.message] = 1;
      }
    });
    return dayBeers;
  };

  var getDayBeerArray = function(beerCount){
    var beers = [];
    if (beerCount) {
      Object.keys(beerCount).forEach(function(beer){
        var beer = {
          'name': beer,
          'count': beerCount[beer]
        };
        beers.push(beer);
      });
    }
    return beers;
  };

  $scope.browseBeers = function(beers, date){
    $scope.contributionBeers = getDayBeerArray(getDayBeerCount(beers));
    $scope.period.date = date;
    $scope.period.name = undefined;
  };

  $scope.getTotalBeers = function(beers){
    var total = 0;
    for (var i=0; beers && i<beers.length; i++){
      total += beers[i].count;
    }
    return total;
  };

  $scope.changePeriod = function(period) {
    $scope.period.date = undefined;
    $scope.period.name = period;
    $scope.contributionBeers = getDayBeerArray($scope.analytics[period]);
  };

});<|endoftext|>


<commit_before>const assert = require('assert');
const Meal = require('../../lib/models/meal');
const expectedValidation = require('../helper/validation');

describe('meal validation', () => {

  it('validates a meal', () => {
    const testMeal = new Meal({
      name: 'grilled cheese',
      ingredients: [{
        name: 'bread',
        category: 'grain'
      },
      {
        name: 'cheese',
        category: 'protein'
      }]
    });
    return testMeal.validate();
  });

  describe('validation failures', () => {

    it('requires a name', () => {
      const meal = new Meal();
      return meal.validate()
        .then(expectedValidation,
        err => {
          const errors = err.errors;
          assert.ok(errors.name && errors.name.kind === 'required');
        });
    });

    it('name is a string', () => {
      const meal = new Meal();
      return meal.validate()
        .then(expectedValidation,
        err => {
          const errors = err.errors;
          assert.ok(errors.name && errors.name.kind === 'string');
        });
    });
  });
});<commit_msg>type not validated in mongoose.<commit_after>const assert = require('assert');
const Meal = require('../../lib/models/meal');
const expectedValidation = require('../helper/validation');

describe('meal validation', () => {

  it('validates a meal', () => {
    const testMeal = new Meal({
      name: 'grilled cheese',
      ingredients: [{
        name: 'bread',
        category: 'grain'
      },
      {
        name: 'cheese',
        category: 'protein'
      }]
    });
    return testMeal.validate();
  });

  describe('validation failures', () => {

    it('requires a name', () => {
      const meal = new Meal();
      return meal.validate()
        .then(expectedValidation,
        err => {
          const errors = err.errors;
          assert.ok(errors.name && errors.name.kind === 'required');
        });
    });
  });
});<|endoftext|>


<commit_before>/*
 * Namespace: lb.base.template.html
 * Base Module for HTML Templates
 *
 * This module defines filter functions for HTML templates, for use with
 * <lb.base.template.applyFilters(input...,filters):any> in the base template
 * module.
 *
 * HTML filters are applied to DOM nodes, which get modified in place. In order
 * to keep the original template for reuse with a different set of values, the
 * node should be cloned before HTML filters are applied.
 *
 * Author:
 * Eric Bréchemier <legalbox@eric.brechemier.name>
 *
 * Copyright:
 * Legal-Box SAS (c) 2010-2011, All Rights Reserved
 *
 * License:
 * BSD License
 * http://creativecommons.org/licenses/BSD/
 *
 * Version:
 * 2011-05-06
 */
/*requires lb.base.template.js */
/*jslint white:false, plusplus:false */
/*global lb, goog, window */
lb.base.template.html = (function() {
  // Builder of
  // Closure for lb.base.template.html module

  // Declare aliases

  var /*requires lb.base.object.js */
      has = lb.base.object.has,
      /*requires lb.base.type.js */
      is = lb.base.type.is,
      /*requires lb.base.array.js */
      toArray = lb.base.array.toArray,
      /*requires lb.base.dom.js */
      dom = lb.base.dom,
      ELEMENT_NODE = dom.ELEMENT_NODE,
      ATTRIBUTE_NODE = dom.ATTRIBUTE_NODE,
      TEXT_NODE = dom.TEXT_NODE,
      applyFilters = lb.base.template.applyFilters,
      /*requires lb.base.template.string.js */
      replaceParamsInString = lb.base.template.string.replaceParams,
      /*requires lb.base.log.js */
      log = lb.base.log.print;

  function topDownParsing(node){
    // Function: topDownParsing(node[,context...],filters)
    // Apply filters recursively to attributes and child nodes.
    //
    // The attributes are processed first (the order is browser-dependent),
    // then child nodes are processed in a depth-first recursion.
    //
    // Parameters:
    //   node - DOM Node, a DOM node. Only elements are processed by this
    //          filter, other nodes are left untouched.
    //   context... - any, optional, variable number of parameters providing
    //             context to the transformation. All context arguments are
    //             forwarded in recursive calls to applyFilters().
    //   filters - array of functions, the list of filter functions to be
    //             applied recursively. This argument is required and always
    //             last, which allows filter functions applied to any number
    //             of context arguments to omit it in their declaration.
    //
    // Note:
    // In Internet Explorer, lots of attribute nodes are present with a default
    // value. Only attributes explicitly defined in the document or through
    // JavaScript are processed: attributes that do not have 'specified'
    // property set to true are ignored.
    //
    // Reference:
    //   specified - Interface Attr
    //   http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-637646024
    if ( !has(node) || node.nodeType !== ELEMENT_NODE ){
      return;
    }

    var args = toArray(arguments),
        attributes = toArray(node.attributes),
        childNodes = toArray(node.childNodes),
        i,
        length,
        attribute;

    for (i=0,length=attributes.length; i<length; i++){
      attribute = attributes[i];
      if ( attribute.specified ) {
        args[0] = attribute;
        try {
          applyFilters.apply(null,args);
        } catch( attributeFilterError ) {
          log(
            'Failed to apply HTML filters to attribute "'+attribute.name+'" '+
            'of element '+node.nodeName+ ( node.id? '#'+node.id :
            (node.className?' class="'+node.className+'"':'') )+
            ': '+attributeFilterError
          );
        }
      }
    }
    for (i=0,length=childNodes.length; i<length; i++){
      args[0] = childNodes[i];
      try {
        applyFilters.apply(null,args);
      } catch ( childNodeFilterError ) {
        log(
          'Failed to apply HTML filters to child node '+childNodes[i]+
          ' in position '+(i+1)+
          ' of element '+node.nodeName+ ( node.id? '#'+node.id :
          (node.className?' class="'+node.className+'"':'') )+
          ': '+childNodeFilterError
        );
      }
    }
  }

  function getBaseUrl(url){
    // (Private) getBaseUrl(url)
    // Get the base URL of the page (without the hash part).
    //
    // This method is extracted and adapted from bezen.template.js
    // in the bezen.org JavaScript library, CC-BY Eric Bréchemier.
    //
    // Parameters::
    //   url - string, optional, defaults to window.location.href, the url
    //         to truncate
    //   Note: I switched from document.URL to window.location.href for
    //         accurate results with local files in Internet Explorer.
    //         Although both share the same value for online files using the
    //         http/https protocols, with the file protocol, in IE,
    //         document.URL will look like
    //           file://D:\web\bezen.org\javascript\test\test-template.html
    //         while the corresponding window.location.href would be
    //           file:///D:/web/bezen.org/javascript/test/test-template.html
    //
    // Returns:
    //   string, the input URL, with the hash part removed
    url = has(url)? url : window.location.href;

    // Remove the fragment part of the url
    var pos = url.indexOf("#");
    return ( pos<0? url: url.slice(0,pos) );
  }

  function getNodeValue(node) {
    // (Private) getNodeValue(node)
    // Get the node value.
    //
    // This method is extracted and adapted from bezen.template.js
    // in the bezen.org JavaScript library, CC-BY Eric Bréchemier.
    //
    // A specific processing is required for URLs in (A) href and (IMG) src
    // attributes, which get transformed to an absolute path in IE 7,
    // prepending the web page URL to the left of the #param#.
    // This method removes the web page URL if found at the start of a
    // href or src attribute.
    //
    // Parameters:
    //   node - DOM node, a node with a value
    //          (PRE: node.nodeValue is truthy)
    //
    // Returns:
    //   string or any, the node value from node.nodeValue, with the URL of the
    //   page removed from the start for href and src attributes.
    //   This value is typically a string. It may also be null, e.g. for the
    //   document itself, and may be a number or even an object (for custom
    //   properties, considered as attributes) in Internet Explorer.
    if ( (node.nodeType === ATTRIBUTE_NODE) &&
         (node.name === 'href' || node.name === 'src')  ) {
      var baseUrl = getBaseUrl();
      if ( node.nodeValue.indexOf(baseUrl) === 0 ) {
        // Remove absolute URL added by IE 7 at start of local href and src
        // The URL is identical to the part of window.location.href before the '#'
        return node.nodeValue.replace(baseUrl,'');
      }
    }
    return node.nodeValue;
  }

  function replaceParams(getValue){
    // Function: replaceParams(getValue): function
    // Get a filter function to replace parameters in attribute and text nodes.
    //
    // This method applies replaceParams() from the base string templates
    // module, and follows the same conventions:
    // - parameters to replace are surrounded by '#' characters
    // - getValue() is called for replacement values
    //
    // See details of parameter format in
    // <lb.base.template.string.replaceParams(getValue): function>.
    //
    // Parameter:
    //   getValue - function, a getter function returning values for the
    //              replacement of parameters:
    //              | function(name): any
    //              The name argument is the name of the parameter to replace.
    //              The getter value should return string values when a
    //              matching property is found, and null otherwise.
    //
    // Returns:
    //   * function, a closure wrapped around the given getter function, with
    //     the following signature:
    //     | Function: filter(htmlNode)
    //     | Replace parameters in attribute and text nodes
    //     | with corresponding values returned by getValue().
    //     |
    //     | The replacements are operated in place in given node.
    //     |
    //     | Parameters:
    //     |   htmlNode - DOM Node, a DOM node. Only attribute and text nodes
    //     |              are considered for parameter replacement.
    //     |              Other nodes are left untouched.
    //   * null when the required getter argument is missing or not a function
    if ( !is(getValue,'function') ){
      return null;
    }
    var replaceParamsWithValues = replaceParamsInString(getValue);
    return function(htmlNode){
      if (  !has(htmlNode) ||
            ( htmlNode.nodeType!==ATTRIBUTE_NODE &&
              htmlNode.nodeType!==TEXT_NODE )  ){
        return;
      }
      var oldValue,
          newValue;

      // In IE7, the base location of the window (without the hash part) is
      // prepended to the nodeValue for img src and a href:
      // e.g. "#param#" becomes "http://example.org/#param#".
      oldValue = getNodeValue(htmlNode);
      newValue = replaceParamsWithValues(oldValue);

      if (newValue !== oldValue) {
        // only set if the new value differs, to avoid issues in IE:
        // for example, setting the nodeValue of input.type attribute fails
        // when the input element is in the DOM.
        htmlNode.nodeValue = newValue;
      }
    };
  }

  return { // public API
    topDownParsing: topDownParsing,
    replaceParams: replaceParams
  };
}());
<commit_msg>Added explicit conversion of number to string to please JSLint<commit_after>/*
 * Namespace: lb.base.template.html
 * Base Module for HTML Templates
 *
 * This module defines filter functions for HTML templates, for use with
 * <lb.base.template.applyFilters(input...,filters):any> in the base template
 * module.
 *
 * HTML filters are applied to DOM nodes, which get modified in place. In order
 * to keep the original template for reuse with a different set of values, the
 * node should be cloned before HTML filters are applied.
 *
 * Author:
 * Eric Bréchemier <legalbox@eric.brechemier.name>
 *
 * Copyright:
 * Legal-Box SAS (c) 2010-2011, All Rights Reserved
 *
 * License:
 * BSD License
 * http://creativecommons.org/licenses/BSD/
 *
 * Version:
 * 2011-06-06
 */
/*requires lb.base.template.js */
/*jslint white:false, plusplus:false */
/*global lb, goog, window */
lb.base.template.html = (function() {
  // Builder of
  // Closure for lb.base.template.html module

  // Declare aliases

  var /*requires lb.base.object.js */
      has = lb.base.object.has,
      /*requires lb.base.type.js */
      is = lb.base.type.is,
      /*requires lb.base.array.js */
      toArray = lb.base.array.toArray,
      /*requires lb.base.dom.js */
      dom = lb.base.dom,
      ELEMENT_NODE = dom.ELEMENT_NODE,
      ATTRIBUTE_NODE = dom.ATTRIBUTE_NODE,
      TEXT_NODE = dom.TEXT_NODE,
      applyFilters = lb.base.template.applyFilters,
      /*requires lb.base.template.string.js */
      replaceParamsInString = lb.base.template.string.replaceParams,
      /*requires lb.base.log.js */
      log = lb.base.log.print;

  function topDownParsing(node){
    // Function: topDownParsing(node[,context...],filters)
    // Apply filters recursively to attributes and child nodes.
    //
    // The attributes are processed first (the order is browser-dependent),
    // then child nodes are processed in a depth-first recursion.
    //
    // Parameters:
    //   node - DOM Node, a DOM node. Only elements are processed by this
    //          filter, other nodes are left untouched.
    //   context... - any, optional, variable number of parameters providing
    //             context to the transformation. All context arguments are
    //             forwarded in recursive calls to applyFilters().
    //   filters - array of functions, the list of filter functions to be
    //             applied recursively. This argument is required and always
    //             last, which allows filter functions applied to any number
    //             of context arguments to omit it in their declaration.
    //
    // Note:
    // In Internet Explorer, lots of attribute nodes are present with a default
    // value. Only attributes explicitly defined in the document or through
    // JavaScript are processed: attributes that do not have 'specified'
    // property set to true are ignored.
    //
    // Reference:
    //   specified - Interface Attr
    //   http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-637646024
    if ( !has(node) || node.nodeType !== ELEMENT_NODE ){
      return;
    }

    var args = toArray(arguments),
        attributes = toArray(node.attributes),
        childNodes = toArray(node.childNodes),
        i,
        length,
        attribute;

    for (i=0,length=attributes.length; i<length; i++){
      attribute = attributes[i];
      if ( attribute.specified ) {
        args[0] = attribute;
        try {
          applyFilters.apply(null,args);
        } catch( attributeFilterError ) {
          log(
            'Failed to apply HTML filters to attribute "'+attribute.name+'" '+
            'of element '+node.nodeName+ ( node.id? '#'+node.id :
            (node.className?' class="'+node.className+'"':'') )+
            ': '+attributeFilterError
          );
        }
      }
    }
    for (i=0,length=childNodes.length; i<length; i++){
      args[0] = childNodes[i];
      try {
        applyFilters.apply(null,args);
      } catch ( childNodeFilterError ) {
        log(
          'Failed to apply HTML filters to child node '+childNodes[i]+
          ' in position '+String(i+1)+
          ' of element '+node.nodeName+ ( node.id? '#'+node.id :
          (node.className?' class="'+node.className+'"':'') )+
          ': '+childNodeFilterError
        );
      }
    }
  }

  function getBaseUrl(url){
    // (Private) getBaseUrl(url)
    // Get the base URL of the page (without the hash part).
    //
    // This method is extracted and adapted from bezen.template.js
    // in the bezen.org JavaScript library, CC-BY Eric Bréchemier.
    //
    // Parameters::
    //   url - string, optional, defaults to window.location.href, the url
    //         to truncate
    //   Note: I switched from document.URL to window.location.href for
    //         accurate results with local files in Internet Explorer.
    //         Although both share the same value for online files using the
    //         http/https protocols, with the file protocol, in IE,
    //         document.URL will look like
    //           file://D:\web\bezen.org\javascript\test\test-template.html
    //         while the corresponding window.location.href would be
    //           file:///D:/web/bezen.org/javascript/test/test-template.html
    //
    // Returns:
    //   string, the input URL, with the hash part removed
    url = has(url)? url : window.location.href;

    // Remove the fragment part of the url
    var pos = url.indexOf("#");
    return ( pos<0? url: url.slice(0,pos) );
  }

  function getNodeValue(node) {
    // (Private) getNodeValue(node)
    // Get the node value.
    //
    // This method is extracted and adapted from bezen.template.js
    // in the bezen.org JavaScript library, CC-BY Eric Bréchemier.
    //
    // A specific processing is required for URLs in (A) href and (IMG) src
    // attributes, which get transformed to an absolute path in IE 7,
    // prepending the web page URL to the left of the #param#.
    // This method removes the web page URL if found at the start of a
    // href or src attribute.
    //
    // Parameters:
    //   node - DOM node, a node with a value
    //          (PRE: node.nodeValue is truthy)
    //
    // Returns:
    //   string or any, the node value from node.nodeValue, with the URL of the
    //   page removed from the start for href and src attributes.
    //   This value is typically a string. It may also be null, e.g. for the
    //   document itself, and may be a number or even an object (for custom
    //   properties, considered as attributes) in Internet Explorer.
    if ( (node.nodeType === ATTRIBUTE_NODE) &&
         (node.name === 'href' || node.name === 'src')  ) {
      var baseUrl = getBaseUrl();
      if ( node.nodeValue.indexOf(baseUrl) === 0 ) {
        // Remove absolute URL added by IE 7 at start of local href and src
        // The URL is identical to the part of window.location.href before the '#'
        return node.nodeValue.replace(baseUrl,'');
      }
    }
    return node.nodeValue;
  }

  function replaceParams(getValue){
    // Function: replaceParams(getValue): function
    // Get a filter function to replace parameters in attribute and text nodes.
    //
    // This method applies replaceParams() from the base string templates
    // module, and follows the same conventions:
    // - parameters to replace are surrounded by '#' characters
    // - getValue() is called for replacement values
    //
    // See details of parameter format in
    // <lb.base.template.string.replaceParams(getValue): function>.
    //
    // Parameter:
    //   getValue - function, a getter function returning values for the
    //              replacement of parameters:
    //              | function(name): any
    //              The name argument is the name of the parameter to replace.
    //              The getter value should return string values when a
    //              matching property is found, and null otherwise.
    //
    // Returns:
    //   * function, a closure wrapped around the given getter function, with
    //     the following signature:
    //     | Function: filter(htmlNode)
    //     | Replace parameters in attribute and text nodes
    //     | with corresponding values returned by getValue().
    //     |
    //     | The replacements are operated in place in given node.
    //     |
    //     | Parameters:
    //     |   htmlNode - DOM Node, a DOM node. Only attribute and text nodes
    //     |              are considered for parameter replacement.
    //     |              Other nodes are left untouched.
    //   * null when the required getter argument is missing or not a function
    if ( !is(getValue,'function') ){
      return null;
    }
    var replaceParamsWithValues = replaceParamsInString(getValue);
    return function(htmlNode){
      if (  !has(htmlNode) ||
            ( htmlNode.nodeType!==ATTRIBUTE_NODE &&
              htmlNode.nodeType!==TEXT_NODE )  ){
        return;
      }
      var oldValue,
          newValue;

      // In IE7, the base location of the window (without the hash part) is
      // prepended to the nodeValue for img src and a href:
      // e.g. "#param#" becomes "http://example.org/#param#".
      oldValue = getNodeValue(htmlNode);
      newValue = replaceParamsWithValues(oldValue);

      if (newValue !== oldValue) {
        // only set if the new value differs, to avoid issues in IE:
        // for example, setting the nodeValue of input.type attribute fails
        // when the input element is in the DOM.
        htmlNode.nodeValue = newValue;
      }
    };
  }

  return { // public API
    topDownParsing: topDownParsing,
    replaceParams: replaceParams
  };
}());
<|endoftext|>


<commit_before>'use strict';

angular
		.module(
				'htm',
				[ 'common.playRoutes', 'common.filters', 'htm.services',
						'ui.bootstrap' ]).controller('EmptyCtrl',
				[ '$scope', '$location', 'playRoutes', 'stateService', EmptyCtrl ]).controller(
						'FightCtrl', [ '$scope', '$timeout', 'playRoutes', 'stateService', FightCtrl ]).controller(
								'OverviewArenaCtrl', [ '$scope', '$timeout', 'stateService', OverviewArenaCtrl ]).controller(
										'ImageCtrl', [ '$scope', 'stateService', ImageCtrl ]).controller(
												'ParticipantFooterCtrl', [ '$scope', 'stateService', ParticipantFooterCtrl ]).controller(
														'ParticipantBioCtrl', [ '$scope', 'stateService', ParticipantBioCtrl ]).config(
				[ '$routeProvider', function($routeProvider) {
					$routeProvider.when('/empty', {
						templateUrl : 'assets/templates/empty.html',
						controller : 'EmptyCtrl'
					}).when('/image', {
						templateUrl : 'assets/templates/image.html',
						controller : 'ImageCtrl'
					}).when('/fight', {
						templateUrl : 'assets/templates/fight.html',
						controller : 'FightCtrl'
					}).when('/overview/arena', {
						templateUrl : 'assets/templates/overview/arena.html',
						controller : 'OverviewArenaCtrl'
					}).when('/participant/footer', {
						templateUrl : 'assets/templates/participant/footer.html',
						controller : 'ParticipantFooterCtrl'
					}).when('/participant/bio', {
						templateUrl : 'assets/templates/participant/bio.html',
						controller : 'ParticipantBioCtrl'
					}).otherwise({
						redirectTo : '/empty'
					});
				} ]).run(
				[
						"$rootScope",
						"$location",
						"$http",
						"stateService",
						function($rootScope, $location, $http, stateService) {
							$rootScope.updateView = function(updateMsg) {
								var update = JSON.parse(updateMsg.data);
								$rootScope.$apply(function() {
									if (update.view) {
										console.log("received update for view " + update.view + ": " + JSON.stringify(update.payload));
										stateService.put(update.view, update.payload);
										$location.path("/" + update.view);
									} else {
										console.log("received update for current view: " + JSON.stringify(update.payload));
										stateService.broadcast(update.payload);
									}
								});
							};

							$rootScope.updateFeed = new EventSource("/updateFeed");
							$rootScope.updateFeed.addEventListener("message",
									$rootScope.updateView, false);

							$('#main').click(function() {
								window.document.getElementById("main").webkitRequestFullScreen();
							});
						} ]);
;<commit_msg>source format of viewer app.js<commit_after>'use strict';

angular.module('htm',
    [ 'common.playRoutes', 'common.filters', 'htm.services', 'ui.bootstrap' ])
    .controller('EmptyCtrl',
        [ '$scope', '$location', 'playRoutes', 'stateService', EmptyCtrl ])
    .controller('FightCtrl',
        [ '$scope', '$timeout', 'playRoutes', 'stateService', FightCtrl ])
    .controller('OverviewArenaCtrl',
        [ '$scope', '$timeout', 'stateService', OverviewArenaCtrl ])
    .controller('ImageCtrl',
        [ '$scope', 'stateService', ImageCtrl ])
    .controller('ParticipantFooterCtrl',
        [ '$scope', 'stateService', ParticipantFooterCtrl ])
    .controller(
        'ParticipantBioCtrl', [ '$scope', 'stateService', ParticipantBioCtrl ])
    .config([ '$routeProvider', function($routeProvider) {
      $routeProvider.when('/empty', {
        templateUrl : 'assets/templates/empty.html',
        controller : 'EmptyCtrl'
      }).when('/image', {
        templateUrl : 'assets/templates/image.html',
        controller : 'ImageCtrl'
      }).when('/fight', {
        templateUrl : 'assets/templates/fight.html',
        controller : 'FightCtrl'
      }).when('/overview/arena', {
        templateUrl : 'assets/templates/overview/arena.html',
        controller : 'OverviewArenaCtrl'
      }).when('/participant/footer', {
        templateUrl : 'assets/templates/participant/footer.html',
        controller : 'ParticipantFooterCtrl'
      }).when('/participant/bio', {
        templateUrl : 'assets/templates/participant/bio.html',
        controller : 'ParticipantBioCtrl'
      }).otherwise({
        redirectTo : '/empty'
      });
    } ]).run(
        [
            "$rootScope",
            "$location",
            "$http",
            "stateService",
            function($rootScope, $location, $http, stateService) {
              $rootScope.updateView = function(updateMsg) {
                var update = JSON.parse(updateMsg.data);
                $rootScope.$apply(function() {
                  if (update.view) {
                    console.log("received update for view " + update.view
                        + ": " + JSON.stringify(update.payload));
                    stateService.put(update.view, update.payload);
                    $location.path("/" + update.view);
                  } else {
                    console.log("received update for current view: "
                        + JSON.stringify(update.payload));
                    stateService.broadcast(update.payload);
                  }
                });
              };

              $rootScope.updateFeed = new EventSource("/updateFeed");
              $rootScope.updateFeed.addEventListener("message",
                  $rootScope.updateView, false);

              $('#main').click(
                  function() {
                    window.document.getElementById("main")
                        .webkitRequestFullScreen();
                  });
            } ]);
;<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { Button } from 'react-bootstrap';
import WarningModal from './warning-modal';
import TutorRouter from '../helpers/router';

const MESSAGES = {
  notAllowed: 'This page can only be viewed by the account holder.',
  notMember: 'You must be a member of this course to use this link. If your instructor sent you this link, ask your instructor for an enrollment link.',
};

@withRouter
class CourseNotFoundWarning extends React.Component {

  static propTypes = {
    areaName: PropTypes.string.isRequired,
    history: PropTypes.object.isRequired,
    dismiss: PropTypes.func,
    messageType: PropTypes.oneOf(Object.keys(MESSAGES)),
  }

  static defaultProps = {
    areaName: 'course',
  }

  goToMyCourses() {
    this.props.history.push(TutorRouter.makePathname('myCourses'));
  }

  render() {
    const { areaName, messageType, dismiss } = this.props;

    return (
      <WarningModal
        onDismiss={this.goToMyCourses}
        title={`Sorry, you can’t access this ${areaName}`}
        footer={<Button className="dismiss" onClick={dismiss}>Close</Button>}
      >
        {MESSAGES[messageType] || MESSAGES.notMember}
      </WarningModal>
    );
  }
}

export { CourseNotFoundWarning };
<commit_msg>fix dismiss<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { Button } from 'react-bootstrap';
import WarningModal from './warning-modal';
import TutorRouter from '../helpers/router';

const MESSAGES = {
  notAllowed: 'This page can only be viewed by the account holder.',
  notMember: 'You must be a member of this course to use this link. If your instructor sent you this link, ask your instructor for an enrollment link.',
};

@withRouter
class CourseNotFoundWarning extends React.Component {

  static propTypes = {
    areaName: PropTypes.string.isRequired,
    history: PropTypes.object.isRequired,
    messageType: PropTypes.oneOf(Object.keys(MESSAGES)),
  }

  static defaultProps = {
    areaName: 'course',
  }

  goToMyCourses = () => {
    this.props.history.push(TutorRouter.makePathname('myCourses'));
  }

  render() {
    const { areaName, messageType } = this.props;

    return (
      <WarningModal
        onDismiss={this.goToMyCourses}
        title={`Sorry, you can’t access this ${areaName}`}
        footer={<Button className="dismiss" onClick={this.goToMyCourses}>Close</Button>}
      >
        {MESSAGES[messageType] || MESSAGES.notMember}
      </WarningModal>
    );
  }
}

export { CourseNotFoundWarning };
<|endoftext|>


<commit_before>import { computed } from 'vendor';
import { isEmpty } from 'lodash';

class Validations {

  constructor(ux) {
    this.ux = ux;
  }

  get form() {
    return this.ux.form;
  }

  get plan() {
    return this.ux.plan;
  }

  @computed get isValid() {
    return !!this[this.ux.steps.currentStepId];
  }

  // tests
  @computed get details() {
    return Boolean(this.form && this.form.isValid);
  }

  @computed get chapters() {
    return !isEmpty(this.plan.pageIds);
  }

  @computed get questions() {
    return !isEmpty(this.plan.exerciseIds);
  }

  @computed get points() {
    return !isEmpty(this.plan.exerciseIds);
  }
}

export default Validations;
<commit_msg>fix validations on reading chapter reorder step<commit_after>import { computed } from 'vendor';
import { isEmpty } from 'lodash';

class Validations {

  constructor(ux) {
    this.ux = ux;
  }

  get form() {
    return this.ux.form;
  }

  get plan() {
    return this.ux.plan;
  }

  @computed get isValid() {
    return !!this[this.ux.steps.currentStepId];
  }

  // tests
  @computed get details() {
    return Boolean(this.form && this.form.isValid);
  }

  @computed get chapters() {
    return !isEmpty(this.plan.pageIds);
  }

  @computed get questions() {
    return !isEmpty(this.plan.exerciseIds);
  }

  @computed get points() {
    return !isEmpty(this.plan.exerciseIds);
  }

  @computed get reorder() {
    return !isEmpty(this.plan.pageIds);
  }
}

export default Validations;
<|endoftext|>


<commit_before>"use strict";

var sort = exports = module.exports = {
    selection: function (arr) {
        for (let i = 0; i < arr.length; i++) {
            var min = {elem: arr[i], pos: i};
            for (let j = i; j < arr.length; j++) {
                if (min.elem > arr[j]) {
                    min.elem = arr[j];
                    min.pos = j;
                }
            }
            util.swap(arr, i, min.pos)
        }
        return arr;
    },
    bubble: function (arr) {
        for (let i = 0; i < arr.length; i++) {
            for (let j = 0; j < (arr.length - 1) - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    util.swap(arr, j, j + 1);
                }
            }
        }
        return arr;
    }
};

var util = require('./util');
util.anal   yze(function (init, done) {
    console.log(sort.selection([8, 7, 6, 2, 4, 1, 3, 5, 1, 3]));
    done(init);
});
util.analyze(function (init, done) {
    console.log(sort.bubble([8, 7, 6, 2, 4, 1, 3, 5, 1, 3]));
    done(init);
});<commit_msg>Update: optimized bubble sort<commit_after>"use strict";

var sort = exports = module.exports = {
    selection: function (arr) {
        for (let i = 0; i < arr.length; i++) {
            var min = {elem: arr[i], pos: i};
            for (let j = i; j < arr.length; j++) {
                if (min.elem > arr[j]) {
                    min.elem = arr[j];
                    min.pos = j;
                }
            }
            util.swap(arr, i, min.pos)
        }
        return arr;
    },
    bubble: function (arr) {
        for (let i = 0; i < arr.length; i++) {
            var swap = false;
            for (let j = 0; j < (arr.length - 1) - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    util.swap(arr, j, j + 1);
                    swap = true;
                }
            }
            if(!swap){
                break;
            }
        }
        return arr;
    }
};

var util = require('./util');
util.analyze(function (init, done) {
    console.log(sort.selection([8, 7, 6, 2, 4, 1, 3, 5, 1, 3]));
    done(init);
});
util.analyze(function (init, done) {
    console.log(sort.bubble([8, 7, 6, 2, 4, 1, 3, 5, 1, 3]));
    done(init);
});<|endoftext|>


<commit_before>
// SmoothScroll v0.9.2
// Licensed under the terms of the MIT license.

// People involved
// - Balazs Galambosi: maintainer (CHANGELOG.txt)
// - Patrick Brunner (patrickb1991@gmail.com)
// - Michael Herf: Pulse Algorithm

// Frame Variables
var frame         = false;
var noscrollframe = false;

// Scroll Variables (tweakable)
var framerate = 50;  // [Hz]
var animtime  = 400; // [px]
var stepsize  = 120; // [px]

// Pulse (less tweakable)
// ratio of 'tail' to 'acceleration'
var pulseAlgorithm = true;
var pulseScale     = 8;
var pulseNormalize = 1;

// Keyboard Settings
var keyboardsupport = true;
var disableKeyboard = false;
var arrowscroll     = 50; // [px]

// Excluded pages
var exclude = "";

// Arrays of timeouts
var up   = [];
var down = [];

// Other Variables
var scrolls;
var deltaX = 0;
var deltaY = 0;
var initdone = false;
var activeElement;

var key = { up: 38, down: 40, spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36 };

/***********************************************
 * SETTINGS
 ***********************************************/

chrome.extension.connect({ name: "smoothscroll" }).
onMessage.addListener(function (settings) {

    // NOTE: + converts to {Number}
    framerate = +settings.framerate;
    animtime  = +settings.animtime;
    stepsize  = +settings.scrollsz;
    exclude   = settings.exclude;
    pulseAlgorithm  = (settings.pulseAlgorithm == "true");
    pulseScale      = +settings.pulseScale;
    keyboardsupport = (settings.keyboardsupport == "true");
    arrowscroll     = +settings.arrscroll;

    scrolls = setupScrolls();
    computePulseScale();

    // it seems that sometimes settings come late
    // and we need to test again for excluded pages
    initTest();

    if (keyboardsupport && !disableKeyboard) {
        addEvent("keydown", keydown);
    }

    // If extension settings were deleted somehow
    if (!framerate) {
        alert("SmoothScroll: Please restart Chrome");
    }
});

/***********************************************
 * INITIALIZE
 ***********************************************/

/**
 * Tests if smooth scrolling is allowed. Shuts down everything if not.
 */
function initTest() {

    // disable keys for google reader (spacebar conflict)
    if (document.URL.indexOf("google.com/reader/view") > -1) {
        disableKeyboard = true;
    }

    // disable everything if the page is blacklisted
    if (exclude) {
        var domains = exclude.split(/[,\n] ?/);
        for (var i = domains.length; i--;) {
            if (document.URL.indexOf(domains[i]) > -1) {
                removeEvent("mousewheel", wheel);
                disableKeyboard = true;
                break;
            }
        }
    }

    // disable keyboard support if anything above requested it
    if (disableKeyboard) {
        removeEvent("keydown", keydown);
    }
}

/**
 * Fills up the scrolls array with easing values.
 * Uses pulse to make it smooth.
 */
function setupScrolls() {

    scrolls = [];

    var last = 0;
    var frames = Math.floor(framerate * animtime / 1000);

    for (var i = 0; i < frames; i++) {
        // scroll is [0, 1]
        var scroll = (i + 1) / frames;
        // transform [0, 1] -> [0, 1]:
        if (pulseAlgorithm) {
           scroll = pulse(scroll);
        }

        // scale and quantize to int so our pixel difference works:
        var iscroll = Math.floor(stepsize * scroll + 0.99);
        scrolls.push(iscroll - last);
        last = iscroll;
    }

    return scrolls;
}

/**
 * Sets up scrolls array, determines if frames are involved.
 */
function init() {

    var body = document.body;
    activeElement = body;

    initTest();

    if (!scrolls) {
      scrolls = setupScrolls();
    }

    // Checks if this script is running in a frame
    if (top != self) {
        frame = true;
        // document.documentElement ?
        if (body.scrollHeight <= body.clientHeight + 10) {
            noscrollframe = true;
        }
    }

    /**
     * This fixes a bug where the areas left and right
     * to the content does not trigger the onmousewheel
     * event on some pages. Acid3 test is excluded.
     */
    if (document.URL !== "http://acid3.acidtests.org/") {
        var underlay = document.createElement('div');
        underlay.setAttribute( "style",
            "z-index: -1; position:absolute; top:0; left: 0; " +
            "width: 100%; height: " + body.scrollHeight + "px;" );
        body.appendChild(underlay);
    }
    initdone = true;
}

/************************************************
 * SCROLLING
 ************************************************/

/**
 * Pushes scroll actions to a given direction Array.
 */
function scrollArray(elem, dir, multiplyX, multiplyY, delay) {

    delay || (delay = 1000);
    clearTimeouts(dir === up ? down : up);

    function step() {

        var scale = scrolls[i++]; // linear or with easing

        // scroll left
        if (multiplyX && scale) {
            var lastLeft = elem.scrollLeft;
            elem.scrollLeft += multiplyX * scale;

            // scroll left failed (edge)
            if (elem.scrollLeft === lastLeft) {
                multiplyX = 0;
            }
        }

        // scroll top
        if (multiplyY && scale) {
            var lastTop = elem.scrollTop;
            elem.scrollTop += multiplyY * scale;

            // scroll top failed (edge)
            if (elem.scrollTop === lastTop) {
                multiplyY = 0;
            }
        }

        // clean up if there's nothing left to do
        if (!multiplyX && !multiplyY) {
            clearTimeouts(dir);
        }
    }

    // populate directions array
    for (var i = scrolls.length; i--;) {
        dir.push(setTimeout(step, i * delay / framerate + 1));
    }
    i = 0; // reset so that step() can increment again
}

/***********************************************
 * EVENTS
 ***********************************************/

/**
 * Mouse wheel handler.
 * NOTE: function logic should be decomposed.
 * @param {Object} event
 */
function wheel(event) {

    if (!initdone) {
        init();
    }

    var target = event.target;
    var noscroll = frame && noscrollframe;

    // use default if there's no overflowing
    // element or default action is prevented
    var elem = overflowingAncestor(target);
    if (!elem || noscroll || event.defaultPrevented ||
        isNodeName(activeElement, "embed") ||
       (isNodeName(target, "embed") && /\.pdf/i.test(target.src))) {
        return true;
    }

    deltaX = event.wheelDeltaX || 0;
    deltaY = event.wheelDeltaY || 0;

    // normalize deltas
    deltaX /= 120;
    deltaY /= 120;

    // synaptics seems to send 1 sometimes,
    // and 120 other times (fix)
    if (Math.abs(deltaX) < 0.01) {
        deltaX *= 120;
    }
    if (Math.abs(deltaY) < 0.01) {
        deltaY *= 120;
    }

    var dir = (deltaY > 0) ? up : down;
    scrollArray(elem, dir, -deltaX, -deltaY);
    event.preventDefault();
}

/**
 * Keydown event handler.
 * @param {Object} event
 */
function keydown(event) {

    var target   = event.target;
    var modifier = event.ctrlKey || event.altKey || event.metaKey;

    // do nothing if user is editing text
    // or using a modifier key (except shift)
    if ( /input|textarea|embed/i.test(target.nodeName) ||
         target.isContentEditable ||
         event.defaultPrevented   ||
         modifier ) {
      return true;
    }
    // spacebar should trigger button press
    if (isNodeName(target, "button") &&
        event.keyCode === key.spacebar) {
      return true;
    }

    var scale, dir, shift;
    var elem = overflowingAncestor(activeElement);
    var clientHeight = elem.clientHeight;

    if (elem == document.body) {
        clientHeight = window.innerHeight;
    }

    switch (event.keyCode) {
        case key.up:
            scale = -arrowscroll;
            dir = up;
            break;
        case key.down:
            scale = arrowscroll;
            dir = down;
            break;
        case key.spacebar: // (+ shift)
            shift = event.shiftKey ? 1 : -1;
            scale = -shift * clientHeight * 0.9;
            dir = (shift > 0) ? up : down;
            break;
        case key.pageup:
            scale = -clientHeight * 0.9;
            dir = up;
            break;
        case key.pagedown:
            scale = clientHeight * 0.9;
            dir = down;
            break;
        case key.home:
            scale = -elem.scrollTop;
            dir = up;
            break;
        case key.end:
            var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
            scale = (damt > 0) ? damt+10 : 0;
            dir = down;
            break;
        default:
            return true; // a key we don't care about
    }
    scale /= stepsize;
    scrollArray(elem, dir, 0, scale);
    event.preventDefault();
}

/***********************************************
 * HELPERS
 ***********************************************/

function addEvent(type, fn, bubble) {
    window.addEventListener(type, fn, (bubble||false));
}

function removeEvent(type, fn, bubble) {
    window.removeEventListener(type, fn, (bubble||false));
}

function isNodeName(el, tag) {
    return el.nodeName.toLowerCase() === tag.toLowerCase();
}

function clearTimeouts(array) {
    while (array.length) {
        clearTimeout(array.pop());
    }
}

function overflowingAncestor(el) {
    var bodyScrollHeight = document.body.scrollHeight;
    do {
        if (bodyScrollHeight === el.scrollHeight) {
            return document.body;
        }
        else if (el.clientHeight + 10 < el.scrollHeight) {
            overflow = getComputedStyle(el, "").getPropertyValue("overflow");
            if (overflow === "scroll" || overflow === "auto") {
                return el;
            }
        }
    } while (el = el.parentNode);
}

/***********************************************
 * PULSE
 ***********************************************/

/**
 * Viscous fluid with a pulse for part and decay for the rest.
 * - Applies a fixed force over an interval (a damped acceleration), and
 * - Lets the exponential bleed away the velocity over a longer interval
 * - Michael Herf, http://stereopsis.com/stopping/
 */
function pulse_(x) {
    var val, start, expx;
    // test
    x = x * pulseScale;
    if (x < 1) { // acceleartion
        val = x - (1 - Math.exp(-x));
    } else {     // tail
        // the previous animation ended here:
        start = Math.exp(-1);
        // simple viscous drag
        x -= 1;
        expx = 1 - Math.exp(-x);
        val = start + (expx * (1 - start));
    }
    return val * pulseNormalize;
}

function computePulseScale() {
    pulseNormalize = 1 / pulse_(1);
}

/**
 * Viscous fluid with a pulse for part and decay for the rest
 */
function pulse(x) {
    if (x >= 1) return 1;
    if (x <= 0) return 0;

    if (pulseNormalize == 1) {
        computePulseScale();
    }
    return pulse_(x);
}

/**
 * Mousedown event only for updating activeElement
 */
function mousedown(event) {
    activeElement = event.target;
}

addEvent("mousedown", mousedown);
addEvent("mousewheel", wheel);
addEvent("DOMContentLoaded", init);
<commit_msg>only do the scroll if the formula gives |delta| >= 1. it also affects edge detection<commit_after>
// SmoothScroll v0.9.2
// Licensed under the terms of the MIT license.

// People involved
// - Balazs Galambosi: maintainer (CHANGELOG.txt)
// - Patrick Brunner (patrickb1991@gmail.com)
// - Michael Herf: Pulse Algorithm

// Frame Variables
var frame         = false;
var noscrollframe = false;

// Scroll Variables (tweakable)
var framerate = 50;  // [Hz]
var animtime  = 400; // [px]
var stepsize  = 120; // [px]

// Pulse (less tweakable)
// ratio of 'tail' to 'acceleration'
var pulseAlgorithm = true;
var pulseScale     = 8;
var pulseNormalize = 1;

// Keyboard Settings
var keyboardsupport = true;
var disableKeyboard = false;
var arrowscroll     = 50; // [px]

// Excluded pages
var exclude = "";

// Arrays of timeouts
var up   = [];
var down = [];

// Other Variables
var scrolls;
var deltaX = 0;
var deltaY = 0;
var initdone = false;
var activeElement;

var key = { up: 38, down: 40, spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36 };

/***********************************************
 * SETTINGS
 ***********************************************/

chrome.extension.connect({ name: "smoothscroll" }).
onMessage.addListener(function (settings) {

    // NOTE: + converts to {Number}
    framerate = +settings.framerate;
    animtime  = +settings.animtime;
    stepsize  = +settings.scrollsz;
    exclude   = settings.exclude;
    pulseAlgorithm  = (settings.pulseAlgorithm == "true");
    pulseScale      = +settings.pulseScale;
    keyboardsupport = (settings.keyboardsupport == "true");
    arrowscroll     = +settings.arrscroll;

    scrolls = setupScrolls();
    computePulseScale();

    // it seems that sometimes settings come late
    // and we need to test again for excluded pages
    initTest();

    if (keyboardsupport && !disableKeyboard) {
        addEvent("keydown", keydown);
    }

    // If extension settings were deleted somehow
    if (!framerate) {
        alert("SmoothScroll: Please restart Chrome");
    }
});

/***********************************************
 * INITIALIZE
 ***********************************************/

/**
 * Tests if smooth scrolling is allowed. Shuts down everything if not.
 */
function initTest() {

    // disable keys for google reader (spacebar conflict)
    if (document.URL.indexOf("google.com/reader/view") > -1) {
        disableKeyboard = true;
    }

    // disable everything if the page is blacklisted
    if (exclude) {
        var domains = exclude.split(/[,\n] ?/);
        for (var i = domains.length; i--;) {
            if (document.URL.indexOf(domains[i]) > -1) {
                removeEvent("mousewheel", wheel);
                disableKeyboard = true;
                break;
            }
        }
    }

    // disable keyboard support if anything above requested it
    if (disableKeyboard) {
        removeEvent("keydown", keydown);
    }
}

/**
 * Fills up the scrolls array with easing values.
 * Uses pulse to make it smooth.
 */
function setupScrolls() {

    scrolls = [];

    var last = 0;
    var frames = Math.floor(framerate * animtime / 1000);

    for (var i = 0; i < frames; i++) {
        // scroll is [0, 1]
        var scroll = (i + 1) / frames;
        // transform [0, 1] -> [0, 1]:
        if (pulseAlgorithm) {
           scroll = pulse(scroll);
        }

        // scale and quantize to int so our pixel difference works:
        var iscroll = Math.floor(stepsize * scroll + 0.99);
        scrolls.push(iscroll - last);
        last = iscroll;
    }

    return scrolls;
}

/**
 * Sets up scrolls array, determines if frames are involved.
 */
function init() {

    var body = document.body;
    activeElement = body;

    initTest();

    if (!scrolls) {
      scrolls = setupScrolls();
    }

    // Checks if this script is running in a frame
    if (top != self) {
        frame = true;
        // document.documentElement ?
        if (body.scrollHeight <= body.clientHeight + 10) {
            noscrollframe = true;
        }
    }

    /**
     * This fixes a bug where the areas left and right
     * to the content does not trigger the onmousewheel
     * event on some pages. Acid3 test is excluded.
     */
    if (document.URL !== "http://acid3.acidtests.org/") {
        var underlay = document.createElement('div');
        underlay.setAttribute( "style",
            "z-index: -1; position: absolute; top: 0; left: 0; " +
            "width: 100%; height: " + body.scrollHeight + "px;" );
        body.appendChild(underlay);
    }

    initdone = true;
}

/************************************************
 * SCROLLING
 ************************************************/

/**
 * Pushes scroll actions to a given direction Array.
 */
function scrollArray(elem, dir, multiplyX, multiplyY, delay) {

    delay || (delay = 1000);
    clearTimeouts(dir === up ? down : up);

    function step() {

        var scale = scrolls[i++]; // linear or with easing
        var addX = parseInt(multiplyX * scale, 10);
        var addY = parseInt(multiplyY * scale, 10);

        // scroll left
        if (multiplyX && addX) {
            var lastLeft = elem.scrollLeft;
            elem.scrollLeft += addX;

            // scroll left failed (edge)
            if (elem.scrollLeft === lastLeft) {
                multiplyX = 0;
            }
        }

        // scroll top
        if (multiplyY && addY) {
            var lastTop = elem.scrollTop;
            elem.scrollTop += addY;

            // scroll top failed (edge)
            if (elem.scrollTop === lastTop) {
                multiplyY = 0;
            }
        }

        // clean up if there's nothing left to do
        if (!multiplyX && !multiplyY) {
            clearTimeouts(dir);
        }
    }

    // populate directions array
    for (var i = scrolls.length; i--;) {
        dir.push(setTimeout(step, i * delay / framerate + 1));
    }
    i = 0; // reset so that step() can increment again
}

/***********************************************
 * EVENTS
 ***********************************************/

/**
 * Mouse wheel handler.
 * NOTE: function logic should be decomposed.
 * @param {Object} event
 */
function wheel(event) {

    if (!initdone) {
        init();
    }

    var target = event.target;
    var noscroll = frame && noscrollframe;

    // use default if there's no overflowing
    // element or default action is prevented
    var elem = overflowingAncestor(target);
    if (!elem || noscroll || event.defaultPrevented ||
        isNodeName(activeElement, "embed") ||
       (isNodeName(target, "embed") && /\.pdf/i.test(target.src))) {
        return true;
    }

    deltaX = event.wheelDeltaX || 0;
    deltaY = event.wheelDeltaY || 0;

    // normalize deltas
    deltaX /= 120;
    deltaY /= 120;

    // synaptics seems to send 1 sometimes,
    // and 120 other times (fix)
    if (Math.abs(deltaX) < 0.01) {
        deltaX *= 120;
    }
    if (Math.abs(deltaY) < 0.01) {
        deltaY *= 120;
    }

    var dir = (deltaY > 0) ? up : down;
    scrollArray(elem, dir, -deltaX, -deltaY);
    event.preventDefault();
}

/**
 * Keydown event handler.
 * @param {Object} event
 */
function keydown(event) {

    var target   = event.target;
    var modifier = event.ctrlKey || event.altKey || event.metaKey;

    // do nothing if user is editing text
    // or using a modifier key (except shift)
    if ( /input|textarea|embed/i.test(target.nodeName) ||
         target.isContentEditable ||
         event.defaultPrevented   ||
         modifier ) {
      return true;
    }
    // spacebar should trigger button press
    if (isNodeName(target, "button") &&
        event.keyCode === key.spacebar) {
      return true;
    }

    var scale, dir, shift;
    var elem = overflowingAncestor(activeElement);
    var clientHeight = elem.clientHeight;

    if (elem == document.body) {
        clientHeight = window.innerHeight;
    }

    switch (event.keyCode) {
        case key.up:
            scale = -arrowscroll;
            dir = up;
            break;
        case key.down:
            scale = arrowscroll;
            dir = down;
            break;
        case key.spacebar: // (+ shift)
            shift = event.shiftKey ? 1 : -1;
            scale = -shift * clientHeight * 0.9;
            dir = (shift > 0) ? up : down;
            break;
        case key.pageup:
            scale = -clientHeight * 0.9;
            dir = up;
            break;
        case key.pagedown:
            scale = clientHeight * 0.9;
            dir = down;
            break;
        case key.home:
            scale = -elem.scrollTop;
            dir = up;
            break;
        case key.end:
            var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
            scale = (damt > 0) ? damt+10 : 0;
            dir = down;
            break;
        default:
            return true; // a key we don't care about
    }
    scale /= stepsize;
    scrollArray(elem, dir, 0, scale);
    event.preventDefault();
}

/***********************************************
 * HELPERS
 ***********************************************/

function addEvent(type, fn, bubble) {
    window.addEventListener(type, fn, (bubble||false));
}

function removeEvent(type, fn, bubble) {
    window.removeEventListener(type, fn, (bubble||false));
}

function isNodeName(el, tag) {
    return el.nodeName.toLowerCase() === tag.toLowerCase();
}

function clearTimeouts(array) {
    while (array.length) {
        clearTimeout(array.pop());
    }
}

function overflowingAncestor(el) {
    var bodyScrollHeight = document.body.scrollHeight;
    do {
        if (bodyScrollHeight === el.scrollHeight) {
            return document.body;
        }
        else if (el.clientHeight + 10 < el.scrollHeight) {
            overflow = getComputedStyle(el, "").getPropertyValue("overflow");
            if (overflow === "scroll" || overflow === "auto") {
                return el;
            }
        }
    } while (el = el.parentNode);
}

/***********************************************
 * PULSE
 ***********************************************/

/**
 * Viscous fluid with a pulse for part and decay for the rest.
 * - Applies a fixed force over an interval (a damped acceleration), and
 * - Lets the exponential bleed away the velocity over a longer interval
 * - Michael Herf, http://stereopsis.com/stopping/
 */
function pulse_(x) {
    var val, start, expx;
    // test
    x = x * pulseScale;
    if (x < 1) { // acceleartion
        val = x - (1 - Math.exp(-x));
    } else {     // tail
        // the previous animation ended here:
        start = Math.exp(-1);
        // simple viscous drag
        x -= 1;
        expx = 1 - Math.exp(-x);
        val = start + (expx * (1 - start));
    }
    return val * pulseNormalize;
}

function computePulseScale() {
    pulseNormalize = 1 / pulse_(1);
}

/**
 * Viscous fluid with a pulse for part and decay for the rest
 */
function pulse(x) {
    if (x >= 1) return 1;
    if (x <= 0) return 0;

    if (pulseNormalize == 1) {
        computePulseScale();
    }
    return pulse_(x);
}

/**
 * Mousedown event only for updating activeElement
 */
function mousedown(event) {
    activeElement = event.target;
}

addEvent("mousedown", mousedown);
addEvent("mousewheel", wheel);
addEvent("DOMContentLoaded", init);
<|endoftext|>


<commit_before>'use babel';
'use strict';

import Command from '../Command';
import { inspect } from 'util';
import * as Discord from 'discord.js'; // eslint-disable-line
import * as Yamdbf from '../../../index'; // eslint-disable-line

export default class Eval extends Command
{
	constructor(bot)
	{
		super(bot, {
			name: 'eval',
			description: 'Evaluate provided Javascript code',
			usage: '<prefix>eval <code>',
			group: 'base',
			ownerOnly: true
		});
	}

	action(message, args, mentions, original)
	{
		const code = original.split(this.name).slice(1).join(this.name).trim(); // eslint-disable-line
		if (!code)
		{
			this._respond(message, '**ERROR:** ```xl\nNo code provided to evaluate.\n```');
			return;
		}

		let evaled = eval(code);
		if (evaled instanceof Promise)
		{
			evaled.then(res =>
			{
				if (typeof res !== 'string') res = inspect(res, { depth: 0 });
				this._respond(message,
					`**INPUT:**\n\`\`\`js\n${code}\n\`\`\`\n**OUTPUT:**\n\`\`\`xl\n${this._clean(res)}\n\`\`\``);
			})
			.catch(err =>
			{
				this._respond(message,
					`**INPUT:**\n\`\`\`js\n${code}\n\`\`\`\n**ERROR:**\n\`\`\`xl\n${this._clean(err)}\n\`\`\``);
			});
		}
		else
		{
			if (typeof evaled !== 'string')	evaled = inspect(evaled, { depth: 0 });
			this._respond(message,
				`**INPUT:**\n\`\`\`js\n${code}\n\`\`\`\n**OUTPUT:**\n\`\`\`xl\n${this._clean(evaled)}\n\`\`\``);
		}
	}

	_clean(text)
	{
		return typeof text === 'string' ? text
			.replace(/`/g, `\`${String.fromCharCode(8203)}`)
			.replace(/@/g, `@${String.fromCharCode(8203)}`)
			.replace(/[\w\d]{24}\.[\w\d]{6}\.[\w\d-_]{27}/g, '[REDACTED]')
			.replace(/email: '[^']+'/g, `email: '[REDACTED]'`)
			: text;
	}
}
<commit_msg>Fix eval command following CommandDispatcher rewrite<commit_after>'use babel';
'use strict';

import Command from '../Command';
import { inspect } from 'util';
import * as Discord from 'discord.js'; // eslint-disable-line
import * as Yamdbf from '../../../index'; // eslint-disable-line

export default class Eval extends Command
{
	constructor(bot)
	{
		super(bot, {
			name: 'eval',
			description: 'Evaluate provided Javascript code',
			usage: '<prefix>eval <code>',
			group: 'base',
			ownerOnly: true
		});
	}

	action(message)
	{
		const code = message.content.split(this.name).slice(1).join(this.name).trim(); // eslint-disable-line
		if (!code)
		{
			this._respond(message, '**ERROR:** ```xl\nNo code provided to evaluate.\n```');
			return;
		}

		let evaled = eval(code);
		if (evaled instanceof Promise)
		{
			evaled.then(res =>
			{
				if (typeof res !== 'string') res = inspect(res, { depth: 0 });
				this._respond(message,
					`**INPUT:**\n\`\`\`js\n${code}\n\`\`\`\n**OUTPUT:**\n\`\`\`xl\n${this._clean(res)}\n\`\`\``);
			})
			.catch(err =>
			{
				this._respond(message,
					`**INPUT:**\n\`\`\`js\n${code}\n\`\`\`\n**ERROR:**\n\`\`\`xl\n${this._clean(err)}\n\`\`\``);
			});
		}
		else
		{
			if (typeof evaled !== 'string')	evaled = inspect(evaled, { depth: 0 });
			this._respond(message,
				`**INPUT:**\n\`\`\`js\n${code}\n\`\`\`\n**OUTPUT:**\n\`\`\`xl\n${this._clean(evaled)}\n\`\`\``);
		}
	}

	_clean(text)
	{
		return typeof text === 'string' ? text
			.replace(/`/g, `\`${String.fromCharCode(8203)}`)
			.replace(/@/g, `@${String.fromCharCode(8203)}`)
			.replace(/[\w\d]{24}\.[\w\d]{6}\.[\w\d-_]{27}/g, '[REDACTED]')
			.replace(/email: '[^']+'/g, `email: '[REDACTED]'`)
			: text;
	}
}
<|endoftext|>


<commit_before>export * from './generic';
export { default as BucketView } from './bucket-view';
<commit_msg>added export for GennyTreeView<commit_after>export * from './generic';
export { default as BucketView } from './bucket-view';
export { default as GennyTreeView } from './genny';<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import {map, find} from 'lodash';

// Components
import {Panel} from './panel';

export class Tabs extends React.Component {
  static propTypes = {
    align: PropTypes.string,
    startTab: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.string,
    ]),
  }

  static defaultProps = {
    align: 'top',
    startTab: 1,
  }

  constructor(props) {
    super(props);

    this.state = {
      activeTab: this.props.startTab,
      tabs: [],
    };
  }

  onSetActiveTab(tab, index, event) {
    event.preventDefault();

    let activeTab;
    if (_.isString(this.props.startTab)) {
      activeTab = tab.props.name;
    } else {
      activeTab = index + 1;
    }

    this.setState({activeTab});
  }

  getTabsAlignment(alignment) {
    switch (alignment) {
    case 'left':
      return 'tabs-left';
    case 'right':
      return 'tabs-right';
    case 'top':
    default:
      return '';
    }
  }

  renderTabs(tabs) {
    return map(tabs, (tab, index) => {
      let isActive = '';
      if (
        (_.isString(this.state.activeTab) && tab.props.name === this.state.activeTab) ||
        (_.isNumber(this.state.activeTab) && this.state.activeTab === index + 1)) {
        // If the user passes in a key to the tab and startTab is a string, check if it's active via the Tab's name. e.g.
        /*
          <Tabs startTab='first'>
            <Tab name='first'>
              First
            </Tab>
            <Tab name='second'>
              Second
            </Tab>
          </Tabs>
         */
        // Else if startTab is a number, calculate based on the order the tabs are passed in
        isActive = 'active';
      }

      return (

 this.onSetActiveTab(tab, index, e)} key={index}>
          {tab}

      );
    });
  }

  renderActiveTabBody(tabs) {
    // if this.state.activeTab is a string, try changing if the <Tab>s have a name and if one has a matching name, return it
    let activeTab;
    if (_.isString(this.state.activeTab)) {
      activeTab = find(tabs, tab => tab.props.name === this.state.activeTab);
    } else {
      activeTab = find(tabs, (tab, index) => this.state.activeTab === index + 1);
    }

    return activeTab ? activeTab.props.children : null;
  }

  render() {
    const alignment = this.getTabsAlignment(this.props.align);
    const isHorizontal = alignment === '';

    return (
      <Panel className={(isHorizontal ? 'horizontal-tabs' : '') + ' tabs-panel'}>

           {this.renderTabs(this.props.children)}

              {this.renderActiveTabBody(this.props.children)}

      </Panel>
    );
  }
}
<commit_msg>Tabs Bug: Can Not Have One Tab (#37)<commit_after>import React, {PropTypes} from 'react';
import {map, find} from 'lodash';

// Components
import {Panel} from './panel';

export class Tabs extends React.Component {
  static propTypes = {
    align: PropTypes.string,
    startTab: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.string,
    ]),
  }

  static defaultProps = {
    align: 'top',
    startTab: 1,
  }

  constructor(props) {
    super(props);

    this.state = {
      activeTab: this.props.startTab,
      tabs: [],
    };
  }

  onSetActiveTab(tab, index, event) {
    event.preventDefault();

    let activeTab;
    if (_.isString(this.props.startTab)) {
      activeTab = tab.props.name;
    } else {
      activeTab = index + 1;
    }

    this.setState({activeTab});
  }

  getTabsAlignment(alignment) {
    switch (alignment) {
    case 'left':
      return 'tabs-left';
    case 'right':
      return 'tabs-right';
    case 'top':
    default:
      return '';
    }
  }

  renderTabs(tabs) {
    return map(tabs, (tab, index) => {
      let isActive = '';
      if (
        (_.isString(this.state.activeTab) && tab.props.name === this.state.activeTab) ||
        (_.isNumber(this.state.activeTab) && this.state.activeTab === index + 1)) {
        // If the user passes in a key to the tab and startTab is a string, check if it's active via the Tab's name. e.g.
        /*
          <Tabs startTab='first'>
            <Tab name='first'>
              First
            </Tab>
            <Tab name='second'>
              Second
            </Tab>
          </Tabs>
         */
        // Else if startTab is a number, calculate based on the order the tabs are passed in
        isActive = 'active';
      }

      return (

 this.onSetActiveTab(tab, index, e)} key={index}>
          {tab}

      );
    });
  }

  renderActiveTabBody(tabs) {
    // if this.state.activeTab is a string, try changing if the <Tab>s have a name and if one has a matching name, return it
    let activeTab;
    if (_.isString(this.state.activeTab)) {
      activeTab = find(tabs, tab => tab.props.name === this.state.activeTab);
    } else {
      activeTab = find(tabs, (tab, index) => this.state.activeTab === index + 1);
    }

    return activeTab ? activeTab.props.children : null;
  }

  render() {
    const tabs = _.isArray(this.props.children) ? this.props.children : [this.props.children];
    const alignment = this.getTabsAlignment(this.props.align);
    const isHorizontal = alignment === '';

    return (
      <Panel className={(isHorizontal ? 'horizontal-tabs' : '') + ' tabs-panel'}>

           {this.renderTabs(tabs)}

              {this.renderActiveTabBody(tabs)}

      </Panel>
    );
  }
}
<|endoftext|>


<commit_before>Template.groupName.helpers({
	name: function() {
		if (!this) return;
		var groupId = ''+this; // it's not a string?! LOL I DUNNO
		miniSubs.subscribe('group', groupId);
		var group = Groups.findOne(groupId);
		return group && group.short;
	}
});
<commit_msg>show not existing groups as "removed group"<commit_after>Template.groupName.helpers({
	name: function() {
		if (!this) return;
		var groupId = ''+this; // it's not a string?! LOL I DUNNO
		miniSubs.subscribe('group', groupId);
		var group = Groups.findOne(groupId);
		if (!group) return "removed group"
		return group && group.short;
	}
});
<|endoftext|>


<commit_before>var request = require('request');
var cat = require('./base-cat.json');

// To avoid O(N) search if scaling to a zillion stores
var hrefMap = {};

// TODO: Do we actually want to force Databox rels despite PAS? Could come later?
var requiredRels = [
	'urn:X-databox:rels:hasVendor', //needed for searching for sensors by manufacture
	'urn:X-databox:rels:hasType',  //needed to find sensors of a particular type
	'urn:X-databox:rels:hasDatasourceid', //needed as its is used to refer to the datasource in API requests
	'urn:X-databox:rels:hasStoreType' //needed to help apps know which Store API the store offers
	//'urn:X-databox:rels:hasUnit', //optional
	//'urn:X-databox:rels:hasLocation', //optional
	//'urn:X-databox:rels:isActuator' //optional
	//
	// Drivers are also free to add any other metadata they see fit
	//
];

/**
 * @return {Boolean} isValid
 */
var isValidItem = function (item) {
	if (!('item-metadata' in item && 'href' in item))
		return false;

	// Hypercat minimum
	var hasDescription = false;
	var hasContentType = false;

	// Databox minimum (yay/nay?)
	var required = requiredRels.slice(0);

	for(var i = 0, len = item['item-metadata'].length; i < len; ++i) {
		var pair = item['item-metadata'][i];
		if (!('rel' in pair &&
					'val' in pair))
			return false;

		if (pair.rel.startsWith('urn:X-hypercat:rels:hasDescription:')) {
			hasDescription = true;
			continue;
		}

		if (pair.rel === 'urn:X-hypercat:rels:isContentType') {
			hasContentType = true;
			continue;
		}

		if (~required.indexOf(pair.rel))
			required.splice(required.indexOf(pair.rel), 1);
	}

	return hasDescription && hasContentType && !required.length;
}

module.exports = function (expressApp, databox_local_name, databox_local_port) {

	var router = require('express').Router({mergeParams: true});

	var app = expressApp;

	// Add a data source to the current Hypercat catalogue
	// Content-Type: application/json
	router.post('/', function (req, res, next) {
		// TODO: Extra auth to differentiate between GET and POST /cat

		const item = req.body;

		if (!isValidItem(item)) {
			// PAS Table 8
			res.status(400).send();
			return;
		}

		// TODO: Decide exactly what is best to do here, since Hypercat specs can't decide
		if (item.href in hrefMap) {
			var existingItem = hrefMap[item.href];
			for (key in existingItem)
				delete existingItem[key];
			for (key in item)
				existingItem[key] = item[key];

			// PAS 5.4.3
			// NOTE: PAS ambiguous about this in several ways
			res.location('https://' + databox_local_name + ':' + databox_local_port);
			res.status(200).send();
			return;
		}

		hrefMap[item.href] = item;
		cat.items.push(item);

		// PAS 5.4.2
		res.location('https://' + databox_local_name + ':' + databox_local_port);
		res.status(201).send();
	});

	//Return the current Hypercat catalogue
	router.get('/', function (req, res, next) {
		res.header('Content-Type', 'application/json');
		res.send(cat);
	});

	return router;
};<commit_msg>Remvove resolved TODO<commit_after>var request = require('request');
var cat = require('./base-cat.json');

// To avoid O(N) search if scaling to a zillion stores
var hrefMap = {};

// TODO: Do we actually want to force Databox rels despite PAS? Could come later?
var requiredRels = [
	'urn:X-databox:rels:hasVendor', //needed for searching for sensors by manufacture
	'urn:X-databox:rels:hasType',  //needed to find sensors of a particular type
	'urn:X-databox:rels:hasDatasourceid', //needed as its is used to refer to the datasource in API requests
	'urn:X-databox:rels:hasStoreType' //needed to help apps know which Store API the store offers
	//'urn:X-databox:rels:hasUnit', //optional
	//'urn:X-databox:rels:hasLocation', //optional
	//'urn:X-databox:rels:isActuator' //optional
	//
	// Drivers are also free to add any other metadata they see fit
	//
];

/**
 * @return {Boolean} isValid
 */
var isValidItem = function (item) {
	if (!('item-metadata' in item && 'href' in item))
		return false;

	// Hypercat minimum
	var hasDescription = false;
	var hasContentType = false;

	// Databox minimum (yay/nay?)
	var required = requiredRels.slice(0);

	for(var i = 0, len = item['item-metadata'].length; i < len; ++i) {
		var pair = item['item-metadata'][i];
		if (!('rel' in pair &&
					'val' in pair))
			return false;

		if (pair.rel.startsWith('urn:X-hypercat:rels:hasDescription:')) {
			hasDescription = true;
			continue;
		}

		if (pair.rel === 'urn:X-hypercat:rels:isContentType') {
			hasContentType = true;
			continue;
		}

		if (~required.indexOf(pair.rel))
			required.splice(required.indexOf(pair.rel), 1);
	}

	return hasDescription && hasContentType && !required.length;
}

module.exports = function (expressApp, databox_local_name, databox_local_port) {

	var router = require('express').Router({mergeParams: true});

	var app = expressApp;

	// Add a data source to the current Hypercat catalogue
	// Content-Type: application/json
	router.post('/', function (req, res, next) {
		const item = req.body;

		if (!isValidItem(item)) {
			// PAS Table 8
			res.status(400).send();
			return;
		}

		// TODO: Decide exactly what is best to do here, since Hypercat specs can't decide
		if (item.href in hrefMap) {
			var existingItem = hrefMap[item.href];
			for (key in existingItem)
				delete existingItem[key];
			for (key in item)
				existingItem[key] = item[key];

			// PAS 5.4.3
			// NOTE: PAS ambiguous about this in several ways
			res.location('https://' + databox_local_name + ':' + databox_local_port);
			res.status(200).send();
			return;
		}

		hrefMap[item.href] = item;
		cat.items.push(item);

		// PAS 5.4.2
		res.location('https://' + databox_local_name + ':' + databox_local_port);
		res.status(201).send();
	});

	//Return the current Hypercat catalogue
	router.get('/', function (req, res, next) {
		res.header('Content-Type', 'application/json');
		res.send(cat);
	});

	return router;
};
<|endoftext|>


<commit_before>'use strict';

var convertExpression = require('./convert-expression');
var validatePattern = require('./pattern-validation');

module.exports = (function(){
  function matchPattern(pattern, value){
    if( pattern.indexOf(',') !== -1 ){
      var patterns = pattern.split(',');
      return patterns.indexOf(value.toString()) !== -1;
    }
    return pattern === value.toString();
  }

  function mustRun(task, date){
    var runInSecond     = matchPattern(task.expressions[0], date.getSeconds());
    var runOnMinute     = matchPattern(task.expressions[1], date.getMinutes());
    var runOnHour       = matchPattern(task.expressions[2], date.getHours());
    var runOnDayOfMonth = matchPattern(task.expressions[3], date.getDate());
    var runOnMonth      = matchPattern(task.expressions[4], date.getMonth() + 1);
    var runOnDayOfWeek  = matchPattern(task.expressions[5], date.getDay());

    var runOnDay = false;

    if (task.initialPattern[2] === '*') {
      runOnDay = runOnDayOfWeek;
    } else if (task.initialPattern[4] === '*') {
      runOnDay = runOnDayOfMonth;
    } else {
      runOnDay = runOnDayOfMonth || runOnDayOfWeek;
    }

    return runInSecond && runOnMinute && runOnHour && runOnDay && runOnMonth;
  }

  function Task(pattern, execution){
    validatePattern(pattern);
    this.initialPattern = pattern.split(' ');
    this.pattern = convertExpression(pattern);
    this.execution = execution;
    this.expressions = this.pattern.split(' ');
  }

  Task.prototype.update = function(date){
    if(mustRun(this, date)){
      try {
        this.execution();
      } catch(err) {
        console.error(err);
      }
    }
  };

  return Task;
}());
<commit_msg>Fix spacing<commit_after>'use strict';

var convertExpression = require('./convert-expression');
var validatePattern = require('./pattern-validation');

module.exports = (function(){
  function matchPattern(pattern, value){
    if( pattern.indexOf(',') !== -1 ){
      var patterns = pattern.split(',');
      return patterns.indexOf(value.toString()) !== -1;
    }
    return pattern === value.toString();
  }

  function mustRun(task, date){
    var runInSecond = matchPattern(task.expressions[0], date.getSeconds());
    var runOnMinute = matchPattern(task.expressions[1], date.getMinutes());
    var runOnHour = matchPattern(task.expressions[2], date.getHours());
    var runOnDayOfMonth = matchPattern(task.expressions[3], date.getDate());
    var runOnMonth = matchPattern(task.expressions[4], date.getMonth() + 1);
    var runOnDayOfWeek = matchPattern(task.expressions[5], date.getDay());

    var runOnDay = false;

    if (task.initialPattern[2] === '*') {
      runOnDay = runOnDayOfWeek;
    } else if (task.initialPattern[4] === '*') {
      runOnDay = runOnDayOfMonth;
    } else {
      runOnDay = runOnDayOfMonth || runOnDayOfWeek;
    }

    return runInSecond && runOnMinute && runOnHour && runOnDay && runOnMonth;
  }

  function Task(pattern, execution){
    validatePattern(pattern);
    this.initialPattern = pattern.split(' ');
    this.pattern = convertExpression(pattern);
    this.execution = execution;
    this.expressions = this.pattern.split(' ');
  }

  Task.prototype.update = function(date){
    if(mustRun(this, date)){
      try {
        this.execution();
      } catch(err) {
        console.error(err);
      }
    }
  };

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