<commit_before>// Private properties
let props = new WeakMap();

/**
 * Verify that the the length value is within the permissable range. The value must
 * be within the valid 32 bit unsigned int range permitted for use with JS Arrays
 * when added to the given start value, which must itself be valid.
 *
 * @param start The value given as the starting index.
 * @param length The value given as the length of the array slice.
 * @returns {Array<Number>} The start and length values cast to integers.
 * @throws {RangeError} Will throw if start or length values are not integers between 0 and 2^32-1.
 */
function validateLength(start, length) {
	start = +start;
	length = +length;

	let intStart = start >>> 0;
	let intLen = length >>> 0;

	if (intStart !== start) {
		throw new RangeError("Invalid start index");
	}

	if (intLen !== length ||
		((intLen + start) >>> 0) !== (intLen + start)) {
		throw new RangeError("Invalid array length");
	}

	return [intStart, intLen];
}

function ArraySlice(array = [], start = 0, length) {
	if (!Array.isArray(array)) {
		throw new TypeError(String(array) + " is not an Array");
	}

	length = (length === undefined) ? array.length - start : length;

	[start, length] = validateLength(start, length)
	let proxy = new Proxy(array, handler);

	props.set(proxy, {
		array: array,
		length: length,
		start: start
	});

	return proxy;
}

let handler = {
	get(target, property, receiver) {
		// console.log("get intercepted", property);

		let p = props.get(receiver);

		if (typeof property !== "symbol" &&
		    Number.isInteger(+property) && +property >= 0) {

			let start = p.start;
			let index = start + (+property);
			return target[index];

		} else if (property === "length") {
			return p.length;
		}

		return Reflect.get(target, property, receiver);
	},

	set(target, property, value, receiver) {
		let p = props.get(receiver);

		if (typeof property !== "symbol" &&
			Number.isInteger(+property) && +property >= 0) {
			let index = p.start + (+property);

			return Reflect.set(target, index, value, receiver);

		} else if (property === "length") {
			let length = validateLength(p.start, value);

			return p.length = length;
		}

		return Reflect.set(target, property, value, receiver);
	}
};

module.exports = ArraySlice;
//export default ArraySlice;
<commit_msg>Proxy set handler must return a boolean<commit_after>// Private properties
let props = new WeakMap();

/**
 * Verify that the the length value is within the permissable range. The value must
 * be within the valid 32 bit unsigned int range permitted for use with JS Arrays
 * when added to the given start value, which must itself be valid.
 *
 * @param start The value given as the starting index.
 * @param length The value given as the length of the array slice.
 * @returns {Array<Number>} The start and length values cast to integers.
 * @throws {RangeError} Will throw if start or length values are not integers between 0 and 2^32-1.
 */
function validateLength(start, length) {
	start = +start;
	length = +length;

	let intStart = start >>> 0;
	let intLen = length >>> 0;

	if (intStart !== start) {
		throw new RangeError("Invalid start index");
	}

	if (intLen !== length ||
		((intLen + start) >>> 0) !== (intLen + start)) {
		throw new RangeError("Invalid array length");
	}

	return [intStart, intLen];
}

function ArraySlice(array = [], start = 0, length) {
	if (!Array.isArray(array)) {
		throw new TypeError(String(array) + " is not an Array");
	}

	length = (length === undefined) ? array.length - start : length;

	[start, length] = validateLength(start, length)
	let proxy = new Proxy(array, handler);

	props.set(proxy, {
		array: array,
		length: length,
		start: start
	});

	return proxy;
}

let handler = {
	get(target, property, receiver) {
		// console.log("get intercepted", property);

		let p = props.get(receiver);

		if (typeof property !== "symbol" &&
		    Number.isInteger(+property) && +property >= 0) {

			let start = p.start;
			let index = start + (+property);
			return target[index];

		} else if (property === "length") {
			return p.length;
		}

		return Reflect.get(target, property, receiver);
	},

	set(target, property, value, receiver) {
		let p = props.get(receiver);

		if (property === "length") {
			let length = validateLength(p.start, value);
			p.length = length;
			return true;
		} else if (typeof property !== "symbol" &&
			Number.isInteger(+property) && +property >= 0) {
			property = p.start + (+property);
		}

		return Reflect.set(target, property, value, receiver);
	}
};

module.exports = ArraySlice;
//export default ArraySlice;
<|endoftext|>


<commit_before><commit_msg>Tweak some jsdoc<commit_after><|endoftext|>


<commit_before>import * as blockly_tools from "./blockly_tools.js";

const TYPE_PREFIX = "babel_";

const colors = {
	Program: 0,
	Identifier: 250,
	NumericLiteral: 150,
	StringLiteral: 150,
	Literal: 150,
	BinaryExpression: 60,
	CallExpression: 60,
  MemberExpression: 60,
  ExpressionStatement: 60,
  BlockStatement: 0,
  FunctionDeclaration: 100
}

// Set some hardcoded validator properties to use later
const initHardcodedValidators = () => {
  // MemverExpression.property can either be an expression or an identifier
  // This depends on the context and is not visible in NODE_FIELDS
  // So we hardcode it for now
  lpe_babel.types.NODE_FIELDS.MemberExpression.property.validate.oneOfNodeTypes = [
    "Expression",
    "Identifier"
  ];
}

const blockDefinitionFromNode = (node, nodetype) => {
	return {
		init: function() {

			// Always add one input with the title
			this.appendDummyInput()
				.appendField(nodetype);

			// Default settings
			if(typeof(colors[nodetype]) !== 'undefined') {
				this.setColour(colors[nodetype]);
			} else {
				this.setColour(20);
			}
			this.lpe_aliases = lpe_babel.types.ALIAS_KEYS[nodetype];

			blockly_tools.updateBlockConnections(this);
			//this.setInputsInline(true);

			// Catch literals (they don't have inputs)
			if(typeof(node) === 'undefined' || node.value) {
				const field_name = 'value';
				this.appendDummyInput(field_name)
					.appendField(field_name)
					.appendField(new Blockly.FieldTextInput(""), field_name);
			} else {
				// Go through the inputs
				for(const field_name in node) {
					const field = node[field_name];

					// Check if this is a chaining input
					if(!field.validate) {
						//console.log("Error: field can't be validated:");
						//console.log(field);
						return {};
					}

					if(field.validate.chainOf) {

						// Decide if this is a series of nodes or a limited selection of nodes
						if(field.validate.chainOf[0].type === 'array') {
							// This is a series of nodes
							this.appendStatementInput(field_name)
								.setCheck(null)
								.appendField(field_name);
						} else {
							// This is a list of possible values
							// Create a properly formatted list
							var possible_values = field.validate.chainOf[1].oneOf.map((value) => {
								return [value, value];
							});
							this.appendDummyInput()
								.appendField(new Blockly.FieldDropdown(possible_values), field_name);

						}

						//console.log(field.validate.chainOf)
					} else if (field.validate.oneOfNodeTypes) {
						this.appendValueInput(field_name)
							.setCheck(field.validate.oneOfNodeTypes/*null*/)
							.appendField(field_name);
					} else if (field.validate.type) {
						this.appendValueInput(field_name)
							.setCheck(field.validate.type/*null*/)
							.appendField(field_name);
					} else {
						this.appendDummyInput(field_name)
							.appendField(field_name)
							.appendField(new Blockly.FieldTextInput(""), field_name);
					}
				}
			}
		}
	}
}

const blockDefinitionForNodeType = (nodetype) => {
	return blockDefinitionFromNode(lpe_babel.types.NODE_FIELDS[nodetype], nodetype)
}

const createBlocksForAST = (ast, workspace) => {
	const parse_node = (node) => {

		const node_meta = lpe_babel.types.NODE_FIELDS[node.type];

		let block = workspace.newBlock(TYPE_PREFIX + node.type);
		block.babel_node = node;

		block.initSvg();
		block.render();

		if(typeof node_meta.value !== 'undefined') {
			block.getField("value").setValue(node.value);
		} else {
			// Go through the inputs
			for(const field_name in node_meta) {
				const field_meta = node_meta[field_name];

				// Check if this is a chaining input
				if(!field_meta.validate) {
					console.log("Error: field can't be validated:");
					console.log(field_meta);
					continue;
				}

				if(field_meta.validate.chainOf) {

					// Decide if this is a series of nodes or a limited selection of nodes
					if(field_meta.validate.chainOf[0].type === 'array') {

						let node_list = node[field_name];

						if(node_list && node_list.length > 0) {
							// Transform list to tree
							for(let i = node_list.length-1; i > 0; i--) {
								node_list[i-1].next = node_list[i];
								node_list.pop();
							}

							blockly_tools.setAsFirstStatement(parse_node(node_list[0]), block, field_name);
						}

					} else {
						block.getField(field_name).setValue(node[field_name]);
					}

					//console.log(field.validate.chainOf)
				} else if (field_meta.validate.oneOfNodeTypes) {
				  if(node[field_name]) {
					  blockly_tools.setAsInput(parse_node(node[field_name]), block, field_name)
				  }
				} else if (field_meta.validate.type) {
					if(node[field_name]) {
					  blockly_tools.setAsInput(parse_node(node[field_name]), block, field_name)
				  }
				} else {
					block.getField(field_name).setValue(node[field_name]);
				}
			}
		}

		if(node.next) {
			blockly_tools.setAsNext(parse_node(node.next), block)
		}

		return block;
	}

	return parse_node(ast.program);
}

const createBlocksForCode = (code, workspace) => {
  try {
	  const ast = lpe_babel.babylon.parse(code);
	  createBlocksForAST(ast, workspace);
  } catch (e) {
    console.error("LPE: Could not parse code");
    workspace.clear();
  }
}

// Returns the XML definition of the toolbox
const getToolboxDefinition = function() {
  initHardcodedValidators();

  const test_types = [
    'Program',
    'VariableDeclaration',
    'VariableDeclarator',
    'Identifier',
    'NumericLiteral',
    'StringLiteral',
    'Literal',
    'BinaryExpression',
    'CallExpression',
    'MemberExpression',
    'ExpressionStatement',
    'BlockStatement',
    'FunctionDeclaration'
  ];
  var toolbox = '<xml>';

  for(var i = 0; i < test_types.length; i++) {
      const type = test_types[i];
      const type_name = 'babel_' + type;
      Blockly.Blocks[type_name] = blockDefinitionForNodeType(type);
      toolbox += '  <block type="' + type_name + '"></block>';
  }

  toolbox += '</xml>';

  return toolbox;
}

export {
	blockDefinitionFromNode,
	blockDefinitionForNodeType,
	createBlocksForAST,
	createBlocksForCode,
	getToolboxDefinition
};<commit_msg>Added support for if/else<commit_after>import * as blockly_tools from "./blockly_tools.js";

const TYPE_PREFIX = "babel_";

const colors = {
	Program: 0,
	Identifier: 250,
	NumericLiteral: 150,
	StringLiteral: 150,
	Literal: 150,
	BinaryExpression: 60,
	CallExpression: 60,
  MemberExpression: 60,
  ExpressionStatement: 60,
  BlockStatement: 0,
  FunctionDeclaration: 100,
  IfStatement: 60
}

// Set some hardcoded validator properties to use later
const initHardcodedValidators = () => {
  // MemverExpression.property can either be an expression or an identifier
  // This depends on the context and is not visible in NODE_FIELDS
  // So we hardcode it for now
  lpe_babel.types.NODE_FIELDS.MemberExpression.property.validate.oneOfNodeTypes = [
    "Expression",
    "Identifier"
  ];
}

