<commit_before>var Lazy        = require('../lazy.js'),
    lodash      = require('lodash'),
    underscore  = require('underscore'),
    Benchmark   = require('benchmark'),
    Race        = require('race.js'),
    stringTable = require('string-table');

Benchmark.options.maxTime = 0.5;
var selectedRace = null;

if (process.argv.length > 2) {
  selectedRace = process.argv[2];
  console.log('Just going to run "' + selectedRace + '" race');

} else {
  console.log('Running all races...');
}

function identity(x) {
  return x;
}

function increment(x) {
  return x + 1;
}

function isEven(x) {
  return x % 2 === 0;
}

function lastLetter(str) {
  return str.charAt(str.length - 1);
}

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

function randomNumbers(count, min, max) {
  var getRandomNumber = function() {
    return randomNumber(min, max);
  };

  return Lazy.generate(getRandomNumber, count).toArray();
}

var alphabet = 'abcdefghijklmnopqrstuvwxyz';
function randomWord() {
  var length = (3 + Math.floor(Math.random() * 7));

  var word = '';
  while (word.length < length) {
    word += alphabet[Math.floor(Math.random() * alphabet.length)];
  }
  return word;
}

function randomWords(count) {
  return Lazy.generate(randomWord, count).toArray();
}

function numbersInput(fn) {
  return [
    {
      name: '5-element array',
      values: [Race.integers(5), fn],
      size: 5
    },
    {
      name: '10-element array',
      values: [Race.integers(10), fn],
      size: 10
    },
    {
      name: '100-element array',
      values: [Race.integers(100), fn],
      size: 100
    }
  ];
}

function randomNumbersInput() {
  return [
    {
      name: '5 random numbers between 1-3',
      values: [randomNumbers(5, 1, 3)],
      size: 5
    },
    {
      name: '10 random numbers between 1-5',
      values: [randomNumbers(10, 1, 5)],
      size: 10
    },
    {
      name: '100 random numbers between 1-25',
      values: [randomNumbers(100, 1, 25)],
      size: 100
    }
  ]
}

function doubleNumbersInput() {
  return [
    {
      name: '2 5-element arrays',
      values: [Race.integers(5), Race.integers(5, 3)],
      size: 5
    },
    {
      name: '2 10-element arrays',
      values: [Race.integers(10), Race.integers(10, 5)],
      size: 10
    },
    {
      name: '2 100-element arrays',
      values: [Race.integers(100), Race.integers(100, 50)],
      size: 100
    }
  ];
}

function nestedNumbersInput() {
  return [
    {
      name: 'Small nested array',
      values: [
        [1, 2, [3, 4, [5, 6], 7, 8], 9, 10]
      ],
      size: 10
    },
    {
      name: 'Medium nested array',
      values: [
        [1, 2, 3, [4, 5], [6, 7, [8, 9, 10, 11], 12], 13, 14, [15, 16], 17, [18, [19, [20]]]]
      ],
      size: 20
    }
  ];
}

function wordsInput(fn) {
  var words = randomWords(100);

  return [
    {
      name: '5-element array',
      values: [words.slice(0, 5), fn],
      size: 5
    },
    {
      name: '10-element array',
      values: [words.slice(0, 10), fn],
      size: 10
    },
    {
      name: '100-element array',
      values: [words.slice(0, 100), fn],
      size: 100
    }
  ];
}

function evaluateSequence(value, other) {
  if (value instanceof Lazy.Sequence) {
    if (other instanceof Array) {
      return value.toArray();
    }

    return value.toObject();
  }

  return value;
}

function orderAwareComparer(x, y) {
  x = evaluateSequence(x, y);
  y = evaluateSequence(y, x);

  return Race.compare(x, y);
}

function orderAgnosticComparer(x, y) {
  x = Lazy(x).sortBy(identity).toArray();
  y = Lazy(y).sortBy(identity).toArray();

  return Race.compare(x, y);
}

var marathon = new Race.Marathon();

function ensureLazyIteration(impl) {
  return function() {
    var sequence = Race.fastApply(impl, arguments);
    sequence.each(function(x, i) {});
    return sequence;
  };
}

function ensureLodashIteration(impl) {
  return function() {
    var result = Race.fastApply(impl, arguments);
    lodash.each(result, function(x, i) {});
    return result;
  };
}

function addRace(name, inputs, options) {
  if (!selectedRace || name === selectedRace) {
    marathon.add(new Race({
      description: name,
      inputs: inputs,
      impls: {
        lazy: ensureLazyIteration(options.lazy),
        lodash: ensureLodashIteration(options.lodash)
      },
      comparer: options.comparer || orderAwareComparer
    }));
  }
}

addRace('map', numbersInput(increment), {
  lazy: function(array, fn) { return Lazy(array).map(fn); },
  lodash: function(array, fn) { return lodash.map(array, fn); }
});

addRace('filter', numbersInput(isEven), {
  lazy: function(array, fn) { return Lazy(array).filter(fn); },
  lodash: function(array, fn) { return lodash.filter(array, fn); }
});

addRace('sortBy', wordsInput(lastLetter), {
  lazy: function(array, fn) { return Lazy(array).sortBy(fn); },
  lodash: function(array, fn) { return lodash.sortBy(array, fn); }
});

addRace('groupBy', wordsInput(lastLetter), {
  lazy: function(array, fn) { return  Lazy(array).groupBy(fn); },
  lodash: function(array, fn) { return lodash.groupBy(array, fn); }
});

addRace('countBy', wordsInput(lastLetter), {
  lazy: function(array, fn) { return Lazy(array).countBy(fn); },
  lodash: function(array, fn) { return lodash.countBy(array, fn); }
});

addRace('uniq', randomNumbersInput(), {
  lazy: function(array) { return Lazy(array).uniq(); },
  lodash: function(array) { return lodash.uniq(array); }
});

addRace('zip', doubleNumbersInput(), {
  lazy: function(array, other) { return Lazy(array).zip(other); },
  lodash: function(array, other) { return lodash.zip(array, other); }
});

addRace('shuffle', randomNumbersInput(), {
  lazy: function(array) { return Lazy(array).shuffle(); },
  lodash: function(array) { return lodash.shuffle(array); },
  comparer: orderAgnosticComparer
});

addRace('flatten', nestedNumbersInput(), {
  lazy: function(array) { return Lazy(array).flatten(); },
  lodash: function(array) { return lodash.flatten(array); }
});

addRace('difference', doubleNumbersInput(), {
  lazy: function(array, other) { return Lazy(array).difference(other); },
  lodash: function(array, other) { return lodash.difference(array, other); }
});

addRace('union', doubleNumbersInput(), {
  lazy: function(array, other) { return Lazy(array).union(other); },
  lodash: function(array, other) { return lodash.union(array, other); }
});

addRace('intersection', doubleNumbersInput(), {
  lazy: function(array, other) { return Lazy(array).intersection(other); },
  lodash: function(array, other) { return lodash.intersection(array, other); }
});

function formatWinner(winner) {
  return winner.impl + ' (by ' + (winner.margin * 100).toFixed(2) + '%)';
}

function formatOverallWinner(resultGroups) {
  var winners = Lazy(resultGroups)
    .countBy(function(resultGroup) {
      return resultGroup.winner.impl;
    })
    .toObject();

  if (Object.keys(winners).length === 1) {
    return Lazy(winners).keys().first();
  }

  var breakdown = Lazy(winners)
    .map(function(count, winner) {
      return winner + ' - ' + count
    })
    .join(', ');

  return 'mixed (' + breakdown + ')';
}

