<commit_before>/**
 * Created by petersquicciarini on 6/4/17.
 */

const winston = require('winston');

if (!process.env.slackClientID || !process.env.slackClientSecret ||
  !process.env.ticketSystemUrl || !process.env.PORT || !process.env.mongoUri ||
  !process.env.ticketSystemAPIKey || !process.env.dattoAPIKey) {
  winston.log('error', 'Please see README for required env vars.');
  process.exit(1);
}

const Botkit = require('./lib/botkit');
const express = require('express');
const bodyParser = require('body-parser');
const mongoStorage = require('botkit-storage-mongo')({mongoUri: process.env.mongoUri});
const url = require('url');
const freshservice = require('./lib/freshservice');
const request = require('request');
const events = require('events');
const eventEmitter = new events.EventEmitter();

const connectionInfo = {
  slackClientID: process.env.slackClientID,
  slackClientSecret: process.env.slackClientSecret,
  ticketSystemUrl: process.env.ticketSystemUrl,
  ticketSystemAPIKey: process.env.ticketSystemAPIKey,
};
const controller = Botkit.slackbot({
  storage: mongoStorage,
  debug: false,
}).configureSlackApp({
  clientId: connectionInfo.slackClientID,
  clientSecret: connectionInfo.slackClientSecret,
  scopes: ['bot', 'channels:read', 'users:read'],
});

// setup webserver

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/public'));
app.listen(process.env.PORT, () => {
  winston.log(`** Starting webserver on port ${process.env.PORT}`);
});

controller.createWebhookEndpoints(app);
controller.createHomepageEndpoint(app);
controller.createOauthEndpoints(app, (err, req, res) => {
  if (err) {
    res.status(500).send(`ERROR: ${err}`);
  } else {
    res.send('Success!');
  }
});

app.post('/datto', (req, res) => {
  if (req.body && req.body.authentication && req.body.authentication === process.env.dattoAPIKey) {
    eventEmitter.emit('dattoAlert', req.body && req.body.dattoalert);
  }
  res.send('Thanks!');
});

// just a simple way to make sure we don't
// connect to the RTM twice for the same team
const activeBots = {};
function trackBot(bot) {
  activeBots[bot.config.token] = bot;
}

controller.on('create_bot', (bot) => {
  if (activeBots[bot.config.token]) {
    // already online! do nothing.
  } else {
    bot.startRTM((err) => {
      if (!err) {
        trackBot(bot);
      }
    });
  }
});

controller.storage.teams.all((err, teams) => {
  if (err) {
    throw new Error(err);
  }
  // connect all teams with bots up to slack!
  Object.keys(teams).forEach((t) => {
    if (teams[t].bot) {
      controller.spawn(teams[t]).startRTM((startErr, bot) => {
        if (startErr) {
          winston.log('error', 'Could not connect to Slack RTM.');
        } else {
          trackBot(bot);
        }
      });
    }
  });
});

controller.on('rtm_open', (bot) => {
  winston.log('info', '** The RTM api just connected!');

  eventEmitter.on('dattoAlert', (alert) => {
    bot.api.channels.list({}, (err, response) => {
      if (response.hasOwnProperty('channels') && response.ok) {
        const alertsChannel = response.channels.find(ch => ch.name === 'datto_alerts');
          // Handle listening for Zapier webhook'd Datto event here and replying
            const msgTemplate = {
              username: 'dorian',
              icon_emoji: ':panda_face:',
              channel: alertsChannel.id,
              text: 'Datto Alert Received', // text from webhook will go here
              attachments: [
                {
                  fallback: alert,
                  callback_id: 'alertResponse',
                  title: alert,
                  color: 'danger',
                  actions: [
                    {
                      name: 'reset',
                      text: 'Reset Alert',
                      value: 'reset',
                      type: 'button'
                    },
                    {
                      name: 'ticket',
                      text: 'Create ticket',
                      value: 'ticket',
                      type: 'button'
                    }
                  ],
                },
              ],
            };
            bot.say(msgTemplate);
      }
    });
  });
});

controller.on('rtm_close', (bot) => {
  winston.log('warn', '** The RTM api just closed');
  bot.startRTM((err) => {
    if (!err) {
      trackBot(bot);
    }
  });
});

controller.on('interactive_message_callback', function(bot, message) {
  bot.api.users.info({user: message.user}, function(err, info){
    let buttonPresser = null;
    if (err) {
      winston.log('error: ** could not get user name of button presser');
    } else {
      buttonPresser = info.user.name;
    }
    if (message.actions[0].value === 'reset') {
      bot.replyInteractive(message, {
        attachments: [
          {
            fallback: 'Alert reset',
            text: message.original_message.attachments[0].title,
            color: 'good',
            fields: [{
              title: `Alert has been reset${buttonPresser ? ' by ' + buttonPresser : '!'}`
            }],
          }
        ]
      });
    } else if (message.actions[0].value === 'ticket') {
      const ticketObject = {
        helpdesk_ticket: {
          description: message.original_message.attachments[0].title,
          subject: message.original_message.attachments[0].title,
          email: 'noreply@dattobackup.com',
          priority: 1,
          status: 2,
          source: 2,
          ticket_type: 'Incident',
        }
      };
      const fs_host = process.env.ticketSystemUrl;
      const apiKey = process.env.ticketSystemAPIKey;
      request(freshservice(fs_host, apiKey, 'POST', 'helpdesk/tickets.json', ticketObject), (err, res, body) => {
        winston.log('info: ** Sending new ticket request to FreshService');
        if (err) {
          winston.log('error: ** Ticket creation failed:', err);
        }
        if (typeof body === 'object' && body.status) {
          bot.replyInteractive(message, {
            attachments: [
              {
                fallback: 'Ticket created',
                text: message.original_message.attachments[0].title,
                color: 'good',
                fields: [{
                  title: `Alert made into a ticket${buttonPresser ? ' by ' + buttonPresser : '!'}`,
                  value: 'https://' + fs_host + '/helpdesk/tickets/' + body.item.helpdesk_ticket.display_id
                }],
              }
            ]
          });
        }
      });
    }
  });
});<commit_msg>Added fields<commit_after>/**
 * Created by petersquicciarini on 6/4/17.
 */

const winston = require('winston');

if (!process.env.slackClientID || !process.env.slackClientSecret ||
  !process.env.ticketSystemUrl || !process.env.PORT || !process.env.mongoUri ||
  !process.env.ticketSystemAPIKey || !process.env.dattoAPIKey) {
  winston.log('error', 'Please see README for required env vars.');
  process.exit(1);
}

const Botkit = require('./lib/botkit');
const express = require('express');
const bodyParser = require('body-parser');
const mongoStorage = require('botkit-storage-mongo')({mongoUri: process.env.mongoUri});
const url = require('url');
const freshservice = require('./lib/freshservice');
const request = require('request');
const events = require('events');
const eventEmitter = new events.EventEmitter();

const connectionInfo = {
  slackClientID: process.env.slackClientID,
  slackClientSecret: process.env.slackClientSecret,
  ticketSystemUrl: process.env.ticketSystemUrl,
  ticketSystemAPIKey: process.env.ticketSystemAPIKey,
};
const controller = Botkit.slackbot({
  storage: mongoStorage,
  debug: false,
}).configureSlackApp({
  clientId: connectionInfo.slackClientID,
  clientSecret: connectionInfo.slackClientSecret,
  scopes: ['bot', 'channels:read', 'users:read'],
});

// setup webserver

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/public'));
app.listen(process.env.PORT, () => {
  winston.log(`** Starting webserver on port ${process.env.PORT}`);
});

controller.createWebhookEndpoints(app);
controller.createHomepageEndpoint(app);
controller.createOauthEndpoints(app, (err, req, res) => {
  if (err) {
    res.status(500).send(`ERROR: ${err}`);
  } else {
    res.send('Success!');
  }
});

app.post('/datto', (req, res) => {
  if (req.body && req.body.authentication && req.body.authentication === process.env.dattoAPIKey) {
    eventEmitter.emit('dattoAlert', { device: req.body.device, reason: req.body.reason, agent: req.body.agent });
  }
  res.send('Thanks!');
});

// just a simple way to make sure we don't
// connect to the RTM twice for the same team
const activeBots = {};
function trackBot(bot) {
  activeBots[bot.config.token] = bot;
}

controller.on('create_bot', (bot) => {
  if (activeBots[bot.config.token]) {
    // already online! do nothing.
  } else {
    bot.startRTM((err) => {
      if (!err) {
        trackBot(bot);
      }
    });
  }
});

controller.storage.teams.all((err, teams) => {
  if (err) {
    throw new Error(err);
  }
  // connect all teams with bots up to slack!
  Object.keys(teams).forEach((t) => {
    if (teams[t].bot) {
      controller.spawn(teams[t]).startRTM((startErr, bot) => {
        if (startErr) {
          winston.log('error', 'Could not connect to Slack RTM.');
        } else {
          trackBot(bot);
        }
      });
    }
  });
});

controller.on('rtm_open', (bot) => {
  winston.log('info', '** The RTM api just connected!');

  eventEmitter.on('dattoAlert', ({ device, reason, agent }) => {
    bot.api.channels.list({}, (err, response) => {
      if (response.hasOwnProperty('channels') && response.ok) {
        const alertsChannel = response.channels.find(ch => ch.name === 'datto_alerts');
          // Handle listening for Zapier webhook'd Datto event here and replying
            const msgTemplate = {
              username: 'dorian',
              icon_emoji: ':panda_face:',
              channel: alertsChannel.id,
              text: 'Datto Alert Received', // text from webhook will go here
              attachments: [
                {
                  fallback: `${device} :: ${agent} :: ${reason}`,
                  callback_id: 'alertResponse',
                  title: `Datto Alert for ${device}`,
                  fields: [
                    {
                      title: 'Agent',
                      value: agent,
                      short: true,
                    },
                    {
                      title: 'Reason',
                      value: reason,
                      short: false,
                    },
                  ],
                  color: 'danger',
                  actions: [
                    {
                      name: 'reset',
                      text: 'Reset Alert',
                      value: 'reset',
                      type: 'button'
                    },
                    {
                      name: 'ticket',
                      text: 'Create ticket',
                      value: 'ticket',
                      type: 'button'
                    }
                  ],
                },
              ],
            };
            bot.say(msgTemplate);
      }
    });
  });
});

controller.on('rtm_close', (bot) => {
  winston.log('warn', '** The RTM api just closed');
  bot.startRTM((err) => {
    if (!err) {
      trackBot(bot);
    }
  });
});

controller.on('interactive_message_callback', function(bot, message) {
  bot.api.users.info({user: message.user}, function(err, info){
    let buttonPresser = null;
    if (err) {
      winston.log('error: ** could not get user name of button presser');
    } else {
      buttonPresser = info.user.name;
    }
    if (message.actions[0].value === 'reset') {
      bot.replyInteractive(message, {
        attachments: [
          {
            fallback: 'Alert reset',
            text: message.original_message.attachments[0].title,
            color: 'good',
            fields: [
              {
                title: `Alert has been reset${buttonPresser ? ' by ' + buttonPresser : '!'}`
              }
            ],
          }
        ]
      });
    } else if (message.actions[0].value === 'ticket') {
      const ticketObject = {
        helpdesk_ticket: {
          description: message.original_message.attachments[0].title,
          subject: message.original_message.attachments[0].title,
          email: 'noreply@dattobackup.com',
          priority: 1,
          status: 2,
          source: 2,
          ticket_type: 'Incident',
        }
      };
      const fs_host = process.env.ticketSystemUrl;
      const apiKey = process.env.ticketSystemAPIKey;
      request(freshservice(fs_host, apiKey, 'POST', 'helpdesk/tickets.json', ticketObject), (err, res, body) => {
        winston.log('info: ** Sending new ticket request to FreshService');
        if (err) {
          winston.log('error: ** Ticket creation failed:', err);
        }
        if (typeof body === 'object' && body.status) {
          bot.replyInteractive(message, {
            attachments: [
              {
                fallback: 'Ticket created',
                text: message.original_message.attachments[0].title,
                color: 'good',
                fields: [
                  {
                    title: `Alert made into a ticket${buttonPresser ? ' by ' + buttonPresser : '!'}`,
                    value: 'https://' + fs_host + '/helpdesk/tickets/' + body.item.helpdesk_ticket.display_id
                  }
                ],
              }
            ]
          });
        }
      });
    }
  });
});<|endoftext|>


