<commit_before>/*
 * grunt-svgstore
 * https://github.com/FWeinb/grunt-svgstore
 *
 * Copyright (c) 2014 Fabrice Weinberg
 * Licensed under the MIT license.
 */
'use strict';

module.exports = function (grunt) {
  var crypto = require('crypto');
  var multiline = require('multiline');
  var path = require('path');

  var beautify = require('js-beautify').html;
  var cheerio = require('cheerio');
  var chalk = require('chalk');

  var md5 = function (str) {
    return crypto.createHash('md5').update(str).digest('hex');
  };

  var symbolAttributes = function(attrs){
    if (typeof attrs === 'undefined') {return '';}

    var result = '';
    Object.keys(attrs).forEach(function (key) {
      result += ' ' + key + '="' + attrs[key] + '"';
    });
    return result;
  };

  var convertNameToId = function( name ){
    var dotPos = name.indexOf('.');
    if ( dotPos > -1){
      name = name.substring(0, dotPos);
    }
    return name;
  };

  // Matching an url() reference. To correct references broken by making ids unique to the source svg
  var urlPattern = /url\(\s*#([^ ]+?)\s*\)/g;

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

  grunt.registerMultiTask('svgstore', 'Merge SVGs from a folder.', function () {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      prefix: '',
      svg: {
          'xmlns': "http://www.w3.org/2000/svg"
      },
      formatting: false,
      includedemo: false,
      symbol: {}
    });

    var symbolAttrs =  symbolAttributes(options.symbol);

    this.files.forEach(function (file) {
      var $resultDocument = cheerio.load('<svg><defs></defs></svg>', { lowerCaseAttributeNames : false }),
          $resultSvg = $resultDocument('svg'),
          $resultDefs = $resultDocument('defs').first(),
          iconNameViewBoxArray = [];  // Used to store information of all icons that are added
                                      // { name : '' }

      // Merge in SVG attributes from option
      for (var attr in options.svg) {
        $resultSvg.attr(attr, options.svg[attr]);
      }

      file.src.filter(function (filepath) {
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('File "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).map(function (filepath) {
        var filename = path.basename(filepath, '.svg');
        var contentStr = grunt.file.read(filepath);
        var uniqueId = md5(contentStr);
        var $ = cheerio.load(contentStr, {
              normalizeWhitespace: true,
              xmlMode: true
            });

        // Map to store references from id to uniqueId + id;
        var mappedIds = {};

        // Make IDs unique
        $('[id]').each(function () {
          var $elem = $(this);
          var id = $elem.attr('id');
          var newId = 'svgstore' + uniqueId + id;
          mappedIds[id] = newId;
          $elem.attr('id', newId);
        });

        // Search for an url() reference in every attribute of every tag
        // replace the id with the unique one.
        $('*').each(function () {
          var $elem = $(this);
          var attrs = $elem.attr();
          Object.keys(attrs).forEach(function (key) {
            var value = attrs[key];
            var match;
            while ((match = urlPattern.exec(value)) !== null) {
              if (mappedIds[match[1]] !== undefined) {
                value = value.replace(match[0], 'url(#' + mappedIds[match[1]] + ')');
              } else {
                grunt.log.warn('Can\'t reference to id "' + match[1] + '" from attribute "' + attr + '" in "' + this[0].name + '" because it is not defined.');
              }
            }
            if (options.cleanup && key === 'style') {
              value = null;
            }
            $elem.attr(key, value);
          });
        });

        var $svg = $('svg');
        var $title = $('title');
        var $desc = $('desc');
        var $def = $('defs').first();

        // Merge in the defs from this svg in the result defs block
        $resultDefs.append($def.html());

        var title = $title.first().html();
        var desc = $desc.first().html();

        // Remove def, title, desc from this svg
        $def.remove();
        $title.remove();
        $desc.remove();

        var id = convertNameToId(filename);

        // If there is no title use the filename
        title = title || id;

        var resultStr = '<symbol' + symbolAttrs + '>' + '<title>' + title + '</title>';

        // Only add desc if it was set
        if ( desc ) {  resultStr +='<desc>'+ desc +'</desc>';  }

        resultStr += $svg.html() + '</symbol>';

        // Create a object
        var $res = cheerio.load(resultStr, { lowerCaseAttributeNames : false });

        $res('symbol').attr('viewBox', $svg.attr('viewBox'));

        var graphicId = options.prefix + id;
        // Add ID to the first element
        $res('*').first().attr('id', graphicId);

        // Append <symbol> to resulting SVG
        $resultSvg.append($res.html());

        // Add icon to the demo.html array
        if (options.includedemo) {
          iconNameViewBoxArray.push({
            name: graphicId
          });
        }
      });

      // Remove defs block if empty
      if ( $resultDefs.html().trim() === '' ) {
        $resultDefs.remove();
      }

      var result = options.formatting ? beautify($resultDocument.xml(), options.formatting) : $resultDocument.xml();
      var destName = path.basename(file.dest, '.svg');

      grunt.file.write(file.dest, result);

      grunt.log.writeln('File ' + chalk.cyan(file.dest) + ' created.');

      if (options.includedemo) {
        $resultSvg.attr('style', 'width:0;height:0;visibility:hidden;');

        var demoHTML = multiline.stripIndent(function () { /*
                <!doctype html>
                <html>
                  <head>
                    <style>
                      svg{
                          width:50px;
                          height:50px;
                          fill:black !important;
                      }
                    </style>
                  <head>
                  <body>
                    {{svg}}
                    {{useBlock}}
                  </body>
               </html>
              */});

        var useBlock = '';
        iconNameViewBoxArray.forEach(function (item) {
          useBlock += '\t\t<svg>\n\t\t\t<use xlink:href="#' + item.name + '"></use>\n\t\t</svg>\n';
        });

        demoHTML = demoHTML.replace('{{svg}}', $resultDocument.xml());
        demoHTML = demoHTML.replace('{{useBlock}}', useBlock);

        var demoPath = path.resolve(path.dirname(file.dest), destName + '-demo.html');
        grunt.file.write(demoPath, demoHTML);
        grunt.log.writeln('Demo file ' + chalk.cyan(demoPath) + ' created.');
      }
    });
  });
};
<commit_msg>Change string-based approach of creating <symbol> elements to a more object-based approach using cheerio.<commit_after>/*
 * grunt-svgstore
 * https://github.com/FWeinb/grunt-svgstore
 *
 * Copyright (c) 2014 Fabrice Weinberg
 * Licensed under the MIT license.
 */
'use strict';

module.exports = function (grunt) {
  var crypto = require('crypto');
  var multiline = require('multiline');
  var path = require('path');

  var beautify = require('js-beautify').html;
  var cheerio = require('cheerio');
  var chalk = require('chalk');

  var md5 = function (str) {
    return crypto.createHash('md5').update(str).digest('hex');
  };

  var convertNameToId = function( name ){
    var dotPos = name.indexOf('.');
    if ( dotPos > -1){
      name = name.substring(0, dotPos);
    }
    return name;
  };

  // Matching an url() reference. To correct references broken by making ids unique to the source svg
  var urlPattern = /url\(\s*#([^ ]+?)\s*\)/g;

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

  grunt.registerMultiTask('svgstore', 'Merge SVGs from a folder.', function () {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      prefix: '',
      svg: {
          'xmlns': "http://www.w3.org/2000/svg"
      },
      formatting: false,
      includedemo: false,
      symbol: {}
    });

    this.files.forEach(function (file) {
      var $resultDocument = cheerio.load('<svg><defs></defs></svg>', { lowerCaseAttributeNames : false }),
          $resultSvg = $resultDocument('svg'),
          $resultDefs = $resultDocument('defs').first(),
          iconNameViewBoxArray = [];  // Used to store information of all icons that are added
                                      // { name : '' }

      // Merge in SVG attributes from option
      for (var attr in options.svg) {
        $resultSvg.attr(attr, options.svg[attr]);
      }

      file.src.filter(function (filepath) {
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('File "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).map(function (filepath) {
        var filename = path.basename(filepath, '.svg');
        var contentStr = grunt.file.read(filepath);
        var uniqueId = md5(contentStr);
        var $ = cheerio.load(contentStr, {
              normalizeWhitespace: true,
              xmlMode: true
            });

        // Map to store references from id to uniqueId + id;
        var mappedIds = {};

        // Make IDs unique
        $('[id]').each(function () {
          var $elem = $(this);
          var id = $elem.attr('id');
          var newId = 'svgstore' + uniqueId + id;
          mappedIds[id] = newId;
          $elem.attr('id', newId);
        });

        // Search for an url() reference in every attribute of every tag
        // replace the id with the unique one.
        $('*').each(function () {
          var $elem = $(this);
          var attrs = $elem.attr();
          Object.keys(attrs).forEach(function (key) {
            var value = attrs[key];
            var match;
            while ((match = urlPattern.exec(value)) !== null) {
              if (mappedIds[match[1]] !== undefined) {
                value = value.replace(match[0], 'url(#' + mappedIds[match[1]] + ')');
              } else {
                grunt.log.warn('Can\'t reference to id "' + match[1] + '" from attribute "' + attr + '" in "' + this[0].name + '" because it is not defined.');
              }
            }
            if (options.cleanup && key === 'style') {
              value = null;
            }
            $elem.attr(key, value);
          });
        });

        var $svg = $('svg');
        var $title = $('title');
        var $desc = $('desc');
        var $def = $('defs').first();
        var defContent = $def.length && $def.html();

        // Merge in the defs from this svg in the result defs block
        if (defContent) {
          $resultDefs.append(defContent);
        }

        var title = $title.first().html();
        var desc = $desc.first().html();

        // Remove def, title, desc from this svg
        $def.remove();
        $title.remove();
        $desc.remove();

        var id = convertNameToId(filename);

        // If there is no title use the filename
        title = title || id;

        // Generate symbol
        var $res = cheerio.load('<symbol>' + $svg.html() + '</symbol>', { lowerCaseAttributeNames: false });
        var $symbol = $res('symbol').first();

        // Merge in symbol attributes from option
        for (var attr in options.symbol) {
          $symbol.attr(attr, options.symbol[attr]);
        }

        // Add title and desc (if provided)
        if (desc) {
          $symbol.prepend('<desc>' + desc + '</desc>');
        }

        if (title) {
          $symbol.prepend('<title>' + title + '</title>');
        }

        // Add viewBox (if present of SVG)
        var viewBox = $svg.attr('viewBox');
        if (viewBox) {
          $symbol.attr('viewBox', viewBox);
        }

        // Add ID to symbol
        var graphicId = options.prefix + id;
        $symbol.attr('id', graphicId);

        // Append <symbol> to resulting SVG
        $resultSvg.append($res.html());

        // Add icon to the demo.html array
        if (options.includedemo) {
          iconNameViewBoxArray.push({
            name: graphicId
          });
        }
      });

      // Remove defs block if empty
      if ( $resultDefs.html().trim() === '' ) {
        $resultDefs.remove();
      }

      var result = options.formatting ? beautify($resultDocument.xml(), options.formatting) : $resultDocument.xml();
      var destName = path.basename(file.dest, '.svg');

      grunt.file.write(file.dest, result);

      grunt.log.writeln('File ' + chalk.cyan(file.dest) + ' created.');

      if (options.includedemo) {
        $resultSvg.attr('style', 'width:0;height:0;visibility:hidden;');

        var demoHTML = multiline.stripIndent(function () { /*
                <!doctype html>
                <html>
                  <head>
                    <style>
                      svg{
                          width:50px;
                          height:50px;
                          fill:black !important;
                      }
                    </style>
                  <head>
                  <body>
                    {{svg}}
                    {{useBlock}}
                  </body>
               </html>
              */});

        var useBlock = '';
        iconNameViewBoxArray.forEach(function (item) {
          useBlock += '\t\t<svg>\n\t\t\t<use xlink:href="#' + item.name + '"></use>\n\t\t</svg>\n';
        });

        demoHTML = demoHTML.replace('{{svg}}', $resultDocument.xml());
        demoHTML = demoHTML.replace('{{useBlock}}', useBlock);

        var demoPath = path.resolve(path.dirname(file.dest), destName + '-demo.html');
        grunt.file.write(demoPath, demoHTML);
        grunt.log.writeln('Demo file ' + chalk.cyan(demoPath) + ' created.');
      }
    });
  });
};
<|endoftext|>