const blockDefinitionFromNode = (node, nodetype) => {
	return {
		init: function() {

			// Always add one input with the title
			this.appendDummyInput()
				.appendField(nodetype);

			// Default settings
			if(typeof(colors[nodetype]) !== 'undefined') {
				this.setColour(colors[nodetype]);
			} else {
				this.setColour(20);
			}
			this.lpe_aliases = lpe_babel.types.ALIAS_KEYS[nodetype];

			blockly_tools.updateBlockConnections(this);
			//this.setInputsInline(true);

			// Catch literals (they don't have inputs)
			if(typeof(node) === 'undefined' || node.value) {
				const field_name = 'value';
				this.appendDummyInput(field_name)
					.appendField(field_name)
					.appendField(new Blockly.FieldTextInput(""), field_name);
			} else {
				// Go through the inputs
				for(const field_name in node) {
					const field = node[field_name];

					// Check if this is a chaining input
					if(!field.validate) {
						//console.log("Error: field can't be validated:");
						//console.log(field);
						return {};
					}

					if(field.validate.chainOf) {

						// Decide if this is a series of nodes or a limited selection of nodes
						if(field.validate.chainOf[0].type === 'array') {
							// This is a series of nodes
							this.appendStatementInput(field_name)
								.setCheck(null)
								.appendField(field_name);
						} else {
							// This is a list of possible values
							// Create a properly formatted list
							var possible_values = field.validate.chainOf[1].oneOf.map((value) => {
								return [value, value];
							});
							this.appendDummyInput()
								.appendField(new Blockly.FieldDropdown(possible_values), field_name);

						}

						//console.log(field.validate.chainOf)
					} else if (field.validate.oneOfNodeTypes) {
						this.appendValueInput(field_name)
							.setCheck(field.validate.oneOfNodeTypes/*null*/)
							.appendField(field_name);
					} else if (field.validate.type) {
						this.appendValueInput(field_name)
							.setCheck(field.validate.type/*null*/)
							.appendField(field_name);
					} else {
						this.appendDummyInput(field_name)
							.appendField(field_name)
							.appendField(new Blockly.FieldTextInput(""), field_name);
					}
				}
			}
		}
	}
}

const blockDefinitionForNodeType = (nodetype) => {
	return blockDefinitionFromNode(lpe_babel.types.NODE_FIELDS[nodetype], nodetype)
}

const createBlocksForAST = (ast, workspace) => {
	const parse_node = (node) => {

		const node_meta = lpe_babel.types.NODE_FIELDS[node.type];

		let block = workspace.newBlock(TYPE_PREFIX + node.type);
		block.babel_node = node;

		block.initSvg();
		block.render();

		if(typeof node_meta.value !== 'undefined') {
			block.getField("value").setValue(node.value);
		} else {
			// Go through the inputs
			for(const field_name in node_meta) {
				const field_meta = node_meta[field_name];

				// Check if this is a chaining input
				if(!field_meta.validate) {
					console.log("Error: field can't be validated:");
					console.log(field_meta);
					continue;
				}

				if(field_meta.validate.chainOf) {

					// Decide if this is a series of nodes or a limited selection of nodes
					if(field_meta.validate.chainOf[0].type === 'array') {

						let node_list = node[field_name];

						if(node_list && node_list.length > 0) {
							// Transform list to tree
							for(let i = node_list.length-1; i > 0; i--) {
								node_list[i-1].next = node_list[i];
								node_list.pop();
							}

							blockly_tools.setAsFirstStatement(parse_node(node_list[0]), block, field_name);
						}

					} else {
						block.getField(field_name).setValue(node[field_name]);
					}

					//console.log(field.validate.chainOf)
				} else if (field_meta.validate.oneOfNodeTypes) {
				  if(node[field_name]) {
					  blockly_tools.setAsInput(parse_node(node[field_name]), block, field_name)
				  }
				} else if (field_meta.validate.type) {
					if(node[field_name]) {
					  blockly_tools.setAsInput(parse_node(node[field_name]), block, field_name)
				  }
				} else {
					block.getField(field_name).setValue(node[field_name]);
				}
			}
		}

		if(node.next) {
			blockly_tools.setAsNext(parse_node(node.next), block)
		}

		return block;
	}

	return parse_node(ast.program);
}

const createBlocksForCode = (code, workspace) => {
  try {
	  const ast = lpe_babel.babylon.parse(code);
	  createBlocksForAST(ast, workspace);
  } catch (e) {
    console.error("LPE: Could not parse code");
    workspace.clear();
  }
}

// Returns the XML definition of the toolbox
const getToolboxDefinition = function() {
  initHardcodedValidators();

  const test_types = [
    'Program',
    'VariableDeclaration',
    'VariableDeclarator',
    'Identifier',
    'NumericLiteral',
    'StringLiteral',
    'Literal',
    'BinaryExpression',
    'CallExpression',
    'MemberExpression',
    'ExpressionStatement',
    'BlockStatement',
    'FunctionDeclaration',
    'IfStatement'
  ];
  var toolbox = '<xml>';

  for(var i = 0; i < test_types.length; i++) {
      const type = test_types[i];
      const type_name = 'babel_' + type;
      Blockly.Blocks[type_name] = blockDefinitionForNodeType(type);
      toolbox += '  <block type="' + type_name + '"></block>';
  }

  toolbox += '</xml>';

  return toolbox;
}

export {
	blockDefinitionFromNode,
	blockDefinitionForNodeType,
	createBlocksForAST,
	createBlocksForCode,
	getToolboxDefinition
};<|endoftext|>


<commit_before>/*
 * Backchannel server allows workers to stream messages back to the Node server
 * in a line-buffered way. Uses SSL.
 */

var _ = require('underscore')
 , Job = require('./models').Job
 , async = require('async')
 , common = require('./common')
 , config = require('./config')
 , crypto = require('crypto')
 , email = require('./email')
 , filter = require('./ansi')
 , fs = require('fs')
 , logging = require('./logging')
 , qs = require('querystring')
 , request = require('request')
 , websockets = require('./websockets')
;

/*
 * fire_webhooks()
 *
 * For each Webhook in the list, send a HTTP POST - in parallel.
 *
 * <repo_config> Repo Config object with the Webhooks to fire.
 * <job> Job object for the task just completed.
 */
var fire_webhooks = exports.fire_webhooks = function(repo_config, job, callback)
{

  var requests = [];

  // Add a function for each webhook
  _.each(repo_config.webhooks, function(webhook) {

    requests.push(function() {
      var body = {
        payload:JSON.stringify(
          {
            test_results: {
                start_time: job.created_timestamp
              , repo_url: repo_config.url
              , finish_time: job.finished_timestamp
              , test_exitcode: job.test_exitcode
              , deploy_exitcode: job.deploy_exitcode
              , github_commit_id: job.github_commit_info.id
            }
          })
      };
      var hmac = crypto.createHmac('sha1', webhook.secret);
      hmac.update(qs.stringify(body).toString('utf8'));
      var signature = "sha1="+hmac.digest('hex');

      console.log("Firing webhook: %s", webhook.url);
      request({
        method: "POST",
        headers:{"x-hub-signature": signature},
        form: body,
        uri: webhook.url
      }, function(e, r, b) {
        if (callback !== undefined) {
          callback(null, {e:e, b:b, r:r});
        }
      });

    });

  });

  // Run them all in parallel
  // XXX could be dangerous if there are too many
  if (requests.length > 10) {
    console.log("Warning: More %s Webhooks fired for user %s", jobs.length, user.email);
  }

  async.parallel(requests, callback);
};

/*
 * send_email()
 *
 * Send email notifications upon job completion.
 *
 * <repo_config> - Repository config object.
 * <job> - Job object.
 */
function send_email(repo_config, job)
{
  if (parseInt(job.test_exitcode, 10) === 0) {
    email.send_test_ok(job, repo_config);
  } else {
    email.send_test_fail(job, repo_config);
  }
}

/*
 * Handle individual backchannel messages
 */
function handle_message(msg)
{
  switch (msg.msg_type) {
    case 'status':
      websockets.user_msg(msg.user_id, 'update', {msg: filter(msg.stderr + msg.stdout),
        time_elapsed: msg.time_elapsed, repo_url:msg.repo_url });
      break;

    case 'done':
      Job.findOne({_id: msg.job_id}).populate('_owner').exec(function (err, job) {
        if (err) throw err;

        job.deploy_exitcode = msg.deployExitcode;
        job.test_exitcode = msg.testExitcode;
        job.finished_timestamp = new Date();
        // XXX Yeah, this isn't the best for performance, but optimize for
        // simplicity at the moment. We can incrementally stream these to S3
        // directly from Worker at some point.
        job.stderr = msg.stderr;
        job.stdout = msg.stdout;
        job.stdmerged = msg.stdmerged;
        job._owner.get_repo_config(job.repo_url, function(err, repo_config) {
          // If there is an auto-detect result, save it
          if (msg.autodetect_result !== null) {
            repo_config.project_type = msg.autodetectResult;
            job._owner.save();
          }
          if (repo_config.webhooks !== undefined) {
            fire_webhooks(repo_config, job);
          }
          // Send email if email notifications are not turned off for this repository.
          if (repo_config.email_notifications !== false) {
            send_email(repo_config, job);
          }
          websockets.user_msg(msg.user_id, 'done',
            {job_type: job.type, repo_url:msg.repo_url, test_exitcode: msg.test_exitcode, deploy_exitcode: msg.deploy_exitcode});
          job.save()
        });
      });
      break;
  }
}

exports.init = function()
{

  common.emitter.on('queue.job_update', function(msg) {
    websockets.user_msg(msg.userId, 'update', {msg: filter(msg.stderr + msg.stdout),
      time_elapsed: msg.timeElapsed, repo_url:msg.repoUrl });
  })

  common.emitter.on('queue.job_complete', function(msg) {
    websockets.user_msg(msg.userId, 'update', {msg: filter(msg.stderr + msg.stdout),
      time_elapsed: msg.timeElapsed, repo_url:msg.repoUrl });
    Job.findOne({_id: msg.jobId}).populate('_owner').exec(function (err, job) {
      if (err) throw err;

      job.deploy_exitcode = msg.deployExitCode;
      job.test_exitcode = msg.testExitCode;
      job.finished_timestamp = new Date();
      // XXX Yeah, this isn't the best for performance, but optimize for
      // simplicity at the moment. We can incrementally stream these to S3
      // directly from Worker at some point.
      job.stderr = msg.stderr;
      job.stdout = msg.stdout;
      job.stdmerged = msg.stdmerged;
      job._owner.get_repo_config(job.repo_url, function(err, repo_config) {
        // If there is an auto-detect result, save it
        if (msg.autodetectResult !== null) {
          repo_config.project_type = msg.autodetectResult;
          job._owner.save();
        }
        if (repo_config.webhooks !== undefined) {
          fire_webhooks(repo_config, job);
        }
        // Send email if email notifications are not turned off for this repository.
        if (repo_config.email_notifications !== false) {
          send_email(repo_config, job);
        }
        websockets.user_msg(msg.userId, 'done',
          {job_type: job.type, repo_url:msg.repoUrl, test_exitcode: msg.testExitCode, deploy_exitcode: msg.deployExitCode});
        job.save();
      });
    });
  })

};
<commit_msg>zap unused handle_message function<commit_after>/*
 * Backchannel server allows workers to stream messages back to the Node server
 * in a line-buffered way. Uses SSL.
 */

