<commit_before>/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           ______     ______     ______   __  __     __     ______
          /\  == \   /\  __ \   /\__  _\ /\ \/ /    /\ \   /\__  _\
          \ \  __<   \ \ \/\ \  \/_/\ \/ \ \  _"-.  \ \ \  \/_/\ \/
           \ \_____\  \ \_____\    \ \_\  \ \_\ \_\  \ \_\    \ \_\
            \/_____/   \/_____/     \/_/   \/_/\/_/   \/_/     \/_/
This is a sample Slack Button application that adds a bot to one or many slack teams.

# RUN THE APP:
  Create a Slack app. Make sure to configure the bot user!
    -> https://api.slack.com/applications/new
  Run your bot from the command line:
    clientId=<my client id> clientSecret=<my client secret> port=3000 node bot.js
# USE THE APP
  Add the app to your Slack by visiting the login page:
    -> http://localhost:3000/login
  After you've added the app, try talking to your bot!
# EXTEND THE APP:
  Botkit is has many features for building cool and useful bots!
  Read all about it here:
    -> http://howdy.ai/botkit
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

/* Uses the slack button feature to offer a real time bot to multiple teams */
var Botkit = require('../lib/Botkit.js');

if (!process.env.clientId || !process.env.clientSecret || !process.env.port) {
  console.log('Error: Specify clientId clientSecret and port in environment');
  process.exit(1);
}

var controller = Botkit.slackbot({
  json_file_store: './db_slackbutton_bot/',
}).configureSlackApp(
  {
    clientId: process.env.clientId,
    clientSecret: process.env.clientSecret,
    scopes: ['bot'],
  }
);

controller.setupWebserver(process.env.port,function(err,webserver) {
  controller.createWebhookEndpoints(controller.webserver);

  controller.createOauthEndpoints(controller.webserver,function(err,req,res) {
    if (err) {
      res.status(500).send('ERROR: ' + err);
    } else {
      res.send('Success!');
    }
  });
});

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

controller.on('create_bot',function(bot,config) {

  if (_bots[bot.config.token]) {
    // already online! do nothing.
  } else {
    bot.startRTM(function(err) {

      if (!err) {
        trackBot(bot);
      }

      bot.startPrivateConversation({user: config.createdBy},function(err,convo) {
        if (err) {
          console.log(err);
        } else {
          convo.say('I am a bot that has just joined your team');
          convo.say('You must now /invite me to a channel so that I can be of use!');
        }
      });

    });
  }

});

// Handle events related to the websocket connection to Slack
controller.on('rtm_open',function(bot) {
  console.log('** The RTM api just connected!');
});

controller.on('rtm_close',function(bot) {
  console.log('** The RTM api just closed');
  // you may want to attempt to re-open
});

controller.hears('hello','direct_message',function(bot,message) {
  bot.reply(message,'Hello!');
});

controller.hears('^stop','direct_message',function(bot,message) {
  bot.reply(message,'Goodbye');
  bot.rtm.close();
});

controller.on(['direct_message','mention','direct_mention'],function(bot,message) {
  bot.api.reactions.add({
    timestamp: message.ts,
    channel: message.channel,
    name: 'robot_face',
  },function(err) {
    if (err) { console.log(err) }
    bot.reply(message,'I heard you loud and clear boss.');
  });
});

controller.storage.teams.all(function(err,teams) {

  if (err) {
    throw new Error(err);
  }

  // connect all teams with bots up to slack!
  for (var t  in teams) {
    if (teams[t].bot) {
      var bot = controller.spawn(teams[t]).startRTM(function(err) {
        if (err) {
          console.log('Error connecting bot to Slack:',err);
        } else {
          trackBot(bot);
        }
      });
    }
  }

});
<commit_msg>correct name of script in header<commit_after>/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           ______     ______     ______   __  __     __     ______
          /\  == \   /\  __ \   /\__  _\ /\ \/ /    /\ \   /\__  _\
          \ \  __<   \ \ \/\ \  \/_/\ \/ \ \  _"-.  \ \ \  \/_/\ \/
           \ \_____\  \ \_____\    \ \_\  \ \_\ \_\  \ \_\    \ \_\
            \/_____/   \/_____/     \/_/   \/_/\/_/   \/_/     \/_/
This is a sample Slack Button application that adds a bot to one or many slack teams.

# RUN THE APP:
  Create a Slack app. Make sure to configure the bot user!
    -> https://api.slack.com/applications/new
  Run your bot from the command line:
    clientId=<my client id> clientSecret=<my client secret> port=3000 node slackbutton_bot.js
# USE THE APP
  Add the app to your Slack by visiting the login page:
    -> http://localhost:3000/login
  After you've added the app, try talking to your bot!
# EXTEND THE APP:
  Botkit is has many features for building cool and useful bots!
  Read all about it here:
    -> http://howdy.ai/botkit
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

/* Uses the slack button feature to offer a real time bot to multiple teams */
var Botkit = require('../lib/Botkit.js');

if (!process.env.clientId || !process.env.clientSecret || !process.env.port) {
  console.log('Error: Specify clientId clientSecret and port in environment');
  process.exit(1);
}

var controller = Botkit.slackbot({
  json_file_store: './db_slackbutton_bot/',
}).configureSlackApp(
  {
    clientId: process.env.clientId,
    clientSecret: process.env.clientSecret,
    scopes: ['bot'],
  }
);

controller.setupWebserver(process.env.port,function(err,webserver) {
  controller.createWebhookEndpoints(controller.webserver);

  controller.createOauthEndpoints(controller.webserver,function(err,req,res) {
    if (err) {
      res.status(500).send('ERROR: ' + err);
    } else {
      res.send('Success!');
    }
  });
});

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

controller.on('create_bot',function(bot,config) {

  if (_bots[bot.config.token]) {
    // already online! do nothing.
  } else {
    bot.startRTM(function(err) {

      if (!err) {
        trackBot(bot);
      }

      bot.startPrivateConversation({user: config.createdBy},function(err,convo) {
        if (err) {
          console.log(err);
        } else {
          convo.say('I am a bot that has just joined your team');
          convo.say('You must now /invite me to a channel so that I can be of use!');
        }
      });

    });
  }

});

// Handle events related to the websocket connection to Slack
controller.on('rtm_open',function(bot) {
  console.log('** The RTM api just connected!');
});

controller.on('rtm_close',function(bot) {
  console.log('** The RTM api just closed');
  // you may want to attempt to re-open
});

controller.hears('hello','direct_message',function(bot,message) {
  bot.reply(message,'Hello!');
});

controller.hears('^stop','direct_message',function(bot,message) {
  bot.reply(message,'Goodbye');
  bot.rtm.close();
});

controller.on(['direct_message','mention','direct_mention'],function(bot,message) {
  bot.api.reactions.add({
    timestamp: message.ts,
    channel: message.channel,
    name: 'robot_face',
  },function(err) {
    if (err) { console.log(err) }
    bot.reply(message,'I heard you loud and clear boss.');
  });
});

controller.storage.teams.all(function(err,teams) {

  if (err) {
    throw new Error(err);
  }

  // connect all teams with bots up to slack!
  for (var t  in teams) {
    if (teams[t].bot) {
      var bot = controller.spawn(teams[t]).startRTM(function(err) {
        if (err) {
          console.log('Error connecting bot to Slack:',err);
        } else {
          trackBot(bot);
        }
      });
    }
  }

});
<|endoftext|>


<commit_before>/*
 * jQuery UI Tag-it!
 *
 * @version v2.0 (06/2011)
 *
 * Copyright 2011, Levy Carneiro Jr.
 * Released under the MIT license.
 * http://aehlke.github.com/tag-it/LICENSE
 *
 * Homepage:
 *   http://aehlke.github.com/tag-it/
 *
 * Authors:
 *   Levy Carneiro Jr.
 *   Martin Rehfeld
 *   Tobias Schmidt
 *   Skylar Challand
 *   Alex Ehlke
 *
 * Maintainer:
 *   Alex Ehlke - Twitter: @aehlke
 *
 * Dependencies:
 *   jQuery v1.4+
 *   jQuery UI v1.8+
 */