<commit_before>'use strict';

const ukParties = require('uk-political-parties');
const _ = require('lodash');
const db = require('./db');
const paResultTypes = require('../../db/model/types');
const order_of_appearance = ['c', 'lab', 'snp', 'ld', 'ukip', 'dup', 'pc', 'green'];

var expires = {};
var last = {};
var age = 1000 * 10;

module.exports = function (howMany) {

  if (last[howMany] && expires[howMany] && Date.now() < expires[howMany]) {
    return last[howMany];
  }

  var selected_parties = order_of_appearance.slice(0, Math.max(howMany - 1, 0));

  // number to count up the global total of seats
  var numSeatsDeclared = 0;

  // make an array of parties we're interested in
  var sopParties = selected_parties.map(function (id) {
    var party = db.parties().findOne({id: id});

    numSeatsDeclared += party.elections.ge15.seats;

    return {
      id: party.id,
      label: ukParties.shortName(party.id),
      colour: party.colour,
      secondaryColour: party.secondary_colour,
      totalWon: party.elections.ge15.seats,
      // netChange: Math.round((Math.random() - 0.5) * 50),
      netChange: 999,

      losses: [],
      gains: [],
    };
  });

  // find all the parties who are not in our selected bunch
  var others = db.parties().find().filter(function (party) {
    return selected_parties.indexOf(party.id) === -1;
  });

  // make an extra 'party' object (kept separate for now)
  var othersParty = {
    id: 'xxx',
    label: 'Others',
    colour: ukParties.colour('other'),
    secondaryColour: ukParties.secondaryColour('other'),
    totalWon: others.reduce(function (total, party) {
        return total + party.elections.ge15.seats;
      }, 0),

    minitable: (function () {
      var customShortNames = {
        'A': 'Alliance',
        'Grn': 'Greens',
        'Oth': 'Other',
        'SF': 'Sinn Fein'
      };
      var minitable = others
        // only parties who have won something
        .filter(function (party) {
          return party.elections.ge15.seats > 0;
        })
        // make the table row objects
        .map(function (party) {
          var shortName = ukParties.shortName(party.id);
          shortName = customShortNames[shortName] || shortName;
          var fullName = ukParties.fullName(party.id);

          return {
            shortName: shortName,
            fullName: fullName,
            numSeats: party.elections.ge15.seats
          };
        })
        // sort by highest number of seats
        .sort(function (a, b) {
          if (a.numSeats > b.numSeats) return -1;
          if (a.numSeats < b.numSeats) return 1;
          return 0;
        });

      // move the 'other' to the end
      var otherRowIndex;
      minitable.forEach(function (row, i) {
        if (row.shortName === 'Other') otherRowIndex = i;
      });
      minitable.push(minitable.splice(otherRowIndex, 1)[0]);

      return minitable;
    })()
  };

  numSeatsDeclared += othersParty.totalWon;

  // go through all the seats and increment the relevant bits and bobs
  db.seats().find().forEach(function (seat) {
    if (seatIsCalled(seat)) {
      // find who lost and who won this seat
      var loserId = seat.elections.last.winner.party;
      var winnerId = seat.elections.ge15.winner.party;

      var loser = _.findWhere(sopParties, {id: loserId});
      var winner = _.findWhere(sopParties, {id: winnerId});

      // sanity check
      if (seat.elections.ge15.change !== (loserId !== winnerId)) {
        console.warn(
          'WARNING: seat.elections.ge15.change is ' + seat.elections.ge15.change + ' for "' + seat.name + '"' +
          ' but loserId is ' + loserId + ' and winnerId is ' + winnerId
        );
      }

      // if this seat has changed hands, add it as a loss to the relevant party
      if (loserId !== winnerId) {
        // nb: we need to use ukParties lookup here, because it might be an 'Other'
        var seatChangeDetails = {
          // loserColour: ukParties.colour(loserId),
          winnerColour: ukParties.colour(winnerId),
          tooltip: seat.name + ' (' + ukParties.shortName(loserId) + ' → ' + ukParties.shortName(winnerId) + ')',
          was: loserId,
          now: winnerId
        };

        if (loser) loser.losses.push(seatChangeDetails);
        if (winner) winner.gains.push(seatChangeDetails);
      }
    }
  });

  // augment the top 5 with extra bits, and sort their squares
  sopParties.forEach(function (party) {
    // sort so the little squares are grouped into parties (with biggest group fist)
    var gainerTotals = {};
    party.losses.forEach(function (seat) {
      if (!gainerTotals[seat.now]) gainerTotals[seat.now] = 0;
      gainerTotals[seat.now]++;
    });
    party.losses.sort(function (a, b) {
      if (gainerTotals[b.now] > gainerTotals[a.now]) return 1;
      if (gainerTotals[b.now] < gainerTotals[a.now]) return -1;
      return 0;
    });

    // party.losses.splice(0, 90); // for seeing how it might really look
  });

  // add "Others" party to the main array
  sopParties.push(othersParty);

  // TODO: should we get the updated date from the PA data somehow?

  var finalData = {
    parties: sopParties,
    headline: 'State of play',
    numSeatsDeclared: numSeatsDeclared,
    updated: new Date()
  };

  expires[howMany] = Date.now() + age;
  last[howMany] = Promise.resolve(finalData);
  return last[howMany];
};

function seatIsCalled(seat) {
  switch(seat.elections.ge15.source.type) {
    case paResultTypes.RUSH:
    case paResultTypes.RESULT:
      return true;
  }
  return false;
}
<commit_msg>add real 'net change' values to state-of-play<commit_after>'use strict';

const ukParties = require('uk-political-parties');
const _ = require('lodash');
const db = require('./db');
const paResultTypes = require('../../db/model/types');
const order_of_appearance = ['c', 'lab', 'snp', 'ld', 'ukip', 'dup', 'pc', 'green'];

var expires = {};
var last = {};
var age = 1000 * 10;

module.exports = function (howMany) {

  if (last[howMany] && expires[howMany] && Date.now() < expires[howMany]) {
    return last[howMany];
  }

  var selected_parties = order_of_appearance.slice(0, Math.max(howMany - 1, 0));

  // number to count up the global total of seats
  var numSeatsDeclared = 0;

  // make an array of parties we're interested in
  var sopParties = selected_parties.map(function (id) {
    var party = db.parties().findOne({id: id});

    numSeatsDeclared += party.elections.ge15.seats;

    return {
      id: party.id,
      label: ukParties.shortName(party.id),
      colour: party.colour,
      secondaryColour: party.secondary_colour,
      totalWon: party.elections.ge15.seats,
      netChange: party.elections.ge15.seats_net_gain,

      losses: [],
      gains: [],
    };
  });

  // find all the parties who are not in our selected bunch
  var others = db.parties().find().filter(function (party) {
    return selected_parties.indexOf(party.id) === -1;
  });

  // make an extra 'party' object (kept separate for now)
  var othersParty = {
    id: 'xxx',
    label: 'Others',
    colour: ukParties.colour('other'),
    secondaryColour: ukParties.secondaryColour('other'),
    totalWon: others.reduce(function (total, party) {
        return total + party.elections.ge15.seats;
      }, 0),

    minitable: (function () {
      var customShortNames = {
        'A': 'Alliance',
        'Grn': 'Greens',
        'Oth': 'Other',
        'SF': 'Sinn Fein'
      };
      var minitable = others
        // only parties who have won something
        .filter(function (party) {
          return party.elections.ge15.seats > 0;
        })
        // make the table row objects
        .map(function (party) {
          var shortName = ukParties.shortName(party.id);
          shortName = customShortNames[shortName] || shortName;
          var fullName = ukParties.fullName(party.id);

          return {
            shortName: shortName,
            fullName: fullName,
            numSeats: party.elections.ge15.seats
          };
        })
        // sort by highest number of seats
        .sort(function (a, b) {
          if (a.numSeats > b.numSeats) return -1;
          if (a.numSeats < b.numSeats) return 1;
          return 0;
        });

      // move the 'other' to the end
      var otherRowIndex;
      minitable.forEach(function (row, i) {
        if (row.shortName === 'Other') otherRowIndex = i;
      });
      minitable.push(minitable.splice(otherRowIndex, 1)[0]);

      return minitable;
    })()
  };

  numSeatsDeclared += othersParty.totalWon;

  // go through all the seats and increment the relevant bits and bobs
  db.seats().find().forEach(function (seat) {
    if (seatIsCalled(seat)) {
      // find who lost and who won this seat
      var loserId = seat.elections.last.winner.party;
      var winnerId = seat.elections.ge15.winner.party;

      var loser = _.findWhere(sopParties, {id: loserId});
      var winner = _.findWhere(sopParties, {id: winnerId});

      // sanity check
      if (seat.elections.ge15.change !== (loserId !== winnerId)) {
        console.warn(
          'WARNING: seat.elections.ge15.change is ' + seat.elections.ge15.change + ' for "' + seat.name + '"' +
          ' but loserId is ' + loserId + ' and winnerId is ' + winnerId
        );
      }

      // if this seat has changed hands, add it as a loss to the relevant party
      if (loserId !== winnerId) {
        // nb: we need to use ukParties lookup here, because it might be an 'Other'
        var seatChangeDetails = {
          // loserColour: ukParties.colour(loserId),
          winnerColour: ukParties.colour(winnerId),
          tooltip: seat.name + ' (' + ukParties.shortName(loserId) + ' → ' + ukParties.shortName(winnerId) + ')',
          was: loserId,
          now: winnerId
        };

        if (loser) loser.losses.push(seatChangeDetails);
        if (winner) winner.gains.push(seatChangeDetails);
      }
    }
  });

  // augment the top 5 with extra bits, and sort their squares
  sopParties.forEach(function (party) {
    // sort so the little squares are grouped into parties (with biggest group fist)
    var gainerTotals = {};
    party.losses.forEach(function (seat) {
      if (!gainerTotals[seat.now]) gainerTotals[seat.now] = 0;
      gainerTotals[seat.now]++;
    });
    party.losses.sort(function (a, b) {
      if (gainerTotals[b.now] > gainerTotals[a.now]) return 1;
      if (gainerTotals[b.now] < gainerTotals[a.now]) return -1;
      return 0;
    });

    // party.losses.splice(0, 90); // for seeing how it might really look
  });

  // add "Others" party to the main array
  sopParties.push(othersParty);

  // TODO: should we get the updated date from the PA data somehow?

  var finalData = {
    parties: sopParties,
    headline: 'State of play',
    numSeatsDeclared: numSeatsDeclared,
    updated: new Date()
  };

  expires[howMany] = Date.now() + age;
  last[howMany] = Promise.resolve(finalData);
  return last[howMany];
};

function seatIsCalled(seat) {
  switch(seat.elections.ge15.source.type) {
    case paResultTypes.RUSH:
    case paResultTypes.RESULT:
      return true;
  }
  return false;
}
<|endoftext|>