var _ = require('underscore')
 , Job = require('./models').Job
 , async = require('async')
 , common = require('./common')
 , config = require('./config')
 , crypto = require('crypto')
 , email = require('./email')
 , filter = require('./ansi')
 , fs = require('fs')
 , logging = require('./logging')
 , qs = require('querystring')
 , request = require('request')
 , websockets = require('./websockets')
;

/*
 * fire_webhooks()
 *
 * For each Webhook in the list, send a HTTP POST - in parallel.
 *
 * <repo_config> Repo Config object with the Webhooks to fire.
 * <job> Job object for the task just completed.
 */
var fire_webhooks = exports.fire_webhooks = function(repo_config, job, callback)
{

  var requests = [];

  // Add a function for each webhook
  _.each(repo_config.webhooks, function(webhook) {

    requests.push(function() {
      var body = {
        payload:JSON.stringify(
          {
            test_results: {
                start_time: job.created_timestamp
              , repo_url: repo_config.url
              , finish_time: job.finished_timestamp
              , test_exitcode: job.test_exitcode
              , deploy_exitcode: job.deploy_exitcode
              , github_commit_id: job.github_commit_info.id
            }
          })
      };
      var hmac = crypto.createHmac('sha1', webhook.secret);
      hmac.update(qs.stringify(body).toString('utf8'));
      var signature = "sha1="+hmac.digest('hex');

      console.log("Firing webhook: %s", webhook.url);
      request({
        method: "POST",
        headers:{"x-hub-signature": signature},
        form: body,
        uri: webhook.url
      }, function(e, r, b) {
        if (callback !== undefined) {
          callback(null, {e:e, b:b, r:r});
        }
      });

    });

  });

  // Run them all in parallel
  // XXX could be dangerous if there are too many
  if (requests.length > 10) {
    console.log("Warning: More %s Webhooks fired for user %s", jobs.length, user.email);
  }

  async.parallel(requests, callback);
};

/*
 * send_email()
 *
 * Send email notifications upon job completion.
 *
 * <repo_config> - Repository config object.
 * <job> - Job object.
 */
function send_email(repo_config, job)
{
  if (parseInt(job.test_exitcode, 10) === 0) {
    email.send_test_ok(job, repo_config);
  } else {
    email.send_test_fail(job, repo_config);
  }
}

exports.init = function()
{

  common.emitter.on('queue.job_update', function(msg) {
    websockets.user_msg(msg.userId, 'update', {msg: filter(msg.stderr + msg.stdout),
      time_elapsed: msg.timeElapsed, repo_url:msg.repoUrl });
  })

  common.emitter.on('queue.job_complete', function(msg) {
    websockets.user_msg(msg.userId, 'update', {msg: filter(msg.stderr + msg.stdout),
      time_elapsed: msg.timeElapsed, repo_url:msg.repoUrl });
    Job.findOne({_id: msg.jobId}).populate('_owner').exec(function (err, job) {
      if (err) throw err;

      job.deploy_exitcode = msg.deployExitCode;
      job.test_exitcode = msg.testExitCode;
      job.finished_timestamp = new Date();
      // XXX Yeah, this isn't the best for performance, but optimize for
      // simplicity at the moment. We can incrementally stream these to S3
      // directly from Worker at some point.
      job.stderr = msg.stderr;
      job.stdout = msg.stdout;
      job.stdmerged = msg.stdmerged;
      job._owner.get_repo_config(job.repo_url, function(err, repo_config) {
        // If there is an auto-detect result, save it
        if (msg.autodetectResult !== null) {
          repo_config.project_type = msg.autodetectResult;
          job._owner.save();
        }
        if (repo_config.webhooks !== undefined) {
          fire_webhooks(repo_config, job);
        }
        // Send email if email notifications are not turned off for this repository.
        if (repo_config.email_notifications !== false) {
          send_email(repo_config, job);
        }
        websockets.user_msg(msg.userId, 'done',
          {job_type: job.type, repo_url:msg.repoUrl, test_exitcode: msg.testExitCode, deploy_exitcode: msg.deployExitCode});
        job.save();
      });
    });
  })

};
<|endoftext|>


<commit_before>/**
 * @file MaterialTimePicker component
 * @author sunday(sunday.wei@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import classNames from 'classnames';

import MaterialDatePickerTextField from '../_MaterialDatePickerTextField';
import TimeList from '../_TimeList';
import Popup from '../Popup';
import Theme from '../Theme';

import Position from '../_statics/Position';

import Util from '../_vendors/Util';

class MaterialTimePicker extends Component {

    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.validValue = true;

        this.state = {
            textFieldValue: props.value,
            popupVisible: false,
            hour: moment().format('HH'),
            minute: moment().format('mm'),
            second: moment().format('ss'),
            triggerEl: null
        };

        this.textFieldChangeHandle = ::this.textFieldChangeHandle;
        this.togglePopup = ::this.togglePopup;
        this.closePopup = ::this.closePopup;
        this.timePickerChangeHandle = ::this.timePickerChangeHandle;

    }

    rangeData(range) {
        let arr = [];
        for (let i = 0; i < range; i++) {
            if (i < 10) {
                i = '0' + i;
            }
            arr.push({text: i, value: true});
        }
        return arr;
    }

    textFieldChangeHandle(text) {
        if (text && text.length) {
            let validDate = '1970-01-01 ' + text;
            let validFormat = 'YYYY-MM-DD ' + this.props.dateFormat;
            const flag = moment(validDate, validFormat, true).isValid();
            if (flag) {
                const hour = moment(validDate).format('HH'),
                    minute = moment(validDate).format('mm'),
                    second = moment(validDate).format('ss');
                this.setState({
                    textFieldValue: text,
                    hour: hour,
                    minute: minute,
                    second: second
                });
            }
        } else {
            this.setState({
                textFieldValue: text
            });
        }
    }

    timePickerChangeHandle(obj) {
        let timer = obj.hour + ':' + obj.minute + ':' + obj.second;
        let validDate = '1970-01-01 ' + timer;
        timer = moment(validDate).format(this.props.dateFormat);
        this.setState({
            hour: obj.hour,
            minute: obj.minute,
            second: obj.second,
            textFieldValue: timer
        });
    }

    togglePopup(e) {
        if (this.validValue) {
            this.setState({
                popupVisible: !this.state.popupVisible,
                triggerEl: e.target
            });
        }
    }

    closePopup() {
        const {textFieldValue} = this.state;
        !this.props.disabled && this.setState({
            popupVisible: false
        }, () => {
            this.props.onChange && this.props.onChange(textFieldValue);
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.props.value || nextProps.dateFormat !== this.props.dateFormat) {
            const value = Util.value2Moment(nextProps.value, nextProps.dateFormat);
            this.setState({
                value,
                textFieldValue: value.format(nextProps.dateFormat)
            });
        }
    }

    componentDidMount() {
        const {value} = this.props;
        let dateFormatValue = '2000-02-01 ' + value;
        if (value) {
            if (moment(dateFormatValue, 'YYYY-MM-DD HH:mm:ss').isValid()) {
                this.setState({
                    textFieldValue: value,
                    hour: moment(dateFormatValue).format('HH'),
                    minute: moment(dateFormatValue).format('mm'),
                    second: moment(dateFormatValue).format('ss')
                });
            } else {
                this.validValue = false;
                console.error('Invalid date');
            }
        }
    }

    render() {

        const {className, style, name, placeholder, maxValue, minValue, dateFormat, label, isLabelAnimate, position, theme} = this.props,
            {popupVisible, textFieldValue, hour, minute, second, triggerEl} = this.state,

            pickerClassName = classNames('material-time-picker', {
                [className]: className
            });

        return (

                <MaterialDatePickerTextField ref="trigger"
                                             className="time-picker-field"
                                             name={name}
                                             label={label}
                                             theme={theme}
                                             isLabelAnimate={isLabelAnimate}
                                             placeholder={placeholder}
                                             value={textFieldValue}
                                             readOnly={!popupVisible}
                                             clearButtonVisible={false}
                                             isFocusedSelectAll={false}
                                             popupVisible={popupVisible}
                                             onChange={this.textFieldChangeHandle}
                                             onClick={e => {
                                                 this.togglePopup(e);
                                             }}/>

                <Popup className="material-time-picker-popup"
                       visible={popupVisible}
                       triggerEl={triggerEl}
                       position={position}
                       hasTriangle={false}
                       onRequestClose={() => {
                           this.closePopup();
                       }}>
                    <TimeList hour={hour}
                              minute={minute}
                              second={second}
                              maxValue={maxValue}
                              minValue={minValue}
                              isRequired={true}
                              dateFormat={dateFormat}
                              popupVisible={popupVisible}
                              onChange={this.timePickerChangeHandle}/>
                </Popup>

        );
    }
}

MaterialTimePicker.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * MaterialTimePicker input name.
     */
    name: PropTypes.string,

    /**
     * The label of the MaterialTimePicker.
     */
    label: PropTypes.any,

    /**
     * The animate of the MaterialTimePicker.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * This is the initial date value of the component.
     */
    value: PropTypes.string,

    /**
     * The ending of a range of valid dates. The range includes the endDate.
     */
    maxValue: PropTypes.string,

    /**
     * The beginning of a range of valid dates. The range includes the startDate.
     */
    minValue: PropTypes.string,

    /**
     * MaterialTimePicker textField element placeholder.
     */
    placeholder: PropTypes.string,

    /**
     * Time format.
     */
    dateFormat: PropTypes.string

};

MaterialTimePicker.defaultProps = {
    name: '',
    value: moment().format('HH:mm:ss'),
    placeholder: 'Time',
    dateFormat: 'HH:mm:ss',
    position: Position.BOTTOM_LEFT
};