<commit_before>const fs = require('fs-extra');
const fileExtension = require('file-extension');

// constractor
function Upload(data){
	return function (req, res, next) {
		moveFile(req.files, data,function(err, files){
			if (err) return res.send(err);
			next();
		});
	}
}
// renaming the file
function filename(name, options){
	if (options.filename == "random") {
		return Math.random().toString(36).substring(7) + '.' + fileExtension(name);
	}else if (options.filename == "same") {
		return name.replace(fileExtension(name), '') + fileExtension(name);
	}else if (options.filename == "plus_date") {
		return name.replace('.' + fileExtension(name), '') + '_' + new Date().toString().replace(/ /g, '_') + '.' + fileExtension(name);
	} else {
		return Math.random().toString(36).substring(7) + '.' + fileExtension(name);
	}
}
// clean the file object from unwanted attributes
function restructure(file){
	return {
		path: file.path,
		type: file.type,
		size: file.size,
		name: file.name
	};
}
// moving the files
function moveFile(files, options, callback){
	let l = 1;
	// loop into the files array and move
	// the file to the the path that used want
	options.filefields.forEach(function(field) {
		if (typeof files[field] == 'undefined') {
			// check if the field is medtory or not
			if (options.used == "maybe") {
				next()
			} else if (options.used == "must") {
				return callback({code: "ExternalError", messege: "Cannot read property '" + field + "' of undefined"}, null)
			}
		}else {
		    var newPath = options.uploadDir + filename(files[field].name, options);
			fs.move(files[field].path,  newPath , function (err) {
				if (err) return callback({code: "InternalError", messege: "Error happen while uploading."}, null)
				files[field].path = newPath;
				files[field] = restructure(files[field]);
				if (options.filefields.length == l) {
				 	return callback(null, files);
				}else{
					l++;
				}
			});
		}
	});

}
module.exports = Upload;<commit_msg>remove clean file<commit_after>"use strict";

const fs = require('fs-extra');
const fileExtension = require('file-extension');

// constractor
function Upload(data){
	return function (req, res, next) {
		moveFile(req.files, data,function(err, files){
			if (err) return res.send(err);
			next();
		});
	}
}
// renaming the file
function filename(name, options){
	if (options.filename == "random") {
		return Math.random().toString(36).substring(7) + '.' + fileExtension(name);
	}else if (options.filename == "same") {
		return name.replace(fileExtension(name), '') + fileExtension(name);
	}else if (options.filename == "plus_date") {
		return name.replace('.' + fileExtension(name), '') + '_' + new Date().toString().replace(/ /g, '_') + '.' + fileExtension(name);
	} else {
		return Math.random().toString(36).substring(7) + '.' + fileExtension(name);
	}
}
// clean the file object from unwanted attributes
function restructure(file){
	return {
		path: file.path,
		type: file.type,
		size: file.size,
		name: file.name
	};
}
// moving the files
function moveFile(files, options, callback){
	let l = 1;
	// loop into the files array and move
	// the file to the the path that used want
	options.filefields.forEach(function(field) {
		if (typeof files[field] == 'undefined') {
			// check if the field is medtory or not
			if (options.used == "maybe") {
				next()
			} else if (options.used == "must") {
				return callback({code: "ExternalError", messege: "Cannot read property '" + field + "' of undefined"}, null)
			}
		}else {
		    var newPath = options.uploadDir + filename(files[field].name, options);
			fs.move(files[field].path,  newPath , function (err) {
				if (err) return callback({code: "InternalError", messege: "Error happen while uploading."}, null)
				files[field].path = newPath;
				files[field] = restructure(files[field]);
				if (options.filefields.length == l) {
				 	return callback(null, files);
				}else{
					l++;
				}
			});
		}
	});

}
module.exports = Upload;<|endoftext|>


<commit_before>var JSONL   = require('json-literal'),
    debug   = require('debug')('mongodb-log'),
    regret  = require('./patterns');
var OPS       = 'command delete getmore query remove update'.split(' '),
    QUERY_OPS = '$exists $gt $gte $in $lt $lte $nin $regex'.split(' ');

function getTimestampFormat(timestamp) {
  var format, l = timestamp.length;
  switch (l) {
  case 19:
    format = 'ctime-pre2.4';
    break;
  case 23:
    format = 'ctime';
    break;
  case 24:
    format = 'iso8601-utc';
    break;
  case 28:
    format = 'iso8601-local';
    break;
  }
  return format;
}
function errorMessage(msg) {
  var message = msg;
  if (msg.indexOf('mongod instance already running?') > -1) {
    message = 'already running';
  }
  return new Error(message);
}
function getEvent(msg) {
  if (msg.indexOf('exception') > -1) {
    return {
      name: 'error',
      data: errorMessage(msg)
    };
  }
  if (msg.indexOf('waiting for connections') > -1) {
    return {
      name: 'ready',
      data: { port: parseInt(/(\d+)/.exec(msg)[1], 10) }
    };
  }
  return null;
}
function Entry(data, opts) {
  opts = opts || {};
  data = data || {};
  this.timestamp = data.timestamp || new Date();
  this.timestamp_format = getTimestampFormat(this.timestamp);
  this.line = data.line;
  this.message = data.message || '';
  this.tokens = data.line ? data.line.split(' ') : [];
  this.thread = data.thread;
  this.event = getEvent(data.message);
  var match;
  // connection accepted format
  if (match = regret('connectionAccepted', data.message)) {
    this.conn = 'conn' + match.connNum;
  } else if (data.thread && data.thread.substring(0, 4) === 'conn') {
    this.conn = data.thread;
  }
  if (!data.line || !data.thread) {
    // Message from shell that is not a log entry
    console.error(data.line);
    return;
  }
  parseOperation(this);
}
function parseNamespaceFields(thisObj) {
  thisObj.namespace = thisObj.tokens[thisObj.timestamp.split(' ').length + 2];
  var namespaceTokens = thisObj.namespace.split('.');
  thisObj.database = namespaceTokens[0];
  thisObj.collection = namespaceTokens.slice(1).join('.');
  var lastToken = namespaceTokens.slice(-1)[0];
  if (lastToken[0] === '$')
    thisObj.index = lastToken.substring(1);
}
function parseOperation(thisObj) {
  // the operation type comes after the thread
  var opTypeIndex = thisObj.tokens.indexOf('[' + thisObj.thread + ']') + 1;

  if (OPS.indexOf(thisObj.tokens[opTypeIndex]) > -1) {
    var lastToken = thisObj.tokens.slice(-1)[0];
    thisObj.duration = parseInt(lastToken.substring(0, lastToken.length - 2));
    thisObj.operation = thisObj.tokens[2];

    parseNamespaceFields(thisObj);
    var currentTokenIndex = parseQuery(thisObj, opTypeIndex + 2);
    parseOperationStats(thisObj, currentTokenIndex);
  }
}
function parseOperationStats(thisObj, currentTokenIndex) {
  var token;
  for (; currentTokenIndex < thisObj.tokens.length; currentTokenIndex++) {
    token = thisObj.tokens[currentTokenIndex];
    parseOperationStat(thisObj, token);
  }
}
function parseOperationStat(thisObj, token) {
  var colonIndex = token.search(':');
  var key, intValue;
  // parsing operation stat fields
  if (colonIndex >= 1) {
    key = token.substring(0, colonIndex);
    intValue = parseInt(token.substring(colonIndex + 1));
    if (!isNaN(intValue))
      thisObj[key] = intValue;
  }
}
function parseQuery(thisObj, currentTokenIndex) {
  if (thisObj.tokens.indexOf('query:') === -1)
    return currentTokenIndex;
  currentTokenIndex++;
  var leftParenCount = 0, rightParenCount = 0;
  var queryStartIndex = currentTokenIndex;
  var token;

  // when the number of left and right parentheses are equal, we've parsed the
  // query object string
  do {
    token = thisObj.tokens[currentTokenIndex];
    if (token === undefined)
      return currentTokenIndex;
    else if (token === '{')
      leftParenCount++;
    else if (token === '}' || token === '},')
      rightParenCount++;

    currentTokenIndex++;
  } while (leftParenCount !== rightParenCount);

  var objectStr = thisObj.tokens.slice(
    queryStartIndex, currentTokenIndex
  ).join(' ');
  var object = JSONL.parse(objectStr);

  if (object['$comment'])
    thisObj.comment = object['$comment'];

  if (object.orderby)
    thisObj.sortShape = object.orderby;

  if (object.query)
    thisObj.query = object.query;
  else if (object['$query'])
    thisObj.query = object['$query'];
  else
    thisObj.query = object;

  parseQueryShape(thisObj);

  return currentTokenIndex;
}
// convert objects to flat string
// don't want the newlines and extra spaces from JSON.stringify
// e.g. {"mongoscope_feature":"get instance collections"} ->
//      "{ mongoscope_feature: \"get instance collections\" }"
function JSONFlatStringify(obj) {
  return JSON.stringify(obj, null, ' ').split(/\s+/).join(' ');
}
function parseQueryShape(thisObj) {
  thisObj.queryShape = parseQueryShapeObject(thisObj.query);
  setQueryPattern(thisObj);
}
function parseQueryShapeObject(obj) {
  objCopy = JSON.parse(JSON.stringify(obj));

  var value;
  for (var key in objCopy) {
    value = objCopy[key];
    if (QUERY_OPS.indexOf(key) > -1)
      return 1;
    if (Array.isArray(value))
      objCopy[key] = parseQueryShapeArray(value);
    else if (typeof value === 'objCopyect' && !(value instanceof RegExp))
      objCopy[key] = parseQueryShapeObjCopyect(value);
    else
      objCopy[key] = 1;
  }
  return objCopy;
}
function parseQueryShapeArray(ary) {
  var ele;
  for (var i = 0; i < ary.length; i++) {
    ele = ary[i];
    if (Array.isArray(ele))
      parseQueryShapeArray(ele);
    else if (typeof ele === 'object')
      parseQueryShapeObject(ele);
  }
  return ary.sort();
}
function setQueryPattern(thisObj) {
  thisObj.queryPattern = thisObj.namespace + ' ' +
    JSONFlatStringify(thisObj.queryShape);
}
module.exports.parse = function (lines, opts) {
  opts = opts || {};
  if (!Array.isArray(lines)) {
    lines = [lines];
  }
  return lines.filter(function (line) {
    return line && line.length > 0;
  }).map(function (line) {
    var match = regret(/^mongodb.log/, line, opts);
    if (match === null)
      return { line: line };
    return new Entry(match);
  });
};<commit_msg>switch console.err to debug for less chattiness<commit_after>var JSONL   = require('json-literal'),
    debug   = require('debug')('mongodb-log'),
    regret  = require('./patterns');
var OPS       = 'command delete getmore query remove update'.split(' '),
    QUERY_OPS = '$exists $gt $gte $in $lt $lte $nin $regex'.split(' ');