(function ($) {

	$.widget('ui.tagit', {
		options: {
			itemName: 'item',
			fieldName: 'tags',
			availableTags: [],
			tagSource: null,
			removeConfirmation: false,
			caseSensitive: true,
			placeholderText: null,
			// When enabled, quotes are not neccesary
			// for inputting multi-word tags.
			allowSpaces: false,
			// The below options are for using a single field instead of several
			// for our form values.
			//
			// When enabled, will use a single hidden field for the form,
			// rather than one per tag. It will delimit tags in the field
			// with singleFieldDelimiter.
			//
			// The easiest way to use singleField is to just instantiate tag-it
			// on an INPUT element, in which case singleField is automatically
			// set to true, and singleFieldNode is set to that element. This
			// way, you don't need to fiddle with these options.
			singleField: false,
			singleFieldDelimiter: ',',
			// Set this to an input DOM node to use an existing form field.
			// Any text in it will be erased on init. But it will be
			// populated with the text of tags as they are created,
			// delimited by singleFieldDelimiter.
			//
			// If this is not set, we create an input node for it,
			// with the name given in settings.fieldName,
			// ignoring settings.itemName.
			singleFieldNode: null,
			// Optionally set a tabindex attribute on the input that gets
			// created for tag-it.
			tabIndex: null,
			// Event callbacks.
			onTagAdded: null,
			onTagRemoved: null,
			onTagClicked: null
		},
		_create: function () {
			// for handling static scoping inside callbacks
			var that = this;

			// There are 2 kinds of DOM nodes this widget can be instantiated on:
			//     1. UL, OL, or some element containing either of these.
			//     2. INPUT, in which case 'singleField' is overridden to true,
			//        a UL is created and the INPUT is hidden.
			if (this.element.is('input')) {
				this.tagList = $('

').insertAfter(this.element);
				this.options.singleField = true;
				this.options.singleFieldNode = this.element;
				this.element.css('display', 'none');
			} else {
				this.tagList = this.element.find('ul, ol').andSelf().last();
			}

			this._tagInput = $('<input type="text">').addClass('ui-widget-content');
			if (this.options.tabIndex) {
				this._tagInput.attr('tabindex', this.options.tabIndex);
			}
			if (this.options.placeholderText) {
				this._tagInput.attr('placeholder', this.options.placeholderText);
			}
			this.options.tagSource = this.options.tagSource || function (search, showChoices) {
				var filter = search.term.toLowerCase();
				var choices = $.grep(that.options.availableTags, function (element) {
					// Only match autocomplete options that begin with the search term.
					// (Case insensitive.)
					return (element.toLowerCase().indexOf(filter) === 0);
				});
				showChoices(that._subtractArray(choices, that.assignedTags()));
			};

			this.tagList
					.addClass('tagit')
					.addClass('ui-widget ui-widget-content ui-corner-all')
					// Create the input field.
					.append($('

').append(this._tagInput))
					.click(function (e) {
						var target = $(e.target);
						if (target.hasClass('tagit-label')) {
							that._trigger('onTagClicked', e, target.closest('.tagit-choice'));
						} else {
							// Sets the focus() to the input field, if the user
							// clicks anywhere inside the UL. This is needed
							// because the input field needs to be of a small size.
							that._tagInput.focus();
						}
					});

			// Add existing tags from the list, if any.
			this.tagList.children('li').each(function () {
				if (!$(this).hasClass('tagit-new')) {
					that.createTag($(this).html(), $(this).attr('class'));
					$(this).remove();
				}
			});

			// Single field support.
			if (this.options.singleField) {
				if (this.options.singleFieldNode) {
					// Add existing tags from the input field.
					var node = $(this.options.singleFieldNode);
					var tags = node.val().split(this.options.singleFieldDelimiter);
					node.val('');
					$.each(tags, function (index, tag) {
						that.createTag(tag);
					});
				} else {
					// Create our single field input after our list.
					this.options.singleFieldNode = this.tagList.after('<input type="hidden" style="display:none;" value="" name="' + this.options.fieldName + '">');
				}
			}

			// Events.
			this._tagInput
					.keydown(function (event) {
						// Backspace is not detected within a keypress, so it must use keydown.
						if (event.which == $.ui.keyCode.BACKSPACE && that._tagInput.val() === '') {
							var tag = that._lastTag();
							if (!that.options.removeConfirmation || tag.hasClass('remove')) {
								// When backspace is pressed, the last tag is deleted.
								that.removeTag(tag);
							} else if (that.options.removeConfirmation) {
								tag.addClass('remove ui-state-highlight');
							}
						} else if (that.options.removeConfirmation) {
							that._lastTag().removeClass('remove ui-state-highlight');
						}

						// Comma/Space/Enter are all valid delimiters for new tags,
						// except when there is an open quote or if setting allowSpaces = true.
						// Tab will also create a tag, unless the tag input is empty, in which case it isn't caught.
						if (
								event.which == $.ui.keyCode.COMMA ||
								event.which == $.ui.keyCode.ENTER ||
								(
										event.which == $.ui.keyCode.TAB &&
										that._tagInput.val() !== ''
										) ||
								(
										event.which == $.ui.keyCode.SPACE &&
										that.options.allowSpaces !== true &&
										(
												$.trim(that._tagInput.val()).replace(/^s*/, '').charAt(0) != '"' ||
												(
														$.trim(that._tagInput.val()).charAt(0) == '"' &&
														$.trim(that._tagInput.val()).charAt($.trim(that._tagInput.val()).length - 1) == '"' &&
														$.trim(that._tagInput.val()).length - 1 !== 0
														)
												)
										)
								) {
							event.preventDefault();
							that.createTag(that._cleanedInput());

							// The autocomplete doesn't close automatically when TAB is pressed.
							// So let's ensure that it closes.
							that._tagInput.autocomplete('close');
						}
					}).blur(function (e) {
				//If autocomplete is enabled and suggestion was clicked, don't add it
				if (that.options.tagSource && that._tagInput.data('autocomplete-open')) {
					that._cleanedInput();
				} else {
					that.createTag(that._cleanedInput());
				}
			});

			// Autocomplete.
			if (this.options.availableTags || this.options.tagSource) {
				this._tagInput.autocomplete({
					source: this.options.tagSource,
					open: function () {
						that._tagInput.data('autocomplete-open', true)
					},
					close: function () {
						that._tagInput.data('autocomplete-open', false)
					},
					select: function (event, ui) {
						that.createTag(ui.item.value);
						// Preventing the tag input to be updated with the chosen value.
						return false;
					}
				});
			}
		},
		_cleanedInput: function () {
			// Returns the contents of the tag input, cleaned and ready to be passed to createTag
			return $.trim(this._tagInput.val().replace(/^"(.*)"$/, '$1'));
		},
		_lastTag: function () {
			return this.tagList.children('.tagit-choice:last');
		},
		assignedTags: function () {
			// Returns an array of tag string values
			var that = this;
			var tags = [];
			if (this.options.singleField) {
				tags = $(this.options.singleFieldNode).val().split(this.options.singleFieldDelimiter);
				if (tags[0] === '') {
					tags = [];
				}
			} else {
				this.tagList.children('.tagit-choice').each(function () {
					tags.push(that.tagLabel(this));
				});
			}
			return tags;
		},
		_updateSingleTagsField: function (tags) {
			// Takes a list of tag string values, updates this.options.singleFieldNode.val to the tags delimited by this.options.singleFieldDelimiter
			$(this.options.singleFieldNode).val(tags.join(this.options.singleFieldDelimiter));
		},
		_subtractArray: function (a1, a2) {
			var result = [];
			for (var i = 0; i < a1.length; i++) {
				if ($.inArray(a1[i], a2) == -1) {
					result.push(a1[i]);
				}
			}
			return result;
		},
		tagLabel: function (tag) {
			// Returns the tag's string label.
			if (this.options.singleField) {
				return $(tag).children('.tagit-label').text();
			} else {
				return $(tag).children('input').val();
			}
		},
		_isNew: function (value) {
			var that = this;
			var isNew = true;
			this.tagList.children('.tagit-choice').each(function (i) {
				if (that._formatStr(value) == that._formatStr(that.tagLabel(this))) {
					isNew = false;
					return;
				}
			});
			return isNew;
		},
		_formatStr: function (str) {
			if (this.options.caseSensitive) {
				return str;
			}
			return $.trim(str.toLowerCase());
		},
		createTag: function (value, additionalClass) {
			that = this;
			// Automatically trims the value of leading and trailing whitespace.
			value = $.trim(value);

			if (!this._isNew(value) || value === '') {
				return false;
			}

			var label = $(this.options.onTagClicked ? '' : '').text(value);

			// Create tag.
			var tag = $('

')
					.addClass('tagit-choice ui-widget-content ui-state-default ui-corner-all')
					.addClass(additionalClass)
					.append(label);

			// Button for removing the tag.
			var removeTagIcon = $('')
					.addClass('ui-icon ui-icon-close');
			var removeTag = $('\xd7') // \xd7 is an X
					.addClass('close')
					.append(removeTagIcon)
					.click(function (e) {
						// Removes a tag when the little 'x' is clicked.
						that.removeTag(tag);
					});
			tag.append(removeTag);

			// Unless options.singleField is set, each tag has a hidden input field inline.
			if (this.options.singleField) {
				var tags = this.assignedTags();
				tags.push(value);
				this._updateSingleTagsField(tags);
			} else {
				var escapedValue = label.html();
				tag.append('<input type="hidden" style="display:none;" value="' + escapedValue + '" name="' + this.options.itemName + '[' + this.options.fieldName + '][]">');
			}

			this._trigger('onTagAdded', null, tag);

			// Cleaning the input.
			this._tagInput.val('');

			// insert tag
			this._tagInput.parent().before(tag);
		},
		removeTag: function (tag, animate) {
			if (typeof animate === 'undefined') {
				animate = true;
			}

			tag = $(tag);

			this._trigger('onTagRemoved', null, tag);

			if (this.options.singleField) {
				var tags = this.assignedTags();
				var removedTagLabel = this.tagLabel(tag);
				tags = $.grep(tags, function (el) {
					return el != removedTagLabel;
				});
				this._updateSingleTagsField(tags);
			}
			// Animate the removal.
			if (animate) {
				tag.fadeOut('fast').hide('blind', {direction: 'horizontal'}, 'fast', function () {
					tag.remove();
				}).dequeue();
			} else {
				tag.remove();
			}
			this._trigger('onTagFinishRemoved', null, tag);
		},
		removeAll: function () {
			// Removes all tags. Takes an optional `animate` argument.
			var that = this;
			this.tagList.children('.tagit-choice').each(function (index, tag) {
				that.removeTag(tag, false);
			});
		}

	});

})(jQuery);<commit_msg>Tags under filter search bar<commit_after>/*
 * jQuery UI Tag-it!
 *
 * @version v2.0 (06/2011)
 *
 * Copyright 2011, Levy Carneiro Jr.
 * Released under the MIT license.
 * http://aehlke.github.com/tag-it/LICENSE
 *
 * Homepage:
 *   http://aehlke.github.com/tag-it/
 *
 * Authors:
 *   Levy Carneiro Jr.
 *   Martin Rehfeld
 *   Tobias Schmidt
 *   Skylar Challand
 *   Alex Ehlke
 *
 * Maintainer:
 *   Alex Ehlke - Twitter: @aehlke
 *
 * Dependencies:
 *   jQuery v1.4+
 *   jQuery UI v1.8+
 */
(function ($) {

	$.widget('ui.tagit', {
		options: {
			itemName: 'item',
			fieldName: 'tags',
			availableTags: [],
			tagSource: null,
			removeConfirmation: false,
			caseSensitive: true,
			placeholderText: null,
			// When enabled, quotes are not neccesary
			// for inputting multi-word tags.
			allowSpaces: false,
			// The below options are for using a single field instead of several
			// for our form values.
			//
			// When enabled, will use a single hidden field for the form,
			// rather than one per tag. It will delimit tags in the field
			// with singleFieldDelimiter.
			//
			// The easiest way to use singleField is to just instantiate tag-it
			// on an INPUT element, in which case singleField is automatically
			// set to true, and singleFieldNode is set to that element. This
			// way, you don't need to fiddle with these options.
			singleField: false,
			singleFieldDelimiter: ',',
			// Set this to an input DOM node to use an existing form field.
			// Any text in it will be erased on init. But it will be
			// populated with the text of tags as they are created,
			// delimited by singleFieldDelimiter.
			//
			// If this is not set, we create an input node for it,
			// with the name given in settings.fieldName,
			// ignoring settings.itemName.
			singleFieldNode: null,
			// Optionally set a tabindex attribute on the input that gets
			// created for tag-it.
			tabIndex: null,
			// Event callbacks.
			onTagAdded: null,
			onTagRemoved: null,
			onTagClicked: null
		},
		_create: function () {
			// for handling static scoping inside callbacks
			var that = this;

			// There are 2 kinds of DOM nodes this widget can be instantiated on:
			//     1. UL, OL, or some element containing either of these.
			//     2. INPUT, in which case 'singleField' is overridden to true,
			//        a UL is created and the INPUT is hidden.
			if (this.element.is('input')) {
				this.tagList = $('

').insertAfter(this.element);
				this.options.singleField = true;
				this.options.singleFieldNode = this.element;
				this.element.css('display', 'none');
			} else {
				this.tagList = this.element.find('ul, ol').andSelf().last();
			}

			this._tagInput = $('<input type="text">').addClass('ui-widget-content');
			if (this.options.tabIndex) {
				this._tagInput.attr('tabindex', this.options.tabIndex);
			}
			if (this.options.placeholderText) {
				this._tagInput.attr('placeholder', this.options.placeholderText);
			}
			this.options.tagSource = this.options.tagSource || function (search, showChoices) {
				var filter = search.term.toLowerCase();
				var choices = $.grep(that.options.availableTags, function (element) {
					// Only match autocomplete options that begin with the search term.
					// (Case insensitive.)
					return (element.toLowerCase().indexOf(filter) === 0);
				});
				showChoices(that._subtractArray(choices, that.assignedTags()));
			};

			this.tagList
					.addClass('tagit')
					.addClass('ui-widget ui-widget-content ui-corner-all')
					// Create the input field.
					.append($('

').append(this._tagInput))
					.click(function (e) {
						var target = $(e.target);
						if (target.hasClass('tagit-label')) {
							that._trigger('onTagClicked', e, target.closest('.tagit-choice'));
						} else {
							// Sets the focus() to the input field, if the user
							// clicks anywhere inside the UL. This is needed
							// because the input field needs to be of a small size.
							that._tagInput.focus();
						}
					});

			// Add existing tags from the list, if any.
			this.tagList.children('li').each(function () {
				if (!$(this).hasClass('tagit-new')) {
					that.createTag($(this).html(), $(this).attr('class'));
					$(this).remove();
				}
			});

			// Single field support.
			if (this.options.singleField) {
				if (this.options.singleFieldNode) {
					// Add existing tags from the input field.
					var node = $(this.options.singleFieldNode);
					var tags = node.val().split(this.options.singleFieldDelimiter);
					node.val('');
					$.each(tags, function (index, tag) {
						that.createTag(tag);
					});
				} else {
					// Create our single field input after our list.
					this.options.singleFieldNode = this.tagList.after('<input type="hidden" style="display:none;" value="" name="' + this.options.fieldName + '">');
				}
			}

			// Events.
			this._tagInput
					.keydown(function (event) {
						// Backspace is not detected within a keypress, so it must use keydown.
						if (event.which == $.ui.keyCode.BACKSPACE && that._tagInput.val() === '') {
							var tag = that._lastTag();
							if (!that.options.removeConfirmation || tag.hasClass('remove')) {
								// When backspace is pressed, the last tag is deleted.
								that.removeTag(tag);
							} else if (that.options.removeConfirmation) {
								tag.addClass('remove ui-state-highlight');
							}
						} else if (that.options.removeConfirmation) {
							that._lastTag().removeClass('remove ui-state-highlight');
						}

						// Comma/Space/Enter are all valid delimiters for new tags,
						// except when there is an open quote or if setting allowSpaces = true.
						// Tab will also create a tag, unless the tag input is empty, in which case it isn't caught.
						if (
								event.which == $.ui.keyCode.COMMA ||
								event.which == $.ui.keyCode.ENTER ||
								(
										event.which == $.ui.keyCode.TAB &&
										that._tagInput.val() !== ''
										) ||
								(
										event.which == $.ui.keyCode.SPACE &&
										that.options.allowSpaces !== true &&
										(
												$.trim(that._tagInput.val()).replace(/^s*/, '').charAt(0) != '"' ||
												(
														$.trim(that._tagInput.val()).charAt(0) == '"' &&
														$.trim(that._tagInput.val()).charAt($.trim(that._tagInput.val()).length - 1) == '"' &&
														$.trim(that._tagInput.val()).length - 1 !== 0
														)
												)
										)
								) {
							event.preventDefault();
							that.createTag(that._cleanedInput());

							// The autocomplete doesn't close automatically when TAB is pressed.
							// So let's ensure that it closes.
							that._tagInput.autocomplete('close');
						}
					}).blur(function (e) {
				//If autocomplete is enabled and suggestion was clicked, don't add it
				if (that.options.tagSource && that._tagInput.data('autocomplete-open')) {
					that._cleanedInput();
				} else {
					that.createTag(that._cleanedInput());
				}
			});

			// Autocomplete.
			if (this.options.availableTags || this.options.tagSource) {
				this._tagInput.autocomplete({
					source: this.options.tagSource,
					open: function () {
						that._tagInput.data('autocomplete-open', true)
					},
					close: function () {
						that._tagInput.data('autocomplete-open', false)
					},
					select: function (event, ui) {
						that.createTag(ui.item.value);
						// Preventing the tag input to be updated with the chosen value.
						return false;
					}
				});
			}
		},
		_cleanedInput: function () {
			// Returns the contents of the tag input, cleaned and ready to be passed to createTag
			return $.trim(this._tagInput.val().replace(/^"(.*)"$/, '$1'));
		},
		_lastTag: function () {
			return this.tagList.children('.tagit-choice:last');
		},
		assignedTags: function () {
			// Returns an array of tag string values
			var that = this;
			var tags = [];
			if (this.options.singleField) {
				tags = $(this.options.singleFieldNode).val().split(this.options.singleFieldDelimiter);
				if (tags[0] === '') {
					tags = [];
				}
			} else {
				this.tagList.children('.tagit-choice').each(function () {
					tags.push(that.tagLabel(this));
				});
			}
			return tags;
		},
		_updateSingleTagsField: function (tags) {
			// Takes a list of tag string values, updates this.options.singleFieldNode.val to the tags delimited by this.options.singleFieldDelimiter
			$(this.options.singleFieldNode).val(tags.join(this.options.singleFieldDelimiter));
		},
		_subtractArray: function (a1, a2) {
			var result = [];
			for (var i = 0; i < a1.length; i++) {
				if ($.inArray(a1[i], a2) == -1) {
					result.push(a1[i]);
				}
			}
			return result;
		},
		tagLabel: function (tag) {
			// Returns the tag's string label.
			if (this.options.singleField) {
				return $(tag).children('.tagit-label').text();
			} else {
				return $(tag).children('input').val();
			}
		},
		_isNew: function (value) {
			var that = this;
			var isNew = true;
			this.tagList.children('.tagit-choice').each(function (i) {
				if (that._formatStr(value) == that._formatStr(that.tagLabel(this))) {
					isNew = false;
					return;
				}
			});
			return isNew;
		},
		_formatStr: function (str) {
			if (this.options.caseSensitive) {
				return str;
			}
			return $.trim(str.toLowerCase());
		},
		createTag: function (value, additionalClass) {
			that = this;
			// Automatically trims the value of leading and trailing whitespace.
			value = $.trim(value);

			if (!this._isNew(value) || value === '') {
				return false;
			}

			var label = $(this.options.onTagClicked ? '' : '').text(value);

			// Create tag.
			var tag = $('

')
					.addClass('tagit-choice ui-widget-content ui-state-default ui-corner-all')
					.addClass(additionalClass)
					.append(label);

			// Button for removing the tag.
			var removeTagIcon = $('')
					.addClass('ui-icon ui-icon-close');
			var removeTag = $('\xd7') // \xd7 is an X
					.addClass('close')
					.append(removeTagIcon)
					.click(function (e) {
						// Removes a tag when the little 'x' is clicked.
						that.removeTag(tag);
					});
			tag.append(removeTag);

			// Unless options.singleField is set, each tag has a hidden input field inline.
			if (this.options.singleField) {
				var tags = this.assignedTags();
				tags.push(value);
				this._updateSingleTagsField(tags);
			} else {
				var escapedValue = label.html();
				tag.append('<input type="hidden" style="display:none;" value="' + escapedValue + '" name="' + this.options.itemName + '[' + this.options.fieldName + '][]">');
			}

			this._trigger('onTagAdded', null, tag);

			// Cleaning the input.
			this._tagInput.val('');

			// insert tag
			this._tagInput.parent().after(tag);
		},
		removeTag: function (tag, animate) {
			if (typeof animate === 'undefined') {
				animate = true;
			}

			tag = $(tag);

			this._trigger('onTagRemoved', null, tag);

			if (this.options.singleField) {
				var tags = this.assignedTags();
				var removedTagLabel = this.tagLabel(tag);
				tags = $.grep(tags, function (el) {
					return el != removedTagLabel;
				});
				this._updateSingleTagsField(tags);
			}
			// Animate the removal.
			if (animate) {
				tag.fadeOut('fast').hide('blind', {direction: 'horizontal'}, 'fast', function () {
					tag.remove();
				}).dequeue();
			} else {
				tag.remove();
			}
			this._trigger('onTagFinishRemoved', null, tag);
		},
		removeAll: function () {
			// Removes all tags. Takes an optional `animate` argument.
			var that = this;
			this.tagList.children('.tagit-choice').each(function (index, tag) {
				that.removeTag(tag, false);
			});
		}

	});

})(jQuery);
<|endoftext|>


<commit_before>'use strict';

/*==========================================
|                  UTIL                    |
|     Here you'll find useful functions    |
==========================================*/

/**
* Get a point a minimum distance away from all players
* @param {game} game - The game object
* @param {Array} playerList - The list containing all player objects
* @param {Number} minimumDistance - The minimum distance from players to spawn from
* @param {Number} maxTryCount - The maximum amount of attempts until returning null
* @return {Point} A Point at least minimumDistance away from all players or null in which case no monster is spawned
*/
var getPosMinDPlayers = function (game, playerList, minimumDistance, maxTryCount)
	{
	var tryCount = 0;

	var acceptablePosition = false;
	while (!acceptablePosition || (tryCount < maxTryCount && maxTryCount != undefined))
		{
		var randomPos = {};
		randomPos.x = game.camera.x + game.rnd.integerInRange(0, game.camera.width);
		randomPos.y = game.camera.y + game.rnd.integerInRange(0, game.camera.height);
		if (dClosestPlayer(playerList, randomPos) >= minimumDistance)
			{
			acceptablePosition = true;
			}
		tryCount++;
		}

	if (randomPos != undefined)
		{
		return randomPos;
		} else
		{
		return null;
		}
	};

/*
* Return the distance between the provided position and the closes player
* @param {Array} players - List of all players
* @param {Point} position - The position to which compare
* @return {Number} The distance in pixels from position to the closest player
*/
var dClosestPlayer = function (players, position)
  {
  var currentMin = 9999999; // Arbitrarily large number
  for (var id in players)
    {
    var player = players[id];
    if (player != undefined && !player.dead)
      {
      var distance = Math.sqrt( Math.pow( (player.sprite.position.x - position.x), 2 ) +
                                Math.pow( (player.sprite.position.y - position.y), 2) );
      if (distance <= currentMin)
        {
        currentMin = distance;
        }
      }
    }
  return currentMin;
  };

/*
* Picks a random entry from a dictionary
* @param {Array} dict - The dictionary from which we pick an object
* @return {Object} A random object from the array
*/

var pickRandomFromDictionary = function (dict)
  {
  var keys = Object.keys(dict);
  var object
  object = dict[keys[ keys.length * Math.random() << 0]];
  return object;
  };

/*
* Resizes the game to fit new window dimensions
*/
var resizeGame = function ()
  {
  var height = window.innerHeight * window.devicePixelRatio;
  var width = window.innerWidth * window.devicePixelRatio;

  if (game != undefined)
    {
    game.width = width;
    game.height = height;
    game.stage.bounds.width = width;
    game.stage.bounds.height = height;

    if (game.renderType === 1)
      {
      game.renderer.resize(width, height);
      Phaser.Canvas.setSmoothingEnabled(game.context, false);
      }
    }
  };

<commit_msg>Added two functions to util<commit_after>'use strict';

/*==========================================
|                  UTIL                    |
|     Here you'll find useful functions    |
==========================================*/

/**
* Get a point a minimum distance away from all players
* @param {game} game - The game object
* @param {Array} playerList - The list containing all player objects
* @param {Number} minimumDistance - The minimum distance from players to spawn from
* @param {Number} maxTryCount - The maximum amount of attempts until returning null
* @return {Point} A Point at least minimumDistance away from all players or null in which case no monster is spawned
*/
var getPosMinDPlayers = function (game, playerList, minimumDistance, maxTryCount)
	{
	var tryCount = 0;

	var acceptablePosition = false;
	while (!acceptablePosition || (tryCount < maxTryCount && maxTryCount != undefined))
		{
		var randomPos = {};
		randomPos.x = game.camera.x + game.rnd.integerInRange(0, game.camera.width);
		randomPos.y = game.camera.y + game.rnd.integerInRange(0, game.camera.height);
		if (dClosestPlayer(playerList, randomPos) >= minimumDistance)
			{
			acceptablePosition = true;
			}
		tryCount++;
		}

	if (randomPos != undefined)
		{
		return randomPos;
		} else
		{
		return null;
		}
	};

/*
* Return the distance between the provided position and the closes player
* @param {Array} players - List of all players
* @param {Point} position - The position to which compare
* @return {Number} The distance in pixels from position to the closest player
*/
var dClosestPlayer = function (players, position)
  {
  var currentMin = 9999999; // Arbitrarily large number
  for (var id in players)
    {
    var player = players[id];
    if (player != undefined && !player.dead)
      {
      var distance = Math.sqrt( Math.pow( (player.sprite.position.x - position.x), 2 ) +
                                Math.pow( (player.sprite.position.y - position.y), 2) );
      if (distance <= currentMin)
        {
        currentMin = distance;
        }
      }
    }
  return currentMin;
  };

/*
* Picks a random entry from a dictionary
* @param {Array} dict - The dictionary from which we pick an object
* @return {Object} A random object from the array
*/

var pickRandomFromDictionary = function (dict)
  {
  var keys = Object.keys(dict);
  var object
  object = dict[keys[ keys.length * Math.random() << 0]];
  return object;
  };

/*
* Resizes the game to fit new window dimensions
*/
var resizeGame = function ()
  {
  var height = window.innerHeight * window.devicePixelRatio;
  var width = window.innerWidth * window.devicePixelRatio;

  if (game != undefined)
    {
    game.width = width;
    game.height = height;
    game.stage.bounds.width = width;
    game.stage.bounds.height = height;

    if (game.renderType === 1)
      {
      game.renderer.resize(width, height);
      Phaser.Canvas.setSmoothingEnabled(game.context, false);
      }
    }
  };

/**
* Returns a list of players around the specified point
* @param {Array} players - List of all players.
* @param {Point} point - The point around which to check
* @param {Number} sizeX - The radius of the square in X direction which we use to check
* @param {Number} sizeY - The radius of the square in Y direction which we use to check
* @return {Array} List of all players within the specified area, or undefined if no players found in the area
*/
var getPlayersAroundPoint = function (players,point,sizeX,sizeY)
{
	//We use the data provided to construct a square around the area

	//Bottom left
	var squarePointsA = {}
	squarePointsA.x = squarePointsA.y = point.x-sizeX-sizeY;

	//Top right
	var squarePointsB = {}
	squarePointsD.x = squarePointsD.y = point.x+sizeX+sizeY;

	return getPlayersInArea(players,squarePointsA,squarePointsB);

}

/**
* Return a list of players inside the provided area defined by two points
* @param {Array} players - List of all players in the game
* @param {Point} botLeft - Represents the bottom left corner coordinates of the square
* @param {Point} topRight - Represents the top right corner coordinates of the square
* @return {Array} Array containing players inside the provided area or undefined if no players found in the area
*/
var getPlayersInArea = function (players, botLeft, topRight)
{
	var returnPlayers = [];
	var keys = Object.keys(players);
	var curPos;
	for(var i = 0; i < Object.keys(players).length; i++)
		{
			curPos = players[keys[i]].sprite.position;
			if(curPos.x > botLeft.x &&
				 curPos.y > botLeft.y &&
				 curPos.x < topRight.x &&
				 curPos.y < topRight.y)
			{
				returnPlayers.push(players[keys[i]]);
			}
		}
		if(returnPlayers.length > 0)
		{
			return returnPlayers;
		}
		return;
}<|endoftext|>


<commit_before>'use strict';   // dont touch
var plugin = []; // dont touch
this.command = []; // dont touch
this.commandName = []; // dont touch
this.gamemodeId = []; // dont touch
this.gamemode = []; // dont touch
this.addToHelp = []; // dont touch

// [General]
this.name = "GiveMeMinionsToo"; // Name of plugin REQUIRED
this.author = "AJS - Dev"; // author REQUIRED
this.description = 'Gives minions to people randomly'; // Desciprtion
this.compatVersion = ''; // compatable with (optional)
this.version = '1.0.0'; // version REQUIRED

// [Extra Commands]
this.commandName[0] = "gmm"; // plugin add-on command names
this.addToHelp[0] = "gmm      : Give me minions command"; // help command add-on (adds this string to the help command)
this.command[0] = function(gameServer,split) {
  if (split[1] == "power") {
    gameServer.GMMpower = !gameServer.GMMpower;
    var s = gameServer.GMMpower ? "on" : "off";
    console.log("[Console] Turned " + s + " plugin");
    return;
  } else if (split[1] = "kill") {
    try {
   clearTimeout(gameServer.intervalTM)
   console.log("[Console] Successevly forced killed give me minions");
   return;
   } catch (e) {
     console.log("[Console] Failed to kill the givememinions plugin")
     return;
   }

  } else {
    console.log("[Console] Please specify a command! Available: Power, Kill");
  }

}; // extra command location

// [Extra Gamemodes]
this.gamemodeId[0] = ''; // gamemodeids of extra plugin gamemodes
this.gamemode[0] = ''; // gamemode location

// [Configs]
this.config = {
switchIntervalTime: 10000,
minionGiveAmount: 30,
botGetMinions: 1,
setPerInterval:  2

}
this.configfile = 'config.ini'

// [Functions]
this.init = function (gameServer, config) {
  this.config = config;
  gameServer.intervalTM;
  gameServer.GMMpower = true;
  gameServer.gmpid = [];
  try {
    clearTimeout(gameServer.intervalTM);
  } catch (e) {
    // nothing
  }
  this.start(gameServer)
  console.log("[Console] Give me minions running!")
  // init, Used to do stuff such as overriding things

};
this.getrandom = function(gameServer) {
  var newrandom = [];
  var a = 0;
  for (var i in gameServer.clients) { // protection, just in case
    if (this.config.botGetMinions == 1 && gameServer.clients[i] && gameServer.gmpid.indexOf(gameServer.clients[i].playerTracker.pID) == -1) {
    newrandom[a] = gameServer.clients[i].playerTracker;
    a ++;
    } else if (gameServer.clients[i].playerTracker.socket.remoteAddress && gameServer.clients[i] && gameServer.gmpid.indexOf(gameServer.clients[i].playerTracker.pID) == -1) {
      newrandom[a] = gameServer.clients[i].playerTracker;
    a ++;
    }
  }
  var item = newrandom[Math.floor(Math.random()*newrandom.length)];
  return item;
}

this.start = function(gameServer) {
  var inttim = function() {
  gameServer.intervalTM = setTimeout(function() {
    if (gameServer.running && gameServer.GMMpower) {
    var nsplit = [];
    nsplit[1] = "destroy";
    gameServer.consoleService.execCommand("minion", nsplit)
    for (var i in this.config.setPerInterval) {
      var random = this.getrandom()
      gameServer.gmpid.push(random.pID)
      var nsplit = [];
      nsplit[1] = random.pID;
      nsplit[2] = this.config.minionGiveAmount;
      gameServer.consoleService.execCommand("minion", nsplit);
    }

    }
    inttim() // loop
  }.bind(this), this.config.switchIntervalTime)

  }.bind(this);
  inttim(); // startloop
}

this.onSecond = function (gameServer) {

  // called every second
};

module.exports = this; // dont touch
<commit_msg>Update index.js<commit_after>'use strict';   // dont touch
var plugin = []; // dont touch
this.command = []; // dont touch
this.commandName = []; // dont touch
this.gamemodeId = []; // dont touch
this.gamemode = []; // dont touch
this.addToHelp = []; // dont touch

// [General]
this.name = "GiveMeMinionsToo"; // Name of plugin REQUIRED
this.author = "AJS - Dev"; // author REQUIRED
this.description = 'Gives minions to people randomly'; // Desciprtion
this.compatVersion = ''; // compatable with (optional)
this.version = '1.0.0'; // version REQUIRED

// [Extra Commands]
this.commandName[0] = "gmm"; // plugin add-on command names
this.addToHelp[0] = "gmm      : Give me minions command"; // help command add-on (adds this string to the help command)
this.command[0] = function(gameServer,split) {
  if (split[1] == "power") {
    gameServer.GMMpower = !gameServer.GMMpower;
    var s = gameServer.GMMpower ? "on" : "off";
    console.log("[Console] Turned " + s + " plugin");
    return;
  } else if (split[1] = "kill") {
    try {
   clearTimeout(gameServer.intervalTM)
   console.log("[Console] Successevly forced killed give me minions");
   return;
   } catch (e) {
     console.log("[Console] Failed to kill the givememinions plugin")
     return;
   }

  } else {
    console.log("[Console] Please specify a command! Available: Power, Kill");
  }

}; // extra command location

// [Extra Gamemodes]
this.gamemodeId[0] = ''; // gamemodeids of extra plugin gamemodes
this.gamemode[0] = ''; // gamemode location

// [Configs]
this.config = {
switchIntervalTime: 10000,
minionGiveAmount: 30,
botGetMinions: 1,
setPerInterval:  2

}
this.configfile = 'config.ini'

// [Functions]
this.init = function (gameServer, config) {
  this.config = config;
  gameServer.intervalTM;
  gameServer.GMMpower = true;
  gameServer.gmpid = [];
  try {
    clearTimeout(gameServer.intervalTM);
  } catch (e) {
    // nothing
  }
  this.start(gameServer);
  console.log("[Console] Give me minions running!")
  // init, Used to do stuff such as overriding things

};
this.getrandom = function(gameServer) {
  var newrandom = [];
  var a = 0;
  for (var i in gameServer.clients) { // protection, just in case
    if (this.config.botGetMinions == 1 && gameServer.clients[i] && gameServer.gmpid.indexOf(gameServer.clients[i].playerTracker.pID) == -1 && !gameServer.clients[i].playerTracker.owner) {
    newrandom[a] = gameServer.clients[i].playerTracker;
    a ++;
    } else if (gameServer.clients[i].playerTracker.socket.remoteAddress && gameServer.clients[i] && gameServer.gmpid.indexOf(gameServer.clients[i].playerTracker.pID) == -1 && !gameServer.clients[i].playerTracker.owner) {
      newrandom[a] = gameServer.clients[i].playerTracker;
    a ++;
    }
  }
  var item = newrandom[Math.floor(Math.random()*newrandom.length)];
  return item;
}

this.start = function(gameServer) {
  var inttim = function() {
  gameServer.intervalTM = setTimeout(function() {
    if (gameServer.running && gameServer.GMMpower) {
    var nsplit = [];
    nsplit[1] = "destroy";
    gameServer.consoleService.execCommand("minion", nsplit)
    for (var i = 0; i<this.config.setPerInterval; i++) {
      var random = this.getrandom(gameServer)
      gameServer.gmpid.push(random.pID)
      var nsplit = [];
      nsplit[1] = random.pID;
      nsplit[2] = this.config.minionGiveAmount;
      gameServer.consoleService.execCommand("minion", nsplit);
    }

    }
    inttim() // loop
  }.bind(this), this.config.switchIntervalTime)

  }.bind(this);
  inttim(); // startloop
}

this.onSecond = function (gameServer) {

  // called every second
};

module.exports = this; // dont touch
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2014 gskinner.com, inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
 */
(function() {
	"use strict";

	var ExpressionHover = function(cm, highlighter) {
		this.initialize(cm, highlighter);
	};
	var p = ExpressionHover.prototype;

	p.cm = null;
	p.tooltip = null;
	p.highlighter = null;
	p.token = null;
	p.offset = 0;
	p.isMouseDown = false;

	p.initialize = function(cm, highlighter) {
		this.cm = cm;
		this.highlighter = highlighter;
		this.offset = highlighter.offset;

		this.tooltip = Tooltip.add(cm.display.lineDiv);
		this.tooltip.on("mousemove", this.onMouseMove, this);
		this.tooltip.on("mouseout", this.onMouseOut, this);

		cm.on("mousedown", $.bind(this, this.onMouseDown));
	};

	p.onMouseDown = function(evt) {
		if (evt.which != 1) { return; }
		this.onMouseMove(); // clear current
		this.isMouseDown = true;
		(window.addEventListener ? window : document).addEventListener("mouseup", $.bind(this, this.onMouseUp));
	};

	p.onMouseUp = function(evt) {
		if (evt.which != 1) { return; }
		this.isMouseDown = false;
	};

	p.onMouseMove = function(evt) {
		if (this.isMouseDown) { return; }
		var index, cm=this.cm, token=this.token, target = null;

		if (evt && token && (index = CMUtils.getCharIndexAt(cm, evt.clientX, evt.clientY+window.pageYOffset)) != null) {
			index -= this.offset;
			while (token) {
				if (index >= token.i && index < token.end) { target = token; break; }
				token = token.next;
			}
		}
		if (target && target.proxy) { target = target.proxy; }

		this.highlighter.selectToken(target);
		var rect = (index != null) && CMUtils.getCharRect(cm, index);
		if (rect) { rect.right = rect.left = evt.clientX; }
		this.tooltip.show(Docs.forToken(target), rect);
	};

	p.onMouseOut = function(evt) {
		this.highlighter.selectToken(null);
	};

window.ExpressionHover = ExpressionHover;
})();
<commit_msg>Fixed an issue with mouse button detection in ExpressionHover.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2014 gskinner.com, inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
 */
(function() {
	"use strict";

	var ExpressionHover = function(cm, highlighter) {
		this.initialize(cm, highlighter);
	};
	var p = ExpressionHover.prototype;

	p.cm = null;
	p.tooltip = null;
	p.highlighter = null;
	p.token = null;
	p.offset = 0;
	p.isMouseDown = false;

	p.initialize = function(cm, highlighter) {
		this.cm = cm;
		this.highlighter = highlighter;
		this.offset = highlighter.offset;

		this.tooltip = Tooltip.add(cm.display.lineDiv);
		this.tooltip.on("mousemove", this.onMouseMove, this);
		this.tooltip.on("mouseout", this.onMouseOut, this);

		cm.on("mousedown", $.bind(this, this.onMouseDown));
	};

	p.onMouseDown = function(cm, evt) {
		if (evt.which == 1 || evt.button == 1) {
			this.onMouseMove(); // clear current
			this.isMouseDown = true;
			(window.addEventListener ? window : document).addEventListener("mouseup", $.bind(this, this.onMouseUp));
		}
	};

	p.onMouseUp = function(evt) {
		if (evt.button == 1 || evt.which == 1) { this.isMouseDown = false; }
	};

	p.onMouseMove = function(evt) {
		if (this.isMouseDown) { return; }
		var index, cm=this.cm, token=this.token, target = null;

		if (evt && token && (index = CMUtils.getCharIndexAt(cm, evt.clientX, evt.clientY+window.pageYOffset)) != null) {
			index -= this.offset;
			while (token) {
				if (index >= token.i && index < token.end) { target = token; break; }
				token = token.next;
			}
		}
		if (target && target.proxy) { target = target.proxy; }

		this.highlighter.selectToken(target);
		var rect = (index != null) && CMUtils.getCharRect(cm, index);
		if (rect) { rect.right = rect.left = evt.clientX; }
		this.tooltip.show(Docs.forToken(target), rect);
	};

	p.onMouseOut = function(evt) {
		this.highlighter.selectToken(null);
	};

window.ExpressionHover = ExpressionHover;
})();
<|endoftext|>


<commit_before>'use strict';

function testHest(req) {
  const authHeader = req.get('authorization');
  if (typeof authHeader !== 'undefined') {
    const authType = authHeader.split(' ', 2)[0];
    const bearerToken = authHeader.split(' ', 2)[1];

    if (authType === 'Bearer') {
      return bearerToken;
    }
  }
}

function testHest2(req) {
  const bearerToken = req.query.access_token;
  if (typeof bearerToken !== 'undefined') {
    return bearerToken;
  }
}

function testHest3(req) {
  const bearerToken = req.body.access_token;
  if (typeof bearerToken !== 'undefined') {
    return bearerToken;
  }
}

/**
 * Return array of functions to search for tokens in requests
 *
 * @param {object} req
 * @return {*[]}
 */
export function getTokenSearchers(req) {
  return [
    () => testHest(req),
    () => testHest2(req),
    () => testHest3(req)
  ];
}
<commit_msg>#576: - Renamed functions with silly names<commit_after>'use strict';

function checkAuthHeader(req) {
  const authHeader = req.get('authorization');
  if (typeof authHeader !== 'undefined') {
    const authType = authHeader.split(' ', 2)[0];
    const bearerToken = authHeader.split(' ', 2)[1];

    if (authType === 'Bearer') {
      return bearerToken;
    }
  }
}

function testQueryAccessToken(req) {
  const bearerToken = req.query.access_token;
  if (typeof bearerToken !== 'undefined') {
    return bearerToken;
  }
}

function testBodyAccessToken(req) {
  const bearerToken = req.body.access_token;
  if (typeof bearerToken !== 'undefined') {
    return bearerToken;
  }
}

/**
 * Return array of functions to search for tokens in requests
 *
 * @param {object} req
 * @return {*[]}
 */
export function getTokenSearchers(req) {
  return [
    () => checkAuthHeader(req),
    () => testQueryAccessToken(req),
    () => testBodyAccessToken(req)
  ];
}
<|endoftext|>


<commit_before>// Copyright 2016, University of Colorado Boulder

//TODO not ready for production use, see https://github.com/phetsims/chipper/issues/516
/**
 * Query parameters used by "post-load" PhET common code.
 * See initialize-globals.js for query parameters used in preload code.
 *
 * Sample usage:
 *
 * var QueryParameters = require( 'CHIPPER/QueryParameters' );
 * if ( QueryParameters.dev ) { ... }
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var chipper = require( 'CHIPPER/chipper' );
  var platform = require( 'PHET_CORE/platform' );

  var QueryParameters = QueryStringMachine.getAll( {

    // enables accessibility features, such as keyboard navigation (mileage may vary!)
    accessibility: { type: 'flag' },

    /**
     * When present, will trigger changes that are more similar to the build environment.
     * Right now, this includes computing higher-resolution mipmaps for the mipmap plugin.
     */
    buildCompatible: { type: 'flag' },

    //TODO not documented in initialize-globals.js
    brand: {
      type: 'string',
      defaultValue: 'adapted-from-phet',
      validValues: [ 'phet', 'phet-io', 'adapted-from-phet' ]
    },

    //TODO not documented in initialize-globals.js
    cacheBuster: { type: 'flag' },

    /**
     * When running one of the UI demo applications, selects a particular UI component in the Components screen.
     * See sun.DemosView.
     */
    component: {
      type: 'string',
      defaultValue: null
    },

    // enables developer-only features, such as showing the layout bounds
    dev: { type: 'flag' },

    // enables assertions
    ea: { type: 'flag' },

    // enables all assertions, as above but with more time-consuming checks
    eall: { type: 'flag' },

    // randomly sends mouse events to sim. value is the average number of mouse events to synthesize per frame.
    fuzzMouse: {
      type: 'number',
      defaultValue: 10
    },

    // Launches the game-up-camera code which delivers images to requests in BrainPOP/Game Up/SnapThought
    gameUp: { type: 'flag' },

    // Enables logging for game-up-camera, see gameUp
    gameUpLogging: { type: 'flag' },

    // for phet-io use relative path for finding the sim, instead of launching from phet-io.colorado.edu
    launchLocalVersion: { type: 'flag' },

    // test with a specific locale
    locale: {
      type: 'string',
      defaultValue: null
    },

    // When a simulation is run from the PhET app, it should set this flag. It alters statistics that the sim sends
    // to Google Analytics and potentially other sources in the future.
    'phet-app': { type: 'flag' },

    // when running a simulation using phetio.js, outputs states and deltas within the phetioEvents data stream, see phetio.js
    'phet-io.emitDeltas': { type: 'flag' },

    // when emitting deltas using phetio.js (see phet-io.emitDeltas) emit deltas that are empty, to simplify playback in some systems like Metacog.
    'phet-io.emitEmptyDeltas': { type: 'flag' },

    // emit the Scenery input events
    'phet-io.emitInputEvents': { type: 'flag' },

    // when running a simulation using phetio.js, outputs the state at the end of every frame
    'phet-io.emitStates': { type: 'flag' },

    // will output type documentation to the console, see https://github.com/phetsims/phet-io/issues/218
    'phet-io.docs': { type: 'flag' },

    // evaluate expressions on phet-io wrapper objects, like: ?phet-io.expressions=[["beaker.beakerScreen.soluteSelector","setVisible",[true]]]
    'phet-io.expressions': {
      type: 'string',
      defaultValue: null
    },

    // Specifies where to log phetioEvents
    'phet-io.log': {
      type: 'string',
      defaultValue: null,
      validValues: [
        null, // no logging
        'console', // stream to console in JSON format
        'lines' // stream colorized human-readable events to the console (Chrome and Firefox only)
      ]
    },

    // Causes a phet-io simulation to launch, even without a wrapper "go-ahead" step, see phet-io#181
    'phet-io.standalone': { type: 'flag' },

    // When running as phet-io assertions are normally thrown when uninstrumented objects are encountered.
    // Setting this to false will allow the simulation to proceed.  Useful for partially instrumented simulations.
    'phet-io.validateTandems': {
      type: 'flag',
      defaultValue: true
    },

    // plays event logging back from the server, provide an optional name for the session
    playbackInputEventLog: { type: 'flag' },

    //TODO document or delete, see https://github.com/phetsims/joist/issues/370
    playbackMode: { type: 'flag' },

    // triggers a post-message that fires when the sim finishes loading, currently used by aqua test-sims
    postMessageOnLoad: { type: 'flag' },

    // passes errors to test-sims
    postMessageOnError: { type: 'flag' },

    // shows profiling information for the sim
    profiler: { type: 'flag' },

    // adds a menu item that will open a window with a QR code with the URL of the simulation
    qrCode: { type: 'flag' },

    // enables input event logging, provide an optional name for the session, log is available via PhET menu
    recordInputEventLog: { type: 'flag' },

    // Specify a renderer for the Sim's rootNode to use. See joist#221 and joist#184.
    rootRenderer: {
      type: 'string',
      defaultValue: platform.edge ? 'canvas' : 'svg', // see https://github.com/phetsims/molarity/issues/24
      validValues: [ 'canvas', 'svg', 'dom', 'webgl' ] // see Node.setRenderer
    },

    //TODO array processing should be done here
    // List of one or more logs to enable in scenery 0.2+, delimited with .
    // For example: ?sceneryLog=Display.Drawable.WebGLBlock
    sceneryLog: {
      type: 'string',
      defaultValue: null
    },

    // Scenery logs will be output to a string instead of the window
    sceneryStringLog: { type: 'flag' },

    // identifier for a single simulation run
    sessionID: {
      type: 'string',
      defaultValue: null
    },

    //TODO not documented in initialize-globals.js
    screenIndex: {
      type: 'number',
      defaultValue: 0
    },

    //TODO array processing should be done here
    screens: {
      type: 'string',
      defaultValue: null
    },

    // Displays an overlay of the current bounds of each CanvasNode
    showCanvasNodeBounds: { type: 'flag' },

    // Displays an overlay of the current bounds of each scenery.FittedBlock
    showFittedBlockBounds: { type: 'flag' },

    // if false, go immediately to screenIndex
    showHomeScreen: { type: 'flag' },

    // Shows pointer areas as dashed lines. touchAreas are red, mouseAreas are blue.
    showPointerAreas: { type: 'flag' },

    // Displays a semi-transparent cursor indicator for the location of each active pointer on the screen.
    showPointers: { type: 'flag' },

    // Shows the visible bounds in ScreenView.js, for debugging the layout outside of the "dev" bounds
    showVisibleBounds: { type: 'flag' },

    /**
     * Sets a string used for various i18n test.  The values are:
     *
     * double: duplicates all of the translated strings which will allow to see (a) if all strings
     *   are translated and (b) whether the layout can accommodate longer strings from other languages.
     *   Note this is a heuristic rule that does not cover all cases.
     *
     * long: an exceptionally long string will be substituted for all strings. Use this to test for layout problems.
     *
     * rtl: a string that tests RTL (right-to-left) capabilities will be substituted for all strings
     *
     * xss: tests for security issues related to https://github.com/phetsims/special-ops/issues/18,
     *   and running a sim should NOT redirect to another page. Preferably should be used for built versions or
     *   other versions where assertions are not enabled (brackets can cause issues for SubSupText, etc.)
     *
     * none|null: the normal translated string will be shown
     *
     * {string}: if any other string provided, that string will be substituted everywhere. This facilitates testing
     *   specific cases, like whether the word 'vitesse' would substitute for 'speed' well.  Also, using "/u20" it
     *   will show whitespace for all of the strings, making it easy to identify non-translated strings.
     */
    stringTest: {
      type: 'string',
      defaultValue: null
    },

    // override strings, value is JSON that is identical to string.json files
    strings: {
      type: 'string',
      defaultValue: null
    },

    // Whether accessibility features are enabled or not.
    virtualCursor: { type: 'flag' },

    // Enables WebGL rendering. See https://github.com/phetsims/scenery/issues/289
    webgl: {
      type: 'flag',
      defaultValue: true
    },

    /**
     * Puts the WebGLLayer into a testing mode which simulates context loss between successively increasing gl
     * calls (starting at 1). This parameter should be used in conjunction with webglContextLossTimeout since
     * it only triggers upon the first context loss.
     */
    webglContextLossIncremental: { type: 'flag' },

    //TODO this one is problematic, it's both a 'flag' and a 'number'
    /**
     * Creates WebGL contexts that can simulate context loss. If a value is specified, it will simulate a context loss
     * after the specified number of milliseconds has elapsed. The value can be omitted to manually simulate the
     * context loss with simScene.simulateWebGLContextLoss()
     */
    webglContextLossTimeout: {
      type: 'number',
      defaultValue: 0
    }
  } );

  chipper.register( 'QueryParameters', QueryParameters );

  return QueryParameters;
} );
<commit_msg>add colorProfile query parameter, https://github.com/phetsims/joist/issues/371<commit_after>// Copyright 2016, University of Colorado Boulder

//TODO not ready for production use, see https://github.com/phetsims/chipper/issues/516
/**
 * Query parameters used by "post-load" PhET common code.
 * See initialize-globals.js for query parameters used in preload code.
 *
 * Sample usage:
 *
 * var QueryParameters = require( 'CHIPPER/QueryParameters' );
 * if ( QueryParameters.dev ) { ... }
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var chipper = require( 'CHIPPER/chipper' );
  var platform = require( 'PHET_CORE/platform' );

  var QueryParameters = QueryStringMachine.getAll( {

    // enables accessibility features, such as keyboard navigation (mileage may vary!)
    accessibility: { type: 'flag' },

    /**
     * When present, will trigger changes that are more similar to the build environment.
     * Right now, this includes computing higher-resolution mipmaps for the mipmap plugin.
     */
    buildCompatible: { type: 'flag' },

    //TODO not documented in initialize-globals.js
    brand: {
      type: 'string',
      defaultValue: 'adapted-from-phet',
      validValues: [ 'phet', 'phet-io', 'adapted-from-phet' ]
    },

    //TODO not documented in initialize-globals.js
    cacheBuster: { type: 'flag' },

    /**
     * The color profile used at startup, relevant only for sims that support multiple color profiles.
     * Such sims are required to support the 'default' profile.  If a sim supports a 'project mode' then
     * it should also have a 'projector' profile.  Other profile names are not currently standardized.
     */
    colorProfile: {
      type: 'string',
      defaultValue: 'default'
    },

    /**
     * When running one of the UI demo applications, selects a particular UI component in the Components screen.
     * See sun.DemosView.
     */
    component: {
      type: 'string',
      defaultValue: null
    },

    // enables developer-only features, such as showing the layout bounds
    dev: { type: 'flag' },

    // enables assertions
    ea: { type: 'flag' },

    // enables all assertions, as above but with more time-consuming checks
    eall: { type: 'flag' },

    // randomly sends mouse events to sim. value is the average number of mouse events to synthesize per frame.
    fuzzMouse: {
      type: 'number',
      defaultValue: 10
    },

    // Launches the game-up-camera code which delivers images to requests in BrainPOP/Game Up/SnapThought
    gameUp: { type: 'flag' },

    // Enables logging for game-up-camera, see gameUp
    gameUpLogging: { type: 'flag' },

    // for phet-io use relative path for finding the sim, instead of launching from phet-io.colorado.edu
    launchLocalVersion: { type: 'flag' },

    // test with a specific locale
    locale: {
      type: 'string',
      defaultValue: null
    },

    // When a simulation is run from the PhET app, it should set this flag. It alters statistics that the sim sends
    // to Google Analytics and potentially other sources in the future.
    'phet-app': { type: 'flag' },

    // when running a simulation using phetio.js, outputs states and deltas within the phetioEvents data stream, see phetio.js
    'phet-io.emitDeltas': { type: 'flag' },

    // when emitting deltas using phetio.js (see phet-io.emitDeltas) emit deltas that are empty, to simplify playback in some systems like Metacog.
    'phet-io.emitEmptyDeltas': { type: 'flag' },

    // emit the Scenery input events
    'phet-io.emitInputEvents': { type: 'flag' },

    // when running a simulation using phetio.js, outputs the state at the end of every frame
    'phet-io.emitStates': { type: 'flag' },

    // will output type documentation to the console, see https://github.com/phetsims/phet-io/issues/218
    'phet-io.docs': { type: 'flag' },

    // evaluate expressions on phet-io wrapper objects, like: ?phet-io.expressions=[["beaker.beakerScreen.soluteSelector","setVisible",[true]]]
    'phet-io.expressions': {
      type: 'string',
      defaultValue: null
    },

    // Specifies where to log phetioEvents
    'phet-io.log': {
      type: 'string',
      defaultValue: null,
      validValues: [
        null, // no logging
        'console', // stream to console in JSON format
        'lines' // stream colorized human-readable events to the console (Chrome and Firefox only)
      ]
    },

    // Causes a phet-io simulation to launch, even without a wrapper "go-ahead" step, see phet-io#181
    'phet-io.standalone': { type: 'flag' },

    // When running as phet-io assertions are normally thrown when uninstrumented objects are encountered.
    // Setting this to false will allow the simulation to proceed.  Useful for partially instrumented simulations.
    'phet-io.validateTandems': {
      type: 'flag',
      defaultValue: true
    },

    // plays event logging back from the server, provide an optional name for the session
    playbackInputEventLog: { type: 'flag' },

    //TODO document or delete, see https://github.com/phetsims/joist/issues/370
    playbackMode: { type: 'flag' },

    // triggers a post-message that fires when the sim finishes loading, currently used by aqua test-sims
    postMessageOnLoad: { type: 'flag' },

    // passes errors to test-sims
    postMessageOnError: { type: 'flag' },

    // shows profiling information for the sim
    profiler: { type: 'flag' },

    // adds a menu item that will open a window with a QR code with the URL of the simulation
    qrCode: { type: 'flag' },

    // enables input event logging, provide an optional name for the session, log is available via PhET menu
    recordInputEventLog: { type: 'flag' },

    // Specify a renderer for the Sim's rootNode to use. See joist#221 and joist#184.
    rootRenderer: {
      type: 'string',
      defaultValue: platform.edge ? 'canvas' : 'svg', // see https://github.com/phetsims/molarity/issues/24
      validValues: [ 'canvas', 'svg', 'dom', 'webgl' ] // see Node.setRenderer
    },

    //TODO array processing should be done here
    // List of one or more logs to enable in scenery 0.2+, delimited with .
    // For example: ?sceneryLog=Display.Drawable.WebGLBlock
    sceneryLog: {
      type: 'string',
      defaultValue: null
    },

    // Scenery logs will be output to a string instead of the window
    sceneryStringLog: { type: 'flag' },

    // identifier for a single simulation run
    sessionID: {
      type: 'string',
      defaultValue: null
    },

    //TODO not documented in initialize-globals.js
    screenIndex: {
      type: 'number',
      defaultValue: 0
    },

    //TODO array processing should be done here
    screens: {
      type: 'string',
      defaultValue: null
    },

    // Displays an overlay of the current bounds of each CanvasNode
    showCanvasNodeBounds: { type: 'flag' },

    // Displays an overlay of the current bounds of each scenery.FittedBlock
    showFittedBlockBounds: { type: 'flag' },

    // if false, go immediately to screenIndex
    showHomeScreen: { type: 'flag' },

    // Shows pointer areas as dashed lines. touchAreas are red, mouseAreas are blue.
    showPointerAreas: { type: 'flag' },

    // Displays a semi-transparent cursor indicator for the location of each active pointer on the screen.
    showPointers: { type: 'flag' },

    // Shows the visible bounds in ScreenView.js, for debugging the layout outside of the "dev" bounds
    showVisibleBounds: { type: 'flag' },

    /**
     * Sets a string used for various i18n test.  The values are:
     *
     * double: duplicates all of the translated strings which will allow to see (a) if all strings
     *   are translated and (b) whether the layout can accommodate longer strings from other languages.
     *   Note this is a heuristic rule that does not cover all cases.
     *
     * long: an exceptionally long string will be substituted for all strings. Use this to test for layout problems.
     *
     * rtl: a string that tests RTL (right-to-left) capabilities will be substituted for all strings
     *
     * xss: tests for security issues related to https://github.com/phetsims/special-ops/issues/18,
     *   and running a sim should NOT redirect to another page. Preferably should be used for built versions or
     *   other versions where assertions are not enabled (brackets can cause issues for SubSupText, etc.)
     *
     * none|null: the normal translated string will be shown
     *
     * {string}: if any other string provided, that string will be substituted everywhere. This facilitates testing
     *   specific cases, like whether the word 'vitesse' would substitute for 'speed' well.  Also, using "/u20" it
     *   will show whitespace for all of the strings, making it easy to identify non-translated strings.
     */
    stringTest: {
      type: 'string',
      defaultValue: null
    },

    // override strings, value is JSON that is identical to string.json files
    strings: {
      type: 'string',
      defaultValue: null
    },

    // Whether accessibility features are enabled or not.
    virtualCursor: { type: 'flag' },

    // Enables WebGL rendering. See https://github.com/phetsims/scenery/issues/289
    webgl: {
      type: 'flag',
      defaultValue: true
    },

    /**
     * Puts the WebGLLayer into a testing mode which simulates context loss between successively increasing gl
     * calls (starting at 1). This parameter should be used in conjunction with webglContextLossTimeout since
     * it only triggers upon the first context loss.
     */
    webglContextLossIncremental: { type: 'flag' },

    //TODO this one is problematic, it's both a 'flag' and a 'number'
    /**
     * Creates WebGL contexts that can simulate context loss. If a value is specified, it will simulate a context loss
     * after the specified number of milliseconds has elapsed. The value can be omitted to manually simulate the
     * context loss with simScene.simulateWebGLContextLoss()
     */
    webglContextLossTimeout: {
      type: 'number',
      defaultValue: 0
    }
  } );

  chipper.register( 'QueryParameters', QueryParameters );

  return QueryParameters;
} );
<|endoftext|>