marathon.start({
  start: function(race) {
    console.log('Starting "' + race.description + '" race...');
  },

  result: function(result) {
    console.log(' * ' + [
      result.input.name,
      result.impl,
      result.perf.toFixed(3) + ' ops/sec'
    ].join('\t'));
  },

  mismatch: function(outputs) {
    console.log(' * mismatch for the "' + outputs.input.name + '" case!');
  },

  complete: function(resultGroups) {
    console.log(' * WINNER: ' + formatOverallWinner(resultGroups));
    console.log('');
  },

  marathonComplete: function(resultGroups) {
    var dataObjects = Lazy(resultGroups)
      .map(function(resultGroup) {
        var dataObject = {
          'race': resultGroup.race,
          'input size': resultGroup.input.size
        };

        Lazy(resultGroup.results).each(function(perf, impl) {
          dataObject[impl] = perf;
        });

        dataObject.winner = formatWinner(resultGroup.winner);

        return dataObject;
      })
      .toArray();

    console.log(stringTable.create(dataObjects, {
      typeFormatters: {
        'number': function(value) {
          return Number(value.toFixed(3));
        }
      },
      capitalizeHeaders: true
    }));
    console.log('');
  }
});
<commit_msg>hmm... lazy is getting a bit whipped here :(<commit_after>var Lazy        = require('../lazy.js'),
    lodash      = require('lodash'),
    underscore  = require('underscore'),
    Benchmark   = require('benchmark'),
    Race        = require('race.js'),
    stringTable = require('string-table');

Benchmark.options.maxTime = 0.5;
var selectedRace = null;

if (process.argv.length > 2) {
  selectedRace = process.argv[2];
  console.log('Just going to run "' + selectedRace + '" race');

} else {
  console.log('Running all races...');
}

function identity(x) {
  return x;
}

function increment(x) {
  return x + 1;
}

function isEven(x) {
  return x % 2 === 0;
}

function lastLetter(str) {
  return str.charAt(str.length - 1);
}

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

function randomNumbers(count, min, max) {
  var getRandomNumber = function() {
    return randomNumber(min, max);
  };

  return Lazy.generate(getRandomNumber, count).toArray();
}

var alphabet = 'abcdefghijklmnopqrstuvwxyz';
function randomWord() {
  var length = (3 + Math.floor(Math.random() * 7));

  var word = '';
  while (word.length < length) {
    word += alphabet[Math.floor(Math.random() * alphabet.length)];
  }
  return word;
}

function randomWords(count) {
  return Lazy.generate(randomWord, count).toArray();
}

function numbersInput(fn) {
  return [
    {
      name: '5-element array',
      values: [Race.integers(5), fn],
      size: 5
    },
    {
      name: '10-element array',
      values: [Race.integers(10), fn],
      size: 10
    },
    {
      name: '100-element array',
      values: [Race.integers(100), fn],
      size: 100
    }
  ];
}

function randomNumbersInput() {
  return [
    {
      name: '5 random numbers between 1-3',
      values: [randomNumbers(5, 1, 3)],
      size: 5
    },
    {
      name: '10 random numbers between 1-5',
      values: [randomNumbers(10, 1, 5)],
      size: 10
    },
    {
      name: '100 random numbers between 1-25',
      values: [randomNumbers(100, 1, 25)],
      size: 100
    }
  ]
}

function doubleNumbersInput() {
  return [
    {
      name: '2 5-element arrays',
      values: [Race.integers(5), Race.integers(5, 3)],
      size: 5
    },
    {
      name: '2 10-element arrays',
      values: [Race.integers(10), Race.integers(10, 5)],
      size: 10
    },
    {
      name: '2 100-element arrays',
      values: [Race.integers(100), Race.integers(100, 50)],
      size: 100
    }
  ];
}

function nestedNumbersInput() {
  return [
    {
      name: 'Small nested array',
      values: [
        [1, 2, [3, 4, [5, 6], 7, 8], 9, 10]
      ],
      size: 10
    },
    {
      name: 'Medium nested array',
      values: [
        [1, 2, 3, [4, 5], [6, 7, [8, 9, 10, 11], 12], 13, 14, [15, 16], 17, [18, [19, [20]]]]
      ],
      size: 20
    }
  ];
}

function wordsInput(fn) {
  var words = randomWords(100);

  return [
    {
      name: '5-element array',
      values: [words.slice(0, 5), fn],
      size: 5
    },
    {
      name: '10-element array',
      values: [words.slice(0, 10), fn],
      size: 10
    },
    {
      name: '100-element array',
      values: [words.slice(0, 100), fn],
      size: 100
    }
  ];
}

function evaluateSequence(value, other) {
  if (value instanceof Lazy.Sequence) {
    if (other instanceof Array) {
      return value.toArray();
    }

    return value.toObject();
  }

  return value;
}

function orderAwareComparer(x, y) {
  x = evaluateSequence(x, y);
  y = evaluateSequence(y, x);

  return Race.compare(x, y);
}

function orderAgnosticComparer(x, y) {
  x = Lazy(x).sortBy(identity).toArray();
  y = Lazy(y).sortBy(identity).toArray();

  return Race.compare(x, y);
}

var marathon = new Race.Marathon();

function ensureLazyIteration(impl) {
  return function() {
    var sequence = Race.fastApply(impl, arguments);
    sequence.each(function(x, i) {});
    return sequence;
  };
}

function ensureLodashIteration(impl) {
  return function() {
    var result = Race.fastApply(impl, arguments);
    lodash.each(result, function(x, i) {});
    return result;
  };
}

function addRace(name, inputs, options) {
  if (!selectedRace || name === selectedRace) {
    marathon.add(new Race({
      description: name,
      inputs: inputs,
      impls: {
        lazy: options.valueOnly ? options.lazy : ensureLazyIteration(options.lazy),
        lodash: options.valueOnly ? options.lodash : ensureLodashIteration(options.lodash)
      },
      comparer: options.comparer || orderAwareComparer
    }));
  }
}

addRace('map', numbersInput(increment), {
  lazy: function(array, fn) { return Lazy(array).map(fn); },
  lodash: function(array, fn) { return lodash.map(array, fn); }
});

addRace('filter', numbersInput(isEven), {
  lazy: function(array, fn) { return Lazy(array).filter(fn); },
  lodash: function(array, fn) { return lodash.filter(array, fn); }
});

addRace('sortBy', wordsInput(lastLetter), {
  lazy: function(array, fn) { return Lazy(array).sortBy(fn); },
  lodash: function(array, fn) { return lodash.sortBy(array, fn); }
});

addRace('groupBy', wordsInput(lastLetter), {
  lazy: function(array, fn) { return  Lazy(array).groupBy(fn); },
  lodash: function(array, fn) { return lodash.groupBy(array, fn); }
});

addRace('countBy', wordsInput(lastLetter), {
  lazy: function(array, fn) { return Lazy(array).countBy(fn); },
  lodash: function(array, fn) { return lodash.countBy(array, fn); }
});

addRace('uniq', randomNumbersInput(), {
  lazy: function(array) { return Lazy(array).uniq(); },
  lodash: function(array) { return lodash.uniq(array); }
});

addRace('zip', doubleNumbersInput(), {
  lazy: function(array, other) { return Lazy(array).zip(other); },
  lodash: function(array, other) { return lodash.zip(array, other); }
});

addRace('shuffle', randomNumbersInput(), {
  lazy: function(array) { return Lazy(array).shuffle(); },
  lodash: function(array) { return lodash.shuffle(array); },
  comparer: orderAgnosticComparer
});

addRace('flatten', nestedNumbersInput(), {
  lazy: function(array) { return Lazy(array).flatten(); },
  lodash: function(array) { return lodash.flatten(array); }
});

addRace('difference', doubleNumbersInput(), {
  lazy: function(array, other) { return Lazy(array).difference(other); },
  lodash: function(array, other) { return lodash.difference(array, other); }
});

addRace('union', doubleNumbersInput(), {
  lazy: function(array, other) { return Lazy(array).union(other); },
  lodash: function(array, other) { return lodash.union(array, other); }
});

addRace('intersection', doubleNumbersInput(), {
  lazy: function(array, other) { return Lazy(array).intersection(other); },
  lodash: function(array, other) { return lodash.intersection(array, other); }
});

addRace('max', numbersInput(), {
  lazy: function(array) { return Lazy(array).max(); },
  lodash: function(array) { return lodash.max(array); },
  valueOnly: true
});

addRace('map-max', numbersInput(increment), {
  lazy: function(array, fn) { return Lazy(array).map(fn).max(); },
  lodash: function(array, fn) { return lodash.max(lodash.map(array, fn)); },
  valueOnly: true
});

addRace('map-filter-max', numbersInput(increment), {
  lazy: function(array, fn) { return Lazy(array).map(fn).filter(isEven).max(); },
  lodash: function(array, fn) { return lodash.max(lodash.filter(lodash.map(array, fn), isEven)); },
  valueOnly: true
});

function formatWinner(winner) {
  return winner.impl + ' (by ' + (winner.margin * 100).toFixed(2) + '%)';
}

function formatOverallWinner(resultGroups) {
  var winners = Lazy(resultGroups)
    .countBy(function(resultGroup) {
      return resultGroup.winner.impl;
    })
    .toObject();

  if (Object.keys(winners).length === 1) {
    return Lazy(winners).keys().first();
  }

  var breakdown = Lazy(winners)
    .map(function(count, winner) {
      return winner + ' - ' + count
    })
    .join(', ');

  return 'mixed (' + breakdown + ')';
}

marathon.start({
  start: function(race) {
    console.log('Starting "' + race.description + '" race...');
  },

  result: function(result) {
    console.log(' * ' + [
      result.input.name,
      result.impl,
      result.perf.toFixed(3) + ' ops/sec'
    ].join('\t'));
  },

  mismatch: function(outputs) {
    console.log(' * mismatch for the "' + outputs.input.name + '" case!');
  },

  complete: function(resultGroups) {
    console.log(' * WINNER: ' + formatOverallWinner(resultGroups));
    console.log('');
  },

  marathonComplete: function(resultGroups) {
    var dataObjects = Lazy(resultGroups)
      .map(function(resultGroup) {
        var dataObject = {
          'race': resultGroup.race,
          'input size': resultGroup.input.size
        };

        Lazy(resultGroup.results).each(function(perf, impl) {
          dataObject[impl] = perf;
        });

        dataObject.winner = formatWinner(resultGroup.winner);

        return dataObject;
      })
      .toArray();

    console.log(stringTable.create(dataObjects, {
      typeFormatters: {
        'number': function(value) {
          return Number(value.toFixed(3));
        }
      },
      capitalizeHeaders: true
    }));
    console.log('');
  }
});
<|endoftext|>


<commit_before>var zeller = require('./zeller');

var export_obj = {};

var days_in_month = {
  1: 31,
  2: 28,
  3: 31,
  4: 30,
  5: 31,
  6: 30,
  7: 31,
  8: 31,
  9: 30,
  10: 31,
  11: 30,
  12: 31
}

var days_of_week = {
  0: "Su",
  1: "Mo",
  2: "Tu",
  3: "We",
  4: "Th",
  5: "Fr",
  6: "Sa"
}

var month_name = {
  1: "January",
  2: "February",
  3: "March",
  4: "April",
  5: "May",
  6: "June",
  7: "July",
  8: "August",
  9: "September",
  10: "October",
  11: "November",
  12: "December"
}

export_obj.numDays = function(month, year){
  return (month === 2 && this.isLeap(year)) ? 29 : days_in_month[month];
}

export_obj.isLeap = function(year) {
  if (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {return true;}
  return false;
}

export_obj.writeYear = function(year) {
  var year = parseInt(year);
  this.buckets = [[],[],[],[],[],[],[],[]];
  for (var i = 1; i < 13; i++) {
    this.writeMonth(i, year, true);
  }
  //console.log(this.buckets);
  console.log(yearHeader());

  for (var j = 0; j <= 9; j+=3) {
    for (var i = 0; i < this.buckets.length; i++) {
      console.log(this.buckets[i][j] + " " + this.buckets[i][j+1] + " " + this.buckets[i][j+2]);
    }
  }

  function yearHeader(){
    var spaces_num = Math.floor((64 - year.toString().length) / 2);
    var spaces = "";
    for (var i = 0; i < spaces_num - 1; i++) {
      spaces += " ";
    }
    return spaces + year + spaces + "\n";
  }
}

// Y is a flag to pass in to tell this to dump output into the class'
// buckets instead of console logging everything,
// which writeYear will use to generate the year's calendar
// (ie, writeMonth is a helper function to writeYear with the flag enabled).
// without the flag it's its own function and prints the specified month.
export_obj.writeMonth = function(month, year, Y){
  var j = 1;
  var month = parseInt(month);
  var year = parseInt(year);
  var numDays = this.numDays(month, year);
  //console.log(numDays, month, year);
  var firstIs = (zeller.calculate(month, 1, year) + 6) % 7;
  // let's get the first day into format: 0 is Sun, 1 is Mon, 6 is Sat.
  if(!Y) {
    console.log(makeHeader());
    console.log("Su Mo Tu We Th Fr Sa");
    console.log(makeFirstLine());
    for (var i = 0; i < 5; i++) {
      console.log(makeOtherLine());
    }
  } else {
    this.buckets[0].push(makeHeader());
    this.buckets[1].push("Su Mo Tu We Th Fr Sa ");
    this.buckets[2].push(makeFirstLine());
    for (var i = 3; i < 8; i++) {
      this.buckets[i].push(makeOtherLine());
    }
  }

  function makeHeader() {
    var line = "";
    var spaces = "";
    var monthTitle = month_name[month];
    var content = monthTitle;
    if (!Y) {content = content + " " + year;}
    var spaces_num = Math.floor((20 - content.length) / 2);
    for (var i = 0; i < spaces_num; i++) {
      spaces += " ";
    }
    line = spaces + content + spaces;
    for (var i = 0; i < (20 - line.length) + 2; i++) {
      line += " ";
    }
    return line;
  }

  function makeFirstLine () {
    var line = "";
    for (var i = 0; i < firstIs; i++) {
      line += "   ";
    }
    for (var i = firstIs; i <= 6; i++) {
      if (i.toString().length === 1) {line += " ";}
      line += j
      if (i !== 7) {line += " ";}
      j++;
    }
    return line;
  }

  function makeOtherLine() {
    var line = "";
    for (var i = 0; i < 7; i++) {
      if (j <= numDays && j.toString().length === 1) {
        line += " " + j;
      } else if (j <= numDays) {
        line += j;
      } else {
        line += "  ";
      }
      if (i !== 7) {line += " ";}
      j++
    }
    return line;
  }
}

module.exports = export_obj;
<commit_msg>clean up<commit_after>var zeller = require('./zeller');

var export_obj = {};
var days_in_month = {1: 31,  2: 28,  3: 31,  4: 30,  5: 31,  6: 30,
                     7: 31,  8: 31,  9: 30, 10: 31, 11: 30, 12: 31};

var days_of_week = {0: "Su", 1: "Mo", 2: "Tu", 3: "We", 4: "Th",
                    5: "Fr", 6: "Sa"};

var month_name = {1: "January", 2: "February", 3: "March",
                  4: "April",   5: "May",      6: "June",
                  7: "July",    8: "August",   9: "September",
                 10: "October",11: "November",12: "December"};

export_obj.numDays = function(month, year){
  return (month === 2 && this.isLeap(year)) ? 29 : days_in_month[month];
}

export_obj.isLeap = function(year) {
  if (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {return true;}
  return false;
}

export_obj.writeYear = function(year) {
  var year = parseInt(year);
  this.buckets = [[],[],[],[],[],[],[],[]];
  for (var i = 1; i < 13; i++) {
    this.writeMonth(i, year, true);
  }
  console.log(yearHeader());

  for (var j = 0; j <= 9; j+=3) {
    for (var i = 0; i < this.buckets.length; i++) {
      console.log(this.buckets[i][j] + " " + this.buckets[i][j+1] + " " + this.buckets[i][j+2]);
    }
  }

  function yearHeader(){
    var spaces_num = Math.floor((64 - year.toString().length) / 2);
    var spaces = "";
    for (var i = 0; i < spaces_num - 1; i++) {
      spaces += " ";
    }
    return spaces + year + spaces + "\n";
  }
}

// Y is a flag to pass in to tell this to dump output into the class'
// buckets instead of console logging everything,
// which writeYear will use to generate the year's calendar
// (ie, writeMonth is a helper function to writeYear with the flag enabled).
// without the flag it's its own function and prints the specified month.
export_obj.writeMonth = function(month, year, Y){
  var j = 1;
  var month = parseInt(month);
  var year = parseInt(year);
  var numDays = this.numDays(month, year);
  //console.log(numDays, month, year);
  var firstIs = (zeller.calculate(month, 1, year) + 6) % 7;
  // let's get the first day into format: 0 is Sun, 1 is Mon, 6 is Sat.
  if(!Y) {
    console.log(makeHeader());
    console.log("Su Mo Tu We Th Fr Sa");
    console.log(makeFirstLine());
    for (var i = 0; i < 5; i++) {
      console.log(makeOtherLine());
    }
  } else {
    this.buckets[0].push(makeHeader());
    this.buckets[1].push("Su Mo Tu We Th Fr Sa ");
    this.buckets[2].push(makeFirstLine());
    for (var i = 3; i < 8; i++) {
      this.buckets[i].push(makeOtherLine());
    }
  }

  function makeHeader() {
    var line = "";
    var spaces = "";
    var monthTitle = month_name[month];
    var content = monthTitle;
    if (!Y) {content = content + " " + year;}
    var spaces_num = Math.floor((20 - content.length) / 2);
    for (var i = 0; i < spaces_num; i++) {
      spaces += " ";
    }
    line = spaces + content + spaces;
    for (var i = 0; i < (20 - line.length) + 2; i++) {
      line += " ";
    }
    return line;
  }

  function makeFirstLine () {
    var line = "";
    for (var i = 0; i < firstIs; i++) {
      line += "   ";
    }
    for (var i = firstIs; i <= 6; i++) {
      if (i.toString().length === 1) {line += " ";}
      line += j
      if (i !== 7) {line += " ";}
      j++;
    }
    return line;
  }

  function makeOtherLine() {
    var line = "";
    for (var i = 0; i < 7; i++) {
      if (j <= numDays && j.toString().length === 1) {
        line += " " + j;
      } else if (j <= numDays) {
        line += j;
      } else {
        line += "  ";
      }
      if (i !== 7) {line += " ";}
      j++
    }
    return line;
  }
}

module.exports = export_obj;
<|endoftext|>


<commit_before>/* jslint node: true, esnext: true */

"use strict";

const path = require("path");
const events = require('events');

const flow = require("./flow");
const progressReporter = require("./progressReporter");
const stepImplementation = require("./stepImplementation");
const endpointImplementation = require("./endpointImplementation");

const flowDefinition = require('kronos-flow');
const flowValidator = flowDefinition.validator;
const flowSchema = flowDefinition.schema;

const stepDefinition = require('kronos-step');
const stepValidator = stepDefinition.validator;
const stepSchema = stepDefinition.schema;

exports.stepImplementation = stepImplementation;
exports.endpointImplementation = endpointImplementation;

const _ = require('lodash');

const log4js = require('log4js');
const logger = log4js.getLogger('kronos-step-service-manager:manager');

/*
 * creates a kronos service manager.
 * Options:
 *    stepDirectories - addittional directories to consult for step implementations
 *    flows - flow declaration to load
 *    validateSchema - do schema validation; defaults to false
 *
 * @param {Object} options
 * @return {Promise} a promise with the service manager as its value
 */
exports.manager = function (options) {
  if (!options) {
    options = {};
  }

  if (!options.hasOwnProperty("validateSchema")) {
    options.validateSchema = false;
  }

  if (!options.progressReporter) {
    options.progressReporter = progressReporter.defaultProgressReporter();
  }

  const flowDefinitions = {};
  const stepImplementations = {};

  const manager = Object.create(new events.EventEmitter(), {
    flowDefinitions: {
      value: flowDefinitions
    },
    stepImplementations: {
      value: stepImplementations
    }
  });

  /**
   * declareFlows function - declares new flows
   * Events:
   * 	emits 'flowDeclard' event for every newly created flow
   * @param  {type} flowDef          A JSON Object which describes the flows
   * @param  {type} progressReporter Optional: A Progresss reporter.
   * @return {type}                  dictionary of the newly created flows
   */
  manager.declareFlows = function (flowDef, progressReporter) {

    function _declare() {
      const flows = flow.create(manager, flowDef, progressReporter);
      for (let fn in flows) {
        flowDefinitions[fn] = flows[fn];
        manager.emit('flowDeclared', flows[fn]);
      }
      return flows;
    }

    if (options.validateSchema) {
      // Check if the given flow matches the flow schema
      if (flowValidator.validate(flowDef, flowSchema)) {
        // The given flow matches the schema
        return _declare();
      } else {
        // The schema validator got an error
        const errors = flowValidator.getLastErrors();
        logger.error(errors);
        throw (errors);
      }
    } else {
      return _declare();
    }
  };

  /**
   * brings a declared flow to live state
   */
  manager.intializeFlow = function (flowName) {
    const flow = flowDefinitions[flowName];
    flow.initialize.apply(flow, this);
  };

  /**
   * declareSteps function - Declare new steps.
   * If there is already a step with the given name, it will be overwritten
   *
   * @param  {object} stepDefinition   The step definition (not the implementation)
   * @param  {string} stepName Optional: A new name under which the step should be registered
   * @param  {string} config Optional: A new config to overwrite the existing config in the step definition
   * @param  {boolean} overwrite Optional: If set to true, an exsiting step with the same name will be overwritten
   * @return {boolean} true if the step could be registered. False if there is a step with the same name
   */
  manager.declareSteps = function (step) {
    if (options.validateSchema) {
      // first make a copy of the given step.
      const stepCopy = _.cloneDeep(step.stepImplementations);

      // a step definition my contain one or more steps.
      for (let stepName in stepCopy) {
        logger.debug(`Check the step name 'stepName'`);

        let tmpStep = stepCopy[stepName];
        delete(tmpStep.initialize); // delete the initilize function from the definition

        if (!stepValidator.validate(tmpStep, stepSchema)) {
          let errors = stepValidator.getLastErrors();
          logger.error(errors);
          throw (errors);
        }
      }
    }

    // if we reach this point there where no errors
    stepImplementation.registerSteps(stepImplementations, step.stepImplementations);
  };

  // create list of all directories to load step definitions from
  const stepDirs = [path.join(__dirname, 'steps')];
  if (options.stepDirectories) {
    if (Array.isArray(options.stepDirectories)) {
      options.stepDirectories.each(function (d) {
        stepDirs.push(d);
      });
    } else {
      stepDirs.push(options.stepDirectories);
    }
  }

  return stepImplementation.registerStepsFromDirs(stepImplementations, stepDirs)
    .then(function (steps) {
      return new Promise(function (resolve) {
        if (options.flows) {
          manager.declareFlows(options.flows, options.progressReporter);
        }

        resolve(manager);
      });
    });
};
<commit_msg>fixed: manager can now handle array of stepDirectories<commit_after>/* jslint node: true, esnext: true */

"use strict";

const path = require("path");
const events = require('events');

const flow = require("./flow");
const progressReporter = require("./progressReporter");
const stepImplementation = require("./stepImplementation");
const endpointImplementation = require("./endpointImplementation");

const flowDefinition = require('kronos-flow');
const flowValidator = flowDefinition.validator;
const flowSchema = flowDefinition.schema;

const stepDefinition = require('kronos-step');
const stepValidator = stepDefinition.validator;
const stepSchema = stepDefinition.schema;

exports.stepImplementation = stepImplementation;
exports.endpointImplementation = endpointImplementation;

const _ = require('lodash');

const log4js = require('log4js');
const logger = log4js.getLogger('kronos-step-service-manager:manager');

/*
 * creates a kronos service manager.
 * Options:
 *    stepDirectories - addittional directories to consult for step implementations
 *    flows - flow declaration to load
 *    validateSchema - do schema validation; defaults to false
 *
 * @param {Object} options
 * @return {Promise} a promise with the service manager as its value
 */
exports.manager = function (options) {
  if (!options) {
    options = {};
  }

  if (!options.hasOwnProperty("validateSchema")) {
    options.validateSchema = false;
  }

  if (!options.progressReporter) {
    options.progressReporter = progressReporter.defaultProgressReporter();
  }

  const flowDefinitions = {};
  const stepImplementations = {};

  const manager = Object.create(new events.EventEmitter(), {
    flowDefinitions: {
      value: flowDefinitions
    },
    stepImplementations: {
      value: stepImplementations
    }
  });

  /**
   * declareFlows function - declares new flows
   * Events:
   * 	emits 'flowDeclard' event for every newly created flow
   * @param  {type} flowDef          A JSON Object which describes the flows
   * @param  {type} progressReporter Optional: A Progresss reporter.
   * @return {type}                  dictionary of the newly created flows
   */
  manager.declareFlows = function (flowDef, progressReporter) {

    function _declare() {
      const flows = flow.create(manager, flowDef, progressReporter);
      for (let fn in flows) {
        flowDefinitions[fn] = flows[fn];
        manager.emit('flowDeclared', flows[fn]);
      }
      return flows;
    }

    if (options.validateSchema) {
      // Check if the given flow matches the flow schema
      if (flowValidator.validate(flowDef, flowSchema)) {
        // The given flow matches the schema
        return _declare();
      } else {
        // The schema validator got an error
        const errors = flowValidator.getLastErrors();
        logger.error(errors);
        throw (errors);
      }
    } else {
      return _declare();
    }
  };

  /**
   * brings a declared flow to live state
   */
  manager.intializeFlow = function (flowName) {
    const flow = flowDefinitions[flowName];
    flow.initialize.apply(flow, this);
  };

  /**
   * declareSteps function - Declare new steps.
   * If there is already a step with the given name, it will be overwritten
   *
   * @param  {object} stepDefinition   The step definition (not the implementation)
   * @param  {string} stepName Optional: A new name under which the step should be registered
   * @param  {string} config Optional: A new config to overwrite the existing config in the step definition
   * @param  {boolean} overwrite Optional: If set to true, an exsiting step with the same name will be overwritten
   * @return {boolean} true if the step could be registered. False if there is a step with the same name
   */
  manager.declareSteps = function (step) {
    if (options.validateSchema) {
      // first make a copy of the given step.
      const stepCopy = _.cloneDeep(step.stepImplementations);

      // a step definition my contain one or more steps.
      for (let stepName in stepCopy) {
        logger.debug(`Check the step name 'stepName'`);

        let tmpStep = stepCopy[stepName];
        delete(tmpStep.initialize); // delete the initilize function from the definition

        if (!stepValidator.validate(tmpStep, stepSchema)) {
          let errors = stepValidator.getLastErrors();
          logger.error(errors);
          throw (errors);
        }
      }
    }

    // if we reach this point there where no errors
    stepImplementation.registerSteps(stepImplementations, step.stepImplementations);
  };

  // create list of all directories to load step definitions from
  const stepDirs = [path.join(__dirname, 'steps')];
  if (options.stepDirectories) {
    const sd = options.stepDirectories;
    if (Array.isArray(sd)) {
      sd.forEach(function (d) {
        stepDirs.push(d);
      });
    } else {
      stepDirs.push(sd);
    }
  }

  return stepImplementation.registerStepsFromDirs(stepImplementations, stepDirs)
    .then(function (steps) {
      return new Promise(function (resolve) {
        if (options.flows) {
          manager.declareFlows(options.flows, options.progressReporter);
        }

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


<commit_before>/*
    The Manager module manages the user list (load/save), the submodules,
    also loads and distributes the application configuration.
*/

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

module.exports = {

    /*
     * Submodules binded to the manager
     */

    submodules: {
        auth: require(path.join(__dirname, 'auth')),
        trigger: require(path.join(__dirname, 'trigger')),
        twitter: require(path.join(__dirname, 'twitter'))
    },

    /*
     * Attributes
     */

    config: null,
    users: {},

    /*
     * Initialization
     */

    init: function(config) {
        this.config = config;
        this.config.users_file = path.join(process.cwd(), this.config.users_file);

        this.load(); // Load the users

        // Modules initialization
        var subs = this.submodules;
        subs.auth.init(config, this);
        subs.trigger.init(this.users, subs.twitter);
        subs.twitter.init(config, this);

        // We need to redefine the "this" reference or the controllers won't find the "set" function
        for(var i in this.controllers) {
            this.controllers[i] = this.controllers[i](this);
        }

        return this;
    },

    /*
     * Controllers : each controller needs to be inside a closure so the "this" keyword could be avoided
     * and the "_this" reference will be used instead
     */

    controllers: {

        settings: function(_this) {
            return function(req, res, next) {
                if(req.session.id) {
                    var utc = parseInt(req.body.utc),
                        hour = parseInt(req.body.hour);

                    if(!isNaN(utc) && !isNaN(hour)) {
                        _this.set(req.session.id, {
                            utc: utc,
                            hour: hour
                        });

                        res.locals.status = 0; // 0 = OK
                    } else {
                        res.locals.status = 1; // 1 = Incorrect arguments
                    }
                } else {
                    res.locals.status = 2; // 2 = Not authenticated
                }

                next();
            };
        }

    },

    /*
     * User list : loading / saving
     */

    load: function() {
        var filename = this.config.users_file;

        filename = (filename[0] == '/') ? filename : path.join(__dirname, filename);

        if(fs.existsSync(filename)) {
            var data = fs.readFileSync(filename, 'utf-8');
            this.users = JSON.parse(data) || {};
        } else {
            console.log('No user list found at the specified location. A new one will be created.');
        }
    },

    save: function() {
        var data = JSON.stringify(this.users),
            filename = this.config.users_file;

        filename = (filename[0] == '/') ? filename : path.join(__dirname, filename);

        fs.writeFile(filename, data, 'utf-8', function(err) {
            err && console.log(err);
        });
    },

    /*
     * User list : management
     */

    set: function(id, details) {
        var user = this.users[id] || {
            id: id,
            name: '',
            access_token: '',
            access_token_secret: '',
            utc: 0,
            hour: 17
        };

        for(var i in user) {
            if(typeof details[i] != 'undefined') {
                user[i] = details[i];
            }
        }

        this.users[id] = user;
        this.save();

        this.submodules.trigger.set(user);

        console.log('NOTICE: User ' + user.name + '[' + id + '] has been set');
    },

    unset: function(user) {
        var id = user.id,
            name = user.name;

        this.submodules.trigger.unset(user);

        this.users[id] = null;
        delete this.users[id];
        this.save();

        console.log('NOTICE: User ' + name + '[' + id + '] has been unset');
    }

};<commit_msg>Improved warning message for the user list<commit_after>/*
    The Manager module manages the user list (load/save), the submodules,
    also loads and distributes the application configuration.
*/

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

module.exports = {

    /*
     * Submodules binded to the manager
     */

    submodules: {
        auth: require(path.join(__dirname, 'auth')),
        trigger: require(path.join(__dirname, 'trigger')),
        twitter: require(path.join(__dirname, 'twitter'))
    },

    /*
     * Attributes
     */

    config: null,
    users: {},

    /*
     * Initialization
     */

    init: function(config) {
        this.config = config;
        this.config.users_file = path.join(process.cwd(), this.config.users_file);

        this.load(); // Load the users

        // Modules initialization
        var subs = this.submodules;
        subs.auth.init(config, this);
        subs.trigger.init(this.users, subs.twitter);
        subs.twitter.init(config, this);

        // We need to redefine the "this" reference or the controllers won't find the "set" function
        for(var i in this.controllers) {
            this.controllers[i] = this.controllers[i](this);
        }

        return this;
    },

    /*
     * Controllers : each controller needs to be inside a closure so the "this" keyword could be avoided
     * and the "_this" reference will be used instead
     */

    controllers: {

        settings: function(_this) {
            return function(req, res, next) {
                if(req.session.id) {
                    var utc = parseInt(req.body.utc),
                        hour = parseInt(req.body.hour);

                    if(!isNaN(utc) && !isNaN(hour)) {
                        _this.set(req.session.id, {
                            utc: utc,
                            hour: hour
                        });

                        res.locals.status = 0; // 0 = OK
                    } else {
                        res.locals.status = 1; // 1 = Incorrect arguments
                    }
                } else {
                    res.locals.status = 2; // 2 = Not authenticated
                }

                next();
            };
        }

    },

    /*
     * User list : loading / saving
     */

    load: function() {
        var filename = this.config.users_file;

        filename = (filename[0] == '/') ? filename : path.join(__dirname, filename);

        if(fs.existsSync(filename)) {
            var data = fs.readFileSync(filename, 'utf-8');
            this.users = JSON.parse(data) || {};
        } else {
            console.log('No user list found at the specified location ('+ filename +'). A new one will be created.');
        }
    },

    save: function() {
        var data = JSON.stringify(this.users),
            filename = this.config.users_file;

        filename = (filename[0] == '/') ? filename : path.join(__dirname, filename);

        fs.writeFile(filename, data, 'utf-8', function(err) {
            err && console.log(err);
        });
    },

    /*
     * User list : management
     */

    set: function(id, details) {
        var user = this.users[id] || {
            id: id,
            name: '',
            access_token: '',
            access_token_secret: '',
            utc: 0,
            hour: 17
        };

        for(var i in user) {
            if(typeof details[i] != 'undefined') {
                user[i] = details[i];
            }
        }

        this.users[id] = user;
        this.save();

        this.submodules.trigger.set(user);

        console.log('NOTICE: User ' + user.name + '[' + id + '] has been set');
    },

    unset: function(user) {
        var id = user.id,
            name = user.name;

        this.submodules.trigger.unset(user);

        this.users[id] = null;
        delete this.users[id];
        this.save();

        console.log('NOTICE: User ' + name + '[' + id + '] has been unset');
    }

};<|endoftext|>


<commit_before>Jobs = new Mongo.Collection("jobs");

if (Meteor.isServer) {
  Meteor.publish("jobs", function(){
    return Jobs.find();
  });

  Meteor.publish("allUsers", function () {
    return Meteor.users.find();
  });

  RssFeed.publish('jobs.rss', function(query){
    var self = this;

    self.setValue('title', self.cdata('DevICT Job Board'));
    self.setValue('description', self.cdata('Listings for Development jobs in the ICT area'));
    self.setValue('link', 'http://104.131.100.18/');
    self.setValue('lastBuildDate', new Date());
    self.setValue('pubDate', new Date());
    self.setValue('ttl', 1);

    Jobs.find({'isExpired': false}).forEach(function(doc){
      self.addItem({
        title: doc.title + ' - ' + doc.company,
        description: doc.category + ' - ' + doc.description,
        link: 'http://104.131.100.18/view/' + doc._id,
        pubDate: doc.createdAt
      });
    });
  });

  Meteor.methods({
    sendEmail: function(to, from, subject, text, resume){
      check([to, from, subject, text], [String]);

      this.unblock();

      attachments = [];
      //Check to see if resume is link or was uploaded
      if(typeof resume != "string"){
        attachments.push(resume);
      }

      //If resume is link
      if(attachments.length == 0){
        text += 'Resume available at ' + resume;
        Email.send({
          to: to,
          from: from,
          subject: subject,
          text: text
        })
      }
      //if resume was uploaded
      else{
        Email.send({
          to: to,
          from: from,
          subject: subject,
          text: text,
          attachments: attachments
        })
      }
    }
  });
}

if (Meteor.isClient){
  Meteor.startup(function(){
    Hooks.init();
  });

  Meteor.subscribe("jobs", function(){
    activeJobs = Jobs.find({'isExpired': false}).fetch();
    for(var i = 0; i < activeJobs.length; i++){
      currentDate = new Date();
      expirationDate = activeJobs[i].createdAt;
      expirationDate.setDate(expirationDate.getDate() + 60);
      if(currentDate > expirationDate){
        console.log("Expiring item ", i);
        Meteor.call("expireJob", activeJobs[i]._id);
      }
    }
  });

   Meteor.subscribe('allUsers');
}

Meteor.methods({
  addJob: function(title, company, category, color, description, perks, isEmail, url){
    //Make sure user is logged in before inserting a task
    if(!Meteor.userId()){
      throw new Meteor.Error("not-authorized");
    }

    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth() + 1;

    return Jobs.insert({
      title: title,
      company: company,
      category: category,
      color: color,
      description: description,
      perks: perks,
      isEmail: isEmail,
      url: url,
      createdAt: today,
      day: dd,
      month: mm,
      isExpired: false,
      owner: Meteor.userId(),
      username: Meteor.user().username
    });
  },
  editJob: function(jobId, title, company, category, color, description, perks, isEmail, url){
      //Make sure user is logged in before inserting a task
      if(!Meteor.userId()){
        throw new Meteor.Error("not-authorized");
      }

      var today = new Date();
      var dd = today.getDate();
      var mm = today.getMonth() + 1;

      Jobs.update(jobId, { $set: {
        title: title,
        company: company,
        category: category,
        color: color,
        description: description,
        perks: perks,
        isEmail: isEmail,
        url: url,
        createdAt: today,
        day: dd,
        month: mm,
        isExpired: false
      }
    });
    return jobId;
  },
  deleteJob: function(jobId){
    job = Jobs.find({ _id: jobId}).fetch();
    if(Meteor.userId() != job[0].owner){
      throw new Meteor.Error("not-authorized");
    }
    Jobs.remove(jobId);
  },
  renewJob: function(jobId){
    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth() + 1;
    Jobs.update(jobId, { $set: { createdAt: today, day: dd, month: mm, isExpired: false } });
  },
  expireJob: function(jobId){
    Jobs.update(jobId, { $set: { isExpired: true } });
  },
  grantAdmin: function(userId){
    var loggedInUser = Meteor.user();
    if (!loggedInUser || !Roles.userIsInRole(loggedInUser, ['admin'])) {
      throw new Meteor.Error(403, "Access denied")
    }
    Roles.setUserRoles(userId, ['admin'])
  }
});
<commit_msg>Allows user to set first admin<commit_after>Jobs = new Mongo.Collection("jobs");

if (Meteor.isServer) {
  Meteor.publish("jobs", function(){
    return Jobs.find();
  });

  Meteor.publish("allUsers", function () {
    return Meteor.users.find();
  });

  RssFeed.publish('jobs.rss', function(query){
    var self = this;

    self.setValue('title', self.cdata('DevICT Job Board'));
    self.setValue('description', self.cdata('Listings for Development jobs in the ICT area'));
    self.setValue('link', 'http://104.131.100.18/');
    self.setValue('lastBuildDate', new Date());
    self.setValue('pubDate', new Date());
    self.setValue('ttl', 1);

    Jobs.find({'isExpired': false}).forEach(function(doc){
      self.addItem({
        title: doc.title + ' - ' + doc.company,
        description: doc.category + ' - ' + doc.description,
        link: 'http://104.131.100.18/view/' + doc._id,
        pubDate: doc.createdAt
      });
    });
  });

  Meteor.methods({
    sendEmail: function(to, from, subject, text, resume){
      check([to, from, subject, text], [String]);

      this.unblock();

      attachments = [];
      //Check to see if resume is link or was uploaded
      if(typeof resume != "string"){
        attachments.push(resume);
      }

      //If resume is link
      if(attachments.length == 0){
        text += 'Resume available at ' + resume;
        Email.send({
          to: to,
          from: from,
          subject: subject,
          text: text
        })
      }
      //if resume was uploaded
      else{
        Email.send({
          to: to,
          from: from,
          subject: subject,
          text: text,
          attachments: attachments
        })
      }
    }
  });
}

if (Meteor.isClient){
  Meteor.startup(function(){
    Hooks.init();
  });

  Meteor.subscribe("jobs", function(){
    activeJobs = Jobs.find({'isExpired': false}).fetch();
    for(var i = 0; i < activeJobs.length; i++){
      currentDate = new Date();
      expirationDate = activeJobs[i].createdAt;
      expirationDate.setDate(expirationDate.getDate() + 60);
      if(currentDate > expirationDate){
        console.log("Expiring item ", i);
        Meteor.call("expireJob", activeJobs[i]._id);
      }
    }
  });

   Meteor.subscribe('allUsers');
}

Meteor.methods({
  addJob: function(title, company, category, color, description, perks, isEmail, url){
    //Make sure user is logged in before inserting a task
    if(!Meteor.userId()){
      throw new Meteor.Error("not-authorized");
    }

    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth() + 1;

    return Jobs.insert({
      title: title,
      company: company,
      category: category,
      color: color,
      description: description,
      perks: perks,
      isEmail: isEmail,
      url: url,
      createdAt: today,
      day: dd,
      month: mm,
      isExpired: false,
      owner: Meteor.userId(),
      username: Meteor.user().username
    });
  },
  editJob: function(jobId, title, company, category, color, description, perks, isEmail, url){
      //Make sure user is logged in before inserting a task
      if(!Meteor.userId()){
        throw new Meteor.Error("not-authorized");
      }

      var today = new Date();
      var dd = today.getDate();
      var mm = today.getMonth() + 1;

      Jobs.update(jobId, { $set: {
        title: title,
        company: company,
        category: category,
        color: color,
        description: description,
        perks: perks,
        isEmail: isEmail,
        url: url,
        createdAt: today,
        day: dd,
        month: mm,
        isExpired: false
      }
    });
    return jobId;
  },
  deleteJob: function(jobId){
    job = Jobs.find({ _id: jobId}).fetch();
    if(Meteor.userId() != job[0].owner){
      throw new Meteor.Error("not-authorized");
    }
    Jobs.remove(jobId);
  },
  renewJob: function(jobId){
    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth() + 1;
    Jobs.update(jobId, { $set: { createdAt: today, day: dd, month: mm, isExpired: false } });
  },
  expireJob: function(jobId){
    Jobs.update(jobId, { $set: { isExpired: true } });
  },
  grantAdmin: function(userId){
    var loggedInUser = Meteor.user();
    if (!loggedInUser || !Roles.userIsInRole(loggedInUser, ['admin'])) {
      throw new Meteor.Error(403, "Access denied");
    }
    Roles.setUserRoles(userId, ['admin']);
  },
  firstAdmin: function(userId){
    if(Roles.getUsersInRole('admin').count() == 0){
      Roles.setUserRoles(userId, ['admin']);
    }
    else{
      throw new Meteor.Error(403, "Access denied");
    }
  }
});
<|endoftext|>


<commit_before>'use strict';

const
  fs = require('fs'),
  nurl = require('url'),
  path = require('path'),
  stream = require('stream'),
  request = require('request');

const ANSWER_METHODS = {
  addArticle: 'article', addPhoto: 'photo', addVideo: 'video',
  addGif: 'gif', addVideoGif: 'mpeg4_gif', addSticker: 'sticker',
  addVoice: 'voice', addDocument: 'document', addLocation: 'location',
  addVenue: 'venue',
  // Cached methods
  cachedPhoto: 'photo', cachedGif: 'gif', cachedVideoGif: 'mpeg4_gif',
  cachedSticker: 'sticker', cachedDocument: 'document', cachedVideo: 'video',
  cachedVoice: 'voice', cachedAudio: 'audio'
};

const DEFAULT_FILE_EXTS = {
  photo: 'jpg', audio: 'mp3', 'document': 'doc',
  sticker: 'webp', voice: 'm4a', 'video': 'mp4'
};

const reURL = /^https?\:\/\/|www\./;

// Methods
const methods = {

  keyboard(keyboard, opt) {
    opt = opt || {};
    const markup = { keyboard };
    if (opt.resize === true) markup['resize_keyboard'] = true;
    if (opt.once === true) markup['one_time_keyboard'] = true;
    if (opt.selective) markup['selective'] = opt.selective;
    return JSON.stringify(markup);
  },

  button(type, text) {
    type = `request_${type}`;
    return { text, [type]: true };
  },

  inlineKeyboard(inline_keyboard) {
    return JSON.stringify({ inline_keyboard });
  },

  inlineButton(text, opt={}) {
    const markup = { text };
    if (opt.url) markup.url = opt.url;
    if (opt.inline || opt.inline === '') markup.switch_inline_query = opt.inline;
    if (opt.callback) markup.callback_data = String(opt.callback);
    return markup;
  },

  answerList(id, opt) {
    return new AnswerList(id, opt);
  },

  getMe: {},

  sendMessage: {
    arguments: ['chat_id', 'text']
  },

  forwardMessage: {
    arguments: ['chat_id', 'from_chat_id', 'message_id']
  },

  sendPhoto(id, photo, opt) {
    return sendFile.call(this, 'photo', id, photo, opt);
  },

  sendAudio(id, audio, opt) {
    return sendFile.call(this, 'audio', id, audio, opt);
  },

  sendDocument(id, doc, opt) {
    return sendFile.call(this, 'document', id, doc, opt);
  },

  sendSticker(id, sticker, opt) {
    return sendFile.call(this, 'sticker', id, sticker, opt);
  },

  sendVideo(id, video, opt) {
    return sendFile.call(this, 'video', id, video, opt);
  },

  sendVoice(id, voice, opt) {
    return sendFile.call(this, 'voice', id, voice, opt);
  },

  sendLocation: {
    arguments: (chat_id, position) => {
      return {
        chat_id, latitude: position[0], longitude: position[1]
      };
    }
  },

  sendVenue: {
    arguments: (chat_id, position, title, address) => {
      return {
        chat_id, latitude: position[0], longitude: position[1], title, address
      }
    },
    options: (form, opt) => {
      if (opt.foursquare) form.foursquare_id = opt.foursquare;
      return form;
    }
  },

  sendContact: {
    arguments: ['chat_id', 'phone_number', 'first_name', 'last_name']
  },

  sendChatAction: {
    short: 'sendAction',
    arguments: ['chat_id', 'action']
  },

  getUserProfilePhotos: {
    short: 'getUserPhoto',
    arguments: 'chat_id',
    options: (form, opt) => {
      if (opt.offset) form.offset = opt.offset;
      if (opt.limit) form.limit = opt.limit;
      return form;
    }
  },

  getFile: {
    arguments: 'file_id',
    then: file => {
      const result = file.result;
      result.fileLink = this.fileLink + result.file_path;
      return result;
    }
  },

  kickChatMember: {
    short: 'kick',
    arguments: ['chat_id', 'user_id']
  },

  unbanChatMember: {
    short: 'unban',
    arguments: ['chat_id', 'user_id']
  },

  answerInlineQuery: {
    short: 'answerQuery',
    arguments: answers => {
      return {
        inline_query_id: answers.id,
        results: answers.results(),
        next_offset: answers.nextOffset,
        is_personal: answers.personal,
        cache_time: answers.cacheTime
      };
    }
  },

  answerCallbackQuery: {
    short: 'answerCallback',
    arguments: ['callback_query_id', 'text', 'show_alert']
  },

  editMessageText: {
    short: 'editText',
    arguments: (obj, text) => editObject(obj, { text })
  },

  editMessageCaption: {
    short: 'editCaption',
    arguments: (obj, caption) => editObject(obj, { caption })
  },

  editMessageReplyMarkup: {
    short: 'editMarkup',
    arguments: (obj, reply_markup) => editObject(obj, { reply_markup })
  },

  setWebhook(url, certificate) {
    let args = !certificate ? [] : [null, { url, certificate }];
    args.unshift('/setWebhook');
    return this.request.apply(this, args);
  }

};

// Functions

function editObject(obj, form) {
  if (obj.chatId && obj.messageId) {
    form.chat_id = obj.chatId;
    form.message_id = obj.messageId;
  } else if (obj.inlineMsgId) {
    form.inline_message_id = obj.inlineMsgId;
  }
  return form;
}

function sendFile(type, chat_id, file, opt={}) {

  const form = this.properties({ chat_id }, opt);
  const defName = `file.${ DEFAULT_FILE_EXTS[type] }`;

  const url = 'send' + type.charAt(0).toUpperCase() + type.slice(1);

  // Send bot action event
  this.event(url, [].slice.call(arguments).splice(0, 1));

  // Set file caption
  if (opt.caption) form.caption = opt.caption;

  if (file instanceof stream.Stream) {
    // File stream object
    if (!opt.fileName)
      opt.fileName = nurl.parse(path.basename(file.path)).pathname;
    form[type] = {
      value: file,
      options: { filename: opt.fileName }
    };
  } else if (Buffer.isBuffer(file)) {
    // File buffer
    if (!opt.fileName) opt.fileName = defName;
    form[type] = {
      value: file,
      options: { filename: opt.fileName }
    };
  } else if (reURL.test(file)) {
    // File url
    if (!opt.fileName)
      opt.fileName = path.basename(nurl.parse(file).pathname) || defName;
    form[type] = {
      value: request.get(file),
      options: { filename: opt.fileName }
    };
  } else if (fs.existsSync(file)) {
    // File location
    if (!opt.fileName) opt.fileName = path.basename(file);
    form[type] = {
      value: fs.createReadStream(file),
      options: { filename: opt.fileName }
    };
  } else {
    // File as 'file_id'
    form[type] = file;
  }

  return this.request(`/${ url }`, null, form);

}

/* Answer List */

class AnswerList {

  constructor(id, opt={}) {
    this.id = id;
    this.cacheTime = Number(opt.cacheTime) || 300;
    this.nextOffset = opt.nextOffset === undefined ? null : opt.nextOffset;
    this.personal = opt.personal === undefined ? false : opt.personal;
    this.list = [];
  }

  add(type, set={}) {
    set.type = type;
    this.list.push(set);
    return set;
  }

  results() {
    return JSON.stringify(this.list);
  }

}

// Add answer methods
{
  for (let prop in ANSWER_METHODS) {
    AnswerList.prototype[prop] = (name => {
      return function(set) {
        return this.add(name, set);
      };
    })(ANSWER_METHODS[prop]);
  }
}

// Export methods
module.exports = methods;
<commit_msg>Fix setWebhook url-only argument<commit_after>'use strict';

const
  fs = require('fs'),
  nurl = require('url'),
  path = require('path'),
  stream = require('stream'),
  request = require('request');

const ANSWER_METHODS = {
  addArticle: 'article', addPhoto: 'photo', addVideo: 'video',
  addGif: 'gif', addVideoGif: 'mpeg4_gif', addSticker: 'sticker',
  addVoice: 'voice', addDocument: 'document', addLocation: 'location',
  addVenue: 'venue',
  // Cached methods
  cachedPhoto: 'photo', cachedGif: 'gif', cachedVideoGif: 'mpeg4_gif',
  cachedSticker: 'sticker', cachedDocument: 'document', cachedVideo: 'video',
  cachedVoice: 'voice', cachedAudio: 'audio'
};

const DEFAULT_FILE_EXTS = {
  photo: 'jpg', audio: 'mp3', 'document': 'doc',
  sticker: 'webp', voice: 'm4a', 'video': 'mp4'
};

const reURL = /^https?\:\/\/|www\./;

// Methods
const methods = {

  keyboard(keyboard, opt) {
    opt = opt || {};
    const markup = { keyboard };
    if (opt.resize === true) markup['resize_keyboard'] = true;
    if (opt.once === true) markup['one_time_keyboard'] = true;
    if (opt.selective) markup['selective'] = opt.selective;
    return JSON.stringify(markup);
  },

  button(type, text) {
    type = `request_${type}`;
    return { text, [type]: true };
  },

  inlineKeyboard(inline_keyboard) {
    return JSON.stringify({ inline_keyboard });
  },

  inlineButton(text, opt={}) {
    const markup = { text };
    if (opt.url) markup.url = opt.url;
    if (opt.inline || opt.inline === '') markup.switch_inline_query = opt.inline;
    if (opt.callback) markup.callback_data = String(opt.callback);
    return markup;
  },

  answerList(id, opt) {
    return new AnswerList(id, opt);
  },

  getMe: {},

  sendMessage: {
    arguments: ['chat_id', 'text']
  },

  forwardMessage: {
    arguments: ['chat_id', 'from_chat_id', 'message_id']
  },

  sendPhoto(id, photo, opt) {
    return sendFile.call(this, 'photo', id, photo, opt);
  },

  sendAudio(id, audio, opt) {
    return sendFile.call(this, 'audio', id, audio, opt);
  },

  sendDocument(id, doc, opt) {
    return sendFile.call(this, 'document', id, doc, opt);
  },

  sendSticker(id, sticker, opt) {
    return sendFile.call(this, 'sticker', id, sticker, opt);
  },

  sendVideo(id, video, opt) {
    return sendFile.call(this, 'video', id, video, opt);
  },

  sendVoice(id, voice, opt) {
    return sendFile.call(this, 'voice', id, voice, opt);
  },

  sendLocation: {
    arguments: (chat_id, position) => {
      return {
        chat_id, latitude: position[0], longitude: position[1]
      };
    }
  },

  sendVenue: {
    arguments: (chat_id, position, title, address) => {
      return {
        chat_id, latitude: position[0], longitude: position[1], title, address
      }
    },
    options: (form, opt) => {
      if (opt.foursquare) form.foursquare_id = opt.foursquare;
      return form;
    }
  },

  sendContact: {
    arguments: ['chat_id', 'phone_number', 'first_name', 'last_name']
  },

  sendChatAction: {
    short: 'sendAction',
    arguments: ['chat_id', 'action']
  },

  getUserProfilePhotos: {
    short: 'getUserPhoto',
    arguments: 'chat_id',
    options: (form, opt) => {
      if (opt.offset) form.offset = opt.offset;
      if (opt.limit) form.limit = opt.limit;
      return form;
    }
  },

  getFile: {
    arguments: 'file_id',
    then: file => {
      const result = file.result;
      result.fileLink = this.fileLink + result.file_path;
      return result;
    }
  },

  kickChatMember: {
    short: 'kick',
    arguments: ['chat_id', 'user_id']
  },

  unbanChatMember: {
    short: 'unban',
    arguments: ['chat_id', 'user_id']
  },

  answerInlineQuery: {
    short: 'answerQuery',
    arguments: answers => {
      return {
        inline_query_id: answers.id,
        results: answers.results(),
        next_offset: answers.nextOffset,
        is_personal: answers.personal,
        cache_time: answers.cacheTime
      };
    }
  },

  answerCallbackQuery: {
    short: 'answerCallback',
    arguments: ['callback_query_id', 'text', 'show_alert']
  },

  editMessageText: {
    short: 'editText',
    arguments: (obj, text) => editObject(obj, { text })
  },

  editMessageCaption: {
    short: 'editCaption',
    arguments: (obj, caption) => editObject(obj, { caption })
  },

  editMessageReplyMarkup: {
    short: 'editMarkup',
    arguments: (obj, reply_markup) => editObject(obj, { reply_markup })
  },

  setWebhook(url, certificate) {
    let args = !certificate ? [{ url }] : [null, { url, certificate }];
    args.unshift('/setWebhook');
    return this.request.apply(this, args);
  }

};

// Functions

function editObject(obj, form) {
  if (obj.chatId && obj.messageId) {
    form.chat_id = obj.chatId;
    form.message_id = obj.messageId;
  } else if (obj.inlineMsgId) {
    form.inline_message_id = obj.inlineMsgId;
  }
  return form;
}

function sendFile(type, chat_id, file, opt={}) {

  const form = this.properties({ chat_id }, opt);
  const defName = `file.${ DEFAULT_FILE_EXTS[type] }`;

  const url = 'send' + type.charAt(0).toUpperCase() + type.slice(1);

  // Send bot action event
  this.event(url, [].slice.call(arguments).splice(0, 1));

  // Set file caption
  if (opt.caption) form.caption = opt.caption;

  if (file instanceof stream.Stream) {
    // File stream object
    if (!opt.fileName)
      opt.fileName = nurl.parse(path.basename(file.path)).pathname;
    form[type] = {
      value: file,
      options: { filename: opt.fileName }
    };
  } else if (Buffer.isBuffer(file)) {
    // File buffer
    if (!opt.fileName) opt.fileName = defName;
    form[type] = {
      value: file,
      options: { filename: opt.fileName }
    };
  } else if (reURL.test(file)) {
    // File url
    if (!opt.fileName)
      opt.fileName = path.basename(nurl.parse(file).pathname) || defName;
    form[type] = {
      value: request.get(file),
      options: { filename: opt.fileName }
    };
  } else if (fs.existsSync(file)) {
    // File location
    if (!opt.fileName) opt.fileName = path.basename(file);
    form[type] = {
      value: fs.createReadStream(file),
      options: { filename: opt.fileName }
    };
  } else {
    // File as 'file_id'
    form[type] = file;
  }

  return this.request(`/${ url }`, null, form);

}

/* Answer List */

class AnswerList {

  constructor(id, opt={}) {
    this.id = id;
    this.cacheTime = Number(opt.cacheTime) || 300;
    this.nextOffset = opt.nextOffset === undefined ? null : opt.nextOffset;
    this.personal = opt.personal === undefined ? false : opt.personal;
    this.list = [];
  }

  add(type, set={}) {
    set.type = type;
    this.list.push(set);
    return set;
  }

  results() {
    return JSON.stringify(this.list);
  }

}

// Add answer methods
{
  for (let prop in ANSWER_METHODS) {
    AnswerList.prototype[prop] = (name => {
      return function(set) {
        return this.add(name, set);
      };
    })(ANSWER_METHODS[prop]);
  }
}

// Export methods
module.exports = methods;
<|endoftext|>


<commit_before>
var fs      = require('fs'),
    path    = require('path'),
    util    = require('util'),

    helpers = require('./helpers'),
    log     = helpers.log;

module.exports = function (options) {
    var settings    = helpers.settings(options),
        assets      = helpers.assets(settings.assetsFile),
        baseUrl     = ''; // for production

    function applyTemplate (sectionName, itemName, template, extension) {
        var result      = '',
            results     = [],
            jstResult   = '',
            jstResults  = [];

        if (!helpers.validSectionAndItem(sectionName, itemName)) {
            return '';
        }

        if (settings.minfied) {
            baseUrl = helpers.baseUrl(assets);

            if (assets.s3.hasOwnProperty('hash')) {
                itemName = itemName + '-' + assets.s3.hash;
            }

            result = util.format(template, baseUrl + sectionName + '/' + itemName + extension);
            results.push(result);
        }
        else {
            assets[sectionName][itemName].forEach(function (item) {
                if (path.extname(item) === '.jst') {
                    var data = fs.readFileSync(process.cwd() + '/' + item, 'utf-8');

                    if (!data) throw new Error('could not read jst file: ' + item);

                    jstResult = util.format(
                        'window.JST["%s"] = function() { return decodeURI("%s") };',
                        path.basename(item, '.jst'),
                        encodeURI(data)
                    );

                    jstResults.push(jstResult);
                }
                else {
                    item = item.replace('public/', '');                 // todo: args (this is gonna hurt someone)

                    result = util.format(template, '/' + item);
                    results.push(result);
                }
            });
        }

        if (jstResults.length > 0) {
            jstResult = '<script>\nwindow.JST = {};\n' + jstResults.join('\n') + '\n</script>';

            results.push(jstResult);
        }

        return results.join('\n');
    }

//
// logging helper - uses debug option
//

    function log (message) {
        if (settings.debug) {
            console.log(message);
            console.log(assets);
        }
    }

//
// section helpers
//

    function javascripts (itemName) {
        var sectionName = 'javascripts',
            template    = '<script src="%s"></script>';

        return applyTemplate(sectionName, itemName, template, '.js');
    }

    function stylesheets (itemName) {
        var sectionName = 'stylesheets',
            template    = '<link href="%s" rel="stylesheet">';

        return applyTemplate(sectionName, itemName, template, '.css');
    }

//
// result
//

    if (settings.express3) {
        return function (req, res, next) {              // use middleware
            res.locals.javascripts = javascripts;
            res.locals.stylesheets = stylesheets;

            next();
        }
    }
    else {
        return {                                        // use express 2.0 helpers
            javascripts: javascripts,
            stylesheets: stylesheets
        };
    }
};<commit_msg>cleanup<commit_after>
var fs      = require('fs'),
    path    = require('path'),
    util    = require('util'),

    helpers = require('./helpers'),
    log     = helpers.log;

module.exports = function (options) {
    var settings    = helpers.settings(options),
        assets      = helpers.assets(settings.assetsFile),
        baseUrl     = ''; // for production

    function applyTemplate (sectionName, itemName, template, extension) {
        var result      = '',
            results     = [],
            jstResult   = '',
            jstResults  = [];

        if (!helpers.validSectionAndItem(assets, sectionName, itemName)) {
            return '';
        }

        if (settings.minfied) {
            baseUrl = helpers.baseUrl(assets);

            if (assets.s3.hasOwnProperty('hash')) {
                itemName = itemName + '-' + assets.s3.hash;
            }

            result = util.format(template, baseUrl + sectionName + '/' + itemName + extension);
            results.push(result);
        }
        else {
            assets[sectionName][itemName].forEach(function (item) {
                if (path.extname(item) === '.jst') {
                    var data = fs.readFileSync(process.cwd() + '/' + item, 'utf-8');

                    if (!data) throw new Error('could not read jst file: ' + item);

                    jstResult = util.format(
                        'window.JST["%s"] = function() { return decodeURI("%s") };',
                        path.basename(item, '.jst'),
                        encodeURI(data)
                    );

                    jstResults.push(jstResult);
                }
                else {
                    item = item.replace('public/', '');                 // todo: args (this is gonna hurt someone)

                    result = util.format(template, '/' + item);
                    results.push(result);
                }
            });
        }

        if (jstResults.length > 0) {
            jstResult = '<script>\nwindow.JST = {};\n' + jstResults.join('\n') + '\n</script>';

            results.push(jstResult);
        }

        return results.join('\n');
    }

//
// logging helper - uses debug option
//

    function log (message) {
        if (settings.debug) {
            console.log(message);
            console.log(assets);
        }
    }

//
// section helpers
//

    function javascripts (itemName) {
        var sectionName = 'javascripts',
            template    = '<script src="%s"></script>';

        return applyTemplate(sectionName, itemName, template, '.js');
    }

    function stylesheets (itemName) {
        var sectionName = 'stylesheets',
            template    = '<link href="%s" rel="stylesheet">';

        return applyTemplate(sectionName, itemName, template, '.css');
    }

//
// result
//

    if (settings.express3) {
        return function (req, res, next) {              // use middleware
            res.locals.javascripts = javascripts;
            res.locals.stylesheets = stylesheets;

            next();
        }
    }
    else {
        return {                                        // use express 2.0 helpers
            javascripts: javascripts,
            stylesheets: stylesheets
        };
    }
};<|endoftext|>