function getTimestampFormat(timestamp) {
  var format, l = timestamp.length;
  switch (l) {
  case 19:
    format = 'ctime-pre2.4';
    break;
  case 23:
    format = 'ctime';
    break;
  case 24:
    format = 'iso8601-utc';
    break;
  case 28:
    format = 'iso8601-local';
    break;
  }
  return format;
}
function errorMessage(msg) {
  var message = msg;
  if (msg.indexOf('mongod instance already running?') > -1) {
    message = 'already running';
  }
  return new Error(message);
}
function getEvent(msg) {
  if (msg.indexOf('exception') > -1) {
    return {
      name: 'error',
      data: errorMessage(msg)
    };
  }
  if (msg.indexOf('waiting for connections') > -1) {
    return {
      name: 'ready',
      data: { port: parseInt(/(\d+)/.exec(msg)[1], 10) }
    };
  }
  return null;
}
function Entry(data, opts) {
  opts = opts || {};
  data = data || {};
  this.timestamp = data.timestamp || new Date();
  this.timestamp_format = getTimestampFormat(this.timestamp);
  this.line = data.line;
  this.message = data.message || '';
  this.tokens = data.line ? data.line.split(' ') : [];
  this.thread = data.thread;
  this.event = getEvent(data.message);
  var match;
  // connection accepted format
  if (match = regret('connectionAccepted', data.message)) {
    this.conn = 'conn' + match.connNum;
  } else if (data.thread && data.thread.substring(0, 4) === 'conn') {
    this.conn = data.thread;
  }
  if (!data.line || !data.thread) {
    // Message from shell that is not a log entry
    debug('unknown line structure', data);
    return;
  }
  parseOperation(this);
}
function parseNamespaceFields(thisObj) {
  thisObj.namespace = thisObj.tokens[thisObj.timestamp.split(' ').length + 2];
  var namespaceTokens = thisObj.namespace.split('.');
  thisObj.database = namespaceTokens[0];
  thisObj.collection = namespaceTokens.slice(1).join('.');
  var lastToken = namespaceTokens.slice(-1)[0];
  if (lastToken[0] === '$')
    thisObj.index = lastToken.substring(1);
}
function parseOperation(thisObj) {
  // the operation type comes after the thread
  var opTypeIndex = thisObj.tokens.indexOf('[' + thisObj.thread + ']') + 1;

  if (OPS.indexOf(thisObj.tokens[opTypeIndex]) > -1) {
    var lastToken = thisObj.tokens.slice(-1)[0];
    thisObj.duration = parseInt(lastToken.substring(0, lastToken.length - 2));
    thisObj.operation = thisObj.tokens[2];

    parseNamespaceFields(thisObj);
    var currentTokenIndex = parseQuery(thisObj, opTypeIndex + 2);
    parseOperationStats(thisObj, currentTokenIndex);
  }
}
function parseOperationStats(thisObj, currentTokenIndex) {
  var token;
  for (; currentTokenIndex < thisObj.tokens.length; currentTokenIndex++) {
    token = thisObj.tokens[currentTokenIndex];
    parseOperationStat(thisObj, token);
  }
}
function parseOperationStat(thisObj, token) {
  var colonIndex = token.search(':');
  var key, intValue;
  // parsing operation stat fields
  if (colonIndex >= 1) {
    key = token.substring(0, colonIndex);
    intValue = parseInt(token.substring(colonIndex + 1));
    if (!isNaN(intValue))
      thisObj[key] = intValue;
  }
}
function parseQuery(thisObj, currentTokenIndex) {
  if (thisObj.tokens.indexOf('query:') === -1)
    return currentTokenIndex;
  currentTokenIndex++;
  var leftParenCount = 0, rightParenCount = 0;
  var queryStartIndex = currentTokenIndex;
  var token;

  // when the number of left and right parentheses are equal, we've parsed the
  // query object string
  do {
    token = thisObj.tokens[currentTokenIndex];
    if (token === undefined)
      return currentTokenIndex;
    else if (token === '{')
      leftParenCount++;
    else if (token === '}' || token === '},')
      rightParenCount++;

    currentTokenIndex++;
  } while (leftParenCount !== rightParenCount);

  var objectStr = thisObj.tokens.slice(
    queryStartIndex, currentTokenIndex
  ).join(' ');
  var object = JSONL.parse(objectStr);

  if (object['$comment'])
    thisObj.comment = object['$comment'];

  if (object.orderby)
    thisObj.sortShape = object.orderby;

  if (object.query)
    thisObj.query = object.query;
  else if (object['$query'])
    thisObj.query = object['$query'];
  else
    thisObj.query = object;

  parseQueryShape(thisObj);

  return currentTokenIndex;
}
// convert objects to flat string
// don't want the newlines and extra spaces from JSON.stringify
// e.g. {"mongoscope_feature":"get instance collections"} ->
//      "{ mongoscope_feature: \"get instance collections\" }"
function JSONFlatStringify(obj) {
  return JSON.stringify(obj, null, ' ').split(/\s+/).join(' ');
}
function parseQueryShape(thisObj) {
  thisObj.queryShape = parseQueryShapeObject(thisObj.query);
  setQueryPattern(thisObj);
}
function parseQueryShapeObject(obj) {
  objCopy = JSON.parse(JSON.stringify(obj));

  var value;
  for (var key in objCopy) {
    value = objCopy[key];
    if (QUERY_OPS.indexOf(key) > -1)
      return 1;
    if (Array.isArray(value))
      objCopy[key] = parseQueryShapeArray(value);
    else if (typeof value === 'objCopyect' && !(value instanceof RegExp))
      objCopy[key] = parseQueryShapeObjCopyect(value);
    else
      objCopy[key] = 1;
  }
  return objCopy;
}
function parseQueryShapeArray(ary) {
  var ele;
  for (var i = 0; i < ary.length; i++) {
    ele = ary[i];
    if (Array.isArray(ele))
      parseQueryShapeArray(ele);
    else if (typeof ele === 'object')
      parseQueryShapeObject(ele);
  }
  return ary.sort();
}
function setQueryPattern(thisObj) {
  thisObj.queryPattern = thisObj.namespace + ' ' +
    JSONFlatStringify(thisObj.queryShape);
}
module.exports.parse = function (lines, opts) {
  opts = opts || {};
  if (!Array.isArray(lines)) {
    lines = [lines];
  }
  return lines.filter(function (line) {
    return line && line.length > 0;
  }).map(function (line) {
    var match = regret(/^mongodb.log/, line, opts);
    if (match === null)
      return { line: line };
    return new Entry(match);
  });
};
<|endoftext|>


<commit_before>module.exports = {
	extends: 'eslint:recommended',
	env: {
		es6: true,
		node: true,
	},

	plugins: [
		'import',
	],

	rules: {
		'array-bracket-spacing': [ 2, 'always' ],
		'comma-dangle': [ 2, {
			arrays: 'always-multiline',
			objects: 'always-multiline',
			imports: 'always-multiline',
			exports: 'always-multiline',
			functions: 'always-multiline',
		} ],
		'comma-spacing': [ 2, { after: true } ],
		'computed-property-spacing': [ 2, 'never' ],
		'eol-last': [ 2, 'always' ],
		'dot-notation': [ 2 ],
		'indent': [ 2, 'tab' ],
		'key-spacing': [ 2, { beforeColon: false, afterColon: true } ],
		'keyword-spacing': [ 2, { before: true, after: true } ],
		'no-cond-assign': [ 2 ],
		'no-duplicate-imports': [ 2 ],
		'no-extra-semi': [ 2 ],
		'no-multi-spaces': [ 2 ],
		'no-spaced-func': [ 2 ],
		'no-sync': [ 2 ],
		'no-trailing-spaces': [ 2 ],
		'no-var': [ 2 ],
		'object-curly-spacing': [ 2, 'always' ],
		'object-shorthand': [ 2 ],
		'prefer-const': [ 2 ],
		'prefer-spread': [ 2 ],
		'semi': [ 2, 'always' ],
		'semi-spacing': [ 2, { before: false, after: true } ],
		'space-before-blocks': [ 2, 'always' ],
		'space-before-function-paren': [ 2, {
			'anonymous': 'never',
			'named': 'never',
			'asyncArrow': 'always',
		} ],
		'space-in-parens': [ 2 ],
		'space-infix-ops': [ 2 ],
		'space-unary-ops': [ 2, { words: true, nonwords: false } ],
		'spaced-comment': [ 2 ],
		'import/order': [ 'error', {
			groups: [
				'builtin',
				[ 'internal', 'external' ],
				[ 'parent', 'sibling', 'index' ],
			],
			'newlines-between': 'always',
		} ],
	},
};
<commit_msg>Replaced deprecated no-spaced-func -> func-call-spacing<commit_after>module.exports = {
	extends: 'eslint:recommended',
	env: {
		es6: true,
		node: true,
	},

	plugins: [
		'import',
	],

	rules: {
		'array-bracket-spacing': [ 2, 'always' ],
		'comma-dangle': [ 2, {
			arrays: 'always-multiline',
			objects: 'always-multiline',
			imports: 'always-multiline',
			exports: 'always-multiline',
			functions: 'always-multiline',
		} ],
		'comma-spacing': [ 2, { after: true } ],
		'computed-property-spacing': [ 2, 'never' ],
		'eol-last': [ 2, 'always' ],
		'func-call-spacing': [ 2, 'never' ],
		'dot-notation': [ 2 ],
		'indent': [ 2, 'tab' ],
		'key-spacing': [ 2, { beforeColon: false, afterColon: true } ],
		'keyword-spacing': [ 2, { before: true, after: true } ],
		'no-cond-assign': [ 2 ],
		'no-duplicate-imports': [ 2 ],
		'no-extra-semi': [ 2 ],
		'no-multi-spaces': [ 2 ],
		'no-sync': [ 2 ],
		'no-trailing-spaces': [ 2 ],
		'no-var': [ 2 ],
		'object-curly-spacing': [ 2, 'always' ],
		'object-shorthand': [ 2 ],
		'prefer-const': [ 2 ],
		'prefer-spread': [ 2 ],
		'semi': [ 2, 'always' ],
		'semi-spacing': [ 2, { before: false, after: true } ],
		'space-before-blocks': [ 2, 'always' ],
		'space-before-function-paren': [ 2, {
			'anonymous': 'never',
			'named': 'never',
			'asyncArrow': 'always',
		} ],
		'space-in-parens': [ 2 ],
		'space-infix-ops': [ 2 ],
		'space-unary-ops': [ 2, { words: true, nonwords: false } ],
		'spaced-comment': [ 2 ],
		'import/order': [ 'error', {
			groups: [
				'builtin',
				[ 'internal', 'external' ],
				[ 'parent', 'sibling', 'index' ],
			],
			'newlines-between': 'always',
		} ],
	},
};
<|endoftext|>


<commit_before>var crypto = require('crypto');
var through = require('through2');

var GLOBAL_CACHE = {};

// look for changes by mtime
function differenceByModifiedTime(stream, firstPass, file, cache, callback) {

    var newTime = file.stat && file.stat.mtime;
    var oldTime = cache[file.path];
    cache[file.path] = newTime.getTime();

    if ((!oldTime && firstPass) || (oldTime && oldTime !== newTime.getTime() )) {
      stream.push(file);
    }

	  return;
};

// look for changes by sha1 hash
function differenceBySha1Hash(stream, firstPass, file, cache, callback) {
    // null cannot be hashed
    if (file.contents === null) {
      // if element is really a file, something weird happened, but it's safer
      // to assume it was changed (because we cannot said that it wasn't)
      // if it's not a file, we don't care, do we? does anybody transform directories?
      if (file.stat.isFile()) {
        stream.push(file);
      }
      return callback();
    }

    var newHash = crypto.createHash('sha1').update(file.contents).digest('hex');
    var currentHash = cache[file.path];
    cache[file.path] = newHash;
    if ((!currentHash && firstPass) || (currentHash && currentHash !== newHash)) {
      stream.push(file);
    }

    return;
};