<commit_before>function FreeWillStuff(session){
	this.session = session;
	this.canRepeat = true;
	this.playerList = [];  //what players are already in the medium when i trigger?
	this.decision = null
	//luck can be good or it can be bad.
	this.minHighValue = 110;

	this.trigger = function(playerList){
		this.decision = null;//reset
		//what the hell roue of doom's corpse. corpses aren't part of the player list!
		for(var i = 0; i<this.session.availablePlayers.length; i++){
			var player = this.session.availablePlayers[i];
			var decision = this.getPlayerDecision(player);
			if(decision){
				var d = new WillPower(player, decision)
				if(!this.decision || d.player.freeWill > this.decision.player.freeWill){  //whoever has the most will makes the decision.
					this.decision = d;
				}
			}
		}
		return this.decision != null;
	}

	this.renderContent = function(div){
		div.append("
"+this.content());
	}

	//in murder mode, plus random. reduce trigger, too. only for self (whether active or passive)
	this.considerDisEngagingMurderMode = function(player){
		return null;
	}

	//hate someone, not in murder mode, self if active, other if passive. plus random, increase trigger, too. if you engage murder mode in someone else, random chance to succesfully manipulate them to hate who you hate.
	this.considerEngagingMurderMode = function(player){

		return null;
	}

	// do it to self if active, do it to someone else if not.  need to have it not be destiny. bonus if there are dead players (want to avenge them/stop more corpses).
	this.considerForceGodTier = function(player){

	}

	//needs to be a murder mode player. more likely if you like them.  if active and you like them a lot, do it yourself. if passive, see if you can get somebody else to do it for you (mastermind)
	this.considerCalmMurderModePlayer = function(player){

	}

	//needs to be a murdermode player,  more likely if you dislike them. if active, do it yourself, if passive, see if you can get somebody else to do it for you. need to be stronger than them.
	this.considerKillMurderModePlayer = function(player){

	}

	//if self, just fucking do it. otherwise, pester them. raise power to min requirement, if it's not already there.
	this.considerMakingEctobiologistDoJob = function(player){

	}

	//if self, just fucking do it. raise land level. otherwise, pester them. raise power to min requirement, if it's not already there.
	this.considerMakingSpacePlayerDoJob = function(player){

	}

	this.getPlayerDecision = function(player){
		var ret = this.considerEngagingMurderMode(player);
		if(ret == null) ret = this.considerDisEngagingMurderMode(player);
		return ret;
	}

	this.processDecision = function(){

	}

	this.content = function(){
		var ret = "Decision Event: ";
		removeFromArray(this.player, this.session.availablePlayers);
		for(var i = 0; i<this.wills.length; i++){
			var will = this.wills[i];
			removeFromArray(will.player, this.session.availablePlayers);
			ret += this.processDecision(will);
		}

		return ret;
	}
}

function WillPower(player, decision){
	this.player = player;
	this.decision = decision;
}<commit_msg>more free will work<commit_after>function FreeWillStuff(session){
	this.session = session;
	this.canRepeat = true;
	this.playerList = [];  //what players are already in the medium when i trigger?
	this.decision = null
	//luck can be good or it can be bad.
	this.minHighValue = 110;

	this.trigger = function(playerList){
		this.decision = null;//reset
		//what the hell roue of doom's corpse. corpses aren't part of the player list!
		for(var i = 0; i<this.session.availablePlayers.length; i++){
			var player = this.session.availablePlayers[i];
			if(player.freeWill > 0){  //don't even get to consider a decision if you don't have free will.
				var decision = this.getPlayerDecision(player);
				if(decision){
					var d = new WillPower(player, decision)
					if(!this.decision || d.player.freeWill > this.decision.player.freeWill){  //whoever has the most will makes the decision.
						this.decision = d;
					}
				}
			}
		}
		return this.decision != null;
	}

	this.renderContent = function(div){
		div.append("
"+this.content());
	}

	//in murder mode, plus random. reduce trigger, too. only for self (whether active or passive)
	//more likely if who you hate is ectobiologist or space
	this.considerDisEngagingMurderMode = function(player){
		return null;
	}

	//hate someone, not in murder mode, self if active, other if passive. plus random, increase trigger, too. if you engage murder mode in someone else, random chance to succesfully manipulate them to hate who you hate.
	//less likely if who you hate is ectobiologist or space
	this.considerEngagingMurderMode = function(player){

		return null;
	}

	// do it to self if active, do it to someone else if not.  need to have it not be destiny. bonus if there are dead players (want to avenge them/stop more corpses).
	this.considerForceGodTier = function(player){

	}

	//needs to be a murder mode player. more likely if you like them.  if active and you like them a lot, do it yourself. if passive, see if you can get somebody else to do it for you (mastermind)
	//more likely if murderMode player is ectobiologist or space
	this.considerCalmMurderModePlayer = function(player){

	}

	//needs to be a murdermode player,  more likely if you dislike them. if active, do it yourself, if passive, see if you can get somebody else to do it for you. need to be stronger than them.
	//less likely if murderMode player is ectobiologist or space
	this.considerKillMurderModePlayer = function(player){

	}

	//if self, just fucking do it. otherwise, pester them. raise power to min requirement, if it's not already there.
	this.considerMakingEctobiologistDoJob = function(player){

	}

	//if self, just fucking do it. raise land level. otherwise, pester them. raise power to min requirement, if it's not already there.
	this.considerMakingSpacePlayerDoJob = function(player){

	}

	this.getPlayerDecision = function(player){
		//reorder things to change prevelance.
		var ret = this.considerCalmMurderModePlayer(player);
		if(ret == null) ret = this.considerKillMurderModePlayer(player);
		if(ret == null) ret = this.considerDisEngagingMurderMode(player);
		if(ret == null) ret = this.considerEngagingMurderMode(player);
		if(ret == null) ret = this.considerMakingEctobiologistDoJob(player);
		if(ret == null) ret = this.considerMakingSpacePlayerDoJob(player);
		if(ret == null) ret = this.considerForceGodTier(player);
		return ret;
	}

	this.processDecision = function(){

	}

	this.content = function(){
		console.log("Decision event: " + this.session.session_id)
		var ret = "Decision Event: ";
		removeFromArray(this.player, this.session.availablePlayers);
		for(var i = 0; i<this.wills.length; i++){
			var will = this.wills[i];
			removeFromArray(will.player, this.session.availablePlayers);
			ret += this.processDecision(will);
		}

		return ret;
	}
}

function WillPower(player, decision){
	this.player = player;
	this.decision = decision;
}<|endoftext|>


<commit_before>const React = require("react");
const PropTypes = require("prop-types");
const { Localized } = require("fluent-react/compat");
const sendEvent = require("../../browser-send-event.js");
const { PenTool } = require("./pen-tool");
const { HighlighterTool } = require("./highlighter-tool");
const { CropTool } = require("./crop-tool");
const { ColorPicker } = require("./color-picker");

exports.Editor = class Editor extends React.Component {
  constructor(props) {
    super(props);
    this.devicePixelRatio = window.devicePixelRatio;
    if (props.clip.image.captureType === "fullPage"
        || props.clip.image.captureType === "fullPageTruncated") {
      this.devicePixelRatio = 1;
    }
    this.canvasWidth = Math.floor(this.props.clip.image.dimensions.x);
    this.canvasHeight = Math.floor(this.props.clip.image.dimensions.y);
    this.state = {
      tool: "",
      color: "",
      lineWidth: "",
      actionsDisabled: true
    };
    this.onMouseUp = this.onMouseUp.bind(this);
    this.selectedTool = React.createRef();
  }

  render() {
    const toolContent = this.renderSelectedTool();
    const toolBar = this.renderToolBar();
    const display = this.loader || this.renderCanvas(toolContent);
    return

      { toolBar }
      { display }

;
  }

  renderCanvas(toolContent) {
    return

      <div
        className={`inverse-color-scheme canvas-container ${this.state.tool}`}
        id="canvas-container"
        style={{ height: this.canvasHeight, width: this.canvasWidth }}>
        <canvas
          className="image-holder centered"
          id="image-holder"
          ref={(image) => { this.imageCanvas = image; }}
          height={this.canvasHeight * this.devicePixelRatio} width={this.canvasWidth * this.devicePixelRatio}
          style={{ height: this.canvasHeight, width: this.canvasWidth }}></canvas>
        {toolContent}

;
  }

  renderSelectedTool() {
    switch (this.state.tool) {
      case "pen":
        return <PenTool
          ref={this.selectedTool}
          color={this.state.color}
          lineWidth={this.state.lineWidth}
          baseCanvas={this.imageCanvas}
          devicePixelRatio={this.devicePixelRatio}
          updateImageCallback={this.onDrawingUpdate.bind(this)} />;
      case "highlighter":
        return <HighlighterTool
          ref={this.selectedTool}
          color={this.state.color}
          lineWidth={this.state.lineWidth}
          baseCanvas={this.imageCanvas}
          devicePixelRatio={this.devicePixelRatio}
          updateImageCallback={this.onDrawingUpdate.bind(this)} />;
      case "cropTool":
        return <CropTool
          ref={this.selectedTool}
          baseCanvas={this.imageCanvas}
          devicePixelRatio={this.devicePixelRatio}
          cancelCropHandler={this.onClickCancelCrop.bind(this)}
          confirmCropHandler={this.onCropUpdate.bind(this)}
          toolbarOverrideCallback={this.overrideToolbar.bind(this)} />;
      default:
        return null;
    }
  }

  overrideToolbar() {
    this.setState({overrideToolbar: this.state.tool});
  }

  isToolActive(tool) {
    return this.state.tool === tool;
  }

  renderToolBar() {
    if (this.selectedTool.current && this.selectedTool.current.renderToolbar) {
      return this.selectedTool.current.renderToolbar();
    }
    const penState = this.isToolActive("pen") ? "active" : "inactive";
    const highlighterState = this.isToolActive("highlighter") ? "active" : "inactive";
    return

          <Localized id="annotationCropButton">
            <button className={`button transparent crop-button`} id="crop" onClick={this.onClickCrop.bind(this)} title="Crop"></button>
          </Localized>
          <Localized id="annotationPenButton">
            <button className={`button transparent pen-button ${penState}`} id="pen" onClick={this.onClickPen.bind(this)} title="Pen"></button>
          </Localized>
          <Localized id="annotationHighlighterButton">
            <button className={`button transparent highlight-button ${highlighterState}`} id="highlight" onClick={this.onClickHighlight.bind(this)} title="Highlighter"></button>
          </Localized>
          <ColorPicker activeTool={this.state.tool}
            setColorCallback={this.setColor.bind(this)}
            color={this.state.color} />
          <Localized id="annotationClearButton">
            <button className={`button transparent clear-button`} id="clear" onClick={this.onClickClear.bind(this)} title="Clear"></button>
          </Localized>

        <Localized id="annotationSaveEditButton">
          <button className="button primary save" id="save" onClick={ this.onClickSave.bind(this) } disabled = { this.state.actionsDisabled } title="Save edit">Save</button>
        </Localized>
        <Localized id="annotationCancelEditButton">
          <button className="button secondary cancel" id="cancel" onClick={this.onClickCancel.bind(this)} title="Cancel editing" disabled = { this.state.actionsDisabled }>Cancel</button>
        </Localized>

;
  }

  setColor(color) {
    this.setState({color});
  }

  renderShotsLoading() {
    return

;
  }

  onClickCrop() {
    this.previousTool = this.state.tool;
    this.setState({tool: "cropTool"});
    sendEvent("crop-select", "annotation-toolbar");
  }

  onDrawingUpdate(affectedArea, incomingCanvas, compositeOp) {
    if (!affectedArea || !incomingCanvas) {
      return;
    }

    this.imageCanvas.globalCompositeOperation = (compositeOp || "source-over");
    this.imageContext.drawImage(incomingCanvas,
      affectedArea.left * this.devicePixelRatio,
      affectedArea.top * this.devicePixelRatio,
      affectedArea.width * this.devicePixelRatio,
      affectedArea.height * this.devicePixelRatio,
      affectedArea.left, affectedArea.top, affectedArea.width, affectedArea.height);
  }

  onCropUpdate(affectedArea, incomingCanvas) {
    if (!affectedArea || !incomingCanvas) {
      this.setState({tool: this.previousTool});
      return;
    }

    const img = new Image();
    img.crossOrigin = "Anonymous";
    img.onload = () => {
      imageContext.scale(this.devicePixelRatio, this.devicePixelRatio);
      imageContext.drawImage(img, 0, 0, affectedArea.width, affectedArea.height);
    };
    this.canvasWidth = affectedArea.width;
    this.canvasHeight = affectedArea.height;
    const imageContext = this.imageCanvas.getContext("2d");
    this.imageContext = imageContext;
    img.src = incomingCanvas.toDataURL("image/png");
    this.setState({tool: this.previousTool});
  }

  onClickCancelCrop() {
    this.setState({tool: this.previousTool});
  }

  onClickClear() {
    this.setState({tool: this.state.tool});
    this.imageContext.clearRect(0, 0, this.imageCanvas.width, this.imageCanvas.height);
    this.canvasHeight = this.props.clip.image.dimensions.y;
    this.canvasWidth = this.props.clip.image.dimensions.x;
    this.renderImage();
    sendEvent("clear-select", "annotation-toolbar");
  }

  onClickCancel() {
    this.props.onCancelEdit(false);
    sendEvent("cancel", "annotation-toolbar");
  }

  onClickSave() {
    this.loader = this.renderShotsLoading();
    this.setState({actionsDisabled: true});
    let dataUrl = this.imageCanvas.toDataURL();

    if (this.props.pngToJpegCutoff && dataUrl.length > this.props.pngToJpegCutoff) {
      const jpegDataUrl = this.imageCanvas.toDataURL("image/jpeg");
      if (jpegDataUrl.length < dataUrl.length) {
        dataUrl = jpegDataUrl;
      }
    }

    const dimensions = {x: this.canvasWidth, y: this.canvasHeight};
    this.props.onClickSave(dataUrl, dimensions);
    sendEvent("save", "annotation-toolbar");
  }

  onClickHighlight() {
    if (this.state.tool !== "highlighter") {
      this.setState({tool: "highlighter", lineWidth: 20});
      sendEvent("highlighter-select", "annotation-toolbar");
    }
  }

  onClickPen() {
    if (this.state.tool !== "pen") {
      this.setState({tool: "pen", lineWidth: 5});
      sendEvent("pen-select", "annotation-toolbar");
    }
  }

  onMouseUp(e) {
    // This is here so that when the user releases the mouse button outside of
    // the canvas area, the drawing will stop.
    if (this.selectedTool.current
        && this.selectedTool.current.onMouseUp) {
      e.stopPropagation();
      this.selectedTool.current.onMouseUp(e);
    }
  }

  renderImage() {
    const imageContext = this.imageCanvas.getContext("2d");
    imageContext.scale(this.devicePixelRatio, this.devicePixelRatio);
    const img = new Image();
    img.crossOrigin = "Anonymous";
    const width = this.props.clip.image.dimensions.x;
    const height = this.props.clip.image.dimensions.y;
    img.onload = () => {
      imageContext.drawImage(img, 0, 0, width, height);
      this.setState({actionsDisabled: false});
    };
    this.imageContext = imageContext;
    img.src = this.props.clip.image.url;
  }

  componentDidMount() {
    document.addEventListener("mouseup", this.onMouseUp);
    this.renderImage();
    this.setState({
      tool: "pen",
      color: "#000",
      lineWidth: 5,
      actionsDisabled: true
    });
  }

  componentWillUnmount() {
    document.removeEventListener("mouseup", this.onMouseUp);
  }

};

exports.Editor.propTypes = {
  clip: PropTypes.object,
  onCancelEdit: PropTypes.func,
  onClickSave: PropTypes.func,
  pngToJpegCutoff: PropTypes.number
};
<commit_msg>Set globalCompositeOperation on context not canvas. (#4473) (#4474)<commit_after>const React = require("react");
const PropTypes = require("prop-types");
const { Localized } = require("fluent-react/compat");
const sendEvent = require("../../browser-send-event.js");
const { PenTool } = require("./pen-tool");
const { HighlighterTool } = require("./highlighter-tool");
const { CropTool } = require("./crop-tool");
const { ColorPicker } = require("./color-picker");

exports.Editor = class Editor extends React.Component {
  constructor(props) {
    super(props);
    this.devicePixelRatio = window.devicePixelRatio;
    if (props.clip.image.captureType === "fullPage"
        || props.clip.image.captureType === "fullPageTruncated") {
      this.devicePixelRatio = 1;
    }
    this.canvasWidth = Math.floor(this.props.clip.image.dimensions.x);
    this.canvasHeight = Math.floor(this.props.clip.image.dimensions.y);
    this.state = {
      tool: "",
      color: "",
      lineWidth: "",
      actionsDisabled: true
    };
    this.onMouseUp = this.onMouseUp.bind(this);
    this.selectedTool = React.createRef();
  }

  render() {
    const toolContent = this.renderSelectedTool();
    const toolBar = this.renderToolBar();
    const display = this.loader || this.renderCanvas(toolContent);
    return

      { toolBar }
      { display }

;
  }

  renderCanvas(toolContent) {
    return

      <div
        className={`inverse-color-scheme canvas-container ${this.state.tool}`}
        id="canvas-container"
        style={{ height: this.canvasHeight, width: this.canvasWidth }}>
        <canvas
          className="image-holder centered"
          id="image-holder"
          ref={(image) => { this.imageCanvas = image; }}
          height={this.canvasHeight * this.devicePixelRatio} width={this.canvasWidth * this.devicePixelRatio}
          style={{ height: this.canvasHeight, width: this.canvasWidth }}></canvas>
        {toolContent}

;
  }

  renderSelectedTool() {
    switch (this.state.tool) {
      case "pen":
        return <PenTool
          ref={this.selectedTool}
          color={this.state.color}
          lineWidth={this.state.lineWidth}
          baseCanvas={this.imageCanvas}
          devicePixelRatio={this.devicePixelRatio}
          updateImageCallback={this.onDrawingUpdate.bind(this)} />;
      case "highlighter":
        return <HighlighterTool
          ref={this.selectedTool}
          color={this.state.color}
          lineWidth={this.state.lineWidth}
          baseCanvas={this.imageCanvas}
          devicePixelRatio={this.devicePixelRatio}
          updateImageCallback={this.onDrawingUpdate.bind(this)} />;
      case "cropTool":
        return <CropTool
          ref={this.selectedTool}
          baseCanvas={this.imageCanvas}
          devicePixelRatio={this.devicePixelRatio}
          cancelCropHandler={this.onClickCancelCrop.bind(this)}
          confirmCropHandler={this.onCropUpdate.bind(this)}
          toolbarOverrideCallback={this.overrideToolbar.bind(this)} />;
      default:
        return null;
    }
  }

  overrideToolbar() {
    this.setState({overrideToolbar: this.state.tool});
  }

  isToolActive(tool) {
    return this.state.tool === tool;
  }

  renderToolBar() {
    if (this.selectedTool.current && this.selectedTool.current.renderToolbar) {
      return this.selectedTool.current.renderToolbar();
    }
    const penState = this.isToolActive("pen") ? "active" : "inactive";
    const highlighterState = this.isToolActive("highlighter") ? "active" : "inactive";
    return

          <Localized id="annotationCropButton">
            <button className={`button transparent crop-button`} id="crop" onClick={this.onClickCrop.bind(this)} title="Crop"></button>
          </Localized>
          <Localized id="annotationPenButton">
            <button className={`button transparent pen-button ${penState}`} id="pen" onClick={this.onClickPen.bind(this)} title="Pen"></button>
          </Localized>
          <Localized id="annotationHighlighterButton">
            <button className={`button transparent highlight-button ${highlighterState}`} id="highlight" onClick={this.onClickHighlight.bind(this)} title="Highlighter"></button>
          </Localized>
          <ColorPicker activeTool={this.state.tool}
            setColorCallback={this.setColor.bind(this)}
            color={this.state.color} />
          <Localized id="annotationClearButton">
            <button className={`button transparent clear-button`} id="clear" onClick={this.onClickClear.bind(this)} title="Clear"></button>
          </Localized>

        <Localized id="annotationSaveEditButton">
          <button className="button primary save" id="save" onClick={ this.onClickSave.bind(this) } disabled = { this.state.actionsDisabled } title="Save edit">Save</button>
        </Localized>
        <Localized id="annotationCancelEditButton">
          <button className="button secondary cancel" id="cancel" onClick={this.onClickCancel.bind(this)} title="Cancel editing" disabled = { this.state.actionsDisabled }>Cancel</button>
        </Localized>

;
  }

  setColor(color) {
    this.setState({color});
  }

  renderShotsLoading() {
    return

;
  }

  onClickCrop() {
    this.previousTool = this.state.tool;
    this.setState({tool: "cropTool"});
    sendEvent("crop-select", "annotation-toolbar");
  }

  onDrawingUpdate(affectedArea, incomingCanvas, compositeOp) {
    if (!affectedArea || !incomingCanvas) {
      return;
    }

    this.imageContext.globalCompositeOperation = (compositeOp || "source-over");
    this.imageContext.drawImage(incomingCanvas,
      affectedArea.left * this.devicePixelRatio,
      affectedArea.top * this.devicePixelRatio,
      affectedArea.width * this.devicePixelRatio,
      affectedArea.height * this.devicePixelRatio,
      affectedArea.left, affectedArea.top, affectedArea.width, affectedArea.height);
  }

  onCropUpdate(affectedArea, incomingCanvas) {
    if (!affectedArea || !incomingCanvas) {
      this.setState({tool: this.previousTool});
      return;
    }

    const img = new Image();
    img.crossOrigin = "Anonymous";
    img.onload = () => {
      imageContext.scale(this.devicePixelRatio, this.devicePixelRatio);
      imageContext.drawImage(img, 0, 0, affectedArea.width, affectedArea.height);
    };
    this.canvasWidth = affectedArea.width;
    this.canvasHeight = affectedArea.height;
    const imageContext = this.imageCanvas.getContext("2d");
    this.imageContext = imageContext;
    img.src = incomingCanvas.toDataURL("image/png");
    this.setState({tool: this.previousTool});
  }

  onClickCancelCrop() {
    this.setState({tool: this.previousTool});
  }

  onClickClear() {
    this.setState({tool: this.state.tool});
    this.imageContext.clearRect(0, 0, this.imageCanvas.width, this.imageCanvas.height);
    this.canvasHeight = this.props.clip.image.dimensions.y;
    this.canvasWidth = this.props.clip.image.dimensions.x;
    this.renderImage();
    sendEvent("clear-select", "annotation-toolbar");
  }

  onClickCancel() {
    this.props.onCancelEdit(false);
    sendEvent("cancel", "annotation-toolbar");
  }

  onClickSave() {
    this.loader = this.renderShotsLoading();
    this.setState({actionsDisabled: true});
    let dataUrl = this.imageCanvas.toDataURL();

    if (this.props.pngToJpegCutoff && dataUrl.length > this.props.pngToJpegCutoff) {
      const jpegDataUrl = this.imageCanvas.toDataURL("image/jpeg");
      if (jpegDataUrl.length < dataUrl.length) {
        dataUrl = jpegDataUrl;
      }
    }

    const dimensions = {x: this.canvasWidth, y: this.canvasHeight};
    this.props.onClickSave(dataUrl, dimensions);
    sendEvent("save", "annotation-toolbar");
  }

  onClickHighlight() {
    if (this.state.tool !== "highlighter") {
      this.setState({tool: "highlighter", lineWidth: 20});
      sendEvent("highlighter-select", "annotation-toolbar");
    }
  }

  onClickPen() {
    if (this.state.tool !== "pen") {
      this.setState({tool: "pen", lineWidth: 5});
      sendEvent("pen-select", "annotation-toolbar");
    }
  }

  onMouseUp(e) {
    // This is here so that when the user releases the mouse button outside of
    // the canvas area, the drawing will stop.
    if (this.selectedTool.current
        && this.selectedTool.current.onMouseUp) {
      e.stopPropagation();
      this.selectedTool.current.onMouseUp(e);
    }
  }

  renderImage() {
    const imageContext = this.imageCanvas.getContext("2d");
    imageContext.scale(this.devicePixelRatio, this.devicePixelRatio);
    const img = new Image();
    img.crossOrigin = "Anonymous";
    const width = this.props.clip.image.dimensions.x;
    const height = this.props.clip.image.dimensions.y;
    img.onload = () => {
      imageContext.drawImage(img, 0, 0, width, height);
      this.setState({actionsDisabled: false});
    };
    this.imageContext = imageContext;
    img.src = this.props.clip.image.url;
  }

  componentDidMount() {
    document.addEventListener("mouseup", this.onMouseUp);
    this.renderImage();
    this.setState({
      tool: "pen",
      color: "#000",
      lineWidth: 5,
      actionsDisabled: true
    });
  }

  componentWillUnmount() {
    document.removeEventListener("mouseup", this.onMouseUp);
  }

};

exports.Editor.propTypes = {
  clip: PropTypes.object,
  onCancelEdit: PropTypes.func,
  onClickSave: PropTypes.func,
  pngToJpegCutoff: PropTypes.number
};
<|endoftext|>


<commit_before>var ContextMenuView = require('../../components/context-menu/context-menu-view');
var CustomListCollection = require('../../components/custom-list/custom-list-collection');
var REQUIRED_OPTS = [
  'ev',
  'isTableOwner',
  'isLocked',
  'isCustomQuery',
  'triggerElementID'
];

module.exports = function (opts) {
  _.each(REQUIRED_OPTS, function (item) {
    if (opts[item] === undefined) throw new Error(item + ' is required');
    this['_' + item] = opts[item];
  }, this);

  var position = { x: this._ev.clientX, y: this._ev.clientY };
  var menuItems = [
    {
      label: _t('dataset.duplicate.' + (this._isCustomQuery ? 'customOption' : 'option')),
      val: 'duplicate',
      action: function () {
        this.trigger('duplicate', this);
      }
    }
  ];

  if (this._isTableOwner) {
    if (!this._isLocked) {
      menuItems.push({
        label: _t('dataset.rename.option'),
        val: 'rename',
        action: function () {
          this.trigger('rename', this);
        }
      });
    }

    menuItems = menuItems.concat([
      {
        label: _t('dataset.lock.option'),
        val: 'lock',
        action: function () {
          this.trigger('lock', this);
        }
      }, {
        label: _t('dataset.delete.option'),
        val: 'delete',
        destructive: true,
        action: function () {
          this.trigger('delete', this);
        }
      }
    ]);
  }

  var collection = new CustomListCollection(menuItems);

  var view = new ContextMenuView({
    collection: collection,
    triggerElementID: this._triggerElementID,
    position: position
  });

  collection.bind('change:selected', function (menuItem) {
    var action = menuItem.get('action');
    action && action.bind(view)(menuItem);
  }, view);

  view.model.bind('change:visible', function (model, isContextMenuVisible) {
    if (view && !isContextMenuVisible) {
      collection.unbind(null, null, view);
      view.model.unbind(null, null, view);
      view.remove();
    }
  }, view);

  return view;
};
<commit_msg>Added unsercore dependency<commit_after>var _ = require('underscore');
var ContextMenuView = require('../../components/context-menu/context-menu-view');
var CustomListCollection = require('../../components/custom-list/custom-list-collection');
var REQUIRED_OPTS = [
  'ev',
  'isTableOwner',
  'isLocked',
  'isCustomQuery',
  'triggerElementID'
];

module.exports = function (opts) {
  _.each(REQUIRED_OPTS, function (item) {
    if (opts[item] === undefined) throw new Error(item + ' is required');
    this['_' + item] = opts[item];
  }, this);

  var position = { x: this._ev.clientX, y: this._ev.clientY };
  var menuItems = [
    {
      label: _t('dataset.duplicate.' + (this._isCustomQuery ? 'customOption' : 'option')),
      val: 'duplicate',
      action: function () {
        this.trigger('duplicate', this);
      }
    }
  ];

  if (this._isTableOwner) {
    if (!this._isLocked) {
      menuItems.push({
        label: _t('dataset.rename.option'),
        val: 'rename',
        action: function () {
          this.trigger('rename', this);
        }
      });
    }

    menuItems = menuItems.concat([
      {
        label: _t('dataset.lock.option'),
        val: 'lock',
        action: function () {
          this.trigger('lock', this);
        }
      }, {
        label: _t('dataset.delete.option'),
        val: 'delete',
        destructive: true,
        action: function () {
          this.trigger('delete', this);
        }
      }
    ]);
  }

  var collection = new CustomListCollection(menuItems);

  var view = new ContextMenuView({
    collection: collection,
    triggerElementID: this._triggerElementID,
    position: position
  });

  collection.bind('change:selected', function (menuItem) {
    var action = menuItem.get('action');
    action && action.bind(view)(menuItem);
  }, view);

  view.model.bind('change:visible', function (model, isContextMenuVisible) {
    if (view && !isContextMenuVisible) {
      collection.unbind(null, null, view);
      view.model.unbind(null, null, view);
      view.remove();
    }
  }, view);

  return view;
};
<|endoftext|>


<commit_before>import template from 'babel-template';
import generate from 'babel-generator';
import * as t from 'babel-types';
import traverse from 'babel-traverse';
import flatten from 'flatten';
import toStringLiteral from './util/toStringLiteral';
import globals from './util/globals';

const warning = `/* !\n` +
        `   ! Please don't edit this file by hand;\n` +
        `   ! it is automatically generated by the css-values module.\n` +
        `   ! */\n\n`;

export let generateProgram = contents => {
    let program = t.program(flatten(contents));

    traverse(program, {
        noScope: true,
        EmptyStatement: function (path) {
            path.remove();
        }
    });

    return warning + generate(program).code + '\n';
};

let generateConditions = (...conditions) => {
    if (conditions.length === 1) {
        return conditions[0];
    }
    return t.logicalExpression(
        '&&',
        generateConditions.apply(null, conditions.slice(0, conditions.length - 1)),
        conditions[conditions.length - 1]
    );
};

export let exportModules = exported => {
    const exportTemplate = template('module.exports = EXPORTS');

    return exportTemplate({
        EXPORTS: t.arrayExpression(exported.map((value, index) => {
            if (index === exported.length - 1) {
                return t.identifier(`\n    ${value}\n`);
            }
            return t.identifier(`\n    ${value}`);
        }))
    });
};

export let requireModules = (...modules) => {
    return modules.map(opts => {
        return template(`var IDENTIFIER = require(MODULE);`)({
            IDENTIFIER: t.identifier(opts.identifier),
            MODULE: t.stringLiteral(opts.module)
        });
    });
};

export let plugin = () => {
    const tmpl = template(`
    module.exports = function isValid (cssString) {
        var parts = cssString.split(':').map(function (value) {
            return value.trim();
        });
        var parsed = valueParser(parts[1]);
        if (parsed.nodes.length === 1 && ~GLOBALS.indexOf(parsed.nodes[0].value)) {
            return true;
        }
        var invalid = validators.some(function (validator) {
            if (!~validator.properties.indexOf(parts[0])) {
                return;
            }
            return !validator(parsed);
        });
        return !invalid;
    }
    `);

    return generateProgram([
        requireModules({
            identifier: 'validators',
            module: './properties/'
        }, {
            identifier: 'valueParser',
            module: 'postcss-value-parser'
        }),
        tmpl({
            GLOBALS: t.arrayExpression(globals.map(toStringLiteral))
        })
    ]);
};

export let property = opts => {
    const tmpl = template(`
    module.exports = function (parsed) {
        var valid = true;
        var count = 0;

        parsed.walk(function (node) {
            WORD
            STRING
            SEPARATOR
        });

        return count > COUNT ? false : valid;
    }
    `);

    const properties = template(`module.exports.properties = EXPORTS;`)({
        EXPORTS: t.arrayExpression(opts.properties.map(toStringLiteral))
    });

    let config = ['SEPARATOR', 'STRING', 'WORD'].reduce((list, key) => {
        list[key] = t.emptyStatement();
        return list;
    }, {});

    config.COUNT = t.numericLiteral(opts.count);

    let conditions = [];
    let dependencies = [];

    if (opts.values && opts.values.length) {
        if (opts.values.length === 1) {
            conditions.push(template(`node.value !== "${opts.values[0]}"`)().expression);
        } else {
            conditions.push(template(`!~VALUES.indexOf(node.value)`)({
                VALUES: t.arrayExpression(opts.values.map(toStringLiteral))
            }).expression);
        }
    }

    ['length', 'integer', 'percentage', 'number', 'time'].forEach(type => {
        if (!opts[type]) {
            return;
        }
        const camel = 'is' + type[0].toUpperCase() + type.slice(1, type.length);
        conditions.push(template(`!${camel}(node.value)`)().expression);
        dependencies.push({
            identifier: camel,
            module: `../../validators/${camel}`
        });
    });

    if (conditions.length) {
        config.WORD = template(`if (node.type === 'word') { inject; count++; }`)({
            inject: template('if (inject) { valid = false; return false; }')({
                inject: generateConditions.apply(null, conditions)
            })
        });
    }

    if (opts.string) {
        config.STRING = template(`if (node.type === 'string') { count++; }`)();
    }

    if (opts.repeat && opts.repeat.separator) {
        config.SEPARATOR = template(`if (node.type === 'div' && node.value === "${opts.repeat.separator}") { count --; }`)();
    }

    return generateProgram([
        requireModules.apply(null, dependencies),
        tmpl(config),
        properties
    ]);
};

export let test = opts => {
    let tests = (prop, valid) => {
        return value => {
            return t.objectExpression([
                t.objectProperty(
                    t.identifier('fixture'),
                    t.stringLiteral(`${prop}: ${value}`)
                ),
                t.objectProperty(
                    t.identifier('valid'),
                    t.identifier(valid ? 'true' : 'false')
                )
            ]);
        };
    };

    return generateProgram([
        template('module.exports = EXPORTS;')({
            EXPORTS: t.arrayExpression(flatten(opts.properties.map(prop => {
                const valid   = opts.valid.map(tests(prop, true));
                const invalid = opts.invalid.map(tests(prop, false));
                return valid.concat(invalid);
            })))
        })
    ]);
};

export let tests = () => {
    const tmpl = template(`
    suites.forEach(function (suite) {
        suite.forEach(function (test) {
            ava(test.fixture, function (t) {
                t.same(plugin(test.fixture), test.valid);
            });
        });
    });
    `);

    return generateProgram([
        requireModules({
            identifier: 'ava',
            module: `ava`
        }, {
            identifier: 'plugin',
            module: `./plugin`
        }, {
            identifier: 'suites',
            module: `./tests`
        }),
        tmpl()
    ]);
};
<commit_msg>Fix indent.<commit_after>import template from 'babel-template';
import generate from 'babel-generator';
import * as t from 'babel-types';
import traverse from 'babel-traverse';
import flatten from 'flatten';
import toStringLiteral from './util/toStringLiteral';
import globals from './util/globals';

const warning = `/* !\n` +
                `   ! Please don't edit this file by hand;\n` +
                `   ! it is automatically generated by the css-values module.\n` +
                `   ! */\n\n`;

export let generateProgram = contents => {
    let program = t.program(flatten(contents));

    traverse(program, {
        noScope: true,
        EmptyStatement: function (path) {
            path.remove();
        }
    });

    return warning + generate(program).code + '\n';
};

let generateConditions = (...conditions) => {
    if (conditions.length === 1) {
        return conditions[0];
    }
    return t.logicalExpression(
        '&&',
        generateConditions.apply(null, conditions.slice(0, conditions.length - 1)),
        conditions[conditions.length - 1]
    );
};

export let exportModules = exported => {
    const exportTemplate = template('module.exports = EXPORTS');

    return exportTemplate({
        EXPORTS: t.arrayExpression(exported.map((value, index) => {
            if (index === exported.length - 1) {
                return t.identifier(`\n    ${value}\n`);
            }
            return t.identifier(`\n    ${value}`);
        }))
    });
};

export let requireModules = (...modules) => {
    return modules.map(opts => {
        return template(`var IDENTIFIER = require(MODULE);`)({
            IDENTIFIER: t.identifier(opts.identifier),
            MODULE: t.stringLiteral(opts.module)
        });
    });
};

export let plugin = () => {
    const tmpl = template(`
    module.exports = function isValid (cssString) {
        var parts = cssString.split(':').map(function (value) {
            return value.trim();
        });
        var parsed = valueParser(parts[1]);
        if (parsed.nodes.length === 1 && ~GLOBALS.indexOf(parsed.nodes[0].value)) {
            return true;
        }
        var invalid = validators.some(function (validator) {
            if (!~validator.properties.indexOf(parts[0])) {
                return;
            }
            return !validator(parsed);
        });
        return !invalid;
    }
    `);

    return generateProgram([
        requireModules({
            identifier: 'validators',
            module: './properties/'
        }, {
            identifier: 'valueParser',
            module: 'postcss-value-parser'
        }),
        tmpl({
            GLOBALS: t.arrayExpression(globals.map(toStringLiteral))
        })
    ]);
};

export let property = opts => {
    const tmpl = template(`
    module.exports = function (parsed) {
        var valid = true;
        var count = 0;

        parsed.walk(function (node) {
            WORD
            STRING
            SEPARATOR
        });

        return count > COUNT ? false : valid;
    }
    `);

    const properties = template(`module.exports.properties = EXPORTS;`)({
        EXPORTS: t.arrayExpression(opts.properties.map(toStringLiteral))
    });

    let config = ['SEPARATOR', 'STRING', 'WORD'].reduce((list, key) => {
        list[key] = t.emptyStatement();
        return list;
    }, {});

    config.COUNT = t.numericLiteral(opts.count);

    let conditions = [];
    let dependencies = [];

    if (opts.values && opts.values.length) {
        if (opts.values.length === 1) {
            conditions.push(template(`node.value !== "${opts.values[0]}"`)().expression);
        } else {
            conditions.push(template(`!~VALUES.indexOf(node.value)`)({
                VALUES: t.arrayExpression(opts.values.map(toStringLiteral))
            }).expression);
        }
    }

    ['length', 'integer', 'percentage', 'number', 'time'].forEach(type => {
        if (!opts[type]) {
            return;
        }
        const camel = 'is' + type[0].toUpperCase() + type.slice(1, type.length);
        conditions.push(template(`!${camel}(node.value)`)().expression);
        dependencies.push({
            identifier: camel,
            module: `../../validators/${camel}`
        });
    });

    if (conditions.length) {
        config.WORD = template(`if (node.type === 'word') { inject; count++; }`)({
            inject: template('if (inject) { valid = false; return false; }')({
                inject: generateConditions.apply(null, conditions)
            })
        });
    }

    if (opts.string) {
        config.STRING = template(`if (node.type === 'string') { count++; }`)();
    }

    if (opts.repeat && opts.repeat.separator) {
        config.SEPARATOR = template(`if (node.type === 'div' && node.value === "${opts.repeat.separator}") { count --; }`)();
    }

    return generateProgram([
        requireModules.apply(null, dependencies),
        tmpl(config),
        properties
    ]);
};

export let test = opts => {
    let tests = (prop, valid) => {
        return value => {
            return t.objectExpression([
                t.objectProperty(
                    t.identifier('fixture'),
                    t.stringLiteral(`${prop}: ${value}`)
                ),
                t.objectProperty(
                    t.identifier('valid'),
                    t.identifier(valid ? 'true' : 'false')
                )
            ]);
        };
    };

    return generateProgram([
        template('module.exports = EXPORTS;')({
            EXPORTS: t.arrayExpression(flatten(opts.properties.map(prop => {
                const valid   = opts.valid.map(tests(prop, true));
                const invalid = opts.invalid.map(tests(prop, false));
                return valid.concat(invalid);
            })))
        })
    ]);
};

export let tests = () => {
    const tmpl = template(`
    suites.forEach(function (suite) {
        suite.forEach(function (test) {
            ava(test.fixture, function (t) {
                t.same(plugin(test.fixture), test.valid);
            });
        });
    });
    `);

    return generateProgram([
        requireModules({
            identifier: 'ava',
            module: `ava`
        }, {
            identifier: 'plugin',
            module: `./plugin`
        }, {
            identifier: 'suites',
            module: `./tests`
        }),
        tmpl()
    ]);
};
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { MongoInternals } from 'meteor/mongo';
import { SystemLogger } from '../../app/logger';
import { settings } from '../../app/settings';
import { Info } from '../../app/utils';
import fs from 'fs';
import path from 'path';
import semver from 'semver';

Meteor.startup(function() {
	const { mongo } = MongoInternals.defaultRemoteCollectionDriver();

	const isOplogEnabled = Boolean(mongo._oplogHandle && mongo._oplogHandle.onOplogEntry);

	let mongoDbVersion;
	let mongoDbEngine;
	try {
		const { version, storageEngine } = Promise.await(mongo.db.command({ serverStatus: 1 }));
		mongoDbVersion = version;
		mongoDbEngine = storageEngine.name;
	} catch (e) {
		mongoDbVersion = 'Error getting version';
		console.error('Error getting MongoDB version');
	}

	const desiredNodeVersion = semver.clean(fs.readFileSync(path.join(process.cwd(), '../../.node_version.txt')).toString());
	const desiredNodeVersionMajor = String(semver.parse(desiredNodeVersion).major);

	return Meteor.setTimeout(function() {
		let msg = [
			`Rocket.Chat Version: ${ Info.version }`,
			`     NodeJS Version: ${ process.versions.node } - ${ process.arch }`,
			`    MongoDB Version: ${ mongoDbVersion }`,
			`     MongoDB Engine: ${ mongoDbEngine }`,
			`           Platform: ${ process.platform }`,
			`       Process Port: ${ process.env.PORT }`,
			`           Site URL: ${ settings.get('Site_Url') }`,
			`   ReplicaSet OpLog: ${ isOplogEnabled ? 'Enabled' : 'Disabled' }`,
		];

		if (Info.commit && Info.commit.hash) {
			msg.push(`        Commit Hash: ${ Info.commit.hash.substr(0, 10) }`);
		}

		if (Info.commit && Info.commit.branch) {
			msg.push(`      Commit Branch: ${ Info.commit.branch }`);
		}

		msg = msg.join('\n');

		if (!isOplogEnabled) {
			msg += ['', '', 'OPLOG / REPLICASET IS REQUIRED TO RUN ROCKET.CHAT, MORE INFORMATION AT:', 'https://rocket.chat/docs/installation/docker-containers/high-availability-install'].join('\n');
			SystemLogger.error_box(msg, 'SERVER ERROR');

			return process.exit(1);
		}

		if (!semver.satisfies(process.versions.node, desiredNodeVersionMajor)) {
			msg += ['', '', 'YOUR CURRENT NODEJS VERSION IS NOT SUPPORTED,', `PLEASE UPGRADE / DOWNGRADE TO VERSION ${ desiredNodeVersionMajor }.X.X`].join('\n');
			SystemLogger.error_box(msg, 'SERVER ERROR');

			return process.exit(1);
		}

		if (!semver.satisfies(mongoDbVersion, '>=3.2.0')) {
			msg += ['', '', 'YOUR CURRENT MONGODB VERSION IS NOT SUPPORTED,', 'PLEASE UPGRADE TO VERSION 3.2 OR LATER'].join('\n');
			SystemLogger.error_box(msg, 'SERVER ERROR');

			return process.exit(1);
		}

		return SystemLogger.startup_box(msg, 'SERVER RUNNING');
	}, 100);
});
<commit_msg>[Fix] switch oplog required doc link to more accurate link (#14288)<commit_after>import { Meteor } from 'meteor/meteor';
import { MongoInternals } from 'meteor/mongo';
import { SystemLogger } from '../../app/logger';
import { settings } from '../../app/settings';
import { Info } from '../../app/utils';
import fs from 'fs';
import path from 'path';
import semver from 'semver';

Meteor.startup(function() {
	const { mongo } = MongoInternals.defaultRemoteCollectionDriver();

	const isOplogEnabled = Boolean(mongo._oplogHandle && mongo._oplogHandle.onOplogEntry);

	let mongoDbVersion;
	let mongoDbEngine;
	try {
		const { version, storageEngine } = Promise.await(mongo.db.command({ serverStatus: 1 }));
		mongoDbVersion = version;
		mongoDbEngine = storageEngine.name;
	} catch (e) {
		mongoDbVersion = 'Error getting version';
		console.error('Error getting MongoDB version');
	}

	const desiredNodeVersion = semver.clean(fs.readFileSync(path.join(process.cwd(), '../../.node_version.txt')).toString());
	const desiredNodeVersionMajor = String(semver.parse(desiredNodeVersion).major);

	return Meteor.setTimeout(function() {
		let msg = [
			`Rocket.Chat Version: ${ Info.version }`,
			`     NodeJS Version: ${ process.versions.node } - ${ process.arch }`,
			`    MongoDB Version: ${ mongoDbVersion }`,
			`     MongoDB Engine: ${ mongoDbEngine }`,
			`           Platform: ${ process.platform }`,
			`       Process Port: ${ process.env.PORT }`,
			`           Site URL: ${ settings.get('Site_Url') }`,
			`   ReplicaSet OpLog: ${ isOplogEnabled ? 'Enabled' : 'Disabled' }`,
		];

		if (Info.commit && Info.commit.hash) {
			msg.push(`        Commit Hash: ${ Info.commit.hash.substr(0, 10) }`);
		}

		if (Info.commit && Info.commit.branch) {
			msg.push(`      Commit Branch: ${ Info.commit.branch }`);
		}

		msg = msg.join('\n');

		if (!isOplogEnabled) {
			msg += ['', '', 'OPLOG / REPLICASET IS REQUIRED TO RUN ROCKET.CHAT, MORE INFORMATION AT:', 'https://go.rocket.chat/i/oplog-required'].join('\n');
			SystemLogger.error_box(msg, 'SERVER ERROR');

			return process.exit(1);
		}

		if (!semver.satisfies(process.versions.node, desiredNodeVersionMajor)) {
			msg += ['', '', 'YOUR CURRENT NODEJS VERSION IS NOT SUPPORTED,', `PLEASE UPGRADE / DOWNGRADE TO VERSION ${ desiredNodeVersionMajor }.X.X`].join('\n');
			SystemLogger.error_box(msg, 'SERVER ERROR');

			return process.exit(1);
		}

		if (!semver.satisfies(mongoDbVersion, '>=3.2.0')) {
			msg += ['', '', 'YOUR CURRENT MONGODB VERSION IS NOT SUPPORTED,', 'PLEASE UPGRADE TO VERSION 3.2 OR LATER'].join('\n');
			SystemLogger.error_box(msg, 'SERVER ERROR');

			return process.exit(1);
		}

		return SystemLogger.startup_box(msg, 'SERVER RUNNING');
	}, 100);
});
<|endoftext|>


<commit_before>import styled from 'styled-components'

export default styled.div`
  border-radius: 2px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.12);
  background-color: #ffffff;
  padding: 20px;
`<commit_msg>Make shadowbox a flex component<commit_after>import styled from 'styled-components'

export default styled.div`
  border-radius: 2px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.12);
  background-color: #ffffff;
  padding: 20px;
  display:flex;
  flex-flow:column;
`<|endoftext|>


<commit_before>
/*
 * GET home page.
 */

var twilio = require('twilio');
var kinectdb = require("../model/kinectdb");
var client = new twilio.RestClient('AC0662afad9cf5f3753a00b71e5b0ad975', '73deaec2c6121bea06685b15c6580fce');

exports.index = function(req, res){
	res.render('index', { title: 'Express' });
	console.log(req.body);
	sendTwilioMessage('+1 514-574-8677','1 647-931-1254',JSON.stringify(req.body));
};

exports.wakeup = function(req, res){
	sendTwilioMessage('+1 514-574-8677','1 647-931-1254', 'Wake up!', function(error, message) {
		res.send(200);
	});
};

exports.takeabreak = function(req, res){
	sendTwilioMessage('+1 514-574-8677','1 647-931-1254', 'Take a break!', function(error, message) {
		res.send(200);
	});
};

function sendTwilioMessage(destinationNumber, fromNumber, body, callback) {
	client.sms.messages.create({
	    to: destinationNumber,
	    from: fromNumber,
	    body: body
	}, function(error, message) {
			var newEntry = new kinectdb.Entry({value: JSON.stringify(req.body)});
			newEntry.save(function(err){
				if (err) {
					console.log("Error saving Entry to DB: " + err);
					res.send(404);
				}
				res.send(200);
			});
	    // The HTTP request to Twilio will run asynchronously. This callback
	    // function will be called when a response is received from Twilio
	    // The "error" variable will contain error information, if any.
	    // If the request was successful, this value will be "falsy"
	    if (!error) {
	        // The second argument to the callback will contain the information
	        // sent back by Twilio for the request. In this case, it is the
	        // information about the text messsage you just sent:
	        console.log('Success! The SID for this SMS message is:');
	        console.log(message.sid);

	        console.log('Message sent on:');
	        console.log(message.dateCreated);

			console.log("Message content: " + body);
	    } else {
	        console.log('Oops! There was an error.'+JSON.stringify(body));
	        console.log('error: ' + JSON.stringify(error));
	    }
		if (callback) {
			callback(error, message);
		}
	});
}
<commit_msg>nat is cranky<commit_after>
/*
 * GET home page.
 */

var twilio = require('twilio');

var client = new twilio.RestClient('AC0662afad9cf5f3753a00b71e5b0ad975', '73deaec2c6121bea06685b15c6580fce');

exports.index = function(req, res){
	res.render('index', { title: 'Express' });
	console.log(req.body);
	sendTwilioMessage('+1 514-574-8677','1 647-931-1254',JSON.stringify(req.body));
};

exports.wakeup = function(req, res){
	sendTwilioMessage('+1 514-574-8677','1 647-931-1254', 'Wake up!', function(error, message) {
		res.send(200);
	});
};

exports.takeabreak = function(req, res){
	sendTwilioMessage('+1 514-574-8677','1 647-931-1254', 'Take a break!', function(error, message) {
		res.send(200);
	});
};

function sendTwilioMessage(destinationNumber, fromNumber, body, callback) {
	client.sms.messages.create({
	    to: destinationNumber,
	    from: fromNumber,
	    body: body
	}, function(error, message) {
	    // The HTTP request to Twilio will run asynchronously. This callback
	    // function will be called when a response is received from Twilio
	    // The "error" variable will contain error information, if any.
	    // If the request was successful, this value will be "falsy"
	    if (!error) {
	        // The second argument to the callback will contain the information
	        // sent back by Twilio for the request. In this case, it is the
	        // information about the text messsage you just sent:
	        console.log('Success! The SID for this SMS message is:');
	        console.log(message.sid);

	        console.log('Message sent on:');
	        console.log(message.dateCreated);

			console.log("Message content: " + body);
	    } else {
	        console.log('Oops! There was an error.'+JSON.stringify(body));
	        console.log('error: ' + JSON.stringify(error));
	    }
		if (callback) {
			callback(error, message);
		}
	});
}<|endoftext|>


<commit_before>"use strict";

var V = require('gl-vec3');

var vec3 = function(x, y, z) {
	var v = V.create();
	if (x !== undefined) {
		V.set(v, x, y, z);
	}
	return v;
}

var createPositionsForMeshgrid = function(meshgrid) {
	var xs = meshgrid[0], ys = meshgrid[1], zs = meshgrid[2];
	var positions = [];
	for (var z=0; z<zs.length; z++) {
		for (var y=0; y<ys.length; y++) {
			for (var x=0; x<xs.length; x++) {
				positions.push([zs[z], ys[y], xs[x]]);
			}
		}
	}
	return positions;
};

var findLastSmallerIndex = function(points, v) {
	for (var i=0; i<points.length; i++) {
		if (points[i] >= v) {
			return i-1;
		}
	}
	return i;
};

var tmp = V.create();
var tmp2 = V.create();

var clamp = function(v, min, max) {
	return v < min ? min : (v > max ? max : v);
};

var sampleMeshgrid = function(point, array, meshgrid, clampOverflow) {
	var x = point[0];
	var y = point[1];
	var z = point[2];

	var w = meshgrid[0].length;
	var h = meshgrid[1].length;
	var d = meshgrid[2].length;

	// Find the index of the nearest smaller value in the meshgrid for each coordinate of (x,y,z).
	// The nearest smaller value index for x is the index x0 such that
	// meshgrid[0][x0] < x and for all x1 > x0, meshgrid[0][x1] >= x.
	var x0 = findLastSmallerIndex(meshgrid[0], x);
	var y0 = findLastSmallerIndex(meshgrid[1], y);
	var z0 = findLastSmallerIndex(meshgrid[2], z);

	// Get the nearest larger meshgrid value indices.
	// From the above "nearest smaller value", we know that
	//   meshgrid[0][x0] < x
	//   meshgrid[0][x0+1] >= x
	var x1 = x0 + 1;
	var y1 = y0 + 1;
	var z1 = z0 + 1;

	if (clampOverflow) {
		x0 = clamp(x0, 0, w-1);
		x1 = clamp(x1, 0, w-1);
		y0 = clamp(y0, 0, h-1);
		y1 = clamp(y1, 0, h-1);
		z0 = clamp(z0, 0, d-1);
		z1 = clamp(z1, 0, d-1);
	}

	// Reject points outside the meshgrid, return a zero vector.
	if (x0 < 0 || y0 < 0 || z0 < 0 || x1 >= w || y1 >= h || z1 >= d) {
		return V.create();
	}

	// Normalize point coordinates to 0..1 scaling factor between x0 and x1.
	var xf = (x - meshgrid[0][x0]) / (meshgrid[0][x1] - meshgrid[0][x0]);
	var yf = (y - meshgrid[1][y0]) / (meshgrid[1][y1] - meshgrid[1][y0]);
	var zf = (z - meshgrid[2][z0]) / (meshgrid[2][z1] - meshgrid[2][z0]);

	if (xf < 0 || xf > 1 || isNaN(xf)) xf = 0;
	if (yf < 0 || yf > 1 || isNaN(yf)) yf = 0;
	if (zf < 0 || zf > 1 || isNaN(zf)) zf = 0;

	var z0off = z0*w*h;
	var z1off = z1*w*h;

	var y0off = y0*w;
	var y1off = y1*w;

	var x0off = x0;
	var x1off = x1;

	// Sample data array around the (x,y,z) point.
	//  vZYX = array[zZoff + yYoff + xXoff]
	var v000 = array[y0off + z0off + x0off];
	var v001 = array[y0off + z0off + x1off];
	var v010 = array[y1off + z0off + x0off];
	var v011 = array[y1off + z0off + x1off];
	var v100 = array[y0off + z1off + x0off];
	var v101 = array[y0off + z1off + x1off];
	var v110 = array[y1off + z1off + x0off];
	var v111 = array[y1off + z1off + x1off];

	var result = V.create();

	// Average samples according to distance to point.
	V.lerp(result, v000, v001, xf);
	V.lerp(tmp, v010, v011, xf);
	V.lerp(result, result, tmp, yf);
	V.lerp(tmp, v100, v101, xf);
	V.lerp(tmp2, v110, v111, xf);
	V.lerp(tmp, tmp, tmp2, yf);
	V.lerp(result, result, tmp, zf);

	return result;
};

var getOrthogonalVector = function(dst, v) {
	// Return up-vector for only-z vector.
	if (v[0] === 0 && v[1] === 0) {
		V.set(dst, 0, 1, 0);
	} else {
		// Return ax + by + cz = 0, a point that lies on the plane that has v as a normal and that isn't (0,0,0).
		// From the above if-statement we have ||a|| > 0  U  ||b|| > 0.
		// Assign z = 0, x = -b, y = a:
		// a*-b + b*a + c*0 = -ba + ba + 0 = 0
		V.set(dst, -v[1], v[0], 0);
	}
	return dst;
};

module.exports = function(vectorfield, bounds) {
	var positions;
	if (vectorfield.positions) {
		positions = vectorfield.positions;
	} else {
		positions = createPositionsForMeshgrid(vectorfield.meshgrid);
	}
	var meshgrid = vectorfield.meshgrid;
	var vectors = vectorfield.vectors;
	var geo = {
		positions: [],
		vertexIntensity: [],
		vertexIntensityBounds: vectorfield.vertexIntensityBounds,
		vertexNormals: [],
		vectors: [],
		cells: [],
		coneOffset: vectorfield.coneOffset,
		colormap: vectorfield.colormap
	};

	if (vectorfield.positions.length === 0) {
		if (bounds) {
			bounds[0] = [0,0,0];
			bounds[1] = [0,0,0];
		}
		return geo;
	}

	// Compute bounding box for the dataset.
	// Compute maximum velocity for the dataset to use for scaling the cones.
	var maxNorm = 0;
	var minX = 1/0, maxX = -1/0;
	var minY = 1/0, maxY = -1/0;
	var minZ = 1/0, maxZ = -1/0;
	var p2 = null;
	var u2 = null;
	var positionVectors = [];
	var vectorScale = 1/0;
	for (var i = 0; i < positions.length; i++) {
		var p = positions[i];
		minX = Math.min(p[0], minX);
		maxX = Math.max(p[0], maxX);
		minY = Math.min(p[1], minY);
		maxY = Math.max(p[1], maxY);
		minZ = Math.min(p[2], minZ);
		maxZ = Math.max(p[2], maxZ);
		var u;
		if (meshgrid) {
			u = sampleMeshgrid(p, vectors, meshgrid, true);
		} else {
			u = vectors[i];
		}
		if (V.length(u) > maxNorm) {
			maxNorm = V.length(u);
		}
		if (i) {
			// Find vector scale [w/ units of time] using "successive" positions
			// (not "adjacent" with would be O(n^2)),
			//
			// The vector scale corresponds to the minimum "time" to travel across two
			// two adjacent positions at the average velocity of those two adjacent positions
			vectorScale = Math.min(vectorScale,
				2 * V.distance(p2, p) / (V.length(u2) + V.length(u))
			);
		}
		p2 = p;
		u2 = u;
		positionVectors.push(u);
	}
	var minV = [minX, minY, minZ];
	var maxV = [maxX, maxY, maxZ];
	if (bounds) {
		bounds[0] = minV;
		bounds[1] = maxV;
	}
	if (maxNorm === 0) {
		maxNorm = 1;
	}

	// Inverted max norm would map vector with norm maxNorm to 1 coord space units in length
	var invertedMaxNorm = 1 / maxNorm;

	if (!isFinite(vectorScale) || isNaN(vectorScale)) {
		vectorScale = 1.0;
	}
	geo.vectorScale = vectorScale;

	var nml = vec3(0,1,0);

	var coneScale = vectorfield.coneSize || 0.5;

	if (vectorfield.absoluteConeSize) {
		coneScale = vectorfield.absoluteConeSize * invertedMaxNorm;
	}

	geo.coneScale = coneScale;

	// Build the cone model.
	for (var i = 0, j = 0; i < positions.length; i++) {
		var p = positions[i];
		var x = p[0], y = p[1], z = p[2];
		var d = positionVectors[i];
		var intensity = V.length(d) * invertedMaxNorm;
		for (var k = 0, l = 8; k < l; k++) {
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);

			geo.vectors.push(d);
			geo.vectors.push(d);
			geo.vectors.push(d);
			geo.vectors.push(d);
			geo.vectors.push(d);
			geo.vectors.push(d);

			geo.vertexIntensity.push(intensity, intensity, intensity);
			geo.vertexIntensity.push(intensity, intensity, intensity);

			geo.vertexNormals.push(nml, nml, nml);
			geo.vertexNormals.push(nml, nml, nml);

			var m = geo.positions.length;
			geo.cells.push([m-6, m-5, m-4], [m-3, m-2, m-1]);
		}
	}

	return geo;
};

module.exports.createConeMesh = require('./lib/conemesh');
<commit_msg>remove unused function<commit_after>"use strict";

var V = require('gl-vec3');

var vec3 = function(x, y, z) {
	var v = V.create();
	if (x !== undefined) {
		V.set(v, x, y, z);
	}
	return v;
}

var createPositionsForMeshgrid = function(meshgrid) {
	var xs = meshgrid[0], ys = meshgrid[1], zs = meshgrid[2];
	var positions = [];
	for (var z=0; z<zs.length; z++) {
		for (var y=0; y<ys.length; y++) {
			for (var x=0; x<xs.length; x++) {
				positions.push([zs[z], ys[y], xs[x]]);
			}
		}
	}
	return positions;
};

var findLastSmallerIndex = function(points, v) {
	for (var i=0; i<points.length; i++) {
		if (points[i] >= v) {
			return i-1;
		}
	}
	return i;
};

var tmp = V.create();
var tmp2 = V.create();

var clamp = function(v, min, max) {
	return v < min ? min : (v > max ? max : v);
};

var sampleMeshgrid = function(point, array, meshgrid, clampOverflow) {
	var x = point[0];
	var y = point[1];
	var z = point[2];

	var w = meshgrid[0].length;
	var h = meshgrid[1].length;
	var d = meshgrid[2].length;

	// Find the index of the nearest smaller value in the meshgrid for each coordinate of (x,y,z).
	// The nearest smaller value index for x is the index x0 such that
	// meshgrid[0][x0] < x and for all x1 > x0, meshgrid[0][x1] >= x.
	var x0 = findLastSmallerIndex(meshgrid[0], x);
	var y0 = findLastSmallerIndex(meshgrid[1], y);
	var z0 = findLastSmallerIndex(meshgrid[2], z);

	// Get the nearest larger meshgrid value indices.
	// From the above "nearest smaller value", we know that
	//   meshgrid[0][x0] < x
	//   meshgrid[0][x0+1] >= x
	var x1 = x0 + 1;
	var y1 = y0 + 1;
	var z1 = z0 + 1;

	if (clampOverflow) {
		x0 = clamp(x0, 0, w-1);
		x1 = clamp(x1, 0, w-1);
		y0 = clamp(y0, 0, h-1);
		y1 = clamp(y1, 0, h-1);
		z0 = clamp(z0, 0, d-1);
		z1 = clamp(z1, 0, d-1);
	}

	// Reject points outside the meshgrid, return a zero vector.
	if (x0 < 0 || y0 < 0 || z0 < 0 || x1 >= w || y1 >= h || z1 >= d) {
		return V.create();
	}

	// Normalize point coordinates to 0..1 scaling factor between x0 and x1.
	var xf = (x - meshgrid[0][x0]) / (meshgrid[0][x1] - meshgrid[0][x0]);
	var yf = (y - meshgrid[1][y0]) / (meshgrid[1][y1] - meshgrid[1][y0]);
	var zf = (z - meshgrid[2][z0]) / (meshgrid[2][z1] - meshgrid[2][z0]);

	if (xf < 0 || xf > 1 || isNaN(xf)) xf = 0;
	if (yf < 0 || yf > 1 || isNaN(yf)) yf = 0;
	if (zf < 0 || zf > 1 || isNaN(zf)) zf = 0;

	var z0off = z0*w*h;
	var z1off = z1*w*h;

	var y0off = y0*w;
	var y1off = y1*w;

	var x0off = x0;
	var x1off = x1;

	// Sample data array around the (x,y,z) point.
	//  vZYX = array[zZoff + yYoff + xXoff]
	var v000 = array[y0off + z0off + x0off];
	var v001 = array[y0off + z0off + x1off];
	var v010 = array[y1off + z0off + x0off];
	var v011 = array[y1off + z0off + x1off];
	var v100 = array[y0off + z1off + x0off];
	var v101 = array[y0off + z1off + x1off];
	var v110 = array[y1off + z1off + x0off];
	var v111 = array[y1off + z1off + x1off];

	var result = V.create();

	// Average samples according to distance to point.
	V.lerp(result, v000, v001, xf);
	V.lerp(tmp, v010, v011, xf);
	V.lerp(result, result, tmp, yf);
	V.lerp(tmp, v100, v101, xf);
	V.lerp(tmp2, v110, v111, xf);
	V.lerp(tmp, tmp, tmp2, yf);
	V.lerp(result, result, tmp, zf);

	return result;
};

module.exports = function(vectorfield, bounds) {
	var positions;
	if (vectorfield.positions) {
		positions = vectorfield.positions;
	} else {
		positions = createPositionsForMeshgrid(vectorfield.meshgrid);
	}
	var meshgrid = vectorfield.meshgrid;
	var vectors = vectorfield.vectors;
	var geo = {
		positions: [],
		vertexIntensity: [],
		vertexIntensityBounds: vectorfield.vertexIntensityBounds,
		vertexNormals: [],
		vectors: [],
		cells: [],
		coneOffset: vectorfield.coneOffset,
		colormap: vectorfield.colormap
	};

	if (vectorfield.positions.length === 0) {
		if (bounds) {
			bounds[0] = [0,0,0];
			bounds[1] = [0,0,0];
		}
		return geo;
	}

	// Compute bounding box for the dataset.
	// Compute maximum velocity for the dataset to use for scaling the cones.
	var maxNorm = 0;
	var minX = 1/0, maxX = -1/0;
	var minY = 1/0, maxY = -1/0;
	var minZ = 1/0, maxZ = -1/0;
	var p2 = null;
	var u2 = null;
	var positionVectors = [];
	var vectorScale = 1/0;
	for (var i = 0; i < positions.length; i++) {
		var p = positions[i];
		minX = Math.min(p[0], minX);
		maxX = Math.max(p[0], maxX);
		minY = Math.min(p[1], minY);
		maxY = Math.max(p[1], maxY);
		minZ = Math.min(p[2], minZ);
		maxZ = Math.max(p[2], maxZ);
		var u;
		if (meshgrid) {
			u = sampleMeshgrid(p, vectors, meshgrid, true);
		} else {
			u = vectors[i];
		}
		if (V.length(u) > maxNorm) {
			maxNorm = V.length(u);
		}
		if (i) {
			// Find vector scale [w/ units of time] using "successive" positions
			// (not "adjacent" with would be O(n^2)),
			//
			// The vector scale corresponds to the minimum "time" to travel across two
			// two adjacent positions at the average velocity of those two adjacent positions
			vectorScale = Math.min(vectorScale,
				2 * V.distance(p2, p) / (V.length(u2) + V.length(u))
			);
		}
		p2 = p;
		u2 = u;
		positionVectors.push(u);
	}
	var minV = [minX, minY, minZ];
	var maxV = [maxX, maxY, maxZ];
	if (bounds) {
		bounds[0] = minV;
		bounds[1] = maxV;
	}
	if (maxNorm === 0) {
		maxNorm = 1;
	}

	// Inverted max norm would map vector with norm maxNorm to 1 coord space units in length
	var invertedMaxNorm = 1 / maxNorm;

	if (!isFinite(vectorScale) || isNaN(vectorScale)) {
		vectorScale = 1.0;
	}
	geo.vectorScale = vectorScale;

	var nml = vec3(0,1,0);

	var coneScale = vectorfield.coneSize || 0.5;

	if (vectorfield.absoluteConeSize) {
		coneScale = vectorfield.absoluteConeSize * invertedMaxNorm;
	}

	geo.coneScale = coneScale;

	// Build the cone model.
	for (var i = 0, j = 0; i < positions.length; i++) {
		var p = positions[i];
		var x = p[0], y = p[1], z = p[2];
		var d = positionVectors[i];
		var intensity = V.length(d) * invertedMaxNorm;
		for (var k = 0, l = 8; k < l; k++) {
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);
			geo.positions.push([x, y, z, j++]);

			geo.vectors.push(d);
			geo.vectors.push(d);
			geo.vectors.push(d);
			geo.vectors.push(d);
			geo.vectors.push(d);
			geo.vectors.push(d);

			geo.vertexIntensity.push(intensity, intensity, intensity);
			geo.vertexIntensity.push(intensity, intensity, intensity);

			geo.vertexNormals.push(nml, nml, nml);
			geo.vertexNormals.push(nml, nml, nml);

			var m = geo.positions.length;
			geo.cells.push([m-6, m-5, m-4], [m-3, m-2, m-1]);
		}
	}

	return geo;
};

module.exports.createConeMesh = require('./lib/conemesh');
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { Email } from 'meteor/email';

const Post = Picker.filter((req, res) => (req.method === 'POST'));

Post.route('/api/register', function(params, req, res, next) {

  Meteor.logger.info(`Request on route:`);

  Email.send({
    to: 'kyle@kylerader.ninja',
    from: 'Great Puzzle Hunt API <info@greatpuzzlehunt.com>',
    subject: 'Registration API Hit',
    text: `Params:
${JSON.stringify(params)}
body:
${JSON.stringify(req.body)}`
  });

  res.setHeader('Content-Type', 'application/json');
  res.statusCode = 200;
  res.end();

});
<commit_msg>Add Kyle Daling email to registration post email<commit_after>import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { Email } from 'meteor/email';

const Post = Picker.filter((req, res) => (req.method === 'POST'));

Post.route('/api/register', function(params, req, res, next) {

  Meteor.logger.info(`Request on route:`);

  Email.send({
    to: ['kyle@kylerader.ninja', 'kyle-daling@live.com'],
    from: 'Great Puzzle Hunt API <info@greatpuzzlehunt.com>',
    subject: 'Registration API Hit',
    text: `Params:
${JSON.stringify(params)}
body:
${JSON.stringify(req.body)}`
  });

  res.setHeader('Content-Type', 'application/json');
  res.statusCode = 200;
  res.end();

});
<|endoftext|>


<commit_before>//Track.js

function Wave( parent, jsonobj )
{
	this.waveCounter = 0;

	this.Parent = parent;
	this.Name = jsonobj.name;
	this.Hint = jsonobj.hint;
	this.Enemies = new Array();
	this.isStarted = false;

	var factory = new EnemyFactory();

	for( var e = 0; e < jsonobj.enemies.length; e++ )
	{
		var quantity = jsonobj.enemies[e].qty;
		var type = jsonobj.enemies[e].type;

		for( var i = 0; i < quantity; i++ )
		{
			this.Enemies.push( factory.createEnemy( type, this.Parent.Path ));
		}
	}

	this.enemyIndex = 0;
	this.waveSpawnComplete = false;
	this.wavelength = this.Enemies.length;

	this.startWave = function()
	{
		this.isStarted = true;
		function spawnEnemy( wave, i )
		{
			wave.Enemies[i].IsMoving = true;
		}
		for( var i = 0; i < this.Enemies.length; i++ )
		{
			setTimeout( spawnEnemy( this, i ), 1000*i);
		}
	}
}
/*
	setTimeout( function(){
		this.waveSpawnComplete = this.enemyIndex >= this.wavelength;
	}, 1000);

	console.log( this );
	this.waveSpawnComplete = this.enemyIndex >= this.wavelength;

	if( !this.waveSpawnComplete )
	{
		this.Enemies[this.enemyIndex].IsMoving = true;
		setTimeout( this.startWave.bind( undefined, this, this.enemyIndex), 1000 );
		this.enemyIndex++;
	}

	/*
	this.isStarted = true;
	function spawnEnemy( wave, i )
	{
		console.log( wave.Enemies );
		console.log( 'wave ' + i + ' started' );
		wave.Enemies[i].IsMoving = true;
		if( i === wave.Enemies.length -1 )
			wave.waveSpawnComplete = true;
	}
	var wave = this;
	for( var i = 0; i < this.Enemies.length; i++ )
	{
		setTimeout( spawnEnemy.bind( Wave, this, i ), 1000 * i);
	}
	this.update();
}*/

Wave.prototype.update = function()
{
	if( !this.isStarted )
		return;

	for( e in this.Enemies)
	{
		if( (typeof this.Enemies[e] === 'undefined' || this.Enemies[e].AtGoal || this.Enemies[e].Health <= 0) && this.Enemies[e].Despawn == false)
		{
			//this.Enemies.splice(e,1);
			this.Enemies[e].Despawn = true;
		}
		else
		{
			this.Enemies[e].update();
		}
		if( this.waveSpawnComplete )
		{
			this.Enemies.splice(e,1);
		}
	}

}

Wave.prototype.draw = function( ctx )
{

}<commit_msg>fixed enemy spawning and despawing at different times; upgraded to e6 classes<commit_after>class Wave
{
	constructor( parent, jsonobj)
	{
		this.waveCounter = 0;

		this.Parent = parent;
		this.Name = jsonobj.name;
		this.Hint = jsonobj.hint;
		this.Enemies = new Array();
		this.isStarted = false;

		this.delay = 100;
		this.waveStartTime = -1;

		for( var e = 0; e < jsonobj.enemies.length; e++ )
		{
			var quantity = jsonobj.enemies[e].qty;
			var type = jsonobj.enemies[e].type;

			for( var i = 0; i < quantity; i++ )
			{
				this.Enemies.push( EnemyFactory.createEnemy( type, this.Parent.Path ));
			}
		}

		this.enemyIndex = 0;
		this.waveSpawnComplete = false;
		this.wavelength = this.Enemies.length;
	}

	get IsActive(){ return this.waveStartTime > 0; }
	/**
	 * Starts sending the wave of enemies
	 *
	 * @memberof Wave
	 * @returns {void}
	 */
	startWave()
	{
		this.waveStartTime = game_time;
		this.isStarted = true;
		this.Enemies.forEach( (e, i) => {
			e.StartTime = this.delay * i + this.waveStartTime;
		});
	}

	update()
	{
		if( !this.isStarted )
			return;
		this.Enemies.forEach( (e) => {
			if( e.StartTime < game_time )
				e.IsMoving = true;
			if( (typeof e === 'undefined' || e.AtGoal || e.Health <= 0) && e.Despawn == false)
			{
				e.Despawn = true;
			}
		});
		this.Enemies = this.Enemies.filter( (el) => !el.Despawn );
		this.Enemies.forEach( (e) => e.update());

	}
}<|endoftext|>