export default MaterialTimePicker;<commit_msg>update MaterialTimePicker<commit_after>/**
 * @file MaterialTimePicker component
 * @author sunday(sunday.wei@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import classNames from 'classnames';

import MaterialDatePickerTextField from '../_MaterialDatePickerTextField';
import TimeList from '../_TimeList';
import Popup from '../Popup';
import Theme from '../Theme';

import Position from '../_statics/Position';

import Util from '../_vendors/Util';

class MaterialTimePicker extends Component {

    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.validValue = true;

        this.state = {
            textFieldValue: props.value,
            popupVisible: false,
            hour: moment().format('HH'),
            minute: moment().format('mm'),
            second: moment().format('ss'),
            triggerEl: null
        };

    }

    rangeData = range => {
        let arr = [];
        for (let i = 0; i < range; i++) {
            if (i < 10) {
                i = '0' + i;
            }
            arr.push({text: i, value: true});
        }
        return arr;
    };

    textFieldChangeHandle = text => {
        if (text && text.length) {
            let validDate = '1970-01-01 ' + text;
            let validFormat = 'YYYY-MM-DD ' + this.props.dateFormat;
            const flag = moment(validDate, validFormat, true).isValid();
            if (flag) {
                const hour = moment(validDate).format('HH'),
                    minute = moment(validDate).format('mm'),
                    second = moment(validDate).format('ss');
                this.setState({
                    textFieldValue: text,
                    hour: hour,
                    minute: minute,
                    second: second
                });
            }
        } else {
            this.setState({
                textFieldValue: text
            });
        }
    };

    timePickerChangeHandle = obj => {
        let timer = obj.hour + ':' + obj.minute + ':' + obj.second;
        let validDate = '1970-01-01 ' + timer;
        timer = moment(validDate).format(this.props.dateFormat);
        this.setState({
            hour: obj.hour,
            minute: obj.minute,
            second: obj.second,
            textFieldValue: timer
        });
    };

    togglePopup = e => {
        if (this.validValue) {
            this.setState({
                popupVisible: !this.state.popupVisible,
                triggerEl: e.target
            });
        }
    };

    closePopup = () => {
        const {textFieldValue} = this.state;
        !this.props.disabled && this.setState({
            popupVisible: false
        }, () => {
            this.props.onChange && this.props.onChange(textFieldValue);
        });
    };

    componentDidMount() {
        const {value} = this.props;
        let dateFormatValue = '2000-02-01 ' + value;
        if (value) {
            if (moment(dateFormatValue, 'YYYY-MM-DD HH:mm:ss').isValid()) {
                this.setState({
                    textFieldValue: value,
                    hour: moment(dateFormatValue).format('HH'),
                    minute: moment(dateFormatValue).format('mm'),
                    second: moment(dateFormatValue).format('ss')
                });
            } else {
                this.validValue = false;
                console.error('Invalid date');
            }
        }
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.props.value || nextProps.dateFormat !== this.props.dateFormat) {
            const value = Util.value2Moment(nextProps.value, nextProps.dateFormat);
            this.setState({
                value,
                textFieldValue: value.format(nextProps.dateFormat)
            });
        }
    }

    render() {

        const {className, style, name, placeholder, maxValue, minValue, dateFormat, label, isLabelAnimate, position, theme} = this.props,
            {popupVisible, textFieldValue, hour, minute, second, triggerEl} = this.state,

            pickerClassName = classNames('material-time-picker', {
                [className]: className
            });

        return (

                <MaterialDatePickerTextField ref="trigger"
                                             className="time-picker-field"
                                             name={name}
                                             label={label}
                                             theme={theme}
                                             isLabelAnimate={isLabelAnimate}
                                             placeholder={placeholder}
                                             value={textFieldValue}
                                             readOnly={!popupVisible}
                                             clearButtonVisible={false}
                                             isFocusedSelectAll={false}
                                             popupVisible={popupVisible}
                                             onChange={this.textFieldChangeHandle}
                                             onClick={e => {
                                                 this.togglePopup(e);
                                             }}/>

                <Popup className="material-time-picker-popup"
                       visible={popupVisible}
                       triggerEl={triggerEl}
                       position={position}
                       hasTriangle={false}
                       onRequestClose={() => {
                           this.closePopup();
                       }}>
                    <TimeList hour={hour}
                              minute={minute}
                              second={second}
                              maxValue={maxValue}
                              minValue={minValue}
                              isRequired={true}
                              dateFormat={dateFormat}
                              popupVisible={popupVisible}
                              onChange={this.timePickerChangeHandle}/>
                </Popup>

        );
    }
}

MaterialTimePicker.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * MaterialTimePicker input name.
     */
    name: PropTypes.string,

    /**
     * The label of the MaterialTimePicker.
     */
    label: PropTypes.any,

    /**
     * The animate of the MaterialTimePicker.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * This is the initial date value of the component.
     */
    value: PropTypes.string,

    /**
     * The ending of a range of valid dates. The range includes the endDate.
     */
    maxValue: PropTypes.string,

    /**
     * The beginning of a range of valid dates. The range includes the startDate.
     */
    minValue: PropTypes.string,

    /**
     * MaterialTimePicker textField element placeholder.
     */
    placeholder: PropTypes.string,

    /**
     * Time format.
     */
    dateFormat: PropTypes.string

};

MaterialTimePicker.defaultProps = {
    name: '',
    value: moment().format('HH:mm:ss'),
    placeholder: 'Time',
    dateFormat: 'HH:mm:ss',
    position: Position.BOTTOM_LEFT
};

export default MaterialTimePicker;<|endoftext|>


<commit_before>import CoreCombatLogParser from 'Parser/Core/CombatLogParser';
import AbilityTracker from 'Parser/Core/Modules/AbilityTracker';
import HealingDone from 'Parser/Core/Modules/HealingDone';
import DamageDone from 'Parser/Core/Modules/DamageDone';
import DamageTaken from 'Parser/Core/Modules/DamageTaken';

import ActiveTargets from './Modules/Features/ActiveTargets';
import Abilities from './Modules/Features/Abilities';
import Gore from './Modules/Features/Gore';
import GalacticGuardian from './Modules/Features/GalacticGuardian';
import GuardianOfElune from './Modules/Features/GuardianOfElune';
import IronFurGoEProcs from './Modules/Features/IronFurGoEProcs';
import FrenziedRegenGoEProcs from './Modules/Features/FrenziedRegenGoEProcs';
import RageWasted from './Modules/Features/RageWasted';
import AntiFillerSpam from './Modules/Features/AntiFillerSpam';

import IronFur from './Modules/Spells/IronFur';
import Thrash from './Modules/Spells/Thrash';
import Moonfire from './Modules/Spells/Moonfire';
import Pulverize from './Modules/Spells/Pulverize';
import Earthwarden from './Modules/Talents/Earthwarden';
import Incarnation from './Modules/Talents/Incarnation';
import FrenziedRegeneration from './Modules/Spells/FrenziedRegeneration';

import SkysecsHold from './Modules/Items/Skysecs';
import LuffaWrappings from './Modules/Items/LuffaWrappings';
import FuryOfNature from './Modules/Items/FuryOfNature';

import Tier21_2P from './Modules/Sets/Tier21_2P';
import Tier21_4P from './Modules/Sets/Tier21_4P';

import AlwaysBeCasting from './Modules/Features/AlwaysBeCasting';

class CombatLogParser extends CoreCombatLogParser {
  static specModules = {
    // Core
    damageTaken: [DamageTaken, { showStatistic: true }],
    healingDone: [HealingDone, { showStatistic: true }],
    damageDone: [DamageDone, { showStatistic: true }],
    abilityTracker: AbilityTracker,

    // Features
    activeTargets: ActiveTargets,
    abilities: Abilities,
    goreProcs: Gore,
    galacticGuardianProcs: GalacticGuardian,
    guardianOfEluneProcs: GuardianOfElune,
    ironFurGoEProcs: IronFurGoEProcs,
    frenziedRegenGoEProcs: FrenziedRegenGoEProcs,
    rageWasted: RageWasted,
    antiFillerSpam: AntiFillerSpam,

    ironFur: IronFur,
    thrash: Thrash,
    moonfire: Moonfire,
    pulverize: Pulverize,
    frenziedRegeneration: FrenziedRegeneration,

    // Talents:
    earthwarden: Earthwarden,
    incarnation: Incarnation,

    // Legendaries:
    skysecs: SkysecsHold,
    luffaWrappings: LuffaWrappings,
    furyOfNature: FuryOfNature,

    // Sets
    tier21_2p: Tier21_2P,
    tier21_4p: Tier21_4P,
  };
}

export default CombatLogParser;
<commit_msg>Oops I fucked up the merge<commit_after>import CoreCombatLogParser from 'Parser/Core/CombatLogParser';
import AbilityTracker from 'Parser/Core/Modules/AbilityTracker';
import HealingDone from 'Parser/Core/Modules/HealingDone';
import DamageDone from 'Parser/Core/Modules/DamageDone';
import DamageTaken from 'Parser/Core/Modules/DamageTaken';

import ActiveTargets from './Modules/Features/ActiveTargets';
import Abilities from './Modules/Features/Abilities';
import Gore from './Modules/Features/Gore';
import GalacticGuardian from './Modules/Features/GalacticGuardian';
import GuardianOfElune from './Modules/Features/GuardianOfElune';
import IronFurGoEProcs from './Modules/Features/IronFurGoEProcs';
import FrenziedRegenGoEProcs from './Modules/Features/FrenziedRegenGoEProcs';
import RageWasted from './Modules/Features/RageWasted';
import AntiFillerSpam from './Modules/Features/AntiFillerSpam';

import IronFur from './Modules/Spells/IronFur';
import Thrash from './Modules/Spells/Thrash';
import Moonfire from './Modules/Spells/Moonfire';
import Pulverize from './Modules/Spells/Pulverize';
import Earthwarden from './Modules/Talents/Earthwarden';
import Incarnation from './Modules/Talents/Incarnation';
import FrenziedRegeneration from './Modules/Spells/FrenziedRegeneration';

import SkysecsHold from './Modules/Items/Skysecs';
import LuffaWrappings from './Modules/Items/LuffaWrappings';
import FuryOfNature from './Modules/Items/FuryOfNature';

import Tier21_2P from './Modules/Sets/Tier21_2P';
import Tier21_4P from './Modules/Sets/Tier21_4P';

class CombatLogParser extends CoreCombatLogParser {
  static specModules = {
    // Core
    damageTaken: [DamageTaken, { showStatistic: true }],
    healingDone: [HealingDone, { showStatistic: true }],
    damageDone: [DamageDone, { showStatistic: true }],
    abilityTracker: AbilityTracker,

    // Features
    activeTargets: ActiveTargets,
    abilities: Abilities,
    goreProcs: Gore,
    galacticGuardianProcs: GalacticGuardian,
    guardianOfEluneProcs: GuardianOfElune,
    ironFurGoEProcs: IronFurGoEProcs,
    frenziedRegenGoEProcs: FrenziedRegenGoEProcs,
    rageWasted: RageWasted,
    antiFillerSpam: AntiFillerSpam,

    ironFur: IronFur,
    thrash: Thrash,
    moonfire: Moonfire,
    pulverize: Pulverize,
    frenziedRegeneration: FrenziedRegeneration,

    // Talents:
    earthwarden: Earthwarden,
    incarnation: Incarnation,

    // Legendaries:
    skysecs: SkysecsHold,
    luffaWrappings: LuffaWrappings,
    furyOfNature: FuryOfNature,

    // Sets
    tier21_2p: Tier21_2P,
    tier21_4p: Tier21_4P,
  };
}

export default CombatLogParser;
<|endoftext|>


<commit_before>/*
 * Increase version number
 *
 * grunt bump
 * grunt bump:git
 * grunt bump:patch
 * grunt bump:minor
 * grunt bump:major
 *
 * @author Vojta Jina <vojta.jina@gmail.com>
 * @author Mathias Paumgarten <mail@mathias-paumgarten.com>
 * @author Adam Biggs <email@adambig.gs>
 */
var semver = require('semver');
var exec = require('child_process').exec;