module.exports = function(options) {
  options = options || {};

  var howToDetermineDifference;

  switch(options.howToDetermineDifference) {
    case "hash":
        howToDetermineDifference = differenceBySha1Hash;
        break;
    case "modification-time":
        console.log ("using mtime");
        howToDetermineDifference = differenceByModifiedTime;
        break;
    default:
        howToDetermineDifference = differenceBySha1Hash;
  }

  var cache = options.cache || GLOBAL_CACHE;
  var firstPass = options.firstPass === true;

  return through.obj(function(file, encoding, callback) {
    howToDetermineDifference(this, firstPass, file, cache, callback);
    callback();
  });

};
<commit_msg>removing dev message<commit_after>var crypto = require('crypto');
var through = require('through2');

var GLOBAL_CACHE = {};

// look for changes by mtime
function differenceByModifiedTime(stream, firstPass, file, cache, callback) {

    var newTime = file.stat && file.stat.mtime;
    var oldTime = cache[file.path];
    cache[file.path] = newTime.getTime();

    if ((!oldTime && firstPass) || (oldTime && oldTime !== newTime.getTime() )) {
      stream.push(file);
    }

	  return;
};

// look for changes by sha1 hash
function differenceBySha1Hash(stream, firstPass, file, cache, callback) {
    // null cannot be hashed
    if (file.contents === null) {
      // if element is really a file, something weird happened, but it's safer
      // to assume it was changed (because we cannot said that it wasn't)
      // if it's not a file, we don't care, do we? does anybody transform directories?
      if (file.stat.isFile()) {
        stream.push(file);
      }
      return callback();
    }

    var newHash = crypto.createHash('sha1').update(file.contents).digest('hex');
    var currentHash = cache[file.path];
    cache[file.path] = newHash;
    if ((!currentHash && firstPass) || (currentHash && currentHash !== newHash)) {
      stream.push(file);
    }

    return;
};

module.exports = function(options) {
  options = options || {};

  var howToDetermineDifference;

  switch(options.howToDetermineDifference) {
    case "hash":
        howToDetermineDifference = differenceBySha1Hash;
        break;
    case "modification-time":
        howToDetermineDifference = differenceByModifiedTime;
        break;
    default:
        howToDetermineDifference = differenceBySha1Hash;
  }

  var cache = options.cache || GLOBAL_CACHE;
  var firstPass = options.firstPass === true;

  return through.obj(function(file, encoding, callback) {
    howToDetermineDifference(this, firstPass, file, cache, callback);
    callback();
  });

};
<|endoftext|>


<commit_before>import { assign } from './util';
import { diff, commitRoot } from './diff/index';
import options from './options';
import { Fragment } from './create-element';

/**
 * Base Component class. Provides `setState()` and `forceUpdate()`, which
 * trigger rendering
 * @param {object} props The initial component props
 * @param {object} context The initial context from parent components'
 * getChildContext
 */
export function Component(props, context) {
	this.props = props;
	this.context = context;
}

/**
 * Update component state and schedule a re-render.
 * @param {object | ((s: object, p: object) => object)} update A hash of state
 * properties to update with new values or a function that given the current
 * state and props returns a new partial state
 * @param {() => void} [callback] A function to be called once component state is
 * updated
 */
Component.prototype.setState = function(update, callback) {
	// only clone state when copying to nextState the first time.
	let s;
	if (this._nextState != null && this._nextState !== this.state) {
		s = this._nextState;
	} else {
		s = this._nextState = assign({}, this.state);
	}

	if (typeof update == 'function') {
		// Some libraries like `immer` mark the current state as readonly,
		// preventing us from mutating it, so we need to clone it. See #2716
		update = update(assign({}, s), this.props);
	}

	if (update) {
		assign(s, update);
	}

	// Skip update if updater function returned null
	if (update == null) return;

	if (this._vnode) {
		if (callback) this._renderCallbacks.push(callback);
		enqueueRender(this);
	}
};

/**
 * Immediately perform a synchronous re-render of the component
 * @param {() => void} [callback] A function to be called after component is
 * re-rendered
 */
Component.prototype.forceUpdate = function(callback) {
	if (this._vnode) {
		// Set render mode so that we can differentiate where the render request
		// is coming from. We need this because forceUpdate should never call
		// shouldComponentUpdate
		this._force = true;
		if (callback) this._renderCallbacks.push(callback);
		enqueueRender(this);
	}
};

/**
 * Accepts `props` and `state`, and returns a new Virtual DOM tree to build.
 * Virtual DOM is generally constructed via [JSX](http://jasonformat.com/wtf-is-jsx).
 * @param {object} props Props (eg: JSX attributes) received from parent
 * element/component
 * @param {object} state The component's current state
 * @param {object} context Context object, as returned by the nearest
 * ancestor's `getChildContext()`
 * @returns {import('./index').ComponentChildren | void}
 */
Component.prototype.render = Fragment;

/**
 * @param {import('./internal').VNode} vnode
 * @param {number | null} [childIndex]
 */
export function getDomSibling(vnode, childIndex) {
	if (childIndex == null) {
		// Use childIndex==null as a signal to resume the search from the vnode's sibling
		return vnode._parent
			? getDomSibling(vnode._parent, vnode._parent._children.indexOf(vnode) + 1)
			: null;
	}

	let sibling;
	for (; childIndex < vnode._children.length; childIndex++) {
		sibling = vnode._children[childIndex];

		if (sibling != null && sibling._dom != null) {
			// Since updateParentDomPointers keeps _dom pointer correct,
			// we can rely on _dom to tell us if this subtree contains a
			// rendered DOM node, and what the first rendered DOM node is
			return sibling._dom;
		}
	}

	// If we get here, we have not found a DOM node in this vnode's children.
	// We must resume from this vnode's sibling (in it's parent _children array)
	// Only climb up and search the parent if we aren't searching through a DOM
	// VNode (meaning we reached the DOM parent of the original vnode that began
	// the search)
	return typeof vnode.type == 'function' ? getDomSibling(vnode) : null;
}

/**
 * Trigger in-place re-rendering of a component.
 * @param {import('./internal').Component} component The component to rerender
 */
function renderComponent(component) {
	let vnode = component._vnode,
		oldDom = vnode._dom,
		parentDom = component._parentDom;

	if (parentDom) {
		let commitQueue = [];
		const oldVNode = assign({}, vnode);
		oldVNode._original = oldVNode;

		let newDom = diff(
			parentDom,
			vnode,
			oldVNode,
			component._globalContext,
			parentDom.ownerSVGElement !== undefined,
			vnode._hydrating != null ? [oldDom] : null,
			commitQueue,
			oldDom == null ? getDomSibling(vnode) : oldDom,
			vnode._hydrating
		);
		commitRoot(commitQueue, vnode);

		if (newDom != oldDom) {
			updateParentDomPointers(vnode);
		}
	}
}

/**
 * @param {import('./internal').VNode} vnode
 */
function updateParentDomPointers(vnode) {
	if ((vnode = vnode._parent) != null && vnode._component != null) {
		vnode._dom = vnode._component.base = null;
		for (let i = 0; i < vnode._children.length; i++) {
			let child = vnode._children[i];
			if (child != null && child._dom != null) {
				vnode._dom = vnode._component.base = child._dom;
				break;
			}
		}

		return updateParentDomPointers(vnode);
	}
}

/**
 * The render queue
 * @type {Array<import('./internal').Component>}
 */
let rerenderQueue = [];

/**
 * Asynchronously schedule a callback
 * @type {(cb: () => void) => void}
 */
/* istanbul ignore next */
// Note the following line isn't tree-shaken by rollup cuz of rollup/rollup#2566
const defer =
	typeof Promise == 'function'
		? Promise.prototype.then.bind(Promise.resolve())
		: setTimeout;

/*
 * The value of `Component.debounce` must asynchronously invoke the passed in callback. It is
 * important that contributors to Preact can consistently reason about what calls to `setState`, etc.
 * do, and when their effects will be applied. See the links below for some further reading on designing
 * asynchronous APIs.
 * * [Designing APIs for Asynchrony](https://blog.izs.me/2013/08/designing-apis-for-asynchrony)
 * * [Callbacks synchronous and asynchronous](https://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/)
 */

let prevDebounce;

let rerenderCount = 0;

/**
 * Enqueue a rerender of a component
 * @param {import('./internal').Component} c The component to rerender
 */
export function enqueueRender(c) {
	if (
		(!c._dirty &&
			(c._dirty = true) &&
			rerenderQueue.push(c) &&
			!rerenderCount++) ||
		prevDebounce !== options.debounceRendering
	) {
		prevDebounce = options.debounceRendering;
		(prevDebounce || defer)(process);
	}
}

/** Flush the render queue by rerendering all queued components */
function process() {
	let queue;
	while ((rerenderCount = rerenderQueue.length)) {
		queue = rerenderQueue.sort((a, b) => a._vnode._depth - b._vnode._depth);
		rerenderQueue = [];
		// Don't update `renderCount` yet. Keep its value non-zero to prevent unnecessary
		// process() calls from getting scheduled while `queue` is still being consumed.
		queue.some(c => {
			if (c._dirty) renderComponent(c);
		});
	}
}
<commit_msg>re-add process._rerenderCount (looks like its used by Prefresh)<commit_after>import { assign } from './util';
import { diff, commitRoot } from './diff/index';
import options from './options';
import { Fragment } from './create-element';

/**
 * Base Component class. Provides `setState()` and `forceUpdate()`, which
 * trigger rendering
 * @param {object} props The initial component props
 * @param {object} context The initial context from parent components'
 * getChildContext
 */
export function Component(props, context) {
	this.props = props;
	this.context = context;
}

/**
 * Update component state and schedule a re-render.
 * @param {object | ((s: object, p: object) => object)} update A hash of state
 * properties to update with new values or a function that given the current
 * state and props returns a new partial state
 * @param {() => void} [callback] A function to be called once component state is
 * updated
 */
Component.prototype.setState = function(update, callback) {
	// only clone state when copying to nextState the first time.
	let s;
	if (this._nextState != null && this._nextState !== this.state) {
		s = this._nextState;
	} else {
		s = this._nextState = assign({}, this.state);
	}

	if (typeof update == 'function') {
		// Some libraries like `immer` mark the current state as readonly,
		// preventing us from mutating it, so we need to clone it. See #2716
		update = update(assign({}, s), this.props);
	}

	if (update) {
		assign(s, update);
	}

	// Skip update if updater function returned null
	if (update == null) return;

	if (this._vnode) {
		if (callback) this._renderCallbacks.push(callback);
		enqueueRender(this);
	}
};

/**
 * Immediately perform a synchronous re-render of the component
 * @param {() => void} [callback] A function to be called after component is
 * re-rendered
 */
Component.prototype.forceUpdate = function(callback) {
	if (this._vnode) {
		// Set render mode so that we can differentiate where the render request
		// is coming from. We need this because forceUpdate should never call
		// shouldComponentUpdate
		this._force = true;
		if (callback) this._renderCallbacks.push(callback);
		enqueueRender(this);
	}
};

/**
 * Accepts `props` and `state`, and returns a new Virtual DOM tree to build.
 * Virtual DOM is generally constructed via [JSX](http://jasonformat.com/wtf-is-jsx).
 * @param {object} props Props (eg: JSX attributes) received from parent
 * element/component
 * @param {object} state The component's current state
 * @param {object} context Context object, as returned by the nearest
 * ancestor's `getChildContext()`
 * @returns {import('./index').ComponentChildren | void}
 */