<commit_before>var Group = React.createClass({
  //mixins: [React.addons.PureRenderMixin],

  onClick: function() {
    Action.select(this.props.group);
  },

  getPortPos: function(obj, portName, dir, self) {
    var width = obj.width;
    var height = obj.height;
    if (obj.getSize) {
      var size = obj.collapsed ? obj.getSize() : obj.getCalculatedSize();
      width = size.width;
      height = size.height;
    }

    var x = self ? 0 : obj.x;
    var y = self ? 0 : obj.y;
    if (self) dir = dir == 'in' ? 'out' : 'in';

    var ports = obj.ports;
    if (!ports) {
      ports = {
        in: Object.keys(Tools.processes[obj.name].input),
        out: Object.keys(Tools.processes[obj.name].output)
      }
    }

    x += (ports[dir].indexOf(portName)+1) * (width / (ports[dir].length + 1));
    y += dir == 'out' ? height : 0;
    y += (dir == 'out' ? 10 : -10) * (self ? - 1 : 1);

    return { x: x, y: y };
  },

  render: function() {
    var group = this.props.group;
    var groups, processez, links;

    //if (!this.props.blank) group.height = 50;

    if (group.groups) {
      groups = group.groups.map(g => <Group key={g.id} group={g}/>);
    }

    if (group.processes) {
      processez = group.processes.map(p => {
        var ports = { in: Object.keys(Tools.processes[p.name].input), out: Object.keys(Tools.processes[p.name].output) }
        var name = p.name;
        if (p.title) name = p.title;
        if (Tools.processes[p.name].title) name = Tools.processes[p.name].title;
        if (Tools.processes[p.name].toTitle) name = Tools.processes[p.name].toTitle(p);
        return <Process width={p.width} height={p.height} x={p.x} y={p.y}
                        name={name} ports={ports} graph={p} id={p.id} key={p.id}
                        selected={p.selected} />;
      });
    }

    if (group.links) {
      var ids = {};
      ids[group.id] = group;
      if (group.groups) group.groups.forEach(g => ids[g.id] = g)
      if (group.processes) group.processes.forEach(p => ids[p.id] = p)

      links = group.links.map(l => {
        var source = this.getPortPos(ids[l.from.id], l.from.port, 'out', l.from.id == group.id);
        var target = this.getPortPos(ids[l.to.id], l.to.port, 'in', l.to.id == group.id);
        return <Connector key={l.from.id+'/'+l.from.port+'/'+l.to.id+'/'+l.to.port} source={source} target={target} graph={l}/>;
      });
    }

    var children = [ groups, processez, links ];

    if (this.props.blank) {
      var size = group.getCalculatedSize();
      return (
        <Process width={size.width} height={size.height} name={group.title || group.name} ports={group.ports}
                 graph={group} id={group.id} blank={true} x={20} y={50}>
          {groups}
          {processez}
          {links}
        </Process>
      );
    } else {
      return (
        <Process width={group.width} height={group.height} name={group.title || group.name} ports={group.ports}
                 x={group.x} y={group.y} graph={group} id={group.id} selected={group.selected}>
        </Process>
      );
    }
  }
});
<commit_msg>less padding for main graph<commit_after>var Group = React.createClass({
  //mixins: [React.addons.PureRenderMixin],

  onClick: function() {
    Action.select(this.props.group);
  },

  getPortPos: function(obj, portName, dir, self) {
    var width = obj.width;
    var height = obj.height;
    if (obj.getSize) {
      var size = obj.collapsed ? obj.getSize() : obj.getCalculatedSize();
      width = size.width;
      height = size.height;
    }

    var x = self ? 0 : obj.x;
    var y = self ? 0 : obj.y;
    if (self) dir = dir == 'in' ? 'out' : 'in';

    var ports = obj.ports;
    if (!ports) {
      ports = {
        in: Object.keys(Tools.processes[obj.name].input),
        out: Object.keys(Tools.processes[obj.name].output)
      }
    }

    x += (ports[dir].indexOf(portName)+1) * (width / (ports[dir].length + 1));
    y += dir == 'out' ? height : 0;
    y += (dir == 'out' ? 10 : -10) * (self ? - 1 : 1);

    return { x: x, y: y };
  },

  render: function() {
    var group = this.props.group;
    var groups, processez, links;

    //if (!this.props.blank) group.height = 50;

    if (group.groups) {
      groups = group.groups.map(g => <Group key={g.id} group={g}/>);
    }

    if (group.processes) {
      processez = group.processes.map(p => {
        var ports = { in: Object.keys(Tools.processes[p.name].input), out: Object.keys(Tools.processes[p.name].output) }
        var name = p.name;
        if (p.title) name = p.title;
        if (Tools.processes[p.name].title) name = Tools.processes[p.name].title;
        if (Tools.processes[p.name].toTitle) name = Tools.processes[p.name].toTitle(p);
        return <Process width={p.width} height={p.height} x={p.x} y={p.y}
                        name={name} ports={ports} graph={p} id={p.id} key={p.id}
                        selected={p.selected} />;
      });
    }

    if (group.links) {
      var ids = {};
      ids[group.id] = group;
      if (group.groups) group.groups.forEach(g => ids[g.id] = g)
      if (group.processes) group.processes.forEach(p => ids[p.id] = p)

      links = group.links.map(l => {
        var source = this.getPortPos(ids[l.from.id], l.from.port, 'out', l.from.id == group.id);
        var target = this.getPortPos(ids[l.to.id], l.to.port, 'in', l.to.id == group.id);
        return <Connector key={l.from.id+'/'+l.from.port+'/'+l.to.id+'/'+l.to.port} source={source} target={target} graph={l}/>;
      });
    }

    var children = [ groups, processez, links ];

    if (this.props.blank) {
      var size = group.getCalculatedSize();
      return (
        <Process width={size.width} height={size.height} name={group.title || group.name} ports={group.ports}
                 graph={group} id={group.id} blank={true} x={group.id == 0 ? 0 : 20} y={group.id == 0 ? 0 : 50}>
          {groups}
          {processez}
          {links}
        </Process>
      );
    } else {
      return (
        <Process width={group.width} height={group.height} name={group.title || group.name} ports={group.ports}
                 x={group.x} y={group.y} graph={group} id={group.id} selected={group.selected}>
        </Process>
      );
    }
  }
});
<|endoftext|>