module.exports = function(grunt) {

  var DESC = 'Increment the version, commit, tag and push.';
  grunt.registerTask('bump', DESC, function(versionType, incOrCommitOnly) {
    var opts = this.options({
      bumpVersion: true,
      files: ['package.json'],
      updateConfigs: [], // array of config properties to update (with files)
      commit: true,
      commitMessage: 'Release v%VERSION%',
      commitFiles: ['package.json'], // '-a' for all files
      createTag: true,
      tagName: 'v%VERSION%',
      tagMessage: 'Version %VERSION%',
      push: true,
      pushTo: 'upstream',
      gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
    });

    if (incOrCommitOnly === 'bump-only') {
      grunt.verbose.writeln('Only incrementing the version.');

      opts.commit = false;
      opts.createTag = false;
      opts.push = false;
    }

    if (incOrCommitOnly === 'commit-only') {
      grunt.verbose.writeln('Only commiting/taggin/pushing.');

      opts.bumpVersion = false;
    }

    var done = this.async();
    var queue = [];
    var next = function() {
      if (!queue.length) {
        return done();
      }
      queue.shift()();
    };
    var runIf = function(condition, behavior) {
      if (condition) {
        queue.push(behavior);
      }
    };

    var globalVersion; // when bumping multiple files
    var gitVersion;    // when bumping using `git describe`
    var VERSION_REGEXP = /([\'|\"]version[\'|\"][ ]*:[ ]*[\'|\"])([\d||A-a|.|-]*)([\'|\"])/i;

    // GET VERSION FROM GIT
    runIf(opts.bumpVersion && versionType === 'git', function(){
      exec('git describe ' + opts.gitDescribeOptions, function(err, stdout, stderr){
        if (err) {
          grunt.fatal('Can not get a version number using `git describe`');
        }
        gitVersion = stdout.trim();
        next();
      });
    });

    // BUMP ALL FILES
    runIf(opts.bumpVersion, function(){
      opts.files.forEach(function(file, idx) {
        var version = null;
        var content = grunt.file.read(file).replace(VERSION_REGEXP, function(match, prefix, parsedVersion, suffix) {
          version = gitVersion || semver.inc(parsedVersion, versionType || 'patch');
          return prefix + version + suffix;
        });

        if (!version) {
          grunt.fatal('Can not find a version to bump in ' + file);
        }

        grunt.file.write(file, content);
        grunt.log.ok('Version bumped to ' + version + (opts.files.length > 1 ? ' (in ' + file + ')' : ''));

        if (!globalVersion) {
          globalVersion = version;
        } else if (globalVersion !== version) {
          grunt.warn('Bumping multiple files with different versions!');
        }

        var configProperty = opts.updateConfigs[idx];
        if (!configProperty) {
          return;
        }

        var cfg = grunt.config(configProperty);
        if (!cfg) {
          return grunt.warn('Can not update "' + configProperty + '" config, it does not exist!');
        }

        cfg.version = version;
        grunt.config(configProperty, cfg);
        grunt.log.ok(configProperty + '\'s version updated');
      });
      next();
    });

    // COMMIT
    runIf(opts.commit, function() {
      var commitMessage = opts.commitMessage.replace('%VERSION%', globalVersion);

      exec('git commit ' + opts.commitFiles.join(' ') + ' -m "' + commitMessage + '"', function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not create the commit:\n  ' + stderr);
        }
        grunt.log.ok('Committed as "' + commitMessage + '"');
        next();
      });
    });

    // CREATE TAG
    runIf(opts.createTag, function() {
      var tagName = opts.tagName.replace('%VERSION%', globalVersion);
      var tagMessage = opts.tagMessage.replace('%VERSION%', globalVersion);

      exec('git tag -a ' + tagName + ' -m "' + tagMessage + '"' , function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not create the tag:\n  ' + stderr);
        }
        grunt.log.ok('Tagged as "' + tagName + '"');
        next();
      });
    });

    // PUSH CHANGES
    runIf(opts.push, function() {
      exec('git push ' + opts.pushTo + ' && git push ' + opts.pushTo + ' --tags', function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not push to ' + opts.pushTo + ':\n  ' + stderr);
        }
        grunt.log.ok('Pushed to ' + opts.pushTo);
        next();
      });
    });

    next();
  });

  // ALIASES
  DESC = 'Increment the version only.';
  grunt.registerTask('bump-only', DESC, function(versionType) {
    grunt.task.run('bump:' + (versionType || '') + ':bump-only');
  });

  DESC = 'Commit, tag, push without incrementing the version.';
  grunt.registerTask('bump-commit', DESC, 'bump::commit-only');
};

<commit_msg>fix: read the version if only commiting<commit_after>/*
 * Increase version number
 *
 * grunt bump
 * grunt bump:git
 * grunt bump:patch
 * grunt bump:minor
 * grunt bump:major
 *
 * @author Vojta Jina <vojta.jina@gmail.com>
 * @author Mathias Paumgarten <mail@mathias-paumgarten.com>
 * @author Adam Biggs <email@adambig.gs>
 */
var semver = require('semver');
var exec = require('child_process').exec;

module.exports = function(grunt) {

  var DESC = 'Increment the version, commit, tag and push.';
  grunt.registerTask('bump', DESC, function(versionType, incOrCommitOnly) {
    var opts = this.options({
      bumpVersion: true,
      files: ['package.json'],
      updateConfigs: [], // array of config properties to update (with files)
      commit: true,
      commitMessage: 'Release v%VERSION%',
      commitFiles: ['package.json'], // '-a' for all files
      createTag: true,
      tagName: 'v%VERSION%',
      tagMessage: 'Version %VERSION%',
      push: true,
      pushTo: 'upstream',
      gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
    });

    if (incOrCommitOnly === 'bump-only') {
      grunt.verbose.writeln('Only incrementing the version.');

      opts.commit = false;
      opts.createTag = false;
      opts.push = false;
    }

    if (incOrCommitOnly === 'commit-only') {
      grunt.verbose.writeln('Only commiting/taggin/pushing.');

      opts.bumpVersion = false;
    }

    var done = this.async();
    var queue = [];
    var next = function() {
      if (!queue.length) {
        return done();
      }
      queue.shift()();
    };
    var runIf = function(condition, behavior) {
      if (condition) {
        queue.push(behavior);
      }
    };

    var globalVersion; // when bumping multiple files
    var gitVersion;    // when bumping using `git describe`
    var VERSION_REGEXP = /([\'|\"]version[\'|\"][ ]*:[ ]*[\'|\"])([\d||A-a|.|-]*)([\'|\"])/i;

    // GET VERSION FROM GIT
    runIf(opts.bumpVersion && versionType === 'git', function(){
      exec('git describe ' + opts.gitDescribeOptions, function(err, stdout, stderr){
        if (err) {
          grunt.fatal('Can not get a version number using `git describe`');
        }
        gitVersion = stdout.trim();
        next();
      });
    });

    // BUMP ALL FILES
    runIf(opts.bumpVersion, function(){
      opts.files.forEach(function(file, idx) {
        var version = null;
        var content = grunt.file.read(file).replace(VERSION_REGEXP, function(match, prefix, parsedVersion, suffix) {
          version = gitVersion || semver.inc(parsedVersion, versionType || 'patch');
          return prefix + version + suffix;
        });

        if (!version) {
          grunt.fatal('Can not find a version to bump in ' + file);
        }

        grunt.file.write(file, content);
        grunt.log.ok('Version bumped to ' + version + (opts.files.length > 1 ? ' (in ' + file + ')' : ''));

        if (!globalVersion) {
          globalVersion = version;
        } else if (globalVersion !== version) {
          grunt.warn('Bumping multiple files with different versions!');
        }

        var configProperty = opts.updateConfigs[idx];
        if (!configProperty) {
          return;
        }

        var cfg = grunt.config(configProperty);
        if (!cfg) {
          return grunt.warn('Can not update "' + configProperty + '" config, it does not exist!');
        }

        cfg.version = version;
        grunt.config(configProperty, cfg);
        grunt.log.ok(configProperty + '\'s version updated');
      });
      next();
    });

    // when only commiting, read the version from package.json / pkg config
    runIf(!opts.bumpVersion, function() {
      if (opts.updateConfigs.length) {
        globalVersion = grunt.config(opts.updateConfigs[0]).version;
      } else {
        globalVersion = grunt.file.readJSON(opts.files[0]).version;
      }

      next();
    });

    // COMMIT
    runIf(opts.commit, function() {
      var commitMessage = opts.commitMessage.replace('%VERSION%', globalVersion);

      exec('git commit ' + opts.commitFiles.join(' ') + ' -m "' + commitMessage + '"', function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not create the commit:\n  ' + stderr);
        }
        grunt.log.ok('Committed as "' + commitMessage + '"');
        next();
      });
    });

    // CREATE TAG
    runIf(opts.createTag, function() {
      var tagName = opts.tagName.replace('%VERSION%', globalVersion);
      var tagMessage = opts.tagMessage.replace('%VERSION%', globalVersion);

      exec('git tag -a ' + tagName + ' -m "' + tagMessage + '"' , function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not create the tag:\n  ' + stderr);
        }
        grunt.log.ok('Tagged as "' + tagName + '"');
        next();
      });
    });

    // PUSH CHANGES
    runIf(opts.push, function() {
      exec('git push ' + opts.pushTo + ' && git push ' + opts.pushTo + ' --tags', function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not push to ' + opts.pushTo + ':\n  ' + stderr);
        }
        grunt.log.ok('Pushed to ' + opts.pushTo);
        next();
      });
    });

    next();
  });

  // ALIASES
  DESC = 'Increment the version only.';
  grunt.registerTask('bump-only', DESC, function(versionType) {
    grunt.task.run('bump:' + (versionType || '') + ':bump-only');
  });

  DESC = 'Commit, tag, push without incrementing the version.';
  grunt.registerTask('bump-commit', DESC, 'bump::commit-only');
};

<|endoftext|>


<commit_before>const gulp = require('gulp');
const gutil = require('gulp-util');
const pkg = require('../package.json');

gulp.task('help', () => {

    gutil.log('');
    gutil.log(gutil.colors.white('blender-gulp v' + pkg.version));
    gutil.log('');
    gutil.log(gutil.colors.black.bgCyan('Build tasks'));
    gutil.log(gutil.colors.green('gulp'), gutil.colors.yellow('[--production]'), ' compile [& minify] assets 📦');
    gutil.log(gutil.colors.green('gulp watch'), '          compile & watch for changes 👀');
    gutil.log(gutil.colors.green('gulp hot'), '            compile & assets from a hot reload server 🔥');
    gutil.log('');
    gutil.log(gutil.colors.black.bgCyan('Utilities'));
    gutil.log(gutil.colors.green('gulp favicon'), '        standalone utility for favicon generation 🌐');
    gutil.log('');
    gutil.log(gutil.colors.black.bgCyan('Linting'));
    gutil.log(gutil.colors.green('gulp lint:js'), '        lint your project\'s js files 🎀');
    gutil.log(gutil.colors.green('gulp lint:sass'), '      lint your project\'s sass files 🎀');
    gutil.log('');
});
<commit_msg>Updated help<commit_after>const gulp = require('gulp');
const gutil = require('gulp-util');
const pkg = require('../package.json');

gulp.task('help', () => {

    gutil.log('');
    gutil.log(gutil.colors.white('blender-gulp v' + pkg.version));
    gutil.log('');
    gutil.log(gutil.colors.black.bgCyan('Build tasks'));
    gutil.log(gutil.colors.green('gulp'), gutil.colors.yellow('[--production]'), ' compile [& minify] assets 📦');
    gutil.log(gutil.colors.green('gulp watch'), '          compile & watch for changes 👀');
    gutil.log(gutil.colors.green('gulp hot'), '            compile & assets from a hot reload server 🔥');
    gutil.log(gutil.colors.dim('gulp webpack'), '        run the `webpack` command',
        gutil.colors.dim('(included in the default task)'));
    gutil.log(gutil.colors.dim('gulp svg'), '            minify svg files',
        gutil.colors.dim('(included in the default task)'));
    gutil.log('');
    gutil.log('');
    gutil.log(gutil.colors.black.bgCyan('Utilities'));
    gutil.log(gutil.colors.green('gulp favicon'), '        standalone utility for favicon generation 🌐');
    gutil.log('');
    gutil.log(gutil.colors.black.bgCyan('Linting'));
    gutil.log(gutil.colors.green('gulp lint:js'), '        lint your project\'s js files 🎀');
    gutil.log(gutil.colors.green('gulp lint:sass'), '      lint your project\'s sass files 🎀');
    gutil.log('');
});
<|endoftext|>