Component.prototype.render = Fragment;

/**
 * @param {import('./internal').VNode} vnode
 * @param {number | null} [childIndex]
 */
export function getDomSibling(vnode, childIndex) {
	if (childIndex == null) {
		// Use childIndex==null as a signal to resume the search from the vnode's sibling
		return vnode._parent
			? getDomSibling(vnode._parent, vnode._parent._children.indexOf(vnode) + 1)
			: null;
	}

	let sibling;
	for (; childIndex < vnode._children.length; childIndex++) {
		sibling = vnode._children[childIndex];

		if (sibling != null && sibling._dom != null) {
			// Since updateParentDomPointers keeps _dom pointer correct,
			// we can rely on _dom to tell us if this subtree contains a
			// rendered DOM node, and what the first rendered DOM node is
			return sibling._dom;
		}
	}

	// If we get here, we have not found a DOM node in this vnode's children.
	// We must resume from this vnode's sibling (in it's parent _children array)
	// Only climb up and search the parent if we aren't searching through a DOM
	// VNode (meaning we reached the DOM parent of the original vnode that began
	// the search)
	return typeof vnode.type == 'function' ? getDomSibling(vnode) : null;
}

/**
 * Trigger in-place re-rendering of a component.
 * @param {import('./internal').Component} component The component to rerender
 */
function renderComponent(component) {
	let vnode = component._vnode,
		oldDom = vnode._dom,
		parentDom = component._parentDom;

	if (parentDom) {
		let commitQueue = [];
		const oldVNode = assign({}, vnode);
		oldVNode._original = oldVNode;

		let newDom = diff(
			parentDom,
			vnode,
			oldVNode,
			component._globalContext,
			parentDom.ownerSVGElement !== undefined,
			vnode._hydrating != null ? [oldDom] : null,
			commitQueue,
			oldDom == null ? getDomSibling(vnode) : oldDom,
			vnode._hydrating
		);
		commitRoot(commitQueue, vnode);

		if (newDom != oldDom) {
			updateParentDomPointers(vnode);
		}
	}
}

/**
 * @param {import('./internal').VNode} vnode
 */
function updateParentDomPointers(vnode) {
	if ((vnode = vnode._parent) != null && vnode._component != null) {
		vnode._dom = vnode._component.base = null;
		for (let i = 0; i < vnode._children.length; i++) {
			let child = vnode._children[i];
			if (child != null && child._dom != null) {
				vnode._dom = vnode._component.base = child._dom;
				break;
			}
		}

		return updateParentDomPointers(vnode);
	}
}

/**
 * The render queue
 * @type {Array<import('./internal').Component>}
 */
let rerenderQueue = [];

/**
 * Asynchronously schedule a callback
 * @type {(cb: () => void) => void}
 */
/* istanbul ignore next */
// Note the following line isn't tree-shaken by rollup cuz of rollup/rollup#2566
const defer =
	typeof Promise == 'function'
		? Promise.prototype.then.bind(Promise.resolve())
		: setTimeout;

/*
 * The value of `Component.debounce` must asynchronously invoke the passed in callback. It is
 * important that contributors to Preact can consistently reason about what calls to `setState`, etc.
 * do, and when their effects will be applied. See the links below for some further reading on designing
 * asynchronous APIs.
 * * [Designing APIs for Asynchrony](https://blog.izs.me/2013/08/designing-apis-for-asynchrony)
 * * [Callbacks synchronous and asynchronous](https://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/)
 */

let prevDebounce;

/**
 * Enqueue a rerender of a component
 * @param {import('./internal').Component} c The component to rerender
 */
export function enqueueRender(c) {
	if (
		(!c._dirty &&
			(c._dirty = true) &&
			rerenderQueue.push(c) &&
			!process._rerenderCount++) ||
		prevDebounce !== options.debounceRendering
	) {
		prevDebounce = options.debounceRendering;
		(prevDebounce || defer)(process);
	}
}

/** Flush the render queue by rerendering all queued components */
function process() {
	let queue;
	while ((process._rerenderCount = rerenderQueue.length)) {
		queue = rerenderQueue.sort((a, b) => a._vnode._depth - b._vnode._depth);
		rerenderQueue = [];
		// Don't update `renderCount` yet. Keep its value non-zero to prevent unnecessary
		// process() calls from getting scheduled while `queue` is still being consumed.
		queue.some(c => {
			if (c._dirty) renderComponent(c);
		});
	}
}
process._rerenderCount = 0;
<|endoftext|>


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

function addZero(i) {
  if (i < 10) {
    i = '0' + i;
  }
  return i;
}

var pingu = {
  logLevel: 1,
  logDir: path.resolve(path.dirname(require.main.filename), 'log'),
  logFile: 'pingu.log',

  /**
    * set the log level without redefining the class
    */

  setLogLevel: function(level) {
    this.logLevel = level;
    console.log('PINGU: Set log level to ' + level);
  },

  /**
    * check the log level
    */

  checkLogLevel: function() {
    console.log('PINGU: Log level is ' + this.logLevel);
  },

  /**
    * set the log directory without redefining the class
    */

  setLogDir: function(dir) {
    this.logDir = path.resolve(path.dirname(require.main.filename), dir);
    console.log('PINGU: Set log directory to ' + dir);
  },

  /**
    * check the log directory
    */

  checkLogDir: function() {
    console.log('PINGU: Log directory is ' + this.logDir);
  },

  log: function(message) {
     var out = 'PINGU [LOG]: ' + message;
    console.log(out);

    if(this.logLevel <= 1) {
      /* write log */
      this.writeLog(out, 'log');
    }
  },

  warn: function(message) {
     var out = 'PINGU [WARN]: ' + message;
    console.warn(out);
    console.trace();

    if(this.logLevel <= 2) {
      /* write log */
      this.writeLog(out, 'warn');
    }
  },

  error: function(message) {
     var out = 'PINGU [ERROR]: ' + message;
    console.error(out);
    console.trace();

    if(this.logLevel <= 3) {
      /* write log */
      this.writeLog(out, 'error');
    }
  },

  /**
    * write our messages to the
    */

  writeLog: function(message, type) {
    if(typeof window === 'undefined') {
      var fs = require('fs');
      var logFile = path.join(this.logDir, this.logFile);

      var now = new Date();
      var date = now.getFullYear() + '-' + addZero(( now.getMonth() + 1 )) + '-' + addZero(now.getDate());
      var time = addZero(now.getHours()) + ':' + addZero(now.getMinutes()) + ':' + addZero(now.getSeconds());
      var dateTime = date + ' ' + time;

      try {

        if (!fs.existsSync(this.logDir)) {
          fs.mkdirSync(this.logDir);
        }

         var append = '[' + dateTime + '] ' + message + '\r\n';

        fs.appendFileSync(logFile, append);

        if(type !== 'log') {
           var stack = new Error().stack;
          fs.appendFileSync(logFile, stack + '\r\n');
        }
      } catch(err) {
        throw err;
      }
    }
  }
};

module.exports = pingu;
<commit_msg>Adding dir function back in as it was accidentally removed in 0.3.0. Additionally tidying up some spacing.<commit_after>var path = require('path');

function addZero(i) {
  if (i < 10) {
    i = '0' + i;
  }
  return i;
}

var pingu = {
  logLevel: 1,
  logDir: path.resolve(path.dirname(require.main.filename), 'log'),
  logFile: 'pingu.log',

  /**
    * set the log level without redefining the class
    */

  setLogLevel: function(level) {
    this.logLevel = level;
    console.log('PINGU: Set log level to ' + level);
  },

  /**
    * check the log level
    */

  checkLogLevel: function() {
    console.log('PINGU: Log level is ' + this.logLevel);
  },

  /**
    * set the log directory without redefining the class
    */

  setLogDir: function(dir) {
    this.logDir = path.resolve(path.dirname(require.main.filename), dir);
    console.log('PINGU: Set log directory to ' + dir);
  },

  /**
    * check the log directory
    */

  checkLogDir: function() {
    console.log('PINGU: Log directory is ' + this.logDir);
  },

  log: function(message) {
    var out = 'PINGU [LOG]: ' + message;
    console.log(out);

    if(this.logLevel <= 1) {
      /* write log */
      this.writeLog(out, 'log');
    }
  },

  dir: function(message) {
    var out = 'PINGU [DIR]: ';
    console.log(out);
    console.dir(message);

    if(this.logLevel <= 1) {
      /* write log */
      this.writeLog(JSON.stringify(message), 'log');
    }
  },

  warn: function(message) {
    var out = 'PINGU [WARN]: ' + message;
    console.warn(out);
    console.trace();

    if(this.logLevel <= 2) {
      /* write log */
      this.writeLog(out, 'warn');
    }
  },

  error: function(message) {
    var out = 'PINGU [ERROR]: ' + message;
    console.error(out);
    console.trace();

    if(this.logLevel <= 3) {
      /* write log */
      this.writeLog(out, 'error');
    }
  },

  /**
    * write our messages to the
    */

  writeLog: function(message, type) {
    if(typeof window === 'undefined') {
      var fs = require('fs');
      var logFile = path.join(this.logDir, this.logFile);

      var now = new Date();
      var date = now.getFullYear() + '-' + addZero(( now.getMonth() + 1 )) + '-' + addZero(now.getDate());
      var time = addZero(now.getHours()) + ':' + addZero(now.getMinutes()) + ':' + addZero(now.getSeconds());
      var dateTime = date + ' ' + time;

      try {

        if (!fs.existsSync(this.logDir)) {
          fs.mkdirSync(this.logDir);
        }

         var append = '[' + dateTime + '] ' + message + '\r\n';

        fs.appendFileSync(logFile, append);

        if(type !== 'log') {
           var stack = new Error().stack;
          fs.appendFileSync(logFile, stack + '\r\n');
        }
      } catch(err) {
        throw err;
      }
    }
  }
};

module.exports = pingu;
<|endoftext|>


<commit_before>var enterSearchMsg = "Search...";
var enterUrlMsg = "Paste URL Here...";
var enterTimeMsg = "Type length of video... (ex. 2:49 or 2 49)";

var pauseImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-pause-4x.png";
var playImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-play-4x.png";

var search;
var url;
var time;

var videos = [];
var videoCounter = 0;
var videoIteration = 0;
var videoPaused;
var timer;

function Timer(callback, delay) {
  var timerId, start, remaining = delay;

  this.pause = function() {
      window.clearTimeout(timerId);
      remaining -= new Date() - start;
  };

  this.resume = function() {
      start = new Date();
      window.clearTimeout(timerId);
      timerId = window.setTimeout(callback, remaining);
  };

  this.resume();
}

function highlight(i) {
  $("tr:nth-child(" + i + ")").attr("id", "newSelected");
  $("tr.selected").removeClass("selected");
  $("#newSelected").addClass("selected");
  $("#newSelected").removeAttr("id");
}

function msConversion(millis) {
  var minutes = Math.floor(millis / 60000);
  var seconds = ((millis % 60000) / 1000).toFixed(0);
  return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
}

function playVideo() {
  highlight(videoIteration);
  var embedUrl = videos[videoIteration]["url"].replace("/watch?v=", "/embed/") + "?autoplay=1";
  $("#youtube").attr("src", embedUrl);
  $("#pauseImg").attr("src", pauseImgSrc);
}

function loopVideo() {
  videoIteration++;
  playVideo();
  timer = new Timer(function() {
    if (videoIteration < videoCounter) {
      loopVideo();
    }
    else {
      timer.pause();
      timer = 0;
      $("#youtube").attr("src", "");
    }
  }, videos[videoIteration]["time"] + 2000);
}

function pauseVideo() {
  if (!videoPaused) {
    timer.pause();
    $("#pauseImg").attr("src", playImgSrc);
    videoPaused = true;
  }
  else {
    timer.resume();
    $("#pauseImg").attr("src", pauseImgSrc);
    videoPaused = false;
  }
}

function backVideo() {
  if (videoIteration - 2 > -1) {
    videoIteration = videoIteration - 2;
    timer = 0;
    loopVideo();
  }
}

function forwardVideo() {
  if (videoIteration + 1 <= videoCounter) {
    timer = 0;
    loopVideo();
  }
}

function input() {
  switch ($("#inputBox").attr("placeholder")) {
    case enterSearchMsg:
      search = $("#inputBox").val();
      if (search.indexOf(";") === -1) {
        var queryUrl = "https://www.youtube.com/results?search_query=" + search.replace(/ /g, "+");
        window.open(queryUrl);
      }
      else {
        search = search.replace(/\;/g, "");
      }
      $("#inputBox").val("").attr("placeholder", enterUrlMsg);
      break;
    case enterUrlMsg:
      url = $("#inputBox").val();
      $("#inputBox").val("").attr("placeholder", enterTimeMsg);
      break;
    case enterTimeMsg:
      time = $("#inputBox").val();
      time = time.replace(/ /g, ":");
      time = time.split(":");
      time = (+time[0]) * 60 + (+time[1]);
      time = time * 1000;

      videoCounter++;
      videos[videoCounter] = [];
      videos[videoCounter]["name"] = search;
      videos[videoCounter]["time"] = time;
      videos[videoCounter]["url"] = url;

      var printTime = msConversion(videos[videoCounter]["time"]);

      $("#videosTable").append("
" + videos[videoCounter]["name"] + "	" + printTime + "
");

      if (videoCounter == 1 || timer == 0) {
        loopVideo();
      }

      $("#inputBox").val("").attr("placeholder", enterSearchMsg);
      break;
  }
}
<commit_msg>trying to fix timing mismatch<commit_after>var enterSearchMsg = "Search...";
var enterUrlMsg = "Paste URL Here...";
var enterTimeMsg = "Type length of video... (ex. 2:49 or 2 49)";

var pauseImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-pause-4x.png";
var playImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-play-4x.png";

var search;
var url;
var time;

var videos = [];
var videoCounter = 0;
var videoIteration = 0;
var videoPaused;
var timer;

function Timer(callback, delay) {
  var timerId, start, remaining = delay;

  this.pause = function() {
      window.clearTimeout(timerId);
      remaining -= new Date() - start;
  };

  this.resume = function() {
      start = new Date();
      window.clearTimeout(timerId);
      timerId = window.setTimeout(callback, remaining);
  };

  this.resume();
}

function highlight(i) {
  $("tr:nth-child(" + i + ")").attr("id", "newSelected");
  $("tr.selected").removeClass("selected");
  $("#newSelected").addClass("selected");
  $("#newSelected").removeAttr("id");
}

function msConversion(millis) {
  var minutes = Math.floor(millis / 60000);
  var seconds = ((millis % 60000) / 1000).toFixed(0);
  return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
}

function playVideo() {
  highlight(videoIteration);
  var embedUrl = videos[videoIteration]["url"].replace("/watch?v=", "/embed/") + "?autoplay=1";
  $("#youtube").attr("src", embedUrl);
  $("#pauseImg").attr("src", pauseImgSrc);
}

function loopVideo() {
  videoIteration++;
  playVideo();
  timer = new Timer(function() {
    if (videoIteration < videoCounter) {
      loopVideo();
    }
    else {
      timer.pause();
      timer = 0;
      $("#youtube").attr("src", "");
    }
  }, videos[videoIteration]["time"] + 2000);
}

function pauseVideo() {
  if (!videoPaused) {
    timer.pause();
    $("#pauseImg").attr("src", playImgSrc);
    videoPaused = true;
  }
  else {
    timer.resume();
    $("#pauseImg").attr("src", pauseImgSrc);
    videoPaused = false;
  }
}

function backVideo() {
  if (videoIteration - 2 > -1) {
    videoIteration = videoIteration - 2;
    if (typeof timer !== "undefined") {
      timer.pause();
    }
    timer = 0;
    loopVideo();
  }
}

function forwardVideo() {
  if (videoIteration + 1 <= videoCounter) {
    timer = 0;
    loopVideo();
  }
}

function input() {
  switch ($("#inputBox").attr("placeholder")) {
    case enterSearchMsg:
      search = $("#inputBox").val();
      if (search.indexOf(";") === -1) {
        var queryUrl = "https://www.youtube.com/results?search_query=" + search.replace(/ /g, "+");
        window.open(queryUrl);
      }
      else {
        search = search.replace(/\;/g, "");
      }
      $("#inputBox").val("").attr("placeholder", enterUrlMsg);
      break;
    case enterUrlMsg:
      url = $("#inputBox").val();
      $("#inputBox").val("").attr("placeholder", enterTimeMsg);
      break;
    case enterTimeMsg:
      time = $("#inputBox").val();
      time = time.replace(/ /g, ":");
      time = time.split(":");
      time = (+time[0]) * 60 + (+time[1]);
      time = time * 1000;

      videoCounter++;
      videos[videoCounter] = [];
      videos[videoCounter]["name"] = search;
      videos[videoCounter]["time"] = time;
      videos[videoCounter]["url"] = url;

      var printTime = msConversion(videos[videoCounter]["time"]);

      $("#videosTable").append("
" + videos[videoCounter]["name"] + "	" + printTime + "
");

      if (videoCounter == 1 || timer == 0) {
        loopVideo();
      }

      $("#inputBox").val("").attr("placeholder", enterSearchMsg);
      break;
  }
}
<|endoftext|>


<commit_before>var fs    = require('fs')
  , map   = require('map-stream')
  , sass  = require('node-sass')
  , path  = require('path')
  , gutil = require('gulp-util')
  , ext   = gutil.replaceExtension
  ;

module.exports = function (options) {
  var opts = options ? options : {};

  function nodeSass (file, cb) {
    var fileDir = path.dirname(file.path);
    var addedLocalDirPath = false;

    if (file.isNull()) {
      return cb(null, file);
    }
    if (path.basename(file.path).indexOf('_') === 0) {
      return cb();
    }

    if (opts.sourceComments === 'map' || opts.sourceComments === 'normal') {
      opts.file = file.path;
    } else {
      opts.data = file.contents.toString();
    }

    if (opts.includePaths && Array.isArray(opts.includePaths)) {
      if (opts.includePaths.indexOf(fileDir) === -1) {
        opts.includePaths.push(fileDir);
        addedLocalDirPath = true;
      }
    } else {
      opts.includePaths = [fileDir];
    }

    opts.success = function (css, map) {
      var sourceMap;
      if (typeof opts.onSuccess === 'function') opts.onSuccess(css, map);

      if (file.sourceMap) opts.makeSourceMaps = true;
      if (map) file.applySourceMap(map);

      file.path      = ext(file.path, '.css');
      file.contents  = new Buffer(css);
      cb(null, file);
    };

    opts.error = function (err) {
      if (opts.errLogToConsole) {
        gutil.log('[gulp-sass] ' + err);
        return cb();
      }

      if (typeof opts.onError === 'function') {
        opts.onError(err);
        return cb();
      }

      return cb(new gutil.PluginError('gulp-sass', err));
    };

    sass.render(opts);

    if (addedLocalDirPath) opts.includePaths.pop();

  }

  return map(nodeSass);
};

function getSourcesContent (sources) {
  sourcesContent = [];

  for (var i = 0; i < sources.length; i++) {
    sourcesContent[i] = fs.readFileSync(sources[i], { encoding: 'utf8' });
  }

  return sourcesContent;
}
<commit_msg>fixes logic<commit_after>var fs    = require('fs')
  , map   = require('map-stream')
  , sass  = require('node-sass')
  , path  = require('path')
  , gutil = require('gulp-util')
  , ext   = gutil.replaceExtension
  ;

module.exports = function (options) {
  var opts = options ? options : {};

  function nodeSass (file, cb) {
    var fileDir = path.dirname(file.path);
    var addedLocalDirPath = false;

    if (file.isNull()) {
      return cb(null, file);
    }
    if (path.basename(file.path).indexOf('_') === 0) {
      return cb();
    }

    if (file.sourceMap) {
      opts.sourceComments = 'map';
      opts.sourceMap = false;
    }

    if (opts.sourceComments === 'map' || opts.sourceComments === 'normal') {
      opts.file = file.path;
    } else {
      opts.data = file.contents.toString();
    }

    if (opts.includePaths && Array.isArray(opts.includePaths)) {
      if (opts.includePaths.indexOf(fileDir) === -1) {
        opts.includePaths.push(fileDir);
        addedLocalDirPath = true;
      }
    } else {
      opts.includePaths = [fileDir];
    }

    opts.success = function (css, map) {
      var sourceMap;
      if (typeof opts.onSuccess === 'function') opts.onSuccess(css, map);

      if (map && file.applySourceMap) {
        // hack to remove the already added sourceMappingURL from libsass
        css = css.replace(/\n\/\*#\s*sourceMappingURL\=.*\*\//, '');

        file.applySourceMap(map);
      }

      file.path      = ext(file.path, '.css');
      file.contents  = new Buffer(css);
      cb(null, file);
    };

    opts.error = function (err) {
      if (opts.errLogToConsole) {
        gutil.log('[gulp-sass] ' + err);
        return cb();
      }

      if (typeof opts.onError === 'function') {
        opts.onError(err);
        return cb();
      }

      return cb(new gutil.PluginError('gulp-sass', err));
    };

    sass.render(opts);

    if (addedLocalDirPath) opts.includePaths.pop();

  }

  return map(nodeSass);
};

function getSourcesContent (sources) {
  sourcesContent = [];

  for (var i = 0; i < sources.length; i++) {
    sourcesContent[i] = fs.readFileSync(sources[i], { encoding: 'utf8' });
  }

  return sourcesContent;
}
<|endoftext|>


<commit_before>var TelegramBot = require('node-telegram-bot-api');
var http = require('http');

var TELEGRAM_TOKEN = process.env.TELEGRAM_TOKEN;
if (TELEGRAM_TOKEN === undefined) {
  console.error("Undefined TELEGRAM_TOKEN enviroment variable");
  process.exit();
}

// Setup polling way
var bot = new TelegramBot(config.token, {polling: true});

// Matches /echo [whatever]
bot.onText(/\/start/, function (msg) {
  var fromId = msg.from.id;
  bot.sendMessage(fromId, "Hola, soy el bot del frontFest! Estaré encantado de responder tus preguntas sobre el evento");
});

// Matches /echo [whatever]
bot.onText(/\/echo (.+)/, function (msg, match) {
  var fromId = msg.from.id;
  var resp = match[1];
  bot.sendMessage(fromId, resp);
});

// Matches /cat
bot.onText(/\/cat/, function (msg) {
  var chatId = msg.chat.id;
  var width = getRandomInt(100, 500);
  var height = getRandomInt(100, 500);
  var photo = `http://placekitten.com/${width}/${height}`;
  bot.sendPhoto(chatId, photo, {caption: 'meow!'});
});

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

//Ask for event location
bot.onText(/\/ubicacion/, function (msg) {
  var chatId = msg.chat.id;
  latitude = '40.412664';
  longitude = '-3.718301';
  title = 'frontFest (Google Campus)';
  address = 'Calle Moreno Nieto, 2, 28005 Madrid, Spain';
  bot.sendVenue(chatId, latitude, longitude, title, address);
  bot.sendMessage(chatId, 'Se accede por la entrada del auditorio');
});

// server to keep alive on heroku
var server = http.createServer(function(request, response) {
  response.end("Hi there! :)");
});
server.listen(process.env.PORT || 8080);<commit_msg>set TELEGRAM_TOKEN to TelegramBot<commit_after>var TelegramBot = require('node-telegram-bot-api');
var http = require('http');

var TELEGRAM_TOKEN = process.env.TELEGRAM_TOKEN;
if (TELEGRAM_TOKEN === undefined) {
  console.error("Undefined TELEGRAM_TOKEN enviroment variable");
  process.exit();
}

// Setup polling way
var bot = new TelegramBot(TELEGRAM_TOKEN, {polling: true});

// Matches /echo [whatever]
bot.onText(/\/start/, function (msg) {
  var fromId = msg.from.id;
  bot.sendMessage(fromId, "Hola, soy el bot del frontFest! Estaré encantado de responder tus preguntas sobre el evento");
});

// Matches /echo [whatever]
bot.onText(/\/echo (.+)/, function (msg, match) {
  var fromId = msg.from.id;
  var resp = match[1];
  bot.sendMessage(fromId, resp);
});

// Matches /cat
bot.onText(/\/cat/, function (msg) {
  var chatId = msg.chat.id;
  var width = getRandomInt(100, 500);
  var height = getRandomInt(100, 500);
  var photo = `http://placekitten.com/${width}/${height}`;
  bot.sendPhoto(chatId, photo, {caption: 'meow!'});
});

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

//Ask for event location
bot.onText(/\/ubicacion/, function (msg) {
  var chatId = msg.chat.id;
  latitude = '40.412664';
  longitude = '-3.718301';
  title = 'frontFest (Google Campus)';
  address = 'Calle Moreno Nieto, 2, 28005 Madrid, Spain';
  bot.sendVenue(chatId, latitude, longitude, title, address);
  bot.sendMessage(chatId, 'Se accede por la entrada del auditorio');
});

// server to keep alive on heroku
var server = http.createServer(function(request, response) {
  response.end("Hi there! :)");
});
server.listen(process.env.PORT || 8080);<|endoftext|>


<commit_before>// helpers for mocking the getting and setting of: position, dimension and scroll position for:
// - elements on the page
// - the page
// - the window

const triggerEvent = require('./events.js').triggerEvent;

function getDescriptorForProperty (prop, obj) {
  const descriptors = Object.getOwnPropertyDescriptors(obj);
  const prototype = Object.getPrototypeOf(obj);

  if ((descriptors !== {}) && (prop in descriptors)) {
    return descriptors[prop];
  }

  // if not in this object's descriptors, check the prototype chain
  if (prototype !== null) {
    return getDescriptorForProperty(prop, prototype);
  }

  // no descriptor for this prop and no prototypes left in the chain
  return null;
};

class WindowMock {
  constructor (jest) {
    this._defaults = {
      height: window.innerHeight,
      width: window.innerWidth
    };
    this.spies = {
      document: {},
      window: {}
    };
    this._jest = jest;
    this._setSpies();
    this._plugJSDOM();
  }

  get top () {
    return window.scrollY;
  }

  get bottom () {
    return window.scrollY + window.innerHeight;
  }

  get height () {
    return window.innerHeight;
  }

  get width () {
    return window.innerWidth
  }

  get scrollPosition () {
    return window.scrollY;
  }

  _setSpies () {

    // remove calls to document.documentElement.clientHeight when jQuery is gone. It's called to support older browsers like IE8
    this.spies.document.clientHeight = this._jest.spyOn(document.documentElement, 'clientHeight', 'get').mockImplementation(() => window.innerHeight);

    // remove calls to document.documentElement.clientWidth when jQuery is gone. It's called to support older browsers like IE8
    this.spies.document.clientWidth = this._jest.spyOn(document.documentElement, 'clientWidth', 'get').mockImplementation(() => window.innerWidth);

  }

  _plugJSDOM () {

    const self = this;

    // JSDOM doesn't support .scrollTo
    this.spies.window.scrollTo = this._jest.fn(function () {
      let y;

      // data sent as props in an object
      if (arguments.length === 1) {
        y = arguments[0].y;
      } else {
        y = arguments[1];
      }

      self.scrollTo(y);

    });

     window.scrollTo = this.spies.window.scrollTo;

  }

  setHeightTo (height) {

    window.innerHeight = height;

  }

  setWidthTo (width) {

    window.innerWidth = width;

  }

  resizeTo (dimensions) {

    this.setHeightTo(dimensions.height);
    this.setWidthTo(dimensions.width);
    triggerEvent(window, 'resize');

  }

  scrollTo (scrollPosition) {

    document.documentElement.scrollTop = scrollPosition;
    window.scrollY = scrollPosition;
    window.pageYOffset = scrollPosition;

    triggerEvent(window, 'scroll');

  }

  reset () {

    window.innerHeight = this._defaults.height;
    window.innerWidth = this._defaults.width;
    this.scrollTo(0);

    // reset all spies
    Object.keys(this.spies).forEach(key => {
      const objectSpies = this.spies[key];
      Object.keys(objectSpies).forEach(key => objectSpies[key].mockClear());
    });

  }
}

class ScreenRenderItem {
  constructor (jest, node) {

    this._jest = jest;
    this._node = node;
    this._storeProps();
    this._mockAPICalls();

  }

  setData (itemData) {

    // check all the item data is present
    const itemProps = Object.keys(itemData);
    const missingKeys = ScreenRenderItem.REQUIRED_PROPS.filter(prop => !itemProps.includes(prop));

    this._data = {};

    if (missingKeys.length) {
      throw Error(`${itemData.name ? itemData.name : itemProps.join(', ')} is missing these properties: ${missingKeys.join(', ')}`);
    }

    // default left if not set
    if (!('offsetLeft' in itemData)) { itemData.offsetLeft = 0; }

    // copy onto internal store
    Object.assign(this._data, itemData);

  }

  _getBoundingClientRect () {
    const {offsetHeight, offsetWidth, offsetTop, offsetLeft} = this._data;
    const x = offsetLeft - window.scrollX;
    const y = offsetTop - window.scrollY;

    return {
      'x': x,
      'y': y,
      'top': (offsetHeight < 0) ? y + offsetHeight : y,
      'left': (offsetWidth < 0) ? x + offsetWidth : x,
      'bottom': (offsetTop + offsetHeight) - window.scrollY,
      'right': (offsetLeft + offsetWidth) - window.scrollX,
    };

  }

  reset () {

    // reset DOMRect mock
    this._node.getBoundingClientRect.mockClear();

    ScreenRenderItem.OFFSET_PROPS.forEach(prop => {

      if (prop in this._propStore) {
        // replace property implementation
        Object.defineProperty(this._node, prop, this._propStore[prop]);
      }

    });

  }

  _storeProps () {

    this._propStore = {};

    ScreenRenderItem.OFFSET_PROPS.forEach(prop => {
      const descriptor = getDescriptorForProperty(prop, this._node);

      if (descriptor !== null) {
        this._propStore[prop] = descriptor;
      }
    });

  }

  // mock any calls to the node's DOM API for position/dimension
  _mockAPICalls () {

    // proxy boundingClientRect property calls to item data
    this._jest.spyOn(this._node, 'getBoundingClientRect').mockImplementation(() => this._getBoundingClientRect());

    // handle calls to offset properties
    ScreenRenderItem.OFFSET_PROPS.forEach(prop => {

      this._jest.spyOn(this._node, prop, 'get').mockImplementation(() => this._data[prop]);

      // proxy DOM API sets for offsetValues (not possible to mock directly)
      Object.defineProperty(this._node, prop, {
        configurable: true,
        set: jest.fn(value => {
          this._data[prop] = value;
          return true;
        })
      });

    });

  }

}
ScreenRenderItem.OFFSET_PROPS = ['offsetHeight', 'offsetWidth', 'offsetTop', 'offsetLeft'];
ScreenRenderItem.REQUIRED_PROPS = ['name', 'offsetHeight', 'offsetHeight', 'offsetWidth', 'offsetTop'];

class ScreenMock {
  constructor (jest) {

    this._jest = jest
    this._items = {};

  }

  mockPositionAndDimension (itemName, node, itemData) {

    if (itemName in this._items) { throw new Error(`${itemName} already has its position and dimension mocked`); }

    const data = Object.assign({ 'name': itemName }, itemData);
    const item = new ScreenRenderItem(this._jest, node);

    item.setData(data);

    this._items[itemName] = item;

  }

  setWindow (windowData) {

    this.window = new WindowMock(this._jest);

    // check all the window data is present
    const missingKeys = Object.keys(windowData).filter(key => !ScreenMock.REQUIRED_WINDOW_PROPS.includes(key));

    if (missingKeys.length) {
      throw Error(`Window definition is missing these properties: ${missingKeys.join(', ')}`);
    }

    this.window.setHeightTo(windowData.height);
    this.window.setWidthTo(windowData.width);
    this.window.scrollTo(windowData.scrollTop);

  }

  scrollTo (scrollTop) {

    this.window.scrollTo(scrollTop);

  }

  reset () {

    Object.keys(this._items).forEach(itemName => this._items[itemName].reset());

  }

}
ScreenMock.REQUIRED_WINDOW_PROPS = ['height', 'width', 'scrollTop'];

exports.WindowMock = WindowMock;
exports.ScreenMock = ScreenMock;
<commit_msg>Make screenMock helper mock more DOM APIs<commit_after>// helpers for mocking the getting and setting of: position, dimension and scroll position for:
// - elements on the page
// - the page
// - the window

const triggerEvent = require('./events.js').triggerEvent;

function getDescriptorForProperty (prop, obj) {
  const descriptors = Object.getOwnPropertyDescriptors(obj);
  const prototype = Object.getPrototypeOf(obj);

  if ((descriptors !== {}) && (prop in descriptors)) {
    return descriptors[prop];
  }

  // if not in this object's descriptors, check the prototype chain
  if (prototype !== null) {
    return getDescriptorForProperty(prop, prototype);
  }

  // no descriptor for this prop and no prototypes left in the chain
  return null;
};

class WindowMock {
  constructor (jest) {
    this._defaults = {
      height: window.innerHeight,
      width: window.innerWidth
    };
    this.spies = {
      document: {},
      window: {}
    };
    this._jest = jest;
    this._setSpies();
    this._plugJSDOM();
  }

  get top () {
    return window.scrollY;
  }

  get bottom () {
    return window.scrollY + window.innerHeight;
  }

  get height () {
    return window.innerHeight;
  }

  get width () {
    return window.innerWidth
  }

  get scrollPosition () {
    return window.scrollY;
  }

  _setSpies () {

    // remove calls to document.documentElement.clientHeight when jQuery is gone. It's called to support older browsers like IE8
    this.spies.document.clientHeight = this._jest.spyOn(document.documentElement, 'clientHeight', 'get').mockImplementation(() => window.innerHeight);

    // remove calls to document.documentElement.clientWidth when jQuery is gone. It's called to support older browsers like IE8
    this.spies.document.clientWidth = this._jest.spyOn(document.documentElement, 'clientWidth', 'get').mockImplementation(() => window.innerWidth);

  }

  _plugJSDOM () {

    const self = this;

    // JSDOM doesn't support .scrollTo
    this.spies.window.scrollTo = this._jest.fn(function () {
      let y;

      // data sent as props in an object
      if (arguments.length === 1) {
        y = arguments[0].y;
      } else {
        y = arguments[1];
      }

      self.scrollTo(y);

    });

     window.scrollTo = this.spies.window.scrollTo;

  }

  setHeightTo (height) {

    window.innerHeight = height;

  }

  setWidthTo (width) {

    window.innerWidth = width;

  }

  resizeTo (dimensions) {

    this.setHeightTo(dimensions.height);
    this.setWidthTo(dimensions.width);
    triggerEvent(window, 'resize');

  }

  scrollTo (scrollPosition) {

    document.documentElement.scrollTop = scrollPosition;
    window.scrollY = scrollPosition;
    window.pageYOffset = scrollPosition;

    triggerEvent(window, 'scroll');

  }

  reset () {

    window.innerHeight = this._defaults.height;
    window.innerWidth = this._defaults.width;
    this.scrollTo(0);

    // reset all spies
    Object.keys(this.spies).forEach(key => {
      const objectSpies = this.spies[key];
      Object.keys(objectSpies).forEach(key => objectSpies[key].mockClear());
    });

  }
}

class ScreenRenderItem {
  constructor (jest, node) {

    this._jest = jest;
    this._node = node;
    this._storeProps();
    this._mockAPICalls();

  }

  setData (itemData) {

    // check all the item data is present
    const itemProps = Object.keys(itemData);
    const missingKeys = ScreenRenderItem.REQUIRED_PROPS.filter(prop => !itemProps.includes(prop));

    this._data = {};

    if (missingKeys.length) {
      throw Error(`${itemData.name ? itemData.name : itemProps.join(', ')} is missing these properties: ${missingKeys.join(', ')}`);
    }

    // default left if not set
    if (!('offsetLeft' in itemData)) { itemData.offsetLeft = 0; }

    // copy onto internal store
    Object.assign(this._data, itemData);

  }

  _getBoundingClientRect () {
    const {offsetHeight, offsetWidth, offsetTop, offsetLeft} = this._data;
    const x = offsetLeft - window.scrollX;
    const y = offsetTop - window.scrollY;

    return {
      'x': x,
      'y': y,
      'top': (offsetHeight < 0) ? y + offsetHeight : y,
      'left': (offsetWidth < 0) ? x + offsetWidth : x,
      'bottom': (offsetTop + offsetHeight) - window.scrollY,
      'right': (offsetLeft + offsetWidth) - window.scrollX,
    };

  }

  reset () {

    // reset DOMRect mock
    this._node.getBoundingClientRect.mockClear();

    ScreenRenderItem.OFFSET_PROPS.forEach(prop => {

      if (prop in this._propStore) {
        // replace property implementation
        Object.defineProperty(this._node, prop, this._propStore[prop]);
      }

    });

  }

  _storeProps () {

    this._propStore = {};

    ScreenRenderItem.OFFSET_PROPS.forEach(prop => {
      const descriptor = getDescriptorForProperty(prop, this._node);

      if (descriptor !== null) {
        this._propStore[prop] = descriptor;
      }
    });

  }

  // mock any calls to the node's DOM API for position/dimension
  _mockAPICalls () {

    // proxy getBoundingClientRect and getClientRects calls to item data
    // assumes getClientRects only returns one clientRect
    this._jest.spyOn(this._node, 'getBoundingClientRect').mockImplementation(() => this._getBoundingClientRect());
    this._jest.spyOn(this._node, 'getClientRects').mockImplementation(() => [this._getBoundingClientRect()]);

    // handle calls to offset properties
    ScreenRenderItem.OFFSET_PROPS.forEach(prop => {

      this._jest.spyOn(this._node, prop, 'get').mockImplementation(() => this._data[prop]);

      // proxy DOM API sets for offsetValues (not possible to mock directly)
      Object.defineProperty(this._node, prop, {
        configurable: true,
        set: jest.fn(value => {
          this._data[prop] = value;
          return true;
        })
      });

    });

  }

}
ScreenRenderItem.OFFSET_PROPS = ['offsetHeight', 'offsetWidth', 'offsetTop', 'offsetLeft'];
ScreenRenderItem.REQUIRED_PROPS = ['name', 'offsetHeight', 'offsetHeight', 'offsetWidth', 'offsetTop'];

class ScreenMock {
  constructor (jest) {

    this._jest = jest
    this._items = {};

  }

  mockPositionAndDimension (itemName, node, itemData) {

    if (itemName in this._items) { throw new Error(`${itemName} already has its position and dimension mocked`); }

    const data = Object.assign({ 'name': itemName }, itemData);
    const item = new ScreenRenderItem(this._jest, node);

    item.setData(data);

    this._items[itemName] = item;

  }

  setWindow (windowData) {

    this.window = new WindowMock(this._jest);

    // check all the window data is present
    const missingKeys = Object.keys(windowData).filter(key => !ScreenMock.REQUIRED_WINDOW_PROPS.includes(key));

    if (missingKeys.length) {
      throw Error(`Window definition is missing these properties: ${missingKeys.join(', ')}`);
    }

    this.window.setHeightTo(windowData.height);
    this.window.setWidthTo(windowData.width);
    this.window.scrollTo(windowData.scrollTop);

  }

  scrollTo (scrollTop) {

    this.window.scrollTo(scrollTop);

  }

  reset () {

    Object.keys(this._items).forEach(itemName => this._items[itemName].reset());

  }

}
ScreenMock.REQUIRED_WINDOW_PROPS = ['height', 'width', 'scrollTop'];

exports.WindowMock = WindowMock;
exports.ScreenMock = ScreenMock;
<|endoftext|>


<commit_before>describe("Label.textAlign", function(){
    var context, core, label;

    beforeEach(function(){
        enchant();
        core = new enchant.Core(320, 320);
        // dummy label for activate canvas layer
        var dummyLabel = new Label('.');
        dummyLabel.moveTo(320, 320);
        core.rootScene.addChild(dummyLabel);
        context = document.getElementsByTagName('canvas')[0].getContext('2d');
        // using multibyte char in tests causes problem when running on phantomjs
        label = new Label('=');
        label.color = "#f00";
        label.font = '10px mono monospace';
    });

    var verifyTextAt = function(textAlign){
        var x = 4, image;
        if(textAlign === 'center') {
            x = label.width / 2;
        } else if (textAlign === 'right') {
            x = label.width - 5;
        }
        // this code is trying to avoid problem about difference of font
        var max = 0;
        for (var y = 0; y < 10; y++) {
            image = context.getImageData(x, y, 1, 1).data;
            max = Math.max(image[0], max);
        }
        return max > 128;
    };

    it("should not be ok with no alignment setting", function(){
        expect(verifyTextAt('left')).to.not.be.ok;
        expect(verifyTextAt('center')).to.not.be.ok;
        expect(verifyTextAt('right')).to.not.be.ok;
    });

    it("should align left", function(){
        label.textAlign = "left";
        core.rootScene.addChild(label);
        expect(verifyTextAt('left')).to.be.ok;
        expect(verifyTextAt('center')).to.not.be.ok;
        expect(verifyTextAt('right')).to.not.be.ok;
    });

    it("should align center", function(){
        label.textAlign = "center";
        core.rootScene.addChild(label);
        expect(verifyTextAt('left')).to.not.be.ok;
        expect(verifyTextAt('center')).to.be.ok;
        expect(verifyTextAt('right')).to.not.be.ok;
    });

    it("should align right", function(){
        label.textAlign = "right";
        core.rootScene.addChild(label);
        expect(verifyTextAt('left')).to.not.be.ok;
        expect(verifyTextAt('center')).to.not.be.ok;
        expect(verifyTextAt('right')).to.be.ok;
    });

    it("should align left as default", function(){
        core.rootScene.addChild(label);
        expect(verifyTextAt('left')).to.be.ok;
        expect(verifyTextAt('center')).to.not.be.ok;
        expect(verifyTextAt('right')).to.not.be.ok;
    });
});
<commit_msg>add Label test<commit_after><|endoftext|>


<commit_before>module.exports = (core, adapter) => {
  core.require(adapter)
  const loader = require('./conf.js')(core)

  return config => {
    core.require(config)
    const defaults = core.merge(true, loader(adapter.configfile), { common: { debug: !!process.env.debug } })

    const common = core.merge(true, defaults.common, config.common)
    const options = core.merge(true, defaults.options, config.options)
    const names = defaults.common.names

    const configuration = {
      common: common,
      options: options,

      builds: {},
      watches: {}
    }

    const dependencies = tasks => {
      tasks = core.array(tasks)
      return Object.keys(tasks).map(index => {
        const key = tasks[index]
        return config[key] ? core.taskname(names.build, key) : key
      })
    }

    const destination = dest => {
      if (dest === false) return null
      if (!dest) return common.dest
      if (core.is.func(dest)) return dest()
      if (core.is.string(dest) && common.desinations[dest]) return common.destinations[dest]
      if (core.is.array(dest)) return dest[0]
      return dest
    }

    const source = src => {
      if (!src) return []
      if (core.is.func(src)) return src()
      if (core.is.string(src) && common.sources[src]) return common.sources[src]
      if (core.is.array(src)) return src
      return core.array(src)
    }

    const task = (key, value) => {
      const name = core.taskname(names.build, key)
      const conf = configuration.builds[key] = {
        build: value.build || value,
        dependencies: dependencies(value.tasks),
        name: name,
        source: core.array(source(key) || source(value.src)),
        target: destination(value.dest)
      }
      return conf
    }

    const watch = (key, value) => {
      const conf = configuration.watches[key] = {
        dependencies: [core.taskname(names.build, key)],
        name: core.taskname(names.watch, key),
        source: core.array(source(key) || source(value.src))
      }
      return conf
    }

    const definitions = Object.keys(config).filter(key => ['common', 'options', 'plugins'].indexOf(key) < 0)
    definitions.map(key => task(key, config[key]))
    definitions.map(key => watch(key, config[key]))

    return configuration
  }
}
<commit_msg>fixin issue with destination<commit_after>module.exports = (core, adapter) => {
  core.require(adapter)
  const loader = require('./conf.js')(core)

  return config => {
    core.require(config)
    const defaults = core.merge(true, loader(adapter.configfile), { common: { debug: !!process.env.debug } })

    const common = core.merge(true, defaults.common, config.common)
    const options = core.merge(true, defaults.options, config.options)
    const names = defaults.common.names

    const configuration = {
      common: common,
      options: options,

      builds: {},
      watches: {}
    }

    const dependencies = tasks => {
      tasks = core.array(tasks)
      return Object.keys(tasks).map(index => {
        const key = tasks[index]
        return config[key] ? core.taskname(names.build, key) : key
      })
    }

    const destination = dest => {
      if (dest === false) return null
      if (!dest) return common.dest
      if (core.is.func(dest)) return dest()
      if (core.is.string(dest)) return common.desinations[dest] ? common.destinations[dest] : dest
      if (core.is.array(dest)) return dest[0]
      return dest
    }

    const source = src => {
      if (!src) return []
      if (core.is.func(src)) return src()
      if (core.is.string(src) && common.sources[src]) return common.sources[src]
      if (core.is.array(src)) return src
      return core.array(src)
    }

    const task = (key, value) => {
      const name = core.taskname(names.build, key)
      const conf = configuration.builds[key] = {
        build: value.build || value,
        dependencies: dependencies(value.tasks),
        name: name,
        source: core.array(source(key) || source(value.src)),
        target: destination(value.dest)
      }
      return conf
    }

    const watch = (key, value) => {
      const conf = configuration.watches[key] = {
        dependencies: [core.taskname(names.build, key)],
        name: core.taskname(names.watch, key),
        source: core.array(source(key) || source(value.src))
      }
      return conf
    }

    const definitions = Object.keys(config).filter(key => ['common', 'options', 'plugins'].indexOf(key) < 0)
    definitions.map(key => task(key, config[key]))
    definitions.map(key => watch(key, config[key]))

    return configuration
  }
}
<|endoftext|>