<commit_before>/*
 * grunt-kissy-template
 * https://github.com/qipbbn/kissy-template
 *
 * Copyright (c) 2013 maxbbn
 * Licensed under the MIT license.
 */

'use strict';

var minify = require('html-minifier').minify;

module.exports = function (grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks
  var kissyModuleTemplate =
    "/**\n" +
      " * Generated By grunt-kissy-template\n" +
      " */\n" +
      "KISSY.add(function(){\n" +
      "    return <%= tpl %>;\n" +
      "});";

  grunt.registerMultiTask('ktpl', 'Your task description goes here.', function () {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      minify: false,
      minifyOption: {
        removeComments: true,
        removeCommentsFromCDATA: true,
        removeCDATASectionsFromCDATA: true,
        collapseWhitespace: true,
        collapseBooleanAttributes: true,
        removeAttributeQuotes: true,
        removeEmptyAttributes: true
      }
    });

    function kissy_template(src, dest) {

      var moduleJS = grunt.template.process(
        kissyModuleTemplate,
        {
          data: {
            tpl: JSON.stringify({
              html: src
            })
          }
        }
      );

      // Write the destination file.
      grunt.file.write(dest, moduleJS);

      // Print a success message.
      grunt.log.writeln('File "' + dest + '" created.');
    }

    // Iterate over all specified file groups.
    this.files.forEach(function (file) {
      // Concat specified files.
      if (file.dest) {
        //if has dest, concat all src files
        var src = file.src.filter(function (filepath) {
          // Warn on and remove invalid source files (if nonull was set).
          if (!grunt.file.exists(filepath)) {
            grunt.log.warn('Source file "' + filepath + '" not found.');
            return false;
          } else {
            return true;
          }
        }).map(function (filepath) {
            // Read file source.
            var content =  grunt.file.read(filepath);

            if (options.minify) {
              try {
                content = minify(content, options.minifyOption);
              } catch (e) {
                grunt.warn("Minify Error: " + filepath);
              }
            }

            return content;

          }).join(' ');

        kissy_template(src, file.dest);

      } else {
        //else each src html file to js file
        file.src.filter(function (filepath) {
          // Warn on and remove invalid source files (if nonull was set).
          if (!grunt.file.exists(filepath)) {
            grunt.log.warn('Source file "' + filepath + '" not found.');
            return false;
          } else {
            return true;
          }
        }).forEach(function(filepath){
            var content = grunt.file.read(filepath);
            if (options.minify) {
              try {
                content = minify(content, options.minifyOption);
              } catch (e) {
                grunt.warn("Minify Error: " + filepath);
              }
            }

            // extname to js
            var dest = filepath.replace(/\.([^.]*)$/, '.js');

            kissy_template(content, dest);

          });
      }
    });
  });

};
<commit_msg>换行符保持一致, fix #2<commit_after>/*
 * grunt-kissy-template
 * https://github.com/qipbbn/kissy-template
 *
 * Copyright (c) 2013 maxbbn
 * Licensed under the MIT license.
 */

'use strict';

var minify = require('html-minifier').minify;

module.exports = function (grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks
  var kissyModuleTemplate =
    "/**\n" +
      " * Generated By grunt-kissy-template\n" +
      " */\n" +
      "KISSY.add(function(){\n" +
      "    return <%= tpl %>;\n" +
      "});";

  grunt.registerMultiTask('ktpl', 'Your task description goes here.', function () {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      minify: false,
      minifyOption: {
        removeComments: true,
        removeCommentsFromCDATA: true,
        removeCDATASectionsFromCDATA: true,
        collapseWhitespace: true,
        collapseBooleanAttributes: true,
        removeAttributeQuotes: true,
        removeEmptyAttributes: true
      }
    });

    function kissy_template(src, dest) {
      src = src.replace(/\r\n/g, '\n');

      var moduleJS = grunt.template.process(
        kissyModuleTemplate,
        {
          data: {
            tpl: JSON.stringify({
              html: src
            })
          }
        }
      );

      // Write the destination file.
      grunt.file.write(dest, moduleJS);

      // Print a success message.
      grunt.log.writeln('File "' + dest + '" created.');
    }

    // Iterate over all specified file groups.
    this.files.forEach(function (file) {
      // Concat specified files.
      if (file.dest) {
        //if has dest, concat all src files
        var src = file.src.filter(function (filepath) {
          // Warn on and remove invalid source files (if nonull was set).
          if (!grunt.file.exists(filepath)) {
            grunt.log.warn('Source file "' + filepath + '" not found.');
            return false;
          } else {
            return true;
          }
        }).map(function (filepath) {
            // Read file source.
            var content =  grunt.file.read(filepath);

            if (options.minify) {
              try {
                content = minify(content, options.minifyOption);
              } catch (e) {
                grunt.warn("Minify Error: " + filepath);
              }
            }

            return content;

          }).join(' ');

        kissy_template(src, file.dest);

      } else {
        //else each src html file to js file
        file.src.filter(function (filepath) {
          // Warn on and remove invalid source files (if nonull was set).
          if (!grunt.file.exists(filepath)) {
            grunt.log.warn('Source file "' + filepath + '" not found.');
            return false;
          } else {
            return true;
          }
        }).forEach(function(filepath){
            var content = grunt.file.read(filepath);
            if (options.minify) {
              try {
                content = minify(content, options.minifyOption);
              } catch (e) {
                grunt.warn("Minify Error: " + filepath);
              }
            }

            // extname to js
            var dest = filepath.replace(/\.([^.]*)$/, '.js');

            kissy_template(content, dest);

          });
      }
    });
  });

};
<|endoftext|>


<commit_before>'use strict';
var path = require('path');
var eachAsync = require('each-async');
var assign = require('object-assign');
var sass = require('node-sass');

module.exports = function (grunt) {
	grunt.verbose.writeln('\n' + sass.info + '\n');

	grunt.registerMultiTask('sass', 'Compile Sass to CSS', function () {
		eachAsync(this.files, function (el, i, next) {
			var opts = this.options({
				precision: 10
			});

			var src = el.src[0];

			if (!src || path.basename(src)[0] === '_') {
				next();
				return;
			}

			sass.render(assign({}, opts, {
				file: src,
				outFile: el.dest
			}), function (err, res) {
				if (err) {
					grunt.log.error(err.message + '\n  ' + 'Line ' + err.line + '  Column ' + err.column + '  ' + path.relative(process.cwd(), err.file) + '\n');
					grunt.warn('');
					next(err);
					return;
				}

				if (this.options.onComplete && this.options.onComplete.call === '[object Function]') {
					res.css = this.options.onComplete(res.css.toString());
				}

				grunt.file.write(el.dest, res.css);

				if (opts.sourceMap) {
					grunt.file.write(this.options.sourceMap, res.map);
				}

				next();
			});
		}.bind(this), this.async());
	});
};
<commit_msg>fix check funcion<commit_after>'use strict';
var path = require('path');
var eachAsync = require('each-async');
var assign = require('object-assign');
var sass = require('node-sass');

module.exports = function (grunt) {
	grunt.verbose.writeln('\n' + sass.info + '\n');

	grunt.registerMultiTask('sass', 'Compile Sass to CSS', function () {
		eachAsync(this.files, function (el, i, next) {
			var opts = this.options({
				precision: 10
			});

			var src = el.src[0];

			if (!src || path.basename(src)[0] === '_') {
				next();
				return;
			}

			sass.render(assign({}, opts, {
				file: src,
				outFile: el.dest
			}), function (err, res) {
				if (err) {
					grunt.log.error(err.message + '\n  ' + 'Line ' + err.line + '  Column ' + err.column + '  ' + path.relative(process.cwd(), err.file) + '\n');
					grunt.warn('');
					next(err);
					return;
				}

				if (this.options.onComplete && typeof(this.options.onComplete) === 'function') {
					res.css = this.options.onComplete(res.css.toString());
				}

				grunt.file.write(el.dest, res.css);

				if (opts.sourceMap) {
					grunt.file.write(this.options.sourceMap, res.map);
				}

				next();
			});
		}.bind(this), this.async());
	});
};
<|endoftext|>


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

var filename = function(uri){
		var lastSlash = uri.lastIndexOf("/"),
			matches = ( lastSlash == -1 ? uri : uri.substr(lastSlash+1) ).match(/^[\w-\s\.]+/);
		return matches ? matches[0] : "";
};
var bundleCounter = 0;

function getName(bundle) {
	var usedBundleNames = {};
	var dirName = "bundles/";

	var bundleNames = bundle.bundles.map(function(appName){
		return (appName+"").replace(".js","");
	});

	// try with just the last part
	var shortened = bundleNames.map(function(l){
		return filename(l);
	}).join('-');

	if (bundle.bundles.length > 1 && shortened.length > 25) {
		var hasher = crypto.createHash("md5");
		hasher.update(shortened);
		var shortenedHash = hasher.digest('hex');
		shortened = shortened.substr(0, 16) + "-" + shortenedHash.substr(0, 8);
	}

	var buildType = bundle.buildType || "js",
		buildTypeSuffix = buildType === "js" ? "" : "."+buildType+"!";

	if(!usedBundleNames[shortened]){
		usedBundleNames[shortened] = true;
		return dirName+shortened+buildTypeSuffix;
	} else if(shortened.length > 50){
		return dirName+shortened.substr(0,50)+"-"+bundleNames.length+"-"+(bundleCounter++)+buildTypeSuffix;
	} else {
		return dirName+shortened+buildTypeSuffix;
	}
}

module.exports = function(bundle) {
	bundle.name = getName(bundle);
};

module.exports.getName = getName;

<commit_msg>Main bundle names should have the full path. If we only use the filename, we may conflict with other main bundles, e.g. `users/list.js` and `tasks/list.js` should be `users/list` and `tasks/list`, whereas under the old behavior, both would have the same name `list`.<commit_after>var crypto = require('crypto');

var filename = function(uri){
		var lastSlash = uri.lastIndexOf("/"),
			matches = ( lastSlash == -1 ? uri : uri.substr(lastSlash+1) ).match(/^[\w-\s\.]+/);
		return matches ? matches[0] : "";
};
var bundleCounter = 0;

function getName(bundle) {
	var usedBundleNames = {};
	var dirName = "bundles/";

	var bundleNames = bundle.bundles.map(function(appName){
		return (appName+"").replace(".js","");
	});

	var shortened = bundleNames.map(function(l){
		return filename(l);
	}).join('-');

	if (bundle.bundles.length > 1 && shortened.length > 25) {
		var hasher = crypto.createHash("md5");
		hasher.update(shortened);
		var shortenedHash = hasher.digest('hex');
		shortened = shortened.substr(0, 16) + "-" + shortenedHash.substr(0, 8);
	}

// If this is a "main" bundle
	if (bundle.bundles.length === 1 ) {
		// Use the full path name, removing trailing ".js"
		shortened = bundle.bundles[0].replace(".js", "");
	}

	var buildType = bundle.buildType || "js",
		buildTypeSuffix = buildType === "js" ? "" : "."+buildType+"!";

	if(!usedBundleNames[shortened]){
		usedBundleNames[shortened] = true;
		return dirName+shortened+buildTypeSuffix;
	} else if(shortened.length > 50){
		return dirName+shortened.substr(0,50)+"-"+bundleNames.length+"-"+(bundleCounter++)+buildTypeSuffix;
	} else {
		return dirName+shortened+buildTypeSuffix;
	}
}

module.exports = function(bundle) {
	bundle.name = getName(bundle);
};

module.exports.getName = getName;

<|endoftext|>


<commit_before>"use strict";

describe("unusedTokenHighlighter", function() {
  var element;
  var state;
  var scope;
  var parentScope;

  var template = '\
    <span\
      unused-token-highlighter\
      uth-check-property="head.id">\
    </span>\
  ';

  function init(template, fn) {
    inject(function($compile, $rootScope, _state_) {
      state = _state_;
      state.replaceState(arethusaMocks.tokens());
      state.postInit();

      parentScope = $rootScope.$new();
      element = angular.element(template);

      if (angular.isFunction(fn)) fn();

      $compile(element)(parentScope);
      scope = element.isolateScope();
      scope.$digest();
    });
  }

  beforeEach(function() {
    module("arethusa.core", function($provide) {
      $provide.value('configurator', arethusaMocks.configurator());
    });
  });

  describe('general behaviour', function() {
    beforeEach(function() { init(template); });

    describe('keeps track of total tokens', function() {
      it('on init', function() {
        var total = state.totalTokens;
        expect(scope.total).toEqual(total);
      });

      it('when a token was added', function() {
        var total = state.totalTokens;
        state.addToken({ id: 28, head: { id: '02' } }, 28);
        expect(scope.total).toEqual(total + 1);
      });

      it('when a token was removed', function() {
        var total = state.totalTokens;
        state.removeToken('01');
        expect(scope.total).toEqual(total - 1);
      });
    });

    describe('keeps track of unused tokens', function() {
      it('when everything is used', function() {
        // All tokens in Arethusa mocks have heads
        expect(scope.unusedCount).toEqual(0);
      });

      it('when not everything is used', function() {
        state.change('01', 'head.id', '');
        expect(scope.unusedCount).toEqual(1);
      });

      it('when things change often', function() {
        state.change('01', 'head.id', '');
        expect(scope.unusedCount).toEqual(1);

        state.change('02', 'head.id', '');
        expect(scope.unusedCount).toEqual(2);

        state.change('02', 'head.id', '01');
        expect(scope.unusedCount).toEqual(1);
      });

      it('when things are changed that were used before', function() {
        expect(scope.unusedCount).toEqual(0);
        state.change('02', 'head.id', '01');
        expect(scope.unusedCount).toEqual(0);
      });
    });

    describe('on click', function() {
      function t1Style() {
        return angular.copy(state.getToken('01').style);
      }

      it('highlights unused tokens', function() {
        expect(t1Style()).toBeUndefined();
        state.change('01', 'head.id', '');

        element.triggerHandler('click');

        expect(t1Style()).toBeDefined();
      });

      it('unhighlights when clicked again', function() {
        expect(t1Style()).toBeUndefined();
        state.change('01', 'head.id', '');

        element.triggerHandler('click');

        var highlightedStyle = t1Style();
        expect(highlightedStyle).toBeDefined();

        element.triggerHandler('click');

        var unhighlightedStyle = t1Style();
        expect(highlightedStyle).not.toEqual(unhighlightedStyle);
      });
    });

    describe('on dblclick', function() {
      it('selects unused tokens', function() {
        expect(state.clickedTokens).toEqual({});

        state.change('01', 'head.id', '');

        element.triggerHandler('dblclick');

        expect(state.clickedTokens).not.toEqual({});
        expect(state.isClicked('01')).toBeTruthy();
      });
    });
  });
});

      it('the style used defaults to a light-red background color', function() {
        var defaultStyle = { "background-color": "rgb(255, 216, 216)" };

        state.change('01', 'head.id', '');

        element.triggerHandler('click');

        expect(t1Style()).toEqual(defaultStyle);
      });
<commit_msg>Add spec for uth-check-property and refactor<commit_after>"use strict";

describe("unusedTokenHighlighter", function() {
  var element;
  var state;
  var scope;
  var parentScope;

  var template1 = '\
    <span\
      unused-token-highlighter\
      uth-check-property="head.id">\
    </span>\
  ';

  var template2 = '\
    <span\
      unused-token-highlighter\
      uth-check-property="relation.label">\
    </span>\
  ';

  function init(template, fn) {
    inject(function($compile, $rootScope, _state_) {
      state = _state_;
      state.replaceState(arethusaMocks.tokens());
      state.postInit();

      parentScope = $rootScope.$new();
      element = angular.element(template);

      if (angular.isFunction(fn)) fn();

      $compile(element)(parentScope);
      scope = element.isolateScope();
      scope.$digest();
    });
  }

  function t1Style() {
    return angular.copy(state.getToken('01').style);
  }

  beforeEach(function() {
    module("arethusa.core", function($provide) {
      $provide.value('configurator', arethusaMocks.configurator());
    });
  });

  describe('general behaviour', function() {
    beforeEach(function() { init(template1); });

    describe('keeps track of total tokens', function() {
      it('on init', function() {
        var total = state.totalTokens;
        expect(scope.total).toEqual(total);
      });

      it('when a token was added', function() {
        var total = state.totalTokens;
        state.addToken({ id: 28, head: { id: '02' } }, 28);
        expect(scope.total).toEqual(total + 1);
      });

      it('when a token was removed', function() {
        var total = state.totalTokens;
        state.removeToken('01');
        expect(scope.total).toEqual(total - 1);
      });
    });

    describe('keeps track of unused tokens', function() {
      it('when everything is used', function() {
        // All tokens in Arethusa mocks have heads
        expect(scope.unusedCount).toEqual(0);
      });

      it('when not everything is used', function() {
        state.change('01', 'head.id', '');
        expect(scope.unusedCount).toEqual(1);
      });

      it('when things change often', function() {
        state.change('01', 'head.id', '');
        expect(scope.unusedCount).toEqual(1);

        state.change('02', 'head.id', '');
        expect(scope.unusedCount).toEqual(2);

        state.change('02', 'head.id', '01');
        expect(scope.unusedCount).toEqual(1);
      });

      it('when things are changed that were used before', function() {
        expect(scope.unusedCount).toEqual(0);
        state.change('02', 'head.id', '01');
        expect(scope.unusedCount).toEqual(0);
      });
    });

    describe('on click', function() {
      it('highlights unused tokens', function() {
        expect(t1Style()).toBeUndefined();
        state.change('01', 'head.id', '');

        element.triggerHandler('click');

        expect(t1Style()).toBeDefined();
      });

      it('unhighlights when clicked again', function() {
        expect(t1Style()).toBeUndefined();
        state.change('01', 'head.id', '');

        element.triggerHandler('click');

        var highlightedStyle = t1Style();
        expect(highlightedStyle).toBeDefined();

        element.triggerHandler('click');

        var unhighlightedStyle = t1Style();
        expect(highlightedStyle).not.toEqual(unhighlightedStyle);
      });

      it('the style used defaults to a light-red background color', function() {
        var defaultStyle = { "background-color": "rgb(255, 216, 216)" };

        state.change('01', 'head.id', '');

        element.triggerHandler('click');

        expect(t1Style()).toEqual(defaultStyle);
      });
    });

    describe('on dblclick', function() {
      it('selects unused tokens', function() {
        expect(state.clickedTokens).toEqual({});

        state.change('01', 'head.id', '');

        element.triggerHandler('dblclick');

        expect(state.clickedTokens).not.toEqual({});
        expect(state.isClicked('01')).toBeTruthy();
      });
    });
  });

  describe('uth-check-property', function() {
    beforeEach(function() { init(template2); });

    it('allows to define the token property checked', function() {
      // Initially all tokens in Arethusa mocks have relation labels
      expect(scope.unusedCount).toEqual(0);

      state.change('01', 'relation.label', '');
      expect(scope.unusedCount).toEqual(1);
    });
  });
});
<|endoftext|>


<commit_before>var referee = require("referee");
var test = require("buster-test");
var formatio = require("formatio");
var sinon = require("sinon");

var stackFilter = require("stack-filter").configure({
    filters: ["buster-node/lib", "buster-node/node_modules"],
    cwd: process.cwd()
});

require("referee-sinon")(referee, sinon);
require("buster-sinon")(sinon, test, stackFilter, formatio);

var formatter = formatio.configure({ quoteStrings: true });
referee.format = formatter.ascii.bind(formatter);

module.exports = {
    referee: referee,
    assert: referee.assert,
    refute: referee.refute,
    expect: referee.expect
};

// Expose buster test sub modules
for (var exp in test) {
    module.exports[exp] = test[exp];
}

// Configure assertion counting
test.testRunner.onCreate(function (runner) {
    referee.on("pass", function () {
        runner.assertionPass();
    });
});

// Configure automagic runner
var runner = test.autoRun({ stackFilter: stackFilter }, {
    end: function (results) {
        process.exit(results.ok ? 0 : 1);
    }
});

test.testContext.on("create", runner);
<commit_msg>export buster.sinon<commit_after>var referee = require("referee");
var test = require("buster-test");
var formatio = require("formatio");
var sinon = require("sinon");

var stackFilter = require("stack-filter").configure({
    filters: ["buster-node/lib", "buster-node/node_modules"],
    cwd: process.cwd()
});

require("referee-sinon")(referee, sinon);
require("buster-sinon")(sinon, test, stackFilter, formatio);

var formatter = formatio.configure({ quoteStrings: true });
referee.format = formatter.ascii.bind(formatter);

module.exports = {
    referee: referee,
    assert: referee.assert,
    refute: referee.refute,
    expect: referee.expect,
    sinon: sinon
};

// Expose buster test sub modules
for (var exp in test) {
    module.exports[exp] = test[exp];
}

// Configure assertion counting
test.testRunner.onCreate(function (runner) {
    referee.on("pass", function () {
        runner.assertionPass();
    });
});

// Configure automagic runner
var runner = test.autoRun({ stackFilter: stackFilter }, {
    end: function (results) {
        process.exit(results.ok ? 0 : 1);
    }
});

test.testContext.on("create", runner);
<|endoftext|>


<commit_before>'use babel'

/* @flow */

import { CompositeDisposable } from 'atom'
import type { Linter$Linter } from './types'

export default class BusySignal {
  provider: ?Object;
  inProgress: Map<?string, Set<Linter$Linter>>;
  subscriptions: CompositeDisposable;

  constructor() {
    this.inProgress = new Map()
    this.subscriptions = new CompositeDisposable()
  }
  attach(registry: Object) {
    this.provider = registry.create();
    this.update()
  }
  update() {
    const provider = this.provider
    if (!provider) {
      return
    }
    provider.clear()
    for (const [filePath, linters] of this.inProgress) {
      const names = []
      for (const linter of linters) {
        names.push(linter.name || 'Unknown')
      }
      const ps = filePath ? `on ${filePath}` : ''
      provider.add(`Linter(s) '${names.join("', '")}' running ${ps}`)
    }
  }
  didBeginLinting(linter: Linter$Linter, filePath: string) {
    let beingExecuted = this.inProgress.get(filePath)
    if (!beingExecuted) {
      beingExecuted = new Set()
      this.inProgress.set(filePath, beingExecuted)
    }
    beingExecuted.add(linter)
    this.update()
  }
  didFinishLinting(linter: Linter$Linter, filePath: string) {
    const beingExecuted = this.inProgress.get(filePath)
    if (beingExecuted) {
      beingExecuted.delete(linter)
      if (!beingExecuted.size) {
        this.inProgress.delete(filePath)
      }
      this.update()
    }
  }
  dispose() {
    this.subscriptions.dispose()
  }
}
<commit_msg>:art: Remove an extra semi colon<commit_after>'use babel'

/* @flow */

import { CompositeDisposable } from 'atom'
import type { Linter$Linter } from './types'

export default class BusySignal {
  provider: ?Object;
  inProgress: Map<?string, Set<Linter$Linter>>;
  subscriptions: CompositeDisposable;

  constructor() {
    this.inProgress = new Map()
    this.subscriptions = new CompositeDisposable()
  }
  attach(registry: Object) {
    this.provider = registry.create()
    this.update()
  }
  update() {
    const provider = this.provider
    if (!provider) {
      return
    }
    provider.clear()
    for (const [filePath, linters] of this.inProgress) {
      const names = []
      for (const linter of linters) {
        names.push(linter.name || 'Unknown')
      }
      const ps = filePath ? `on ${filePath}` : ''
      provider.add(`Linter(s) '${names.join("', '")}' running ${ps}`)
    }
  }
  didBeginLinting(linter: Linter$Linter, filePath: string) {
    let beingExecuted = this.inProgress.get(filePath)
    if (!beingExecuted) {
      beingExecuted = new Set()
      this.inProgress.set(filePath, beingExecuted)
    }
    beingExecuted.add(linter)
    this.update()
  }
  didFinishLinting(linter: Linter$Linter, filePath: string) {
    const beingExecuted = this.inProgress.get(filePath)
    if (beingExecuted) {
      beingExecuted.delete(linter)
      if (!beingExecuted.size) {
        this.inProgress.delete(filePath)
      }
      this.update()
    }
  }
  dispose() {
    this.subscriptions.dispose()
  }
}
<|endoftext|>


<commit_before>'use babel'

/* @flow */

import { CompositeDisposable } from 'atom'
import type { Linter$Linter } from './types'

export default class BusySignal {
  provider: ?Object;
  inProgress: Map<?string, Set<Linter$Linter>>;
  subscriptions: CompositeDisposable;

  constructor() {
    this.inProgress = new Map()
    this.subscriptions = new CompositeDisposable()
  }
  attach(registry: Object) {
    this.provider = registry.create()
    this.update()
  }
  update() {
    const provider = this.provider
    if (!provider) {
      return
    }
    provider.clear()
    for (const [filePath, linters] of this.inProgress) {
      const names = []
      for (const linter of linters) {
        names.push(linter.name || 'Unknown')
      }
      const ps = filePath ? `on ${filePath}` : ''
      provider.add(`Linter(s) ${names.join(', ')} running ${ps}`)
    }
  }
  didBeginLinting(linter: Linter$Linter, filePath: string) {
    let beingExecuted = this.inProgress.get(filePath)
    if (!beingExecuted) {
      beingExecuted = new Set()
      this.inProgress.set(filePath, beingExecuted)
    }
    beingExecuted.add(linter)
    this.update()
  }
  didFinishLinting(linter: Linter$Linter, filePath: string) {
    const beingExecuted = this.inProgress.get(filePath)
    if (beingExecuted) {
      beingExecuted.delete(linter)
      if (!beingExecuted.size) {
        this.inProgress.delete(filePath)
      }
      this.update()
    }
  }
  dispose() {
    this.subscriptions.dispose()
  }
}
<commit_msg>:art: Minor status icon fix<commit_after>'use babel'

/* @flow */

import { CompositeDisposable } from 'atom'
import type { Linter$Linter } from './types'

export default class BusySignal {
  provider: ?Object;
  inProgress: Map<?string, Set<Linter$Linter>>;
  subscriptions: CompositeDisposable;

  constructor() {
    this.inProgress = new Map()
    this.subscriptions = new CompositeDisposable()
  }
  attach(registry: Object) {
    this.provider = registry.create()
    this.update()
  }
  update() {
    const provider = this.provider
    if (!provider) {
      return
    }
    provider.clear()
    for (const [filePath, linters] of this.inProgress) {
      const names = []
      for (const linter of linters) {
        names.push(linter.name || 'Unknown')
      }
      const ps = filePath ? `on ${filePath}` : ''
      provider.add(`Linter(s) '${names.join("', '")}' running ${ps}`)
    }
  }
  didBeginLinting(linter: Linter$Linter, filePath: string) {
    let beingExecuted = this.inProgress.get(filePath)
    if (!beingExecuted) {
      beingExecuted = new Set()
      this.inProgress.set(filePath, beingExecuted)
    }
    beingExecuted.add(linter)
    this.update()
  }
  didFinishLinting(linter: Linter$Linter, filePath: string) {
    const beingExecuted = this.inProgress.get(filePath)
    if (beingExecuted) {
      beingExecuted.delete(linter)
      if (!beingExecuted.size) {
        this.inProgress.delete(filePath)
      }
      this.update()
    }
  }
  dispose() {
    this.subscriptions.dispose()
  }
}
<|endoftext|>


<commit_before>// Load modules

var Utils = require('../utils');

// Declare internals

var internals = {};

internals.getCached = function (cache, key, logFunc, tags, callback) {

    // Check if cache enabled

    if (!cache.isMode('server')) {
        return callback();
    }

    // Lookup in cache

    var timer = new Utils.Timer();
    cache.get(key, function (err, cached) {

        if (err) {
            logFunc(tags.concat(['cache', 'get', 'error']), err.message);
            return callback();
        }

        if (!cached ||
            !cached.item) {

            // Not found (or invalid)
            logFunc(tags.concat(['cache', 'get']), { msec: timer.elapsed() });
            return callback();
        }

        logFunc(tags.concat(['cache', 'get']), { msec: timer.elapsed(), stored: cached.stored, ttl: cached.ttl, isStale: cached.isStale });
        return callback(cached);
    });
};

internals.saveToCache = function (cache, key, logFunc, tags, value, ttl) {

    if (!cache.isMode('server')) {
        return;
    }

    // Lazy save

    var timer = new Utils.Timer();
    cache.set(key, value, ttl, function (err) {

        if (err) {
            logFunc(tags.concat(['cache', 'set', 'error']), { msec: timer.elapsed(), error: err.message });
        }
        else {
            logFunc(tags.concat(['cache', 'set'], { msec: timer.elapsed() }));
        }
    });
};

exports.process = function (cache, key, logFunc, tags, generateFunc, callback) {

    // Get from cache

    internals.getCached(cache, key, logFunc, tags, function (cached) {

        // Check if found and fresh

        if (cached &&
            !cached.isStale) {

            return callback(cached.item, cached);
        }

        // Not in cache, or cache stale

        var wasCallbackCalled = false;                                      // Track state between stale timeout and generate fresh

        if (cached &&
            cached.isStale) {

            // Set stale timeout

            cached.ttl -= cache.rule.staleTimeout;       // Adjust TTL for when the timeout is invoked
            setTimeout(function () {

                if (wasCallbackCalled) {
                    return;
                }

                return callback(cached.item, cached);
            },
            cache.rule.staleTimeout);
        }

        // Generate new value

        generateFunc(function (err, value, ttl) {

            // Check if already sent stale value

            if (wasCallbackCalled) {
                if (err) {

                    // Invalidate cache

                    cache.drop(key, function (cacheErr) {

                        if (cacheErr) {
                            logFunc(tags.concat(['cache', 'drop', 'error']), cacheErr.message);
                        }
                        else {
                            logFunc(tags.concat(['cache', 'drop']));
                        }
                    });
                }
                else {
                    // Replace stale cache copy with late-coming fresh copy
                    internals.saveToCache(cache, key, logFunc, tags, value, ttl);
                }

                return;
            }

            // New value (arrived before stale timeout if enabled)

            wasCallbackCalled = true;

            // Save to cache (lazy) and continue
            internals.saveToCache(cache, key, logFunc, tags, value, ttl);
            return callback(value);
        });
    });
};

<commit_msg>Missing stale timeout sync<commit_after>// Load modules

var Utils = require('../utils');

// Declare internals

var internals = {};

internals.getCached = function (cache, key, logFunc, tags, callback) {

    // Check if cache enabled

    if (!cache.isMode('server')) {
        return callback();
    }

    // Lookup in cache

    var timer = new Utils.Timer();
    cache.get(key, function (err, cached) {

        if (err) {
            logFunc(tags.concat(['cache', 'get', 'error']), err.message);
            return callback();
        }

        if (!cached ||
            !cached.item) {

            // Not found (or invalid)
            logFunc(tags.concat(['cache', 'get']), { msec: timer.elapsed() });
            return callback();
        }

        logFunc(tags.concat(['cache', 'get']), { msec: timer.elapsed(), stored: cached.stored, ttl: cached.ttl, isStale: cached.isStale });
        return callback(cached);
    });
};

internals.saveToCache = function (cache, key, logFunc, tags, value, ttl) {

    if (!cache.isMode('server')) {
        return;
    }

    // Lazy save

    var timer = new Utils.Timer();
    cache.set(key, value, ttl, function (err) {

        if (err) {
            logFunc(tags.concat(['cache', 'set', 'error']), { msec: timer.elapsed(), error: err.message });
        }
        else {
            logFunc(tags.concat(['cache', 'set'], { msec: timer.elapsed() }));
        }
    });
};

exports.process = function (cache, key, logFunc, tags, generateFunc, callback) {

    // Get from cache

    internals.getCached(cache, key, logFunc, tags, function (cached) {

        // Check if found and fresh

        if (cached &&
            !cached.isStale) {

            return callback(cached.item, cached);
        }

        // Not in cache, or cache stale

        var wasCallbackCalled = false;                                      // Track state between stale timeout and generate fresh

        if (cached &&
            cached.isStale) {

            // Set stale timeout

            cached.ttl -= cache.rule.staleTimeout;       // Adjust TTL for when the timeout is invoked
            setTimeout(function () {

                if (wasCallbackCalled) {
                    return;
                }

                wasCallbackCalled = true;
                return callback(cached.item, cached);
            },
            cache.rule.staleTimeout);
        }

        // Generate new value

        generateFunc(function (err, value, ttl) {

            // Check if already sent stale value

            if (wasCallbackCalled) {
                if (err) {

                    // Invalidate cache

                    cache.drop(key, function (cacheErr) {

                        if (cacheErr) {
                            logFunc(tags.concat(['cache', 'drop', 'error']), cacheErr.message);
                        }
                        else {
                            logFunc(tags.concat(['cache', 'drop']));
                        }
                    });
                }
                else {
                    // Replace stale cache copy with late-coming fresh copy
                    internals.saveToCache(cache, key, logFunc, tags, value, ttl);
                }

                return;
            }

            // New value (arrived before stale timeout if enabled)

            wasCallbackCalled = true;

            // Save to cache (lazy) and continue
            internals.saveToCache(cache, key, logFunc, tags, value, ttl);
            return callback(value);
        });
    });
};

<|endoftext|>