<commit_before>_RELEASE_VERSION = "2.0.3";

Package.describe({
  name: "houston:admin",
  summary: "A zero-config Meteor Admin",
  version: _RELEASE_VERSION,
  git: "https://github.com/gterrono/houston.git"
});

Package.on_use(function(api) {
  api.versionsFrom('METEOR@1.0');

  //////////////////////////////////////////////////////////////////
  // Meteor-provided packages
  //////////////////////////////////////////////////////////////////
  api.use('deps@1.0.0', ['client', 'server']);
  api.use('coffeescript@1.0.0', ['client', 'server']);
  api.use('accounts-base@1.0.0', ['client', 'server']);  // ?optional
  api.use('accounts-password@1.0.0', ['client', 'server']);
  api.use('templating@1.0.0', 'client');  // ?optional
  api.use('check@1.0.0', 'client');
  api.use('spacebars@1.0.0', 'client');

  //////////////////////////////////////////////////////////////////
  // Third-party package dependencies
  //////////////////////////////////////////////////////////////////
  api.use('iron:router@1.0.1', 'client');
  api.use('tmeasday:paginated-subscription@0.2.4', 'client');
  api.use('dburles:mongo-collection-instances@0.3.4', ['client', 'server']);

  //////////////////////////////////////////////////////////////////
  // internal files
  //////////////////////////////////////////////////////////////////
  // load html first, https://github.com/meteor/meteor/issues/282
  api.add_files([
    // views
    'client/admin_login.html', 'client/db_view.html',
    'client/collection_view.html', 'client/document_view.html',
    'client/admin_change_password.html', 'client/custom_template_view.html',
    // partials
    'client/partials/admin_nav.html',
    'client/partials/flash_message.html',
    'client/partials/custom_actions.html',
    // layout
    'client/master_layout.html',
    'client/third-party/collapse.js.html',
    'client/third-party/bootstrap.html',
    'client/style.css.html'
    ],
  'client');

  api.add_files(['lib/collections.coffee',
                 'lib/shared.coffee',
                 'lib/menu.coffee'],
                ['client', 'server']);

  api.add_files([
    // shared
    'client/lib/shared.coffee',
    // shared partials
    'client/partials/admin_nav.coffee',
    'client/partials/flash_message.coffee',
    'client/partials/custom_actions.coffee',
    // view logic
    'client/custom_template_view.coffee', 'client/admin_login.coffee',
    'client/collection_view.coffee', 'client/document_view.coffee',
    'client/admin_change_password.coffee', 'client/db_view.coffee',
    // router
    'client/router.coffee'
    ],
  'client');

  api.add_files(['server/publications.coffee', 'server/exports.coffee', 'server/methods.coffee'], 'server');
});
<commit_msg>bumped version to 2.0.4<commit_after>_RELEASE_VERSION = "2.0.4";

Package.describe({
  name: "houston:admin",
  summary: "A zero-config Meteor Admin",
  version: _RELEASE_VERSION,
  git: "https://github.com/gterrono/houston.git"
});

Package.on_use(function(api) {
  api.versionsFrom('METEOR@1.0');

  //////////////////////////////////////////////////////////////////
  // Meteor-provided packages
  //////////////////////////////////////////////////////////////////
  api.use('deps@1.0.0', ['client', 'server']);
  api.use('coffeescript@1.0.0', ['client', 'server']);
  api.use('accounts-base@1.0.0', ['client', 'server']);  // ?optional
  api.use('accounts-password@1.0.0', ['client', 'server']);
  api.use('templating@1.0.0', 'client');  // ?optional
  api.use('check@1.0.0', 'client');
  api.use('spacebars@1.0.0', 'client');

  //////////////////////////////////////////////////////////////////
  // Third-party package dependencies
  //////////////////////////////////////////////////////////////////
  api.use('iron:router@1.0.1', 'client');
  api.use('tmeasday:paginated-subscription@0.2.4', 'client');
  api.use('dburles:mongo-collection-instances@0.3.4', ['client', 'server']);

  //////////////////////////////////////////////////////////////////
  // internal files
  //////////////////////////////////////////////////////////////////
  // load html first, https://github.com/meteor/meteor/issues/282
  api.add_files([
    // views
    'client/admin_login.html', 'client/db_view.html',
    'client/collection_view.html', 'client/document_view.html',
    'client/admin_change_password.html', 'client/custom_template_view.html',
    // partials
    'client/partials/admin_nav.html',
    'client/partials/flash_message.html',
    'client/partials/custom_actions.html',
    // layout
    'client/master_layout.html',
    'client/third-party/collapse.js.html',
    'client/third-party/bootstrap.html',
    'client/style.css.html'
    ],
  'client');

  api.add_files(['lib/collections.coffee',
                 'lib/shared.coffee',
                 'lib/menu.coffee'],
                ['client', 'server']);

  api.add_files([
    // shared
    'client/lib/shared.coffee',
    // shared partials
    'client/partials/admin_nav.coffee',
    'client/partials/flash_message.coffee',
    'client/partials/custom_actions.coffee',
    // view logic
    'client/custom_template_view.coffee', 'client/admin_login.coffee',
    'client/collection_view.coffee', 'client/document_view.coffee',
    'client/admin_change_password.coffee', 'client/db_view.coffee',
    // router
    'client/router.coffee'
    ],
  'client');

  api.add_files(['server/publications.coffee', 'server/exports.coffee', 'server/methods.coffee'], 'server');
});
<|endoftext|>


<commit_before>Package.describe({
  summary: "VisualCaptcha better integrated with meteor"
});

Npm.depends({
  "visualcaptcha" : "0.0.2"
})

Package.on_use(function (api, where) {
  //api.use('server');
  api.use(['deps','underscore', 'templating',
           'handlebars', 'spark', 'session', 'jquery'], 'client');
  api.add_files('lib/index.js', 'server');
  api.add_files('client/visualcaptcha.jquery.js', 'client');
  api.add_files('client/captcha.css', 'client');
  api.add_files('client/captcha.html', 'client');
  api.add_files('client/captcha.js', 'client');
  api.add_files('images/img/refresh.png');
  api.add_files('images/img/refresh@2x.png');
  api.add_files('images/img/accessibility.png');
  api.add_files('images/img/accessibility@2x.png');
  api.add_files('server/captcha.js', 'server');
  api.export(['VisualCaptcha'], 'server');

});
<commit_msg>and another issue<commit_after>Package.describe({
  summary: "VisualCaptcha better integrated with meteor"
});

Npm.depends({
  "visualcaptcha" : "0.0.2"
})

Package.on_use(function (api, where) {
  //api.use('server');
  api.use(['deps','underscore', 'templating',
           'handlebars', 'spark', 'session', 'jquery'], 'client');
  api.use('iron-router','server')
  api.add_files('lib/index.js', 'server');
  api.add_files('client/visualcaptcha.jquery.js', 'client');
  api.add_files('client/captcha.css', 'client');
  api.add_files('client/captcha.html', 'client');
  api.add_files('client/captcha.js', 'client');
  api.add_files('images/img/refresh.png');
  api.add_files('images/img/refresh@2x.png');
  api.add_files('images/img/accessibility.png');
  api.add_files('images/img/accessibility@2x.png');
  api.add_files('server/captcha.js', 'server');
  api.export(['VisualCaptcha'], 'server');

});
<|endoftext|>


<commit_before>Package.describe({
  summary: 'Routing specifically designed for Meteor'
});

Package.on_use(function (api) {
  api.use('reactive-dict', ['client', 'server']);
  api.use('deps', ['client', 'server']);
  api.use('underscore', ['client', 'server']);
  api.use('ejson', ['client', 'server']);
  api.use('jquery', 'client');

  // default ui manager
  // use unordered: true becuase of circular dependency

  // XXX commenting out for now because this is somehow causing problems
  //api.use('blaze-layout', 'client', {unordered: true});

  // for default helpers like pathFor, urlFor
  api.use('ui', 'client', {weak: true});

  api.add_files('lib/utils.js', ['client', 'server']);
  api.add_files('lib/route.js', ['client', 'server']);
  api.add_files('lib/route_controller.js', ['client', 'server']);
  api.add_files('lib/router.js', ['client', 'server']);

  api.add_files('lib/client/location.js', 'client');
  api.add_files('lib/client/router.js', 'client');
  api.add_files('lib/client/wait_list.js', 'client');
  api.add_files('lib/client/hooks.js', 'client');
  api.add_files('lib/client/route_controller.js', 'client');
  api.add_files('lib/client/helpers.js', 'client');

  api.add_files('lib/server/route_controller.js', 'server');
  api.add_files('lib/server/router.js', 'server');

  api.use('webapp', 'server');
  Npm.depends({connect: '2.7.10'});

  api.export('RouteController', ['client', 'server']);
  api.export('Route', ['client', 'server']);
  api.export('Router', ['client', 'server']);
  api.export('IronLocation', 'client');

  api.export('Utils', ['client', 'server'], {testOnly: true});
  api.export('IronRouter', ['client', 'server'], {testOnly: true});
  api.export('WaitList', 'client', {testOnly: true});
});

Package.on_test(function (api) {
  api.use('iron-router', ['client', 'server']);
  api.use('tinytest', ['client', 'server']);
  api.use('test-helpers', ['client', 'server']);
  api.use('reactive-dict', ['client', 'server']);

  api.add_files('test/test_helpers.js', ['client', 'server']);

  // client and server
  api.add_files('test/both/route.js', ['client', 'server']);
  api.add_files('test/both/route_controller.js', ['client', 'server']);
  api.add_files('test/both/router.js', ['client', 'server']);
  api.add_files('test/both/utils.js', ['client', 'server']);

  // server only
  api.add_files('test/server/router.js', 'server');

  // client only
  api.add_files('test/client/router.js', 'client');
  api.add_files('test/client/route_controller.js', 'client');
  api.add_files('test/client/wait_list.js', 'client');
});
<commit_msg>Bump connect version.<commit_after>Package.describe({
  summary: 'Routing specifically designed for Meteor'
});

Package.on_use(function (api) {
  api.use('reactive-dict', ['client', 'server']);
  api.use('deps', ['client', 'server']);
  api.use('underscore', ['client', 'server']);
  api.use('ejson', ['client', 'server']);
  api.use('jquery', 'client');

  // default ui manager
  // use unordered: true becuase of circular dependency

  // XXX commenting out for now because this is somehow causing problems
  //api.use('blaze-layout', 'client', {unordered: true});

  // for default helpers like pathFor, urlFor
  api.use('ui', 'client', {weak: true});

  api.add_files('lib/utils.js', ['client', 'server']);
  api.add_files('lib/route.js', ['client', 'server']);
  api.add_files('lib/route_controller.js', ['client', 'server']);
  api.add_files('lib/router.js', ['client', 'server']);

  api.add_files('lib/client/location.js', 'client');
  api.add_files('lib/client/router.js', 'client');
  api.add_files('lib/client/wait_list.js', 'client');
  api.add_files('lib/client/hooks.js', 'client');
  api.add_files('lib/client/route_controller.js', 'client');
  api.add_files('lib/client/helpers.js', 'client');

  api.add_files('lib/server/route_controller.js', 'server');
  api.add_files('lib/server/router.js', 'server');

  api.use('webapp', 'server');
  Npm.depends({connect: '2.9.0'});

  api.export('RouteController', ['client', 'server']);
  api.export('Route', ['client', 'server']);
  api.export('Router', ['client', 'server']);
  api.export('IronLocation', 'client');

  api.export('Utils', ['client', 'server'], {testOnly: true});
  api.export('IronRouter', ['client', 'server'], {testOnly: true});
  api.export('WaitList', 'client', {testOnly: true});
});

Package.on_test(function (api) {
  api.use('iron-router', ['client', 'server']);
  api.use('tinytest', ['client', 'server']);
  api.use('test-helpers', ['client', 'server']);
  api.use('reactive-dict', ['client', 'server']);

  api.add_files('test/test_helpers.js', ['client', 'server']);

  // client and server
  api.add_files('test/both/route.js', ['client', 'server']);
  api.add_files('test/both/route_controller.js', ['client', 'server']);
  api.add_files('test/both/router.js', ['client', 'server']);
  api.add_files('test/both/utils.js', ['client', 'server']);

  // server only
  api.add_files('test/server/router.js', 'server');

  // client only
  api.add_files('test/client/router.js', 'client');
  api.add_files('test/client/route_controller.js', 'client');
  api.add_files('test/client/wait_list.js', 'client');
});
<|endoftext|>


<commit_before>Package.describe({
  name: 'jagi:astronomy',
  version: '2.5.5',
  summary: 'Model layer for Meteor',
  git: 'https://github.com/jagi/meteor-astronomy.git'
});

Npm.depends({
  lodash: '4.17.4'
});

Package.onUse(function(api) {
  api.versionsFrom('1.3');

  api.use([
    'ecmascript',
    'es5-shim',
    'ddp',
    'mongo',
    'check',
    'minimongo',
    'ejson',
    'mdg:validation-error@0.5.1'
  ], ['client', 'server']);

  api.mainModule('lib/main.js', ['client', 'server']);
});

////////////////////////////////////////////////////////////////////////////////

Package.onTest(function(api) {
  api.use([
    'practicalmeteor:mocha',
    'tinytest',
    'ecmascript',
    'es5-shim',
    'insecure',
    'mongo',
    'ejson',
    'jagi:astronomy@2.5.5'
  ], ['client', 'server']);

  api.addFiles('test/utils.js', ['client', 'server']);
  // Core.
  api.addFiles([
    'test/core/inherit.js',
    'test/core/extend.js',
    'test/core/state.js',
    'test/core/ejson.js'
  ], ['client', 'server']);
  // Modules.
  // Modules - Behaviors.
  api.addFiles([
    'test/modules/behaviors/create.js',
    'test/modules/behaviors/apply.js'
  ], ['client', 'server']);
  // Modules - Validators.
  api.addFiles([
    'test/modules/validators/create.js',
    'test/modules/validators/apply.js',
    'test/modules/validators/validate.js',
    'test/modules/validators/validate_callback.js'
  ], ['client', 'server']);
  // Modules - Storage.
  api.addFiles([
    'test/modules/storage/is_new.js',
    'test/modules/storage/init.js',
    'test/modules/storage/type_field.js',
    'test/modules/storage/transform.js',
    'test/modules/storage/document_insert.js',
    'test/modules/storage/document_update.js',
    'test/modules/storage/document_remove.js',
    'test/modules/storage/class_insert.js',
    'test/modules/storage/class_update.js',
    'test/modules/storage/class_remove.js',
    'test/modules/storage/reload.js',
    'test/modules/storage/copy.js',
  ], ['client', 'server']);
  // Modules - Events.
  api.addFiles([
    'test/modules/events/order.js',
    'test/modules/events/propagation.js',
    'test/modules/events/cancelable.js'
  ], ['client', 'server']);
  // Modules - Fields.
  api.addFiles([
    'test/modules/fields/cast.js',
    'test/modules/fields/default.js',
    'test/modules/fields/definition.js',
    'test/modules/fields/enum.js',
    'test/modules/fields/get.js',
    'test/modules/fields/merge.js',
    'test/modules/fields/optional.js',
    'test/modules/fields/raw.js',
    'test/modules/fields/set.js'
  ], ['client', 'server']);
  // Modules - Indexes.
  api.addFiles([
    // 'test/indexes/indexes_definition.js'
  ], 'server');
  // Modules - Methods.
  api.addFiles([
    'test/modules/helpers/definition.js'
  ], ['client', 'server']);
});<commit_msg>Bump version to 2.5.6<commit_after>Package.describe({
  name: 'jagi:astronomy',
  version: '2.5.6',
  summary: 'Model layer for Meteor',
  git: 'https://github.com/jagi/meteor-astronomy.git'
});

Npm.depends({
  lodash: '4.17.4'
});

Package.onUse(function(api) {
  api.versionsFrom('1.3');

  api.use([
    'ecmascript',
    'es5-shim',
    'ddp',
    'mongo',
    'check',
    'minimongo',
    'ejson',
    'mdg:validation-error@0.5.1'
  ], ['client', 'server']);

  api.mainModule('lib/main.js', ['client', 'server']);
});

////////////////////////////////////////////////////////////////////////////////

Package.onTest(function(api) {
  api.use([
    'practicalmeteor:mocha',
    'tinytest',
    'ecmascript',
    'es5-shim',
    'insecure',
    'mongo',
    'ejson',
    'jagi:astronomy@2.5.6'
  ], ['client', 'server']);

  api.addFiles('test/utils.js', ['client', 'server']);
  // Core.
  api.addFiles([
    'test/core/inherit.js',
    'test/core/extend.js',
    'test/core/state.js',
    'test/core/ejson.js'
  ], ['client', 'server']);
  // Modules.
  // Modules - Behaviors.
  api.addFiles([
    'test/modules/behaviors/create.js',
    'test/modules/behaviors/apply.js'
  ], ['client', 'server']);
  // Modules - Validators.
  api.addFiles([
    'test/modules/validators/create.js',
    'test/modules/validators/apply.js',
    'test/modules/validators/validate.js',
    'test/modules/validators/validate_callback.js'
  ], ['client', 'server']);
  // Modules - Storage.
  api.addFiles([
    'test/modules/storage/is_new.js',
    'test/modules/storage/init.js',
    'test/modules/storage/type_field.js',
    'test/modules/storage/transform.js',
    'test/modules/storage/document_insert.js',
    'test/modules/storage/document_update.js',
    'test/modules/storage/document_remove.js',
    'test/modules/storage/class_insert.js',
    'test/modules/storage/class_update.js',
    'test/modules/storage/class_remove.js',
    'test/modules/storage/reload.js',
    'test/modules/storage/copy.js',
  ], ['client', 'server']);
  // Modules - Events.
  api.addFiles([
    'test/modules/events/order.js',
    'test/modules/events/propagation.js',
    'test/modules/events/cancelable.js'
  ], ['client', 'server']);
  // Modules - Fields.
  api.addFiles([
    'test/modules/fields/cast.js',
    'test/modules/fields/default.js',
    'test/modules/fields/definition.js',
    'test/modules/fields/enum.js',
    'test/modules/fields/get.js',
    'test/modules/fields/merge.js',
    'test/modules/fields/optional.js',
    'test/modules/fields/raw.js',
    'test/modules/fields/set.js'
  ], ['client', 'server']);
  // Modules - Indexes.
  api.addFiles([
    // 'test/indexes/indexes_definition.js'
  ], 'server');
  // Modules - Methods.
  api.addFiles([
    'test/modules/helpers/definition.js'
  ], ['client', 'server']);
});<|endoftext|>


<commit_before>var Router = Backbone.Router.extend({
	routes: {
		"": "clear",
		"feed/:id(/search/*query)": "viewFeed",
		"folder/:id(/search/*query)": "viewFolder",
		"item(/search/*query)": "viewAllItems"
	},
	initialize: function() {
		this.itemList = new Backbone.Marionette.Region({
			el: '#item-list'
		});
	},
	clear: function() {
		$('#item-list').scrollTop(0);

		this.itemList.close();

		if(currentSelection !== null) {
			currentSelection.set('active', false);
			currentSelection = null;
		}

		$('.mobile-item-button').addClass('invisible');
		$('#item-list').addClass('hidden-phone');
		$('.feed-list').removeClass('hidden-phone');
	},
	updateItemList : function(model, query) {
		var that = this;
		$('#item-list').scrollTop(0);

		var options = {
			reset: true,
			reset_pagination: true,
			success: function() {
				that.itemList.show(items);
			}
		};

		// Prepare search query
		if(query !== null) {
			options.data = {};
			if(query.match(/^title/)) {
				options.data.search_title = true;
				options.data.query = query.split('/')[1];
			}
			else {
				options.data.query = query;
			}
		}

		items = new ItemListView({collection: model.items});
		model.items.fetch(options);

		if(currentSelection !== null && currentSelection !== model) {
			currentSelection.set('active', false);
			currentSelection.items.query = '';
			currentSelection.items.search_title = false;
		}
		model.set('active', true);
		currentSelection = model;

		$('#item-list').removeClass('hidden-phone');
		$('.feed-list').addClass('hidden-phone');
		$('.mobile-item-button').removeClass('invisible');
		$('#item-list').focus();
	},
	viewFeed: function(id, query) {
		var model = null;
		folders.each(function(folder) {
			if(folder.feeds.get(id)) {
				model = folder.feeds.get(id);
			}
		});

		this.updateItemList(model, query);
	},
	viewFolder: function(id, query) {
		var model = folders.get(id);

		this.updateItemList(model, query);
	},
	viewAllItems: function(query) {
		var model = folderList.allItemsFolder;
		this.updateItemList(model, query);
	},
	goToModel: function(model) {
		if(model instanceof Folder) {
			this.navigate('folder/' + model.id, {trigger: true});
		}
		else if(model instanceof Feed) {
			this.navigate('feed/' + model.id, {trigger: true});
		}
		else {
			this.navigate('item', {trigger: true});
		}
    }
});
<commit_msg>Small fix for search filter reset<commit_after>var Router = Backbone.Router.extend({
	routes: {
		"": "clear",
		"feed/:id(/search/*query)": "viewFeed",
		"folder/:id(/search/*query)": "viewFolder",
		"item(/search/*query)": "viewAllItems"
	},
	initialize: function() {
		this.itemList = new Backbone.Marionette.Region({
			el: '#item-list'
		});
	},
	clear: function() {
		$('#item-list').scrollTop(0);

		this.itemList.close();

		if(currentSelection !== null) {
			currentSelection.set('active', false);
			currentSelection = null;
		}

		$('.mobile-item-button').addClass('invisible');
		$('#item-list').addClass('hidden-phone');
		$('.feed-list').removeClass('hidden-phone');
	},
	updateItemList : function(model, query) {
		var that = this;
		$('#item-list').scrollTop(0);

		var options = {
			reset: true,
			reset_pagination: true,
			success: function() {
				that.itemList.show(items);
			}
		};

		// Prepare search query
		if(query !== null) {
			options.data = {};
			if(query.match(/^title/)) {
				options.data.search_title = true;
				options.data.query = query.split('/')[1];
			}
			else {
				options.data.query = query;
			}
		}

		if(currentSelection !== null) {
			currentSelection.set('active', false);
			currentSelection.items.query = '';
			currentSelection.items.search_title = false;
		}
		model.set('active', true);
		currentSelection = model;

		items = new ItemListView({collection: model.items});
		model.items.fetch(options);

		$('#item-list').removeClass('hidden-phone');
		$('.feed-list').addClass('hidden-phone');
		$('.mobile-item-button').removeClass('invisible');
		$('#item-list').focus();
	},
	viewFeed: function(id, query) {
		var model = null;
		folders.each(function(folder) {
			if(folder.feeds.get(id)) {
				model = folder.feeds.get(id);
			}
		});

		this.updateItemList(model, query);
	},
	viewFolder: function(id, query) {
		var model = folders.get(id);

		this.updateItemList(model, query);
	},
	viewAllItems: function(query) {
		var model = folderList.allItemsFolder;
		this.updateItemList(model, query);
	},
	goToModel: function(model) {
		if(model instanceof Folder) {
			this.navigate('folder/' + model.id, {trigger: true});
		}
		else if(model instanceof Feed) {
			this.navigate('feed/' + model.id, {trigger: true});
		}
		else {
			this.navigate('item', {trigger: true});
		}
    }
});
<|endoftext|>


<commit_before>(function(Padawan) {
	if (window.Padawan) {
		console.error(new Error("Conflict! window.Padawan already exists!"));
	} else {
		Padawan();
	}
})(function() {
	function Padawan(target, message, options) {
		this.target = target;
		this.message = message;
		this.options = options;
		this.tooltip = null;
		this.arrow = null;
		this.width = null;
	};
	Padawan.api = Padawan.prototype = {
		_: {
			setup: function(Padawan) {
				if (Padawan.options) {
					for (var option in Padawan.options) {
						if (Padawan.hasOwnProperty(option)) {
							Padawan[option] = Padawan.options[option];
						} else if (window.Padawan.api.hasOwnProperty(option)) {
							window.Padawan.api[option].call(Padawan, Padawan.options[option]);
						};
					};
				};
			},
			make: {
				tooltip: function(Padawan) {
					Padawan.tooltip.classList.add("padawan-tip");
					Padawan.tooltip.appendChild(this.arrow(Padawan));
					Padawan.tooltip.appendChild(this.message(Padawan));
						// get tooltip width:
						Padawan.tooltip.style.visibility = "hidden";
						document.body.appendChild(Padawan.tooltip);
						Padawan.width = Padawan.tooltip.offsetWidth;
						document.body.removeChild(Padawan.tooltip);
						Padawan.tooltip.style.visibility = "visible";
					return Padawan.tooltip;
				},
				arrow: function(Padawan) {
					Padawan.arrow = document.createElement("div");
					Padawan.arrow.classList.add("padawan-arrow");
					return Padawan.arrow;
				},
				message: function(Padawan) {
					var message = document.createElement("div");
					message.classList.add("padawan-message");
					if (Padawan.message) message.textContent = Padawan.message;
					if (Padawan.options && Padawan.options.html) message.innerHTML = Padawan.options.html;
					return message;
				}
			}
		},
		observe: function() {
			var _this = this;
			if (!(_this.target instanceof HTMLElement) && typeof _this.target === "object") {
				_this.options = _this.target;
			} else if (typeof _this.message === "object") {
				_this.options = _this.message;
			};
			_this.tooltip = document.createElement("div");
			_this._.setup(_this);
			_this._.make.tooltip(_this);
			console.log(_this);
			_this.target.addEventListener("mouseenter", function(e) {
				var target = _this.target;
				if ((target.offsetLeft + target.offsetWidth/2) - (_this.width/2) < 0) {
					_this.tooltip.style.left = target.offsetLeft + "px";
				} else {
					_this.tooltip.style.left = target.offsetLeft + (target.offsetWidth/2) - (_this.width/2) + "px";
					_this.arrow.style.left = (_this.width/2) - 8 + "px";
				};
				_this.tooltip.style.top = _this.target.offsetTop + _this.target.offsetHeight + 8 + "px";
				document.body.appendChild(_this.tooltip);
			});
			_this.target.addEventListener("mouseleave", function() {
				_this.tooltip.parentNode.removeChild(_this.tooltip);
			});
		}
	};
	window.Padawan = Padawan;
	window.addEventListener("load", function() {
		var tooltips = document.querySelectorAll("[data-padawan]");
		for (var i = 0, count = tooltips.length; i < count; i ++) {
			new Padawan(tooltips[i], tooltips[i].dataset.padawan).observe();
		};
	});
});<commit_msg>added parentNode check for removal<commit_after>(function(Padawan) {
	if (window.Padawan) {
		console.error(new Error("Conflict! window.Padawan already exists!"));
	} else {
		Padawan();
	}
})(function() {
	function Padawan(target, message, options) {
		this.target = target;
		this.message = message;
		this.options = options;
		this.tooltip = null;
		this.arrow = null;
		this.width = null;
	};
	Padawan.api = Padawan.prototype = {
		_: {
			setup: function(Padawan) {
				if (Padawan.options) {
					for (var option in Padawan.options) {
						if (Padawan.hasOwnProperty(option)) {
							Padawan[option] = Padawan.options[option];
						} else if (window.Padawan.api.hasOwnProperty(option)) {
							window.Padawan.api[option].call(Padawan, Padawan.options[option]);
						};
					};
				};
			},
			make: {
				tooltip: function(Padawan) {
					Padawan.tooltip.classList.add("padawan-tip");
					Padawan.tooltip.appendChild(this.arrow(Padawan));
					Padawan.tooltip.appendChild(this.message(Padawan));
						// get tooltip width:
						Padawan.tooltip.style.visibility = "hidden";
						document.body.appendChild(Padawan.tooltip);
						Padawan.width = Padawan.tooltip.offsetWidth;
						document.body.removeChild(Padawan.tooltip);
						Padawan.tooltip.style.visibility = "visible";
					return Padawan.tooltip;
				},
				arrow: function(Padawan) {
					Padawan.arrow = document.createElement("div");
					Padawan.arrow.classList.add("padawan-arrow");
					return Padawan.arrow;
				},
				message: function(Padawan) {
					var message = document.createElement("div");
					message.classList.add("padawan-message");
					if (Padawan.message) message.textContent = Padawan.message;
					if (Padawan.options && Padawan.options.html) message.innerHTML = Padawan.options.html;
					return message;
				}
			}
		},
		observe: function() {
			var _this = this;
			if (!(_this.target instanceof HTMLElement) && typeof _this.target === "object") {
				_this.options = _this.target;
			} else if (typeof _this.message === "object") {
				_this.options = _this.message;
			};
			_this.tooltip = document.createElement("div");
			_this._.setup(_this);
			_this._.make.tooltip(_this);
			_this.target.addEventListener(_this.options && _this.options.event || "mouseenter", function(e) {
				var target = _this.target;
				if ((target.offsetLeft + target.offsetWidth/2) - (_this.width/2) < 0) {
					_this.tooltip.style.left = target.offsetLeft + "px";
				} else {
					_this.tooltip.style.left = target.offsetLeft + (target.offsetWidth/2) - (_this.width/2) + "px";
					_this.arrow.style.left = (_this.width/2) - 8 + "px";
				};
				_this.tooltip.style.top = _this.target.offsetTop + _this.target.offsetHeight + 8 + "px";
				document.body.appendChild(_this.tooltip);
			});
			_this.target.addEventListener("mouseleave", function() {
				if (_this.tooltip.parentNode) {
					_this.tooltip.parentNode.removeChild(_this.tooltip);
				};
			});
		}
	};
	window.Padawan = Padawan;
	window.addEventListener("load", function() {
		var tooltips = document.querySelectorAll("[data-padawan]");
		for (var i = 0, count = tooltips.length; i < count; i ++) {
			new Padawan(tooltips[i], tooltips[i].dataset.padawan).observe() || "missing message argument...";
		};
	});
});<|endoftext|>


<commit_before>/**
	generate, animate, and display a paddler

	paddlers are procedurally-generated creatures with
	bilateral symmetry. flaps of tissue that look like
	tentacles or wings extend from cylindrical bodies.
	continuous paddling motions of these flaps permits
	them to move through the air.

	@namespace GAS
	@class paddler
**/

GAS.paddler = {

	DRAW_RADIUS: 1,
	SORT_ORDER: 2,

	VIEW_ANGLE: Math.cos(120 * Math.PI / 180),

	SHAPE: [0, 0.25, 0.5, 0.8, 0.9, 0.8, 0.7, 0.4],

	IDLE_FLAP: 0.05,
	SLOW_FLAP: 0.25,
	FAST_FLAP: 0.65,

	SLOW_SPEED: 1,
	FAST_SPEED: 10,

	colorBase: 128,

	/**
		create and init objects usable by all paddler instances

		@method init
	**/

	init: function() {
		this.shader = SOAR.shader.create(
			GAS.display,
			SOAR.textOf("vs-paddler"), SOAR.textOf("fs-paddler"),
			["position", "texturec"],
			["projector", "modelview", "rotations", "center", "wing", "mouth"],
			["skin"]
		);

		this.mesh = this.makeMesh();
		this.skin = this.makeSkin();
	},

	/**
		generate and return a new paddler object

		@method create
		@param x, y, z numbers, position
		@return object, the new paddler
	**/

	create: function(x, y, z) {
		var o = Object.create(GAS.paddler);

		o.position = SOAR.vector.create(x, y, z);
		o.velocity = SOAR.vector.create();
		o.rotator = SOAR.rotator.create();

		o.speed = 0;
		o.haste = 0;

		o.skin = this.makeSkin();

		o.wing = 0;
		o.mouth = 0.25 * Math.PI;

		o.scratch = {
			p: SOAR.vector.create(),
			r: SOAR.vector.create()
		};

		return o;
	},

	/**
		generate random skin texture

		@method makeSkin
		@return the texture object
	**/

	makeSkin: function() {
		var ctx = GAS.texture.context;
		var w = 512;
		var h = 256;
		var hw = w * 0.5;
		var hh = h * 0.5;
		var qw = hw * 0.5;
		var r, g, b, base, coat;
		var i, x, y, s, hs;

		ctx.clearRect(0, 0, w, h);
		r = ((this.colorBase + 1) * 3) % 256;
		g = ((r + 1) * 3) % 256;
		b = ((g + 1) * 3) % 256;
		base = "rgb(" + r + ", " + g + ", " + b + ")";
		coat = "rgb(" + (256 - r) + ", " + (256 - g) + ", " + (256 - b) + ")";
		this.colorBase = ((b + 1) * 3) % 256;

		ctx.fillStyle = base;
		ctx.fillRect(0, 0, w, h);

		// top half is darker
		ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
		ctx.fillRect(0, 0, hw, h);

		// closure function to draw a spot
		function spot(x, y, r) {
			ctx.beginPath();
			ctx.arc(x, y, r, 0, SOAR.PIMUL2, false);
			ctx.fill();
			ctx.stroke();
		}

		// add symmetric spots
		ctx.fillStyle = coat;
		ctx.strokeStyle = "rgb(0, 0, 0)";
		ctx.lineWidth = 2;
		for (i = 0; i < 100; i++) {
			s = GAS.random(4, 16);
			hs = s / 2;
			x = GAS.random(hs, qw - hs);
			y = GAS.random(hs, h - hs - 20);

			// left side, top
			spot(x, y, hs);

			// right side, top
			spot(hw - x, y, hs);

			// left side, bottom
			spot(hw + x, y, hs);

			// right side, bottom
			spot(w - x, y, hs);
		}

		// add mouth stripe
		ctx.fillStyle = "rgb(0, 0, 0)";
		ctx.fillRect(0, h - 4, w, h);

		// add eye spots to top only
		ctx.fillStyle = "rgb(255, 255, 255)";
		ctx.beginPath();
		ctx.arc(qw - 20, h - 15, 5, 0, SOAR.PIMUL2, false);
		ctx.fill();
		ctx.stroke();
		ctx.beginPath();
		ctx.arc(qw + 20, h - 15, 5, 0, SOAR.PIMUL2, false);
		ctx.fill();
		ctx.stroke();

		ctx.fillStyle = "rgb(0, 0, 0)";
		ctx.beginPath();
		ctx.arc(qw - 20, h - 15, 2, 0, SOAR.PIMUL2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(qw + 20, h - 15, 2, 0, SOAR.PIMUL2, false);
		ctx.fill();

		return SOAR.texture.create(
			GAS.display,
			ctx.getImageData(0, 0, w, h)
		);
	},

	/**
		generate a paddler model mesh

		@method makeMesh
		@return object, the generated mesh
	**/

	makeMesh: function() {
		var i, r;

		var mesh = SOAR.mesh.create(GAS.display)
		mesh.add(this.shader.position, 3);
		mesh.add(this.shader.texturec, 2);

		var shaper = SOAR.noise1D.create(0, 0.5, 8, 8);
		shaper.interpolate = SOAR.interpolator.linear;
		shaper.map = new Float32Array(this.SHAPE);

		SOAR.subdivide(6, -0.5, -0.5, 0.5, 0.5,
			function(x0, z0, x1, z1, x2, z2) {
				var y0, y1, y2;
				var tz0, tz1, tz2;
				var tx0, tx1, tx2;
				var r0, r1, r2;

				tz0 = z0 + 0.5;
				tz1 = z1 + 0.5;
				tz2 = z2 + 0.5;

				r0 = Math.sqrt(shaper.get(tz0));
				r1 = Math.sqrt(shaper.get(tz1));
				r2 = Math.sqrt(shaper.get(tz2));

				y0 = 0.25 * r0 * Math.cos(x0 * Math.PI);
				y1 = 0.25 * r1 * Math.cos(x1 * Math.PI);
				y2 = 0.25 * r2 * Math.cos(x2 * Math.PI);

				x0 = 1.5 * x0 * r0;
				x1 = 1.5 * x1 * r1;
				x2 = 1.5 * x2 * r2;

				tx0 = 0.5 * (x0 + 0.5);
				tx1 = 0.5 * (x1 + 0.5);
				tx2 = 0.5 * (x2 + 0.5);

				if (tz0 < 0.001)
					z0 += 0.05;
				if (tz1 < 0.001)
					z1 += 0.05;
				if (tz2 < 0.001)
					z2 += 0.05;

				mesh.set(x0, y0, z0, tx0, tz0);
				mesh.set(x1, y1, z1, tx1, tz1);
				mesh.set(x2, y2, z2, tx2, tz2);

				y0 = -0.5 * y0;
				y1 = -0.5 * y1;
				y2 = -0.5 * y2;

				mesh.set(x0, y0, z0, tx0 + 0.5, tz0);
				mesh.set(x2, y2, z2, tx2 + 0.5, tz2);
				mesh.set(x1, y1, z1, tx1 + 0.5, tz1);
			}
		);

		mesh.build();

		return mesh;
	},

	/**
		update kinematics

		@method update
	**/

	update: function() {
		var s = this.scratch;
		var m = this.model;
		var dt = SOAR.interval * 0.001;
		var ds;

		// haste tells us how we're supposed to be moving
		switch(this.haste) {

		case 0:

			if (this.speed > 0) {
				// decelerate based on how fast we're going
				ds = (this.speed > this.SLOW_SPEED ? this.FAST_SPEED : this.SLOW_SPEED) * 2 * dt;
				this.speed = Math.max(0, this.speed - ds);
			}
			this.wing += this.IDLE_FLAP;
			break;

		case 1:

			if (this.speed < this.SLOW_SPEED) {
				// accelerate from zero
				ds = this.SLOW_SPEED * 2 * dt;
				this.speed = Math.min(this.SLOW_SPEED, this.speed + ds);
			} else if (this.speed > this.SLOW_SPEED) {
				// decelerate from faster speed
				ds = this.FAST_SPEED * 2 * dt;
				this.speed = Math.max(this.SLOW_SPEED, this.speed - ds);
			}
			this.wing += this.SLOW_FLAP;
			break;

		case 2:

			if (this.speed < this.FAST_SPEED) {
				// accelerate
				ds = this.FAST_SPEED * 2 * dt;
				this.speed = Math.min(this.FAST_SPEED, this.speed + ds);
				this.wing += this.FAST_FLAP;
			} else {
				this.wing += this.SLOW_FLAP;
			}
			break;
		}

		this.wing = this.wing % SOAR.PIMUL2;

		this.velocity.copy(this.rotator.front).mul(this.speed * dt);
		this.position.add(this.velocity);
	},

	/**
		orient "front" to a particular vector

		note: p must be normalized!

		@method pointTo
		@param p object, vector to align front
		@param t number, rate at which to align
	**/

	pointTo: function(p, t) {
		var r = this.rotator;
		var q = r.scratch.q;
		var fr = this.rotator.front;
		fr.cross(p).neg();
		q.setFromAxisAngle(fr.x, fr.y, fr.z, t).norm();
		r.product.mul(q).norm();
		// reduces roll and regenerates vectors/matrixes
		r.turn(0, 0, this.rotator.right.y);
	},

	/**
		determines if the paddler can see another paddler

		@method isSeeing
		@param o object, the second paddler object
		@return true if the other paddler is in FOV
	**/

	isSeeing: function(o) {
		var eye = this.scratch.p;
		var ray = this.scratch.r;

		eye.copy(this.rotator.front).add(this.rotator.up).mul(0.5).norm();
		ray.copy(this.position).sub(o.position).norm();
		return eye.dot(ray) < this.VIEW_ANGLE;
	},

	/**
		draw the paddlers

		@method draw
	**/

	draw: function() {
		var gl = GAS.display.gl;
		var shader = this.shader;
		var camera = GAS.player.camera;

		if (GAS.map.lastDraw !== shader) {
			gl.disable(gl.BLEND);
			gl.enable(gl.CULL_FACE);
			gl.cullFace(gl.BACK);
			shader.activate();
			gl.uniformMatrix4fv(shader.projector, false, camera.matrix.projector);
			gl.uniformMatrix4fv(shader.modelview, false, camera.matrix.modelview);
			GAS.map.lastDraw = shader;
		}

		gl.uniformMatrix4fv(shader.rotations, false, this.rotator.matrix.transpose);
		gl.uniform3f(shader.center, this.position.x, this.position.y, this.position.z);
		gl.uniform1f(shader.wing, this.wing);
		gl.uniform1f(shader.mouth, this.mouth);
		this.skin.bind(0, shader.skin);
		this.mesh.draw();
	}

};

<commit_msg>Cuts paddler texture size by half by mirroring via texture coordinates.<commit_after>/**
	generate, animate, and display a paddler

	paddlers are procedurally-generated creatures with
	bilateral symmetry. flaps of tissue that look like
	tentacles or wings extend from cylindrical bodies.
	continuous paddling motions of these flaps permits
	them to move through the air.

	@namespace GAS
	@class paddler
**/

GAS.paddler = {

	DRAW_RADIUS: 1,
	SORT_ORDER: 2,

	VIEW_ANGLE: Math.cos(120 * Math.PI / 180),

	SHAPE: [0, 0.25, 0.5, 0.8, 0.9, 0.8, 0.7, 0.4],

	IDLE_FLAP: 0.05,
	SLOW_FLAP: 0.25,
	FAST_FLAP: 0.65,

	SLOW_SPEED: 1,
	FAST_SPEED: 10,

	colorBase: 128,

	/**
		create and init objects usable by all paddler instances

		@method init
	**/

	init: function() {
		this.shader = SOAR.shader.create(
			GAS.display,
			SOAR.textOf("vs-paddler"), SOAR.textOf("fs-paddler"),
			["position", "texturec"],
			["projector", "modelview", "rotations", "center", "wing", "mouth"],
			["skin"]
		);

		this.mesh = this.makeMesh();
		this.skin = this.makeSkin();
	},

	/**
		generate and return a new paddler object

		@method create
		@param x, y, z numbers, position
		@return object, the new paddler
	**/

	create: function(x, y, z) {
		var o = Object.create(GAS.paddler);

		o.position = SOAR.vector.create(x, y, z);
		o.velocity = SOAR.vector.create();
		o.rotator = SOAR.rotator.create();

		o.speed = 0;
		o.haste = 0;

		o.skin = this.makeSkin();

		o.wing = 0;
		o.mouth = 0.25 * Math.PI;

		o.scratch = {
			p: SOAR.vector.create(),
			r: SOAR.vector.create()
		};

		return o;
	},

	/**
		generate random skin texture

		@method makeSkin
		@return the texture object
	**/

	makeSkin: function() {
		var ctx = GAS.texture.context;
		var w = 256;
		var h = 256;
		var hw = w * 0.5;
		var hh = h * 0.5;
		var r, g, b, base, coat;
		var i, x, y, s, hs;

		ctx.clearRect(0, 0, w, h);
		r = ((this.colorBase + 1) * 3) % 256;
		g = ((r + 1) * 3) % 256;
		b = ((g + 1) * 3) % 256;
		base = "rgb(" + r + ", " + g + ", " + b + ")";
		coat = "rgb(" + (256 - r) + ", " + (256 - g) + ", " + (256 - b) + ")";
		this.colorBase = ((b + 1) * 3) % 256;

		ctx.fillStyle = base;
		ctx.fillRect(0, 0, w, h);

		// top half is darker
		ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
		ctx.fillRect(0, 0, hw, h);

		// closure function to draw a spot
		function spot(x, y, r) {
			ctx.beginPath();
			ctx.arc(x, y, r, 0, SOAR.PIMUL2, false);
			ctx.fill();
			ctx.stroke();
		}

		// add symmetric spots
		ctx.fillStyle = coat;
		ctx.strokeStyle = "rgb(0, 0, 0)";
		ctx.lineWidth = 2;
		for (i = 0; i < 100; i++) {
			s = GAS.random(4, 16);
			hs = s / 2;
			x = GAS.random(hs, hw - hs);
			y = GAS.random(hs, h - hs - 20);

			// top
			spot(x, y, hs);

			// bottom
			spot(hw + x, y, hs);
		}

		// add mouth stripe
		ctx.fillStyle = "rgb(0, 0, 0)";
		ctx.fillRect(0, h - 4, w, h);

		// add eye spot to top only
		ctx.fillStyle = "rgb(255, 255, 255)";
		ctx.beginPath();
		ctx.arc(hw - 20, h - 15, 5, 0, SOAR.PIMUL2, false);
		ctx.fill();
		ctx.stroke();
		ctx.fillStyle = "rgb(0, 0, 0)";
		ctx.beginPath();
		ctx.arc(hw - 20, h - 15, 2, 0, SOAR.PIMUL2, false);
		ctx.fill();

		return SOAR.texture.create(
			GAS.display,
			ctx.getImageData(0, 0, w, h)
		);
	},

	/**
		generate a paddler model mesh

		@method makeMesh
		@return object, the generated mesh
	**/

	makeMesh: function() {
		var i, r;

		var mesh = SOAR.mesh.create(GAS.display)
		mesh.add(this.shader.position, 3);
		mesh.add(this.shader.texturec, 2);

		var shaper = SOAR.noise1D.create(0, 0.5, 8, 8);
		shaper.interpolate = SOAR.interpolator.linear;
		shaper.map = new Float32Array(this.SHAPE);

		SOAR.subdivide(6, -0.5, -0.5, 0.5, 0.5,
			function(x0, z0, x1, z1, x2, z2) {
				var y0, y1, y2;
				var tz0, tz1, tz2;
				var tx0, tx1, tx2;
				var r0, r1, r2;

				tz0 = z0 + 0.5;
				tz1 = z1 + 0.5;
				tz2 = z2 + 0.5;

				r0 = Math.sqrt(shaper.get(tz0));
				r1 = Math.sqrt(shaper.get(tz1));
				r2 = Math.sqrt(shaper.get(tz2));

				y0 = 0.25 * r0 * Math.cos(x0 * Math.PI);
				y1 = 0.25 * r1 * Math.cos(x1 * Math.PI);
				y2 = 0.25 * r2 * Math.cos(x2 * Math.PI);

				x0 = 1.5 * x0 * r0;
				x1 = 1.5 * x1 * r1;
				x2 = 1.5 * x2 * r2;

				// cut x texture off at 0.49 to prevent
				// top & bottom textures crossing over
				tx0 = Math.min(0.5 - Math.abs(x0), 0.49);
				tx1 = Math.min(0.5 - Math.abs(x1), 0.49);
				tx2 = Math.min(0.5 - Math.abs(x2), 0.49);

				// paddler mouth should tuck inwards
				if (tz0 < 0.001)
					z0 += 0.05;
				if (tz1 < 0.001)
					z1 += 0.05;
				if (tz2 < 0.001)
					z2 += 0.05;

				mesh.set(x0, y0, z0, tx0, tz0);
				mesh.set(x1, y1, z1, tx1, tz1);
				mesh.set(x2, y2, z2, tx2, tz2);

				y0 = -0.5 * y0;
				y1 = -0.5 * y1;
				y2 = -0.5 * y2;

				mesh.set(x0, y0, z0, tx0 + 0.5, tz0);
				mesh.set(x2, y2, z2, tx2 + 0.5, tz2);
				mesh.set(x1, y1, z1, tx1 + 0.5, tz1);
			}
		);

		mesh.build();

		return mesh;
	},

	/**
		update kinematics

		@method update
	**/

	update: function() {
		var s = this.scratch;
		var m = this.model;
		var dt = SOAR.interval * 0.001;
		var ds;

		// haste tells us how we're supposed to be moving
		switch(this.haste) {

		case 0:

			if (this.speed > 0) {
				// decelerate based on how fast we're going
				ds = (this.speed > this.SLOW_SPEED ? this.FAST_SPEED : this.SLOW_SPEED) * 2 * dt;
				this.speed = Math.max(0, this.speed - ds);
			}
			this.wing += this.IDLE_FLAP;
			break;

		case 1:

			if (this.speed < this.SLOW_SPEED) {
				// accelerate from zero
				ds = this.SLOW_SPEED * 2 * dt;
				this.speed = Math.min(this.SLOW_SPEED, this.speed + ds);
			} else if (this.speed > this.SLOW_SPEED) {
				// decelerate from faster speed
				ds = this.FAST_SPEED * 2 * dt;
				this.speed = Math.max(this.SLOW_SPEED, this.speed - ds);
			}
			this.wing += this.SLOW_FLAP;
			break;

		case 2:

			if (this.speed < this.FAST_SPEED) {
				// accelerate
				ds = this.FAST_SPEED * 2 * dt;
				this.speed = Math.min(this.FAST_SPEED, this.speed + ds);
				this.wing += this.FAST_FLAP;
			} else {
				this.wing += this.SLOW_FLAP;
			}
			break;
		}

		this.wing = this.wing % SOAR.PIMUL2;

		this.velocity.copy(this.rotator.front).mul(this.speed * dt);
		this.position.add(this.velocity);
	},

	/**
		orient "front" to a particular vector

		note: p must be normalized!

		@method pointTo
		@param p object, vector to align front
		@param t number, rate at which to align
	**/

	pointTo: function(p, t) {
		var r = this.rotator;
		var q = r.scratch.q;
		var fr = this.rotator.front;
		fr.cross(p).neg();
		q.setFromAxisAngle(fr.x, fr.y, fr.z, t).norm();
		r.product.mul(q).norm();
		// reduces roll and regenerates vectors/matrixes
		r.turn(0, 0, this.rotator.right.y);
	},

	/**
		determines if the paddler can see another paddler

		@method isSeeing
		@param o object, the second paddler object
		@return true if the other paddler is in FOV
	**/

	isSeeing: function(o) {
		var eye = this.scratch.p;
		var ray = this.scratch.r;

		eye.copy(this.rotator.front).add(this.rotator.up).mul(0.5).norm();
		ray.copy(this.position).sub(o.position).norm();
		return eye.dot(ray) < this.VIEW_ANGLE;
	},

	/**
		draw the paddlers

		@method draw
	**/

	draw: function() {
		var gl = GAS.display.gl;
		var shader = this.shader;
		var camera = GAS.player.camera;

		if (GAS.map.lastDraw !== shader) {
			gl.disable(gl.BLEND);
			gl.enable(gl.CULL_FACE);
			gl.cullFace(gl.BACK);
			shader.activate();
			gl.uniformMatrix4fv(shader.projector, false, camera.matrix.projector);
			gl.uniformMatrix4fv(shader.modelview, false, camera.matrix.modelview);
			GAS.map.lastDraw = shader;
		}

		gl.uniformMatrix4fv(shader.rotations, false, this.rotator.matrix.transpose);
		gl.uniform3f(shader.center, this.position.x, this.position.y, this.position.z);
		gl.uniform1f(shader.wing, this.wing);
		gl.uniform1f(shader.mouth, this.mouth);
		this.skin.bind(0, shader.skin);
		this.mesh.draw();
	}

};

<|endoftext|>


<commit_before>"use strict";

//let _ = require("lodash");
let Promise	= require("bluebird");

let Benchmarkify = require("benchmarkify");
let benchmark = new Benchmarkify("Moleculer common benchmarks").printHeader();

let ServiceBroker = require("../../src/service-broker");

function createBroker(opts) {
	// Create broker
	let broker = new ServiceBroker(opts);
	broker.loadService(__dirname + "/../user.service");
	broker.start();

	return broker;
}

let bench1 = benchmark.createSuite("Local call");
(function() {
	let broker = createBroker();
	bench1.ref("broker.call (normal)", done => {
		return broker.call("users.empty").then(done);
	});

	bench1.add("broker.call (with params)", done => {
		return broker.call("users.empty", { id: 5, sort: "name created", limit: 10 }).then(done);
	});

})();

// ----------------------------------------------------------------
let bench2 = benchmark.createSuite("Call with middlewares");

(function() {
	let broker = createBroker();
	bench2.ref("No middlewares", done => {
		return broker.call("users.empty").then(done);
	});
})();

(function() {
	let broker = createBroker();

	let mw1 = handler => {
		return ctx => Promise.resolve().then(() => handler(ctx).then(res => res));
	};
	broker.use(mw1, mw1, mw1, mw1, mw1);

	bench2.add("5 middlewares", done => {
		return broker.call("users.empty").then(done);
	});
})();

// ----------------------------------------------------------------
let bench3 = benchmark.createSuite("Call with statistics & metrics");

(function() {
	let broker = createBroker();
	bench3.ref("No statistics", done => {
		return broker.call("users.empty").then(done);
	});
})();

(function() {
	let broker = createBroker({ metrics: true });
	bench3.add("With metrics", done => {
		return broker.call("users.empty").then(done);
	});
})();

(function() {
	let broker = createBroker({ statistics: true });
	bench3.add("With statistics", done => {
		return broker.call("users.empty").then(done);
	});
})();

(function() {
	let broker = createBroker({ metrics: true, statistics: true });
	bench3.add("With metrics & statistics", done => {
		return broker.call("users.empty").then(done);
	});
})();

// ----------------------------------------------------------------
let bench4 = benchmark.createSuite("Remote call with FakeTransporter");

(function() {

	let Transporter = require("../../src/transporters/fake");
	let Serializer = require("../../src/serializers/json");

	let b1 = new ServiceBroker({
		transporter: new Transporter(),
		requestTimeout: 0,
		serializer: new Serializer(),
		nodeID: "node-1",

	});

	let b2 = new ServiceBroker({
		transporter: new Transporter(),
		requestTimeout: 0,
		serializer: new Serializer(),
		nodeID: "node-2"
	});

	b2.createService({
		name: "echo",
		actions: {
			reply(ctx) {
				return ctx.params;
			}
		}
	});

	b1.start().then(() => b2.start());

	let c = 0;
	bench4.add("Remote call echo.reply", done => {
		return b1.call("echo.reply", { a: c++ }).then(done);
	});
})();

module.exports = benchmark.run([bench1, bench2, bench3, bench4]);

/*

===============================
  Moleculer common benchmarks
===============================

Platform info:
==============
   Windows_NT 6.1.7601 x64
   Node.JS: 6.10.0
   V8: 5.1.281.93
   Intel(R) Core(TM) i7-4770K CPU @ 3.50GHz × 8

Suite: Local call
√ broker.call (normal) x 856,356 ops/sec ±0.33% (86 runs sampled)
√ broker.call (with params) x 816,742 ops/sec ±1.36% (85 runs sampled)

   broker.call (normal)          0.00%    (856,356 ops/sec)
   broker.call (with params)    -4.63%    (816,742 ops/sec)
-----------------------------------------------------------------------

Suite: Call with middlewares
√ No middlewares x 803,110 ops/sec ±1.02% (84 runs sampled)
√ 5 middlewares x 808,488 ops/sec ±1.03% (88 runs sampled)

   No middlewares    -0.67%    (803,110 ops/sec)
   5 middlewares      0.00%    (808,488 ops/sec)
-----------------------------------------------------------------------

Suite: Call with statistics & metrics
√ No statistics x 812,022 ops/sec ±0.77% (87 runs sampled)
√ With metrics x 199,014 ops/sec ±1.49% (85 runs sampled)
√ With statistics x 522,074 ops/sec ±1.06% (88 runs sampled)
√ With metrics & statistics x 191,070 ops/sec ±1.45% (77 runs sampled)

   No statistics                 0.00%    (812,022 ops/sec)
   With metrics                -75.49%    (199,014 ops/sec)
   With statistics             -35.71%    (522,074 ops/sec)
   With metrics & statistics   -76.47%    (191,070 ops/sec)
-----------------------------------------------------------------------

Suite: Remote call with FakeTransporter
√ Remote call echo.reply x 45,211 ops/sec ±1.00% (79 runs sampled)

   Remote call echo.reply     0.00%     (45,211 ops/sec)
-----------------------------------------------------------------------

*/<commit_msg>remove only stat bench test<commit_after>"use strict";

//let _ = require("lodash");
let Promise	= require("bluebird");

let Benchmarkify = require("benchmarkify");
let benchmark = new Benchmarkify("Moleculer common benchmarks").printHeader();

let ServiceBroker = require("../../src/service-broker");

function createBroker(opts) {
	// Create broker
	let broker = new ServiceBroker(opts);
	broker.loadService(__dirname + "/../user.service");
	broker.start();

	return broker;
}

let bench1 = benchmark.createSuite("Local call");
(function() {
	let broker = createBroker();
	bench1.ref("broker.call (normal)", done => {
		return broker.call("users.empty").then(done);
	});

	bench1.add("broker.call (with params)", done => {
		return broker.call("users.empty", { id: 5, sort: "name created", limit: 10 }).then(done);
	});

})();

// ----------------------------------------------------------------
let bench2 = benchmark.createSuite("Call with middlewares");

(function() {
	let broker = createBroker();
	bench2.ref("No middlewares", done => {
		return broker.call("users.empty").then(done);
	});
})();

(function() {
	let broker = createBroker();

	let mw1 = handler => {
		return ctx => Promise.resolve().then(() => handler(ctx).then(res => res));
	};
	broker.use(mw1, mw1, mw1, mw1, mw1);

	bench2.add("5 middlewares", done => {
		return broker.call("users.empty").then(done);
	});
})();

// ----------------------------------------------------------------
let bench3 = benchmark.createSuite("Call with statistics & metrics");

(function() {
	let broker = createBroker();
	bench3.ref("No statistics", done => {
		return broker.call("users.empty").then(done);
	});
})();

(function() {
	let broker = createBroker({ metrics: true });
	bench3.add("With metrics", done => {
		return broker.call("users.empty").then(done);
	});
})();

/*(function() {
	let broker = createBroker({ statistics: true });
	bench3.add("With statistics", done => {
		return broker.call("users.empty").then(done);
	});
})();*/

(function() {
	let broker = createBroker({ metrics: true, statistics: true });
	bench3.add("With metrics & statistics", done => {
		return broker.call("users.empty").then(done);
	});
})();

// ----------------------------------------------------------------
let bench4 = benchmark.createSuite("Remote call with FakeTransporter");

(function() {

	let Transporter = require("../../src/transporters/fake");
	let Serializer = require("../../src/serializers/json");

	let b1 = new ServiceBroker({
		transporter: new Transporter(),
		requestTimeout: 0,
		serializer: new Serializer(),
		nodeID: "node-1",

	});

	let b2 = new ServiceBroker({
		transporter: new Transporter(),
		requestTimeout: 0,
		serializer: new Serializer(),
		nodeID: "node-2"
	});

	b2.createService({
		name: "echo",
		actions: {
			reply(ctx) {
				return ctx.params;
			}
		}
	});

	b1.start().then(() => b2.start());

	let c = 0;
	bench4.add("Remote call echo.reply", done => {
		return b1.call("echo.reply", { a: c++ }).then(done);
	});
})();

module.exports = benchmark.run([bench1, bench2, bench3, bench4]);

/*

===============================
  Moleculer common benchmarks
===============================

Platform info:
==============
   Windows_NT 6.1.7601 x64
   Node.JS: 6.10.0
   V8: 5.1.281.93
   Intel(R) Core(TM) i7-4770K CPU @ 3.50GHz × 8

Suite: Local call
√ broker.call (normal) x 856,356 ops/sec ±0.33% (86 runs sampled)
√ broker.call (with params) x 816,742 ops/sec ±1.36% (85 runs sampled)

   broker.call (normal)          0.00%    (856,356 ops/sec)
   broker.call (with params)    -4.63%    (816,742 ops/sec)
-----------------------------------------------------------------------

Suite: Call with middlewares
√ No middlewares x 803,110 ops/sec ±1.02% (84 runs sampled)
√ 5 middlewares x 808,488 ops/sec ±1.03% (88 runs sampled)

   No middlewares    -0.67%    (803,110 ops/sec)
   5 middlewares      0.00%    (808,488 ops/sec)
-----------------------------------------------------------------------

Suite: Call with statistics & metrics
√ No statistics x 812,022 ops/sec ±0.77% (87 runs sampled)
√ With metrics x 199,014 ops/sec ±1.49% (85 runs sampled)
√ With statistics x 522,074 ops/sec ±1.06% (88 runs sampled)
√ With metrics & statistics x 191,070 ops/sec ±1.45% (77 runs sampled)

   No statistics                 0.00%    (812,022 ops/sec)
   With metrics                -75.49%    (199,014 ops/sec)
   With statistics             -35.71%    (522,074 ops/sec)
   With metrics & statistics   -76.47%    (191,070 ops/sec)
-----------------------------------------------------------------------

Suite: Remote call with FakeTransporter
√ Remote call echo.reply x 45,211 ops/sec ±1.00% (79 runs sampled)

   Remote call echo.reply     0.00%     (45,211 ops/sec)
-----------------------------------------------------------------------

*/<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, 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.

'use strict';

var NullStatsd = require('uber-statsd-client/null');
var parseArgs = require('minimist');
var process = require('process');
var assert = require('assert');

var TChannel = require('../channel.js');
var Reporter = require('../tcollector/reporter.js');
var ServiceProxy = require('../hyperbahn/service_proxy.js');
var FakeEgressNodes = require('../test/lib/fake-egress-nodes.js');

var argv = parseArgs(process.argv.slice(2), {
    boolean: ['trace']
});

if (argv.type === 'bench-relay') {
    process.title = 'nodejs-benchmarks-relay_bench_server';
} else if (argv.type === 'trace-relay') {
    process.title = 'nodejs-benchmarks-relay_trace_server';
}

RelayServer(argv);

function RelayServer(opts) {
    /*eslint max-statements: [2, 25]*/
    if (!(this instanceof RelayServer)) {
        return new RelayServer(opts);
    }

    var self = this;

    assert(opts.benchPort, 'benchPort required');
    assert(opts.benchRelayPort, 'benchRelayPort required');
    assert(opts.tracePort, 'tracePort required');
    assert(opts.traceRelayPort, 'traceRelayPort required');
    assert(
        opts.type === 'bench-relay' || opts.type === 'trace-relay',
        'a valid type required'
    );
    assert('trace' in opts, 'trace is a required options');
    assert('debug' in opts, 'debug is a required options');

    var benchHostPort = '127.0.0.1:' + opts.benchPort;
    var benchRelayHostPort = '127.0.0.1:' + opts.benchRelayPort;
    var traceHostPort = '127.0.0.1:' + opts.tracePort;
    var traceRelayHostPort = '127.0.0.1:' + opts.traceRelayPort;

    self.relay = TChannel({
        statTags: {
            app: 'relay-server'
        },
        logger: opts.debug ? require('debug-logtron')('relay') : null,
        trace: true,
        statsd: NullStatsd()
    });
    self.relay.handler = ServiceProxy({
        channel: self.relay,
        egressNodes: FakeEgressNodes({
            hostPort: opts.type === 'bench-relay' ?
                benchRelayHostPort : opts.type === 'trace-relay' ?
                traceRelayHostPort : null,
            topology: {
                'benchmark': [benchRelayHostPort],
                'tcollector': [traceRelayHostPort]
            }
        })
    });

    self.tcollectorChannel = TChannel({
        trace: false,
        statsd: NullStatsd(),
        logger: self.relay.logger,
        statTags: {
            app: 'relay-server'
        }
    });
    self.reporter = Reporter({
        channel: self.tcollectorChannel.makeSubChannel({
            serviceName: 'tcollector',
            peers: [traceRelayHostPort]
        }),
        logger: self.relay.logger,
        callerName: opts.type
    });

    if (opts.trace) {
        self.relay.tracer.reporter = function report(span) {
            self.reporter.report(span, {
                timeout: 10 * 1000
            });
        };
    }

    if (opts.type === 'bench-relay') {
        self.relay.handler.createServiceChannel('benchmark');
        self.relay.listen(opts.benchRelayPort, '127.0.0.1', onListen);
    } else if (opts.type === 'trace-relay') {
        self.relay.handler.createServiceChannel('tcollector');
        self.relay.listen(opts.traceRelayPort, '127.0.0.1', onListen);
    }

    function onListen() {
        var peer;

        if (opts.type === 'bench-relay') {
            peer = self.relay.handler.getServicePeer(
                'benchmark', benchHostPort
            );
            peer.connect();
        } else if (opts.type === 'trace-relay') {
            peer = self.relay.handler.getServicePeer(
                'tcollector', traceHostPort
            );
            peer.connect();
        }
    }
}
<commit_msg>relay: turn off tracing completely<commit_after>// Copyright (c) 2015 Uber Technologies, 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.

'use strict';

var NullStatsd = require('uber-statsd-client/null');
var parseArgs = require('minimist');
var process = require('process');
var assert = require('assert');

var TChannel = require('../channel.js');
var Reporter = require('../tcollector/reporter.js');
var ServiceProxy = require('../hyperbahn/service_proxy.js');
var FakeEgressNodes = require('../test/lib/fake-egress-nodes.js');

var argv = parseArgs(process.argv.slice(2), {
    boolean: ['trace']
});

if (argv.type === 'bench-relay') {
    process.title = 'nodejs-benchmarks-relay_bench_server';
} else if (argv.type === 'trace-relay') {
    process.title = 'nodejs-benchmarks-relay_trace_server';
}

RelayServer(argv);

function RelayServer(opts) {
    /*eslint max-statements: [2, 25]*/
    if (!(this instanceof RelayServer)) {
        return new RelayServer(opts);
    }

    var self = this;

    assert(opts.benchPort, 'benchPort required');
    assert(opts.benchRelayPort, 'benchRelayPort required');
    assert(opts.tracePort, 'tracePort required');
    assert(opts.traceRelayPort, 'traceRelayPort required');
    assert(
        opts.type === 'bench-relay' || opts.type === 'trace-relay',
        'a valid type required'
    );
    assert('trace' in opts, 'trace is a required options');
    assert('debug' in opts, 'debug is a required options');

    var benchHostPort = '127.0.0.1:' + opts.benchPort;
    var benchRelayHostPort = '127.0.0.1:' + opts.benchRelayPort;
    var traceHostPort = '127.0.0.1:' + opts.tracePort;
    var traceRelayHostPort = '127.0.0.1:' + opts.traceRelayPort;

    self.relay = TChannel({
        statTags: {
            app: 'relay-server'
        },
        logger: opts.debug ? require('debug-logtron')('relay') : null,
        trace: false,
        statsd: NullStatsd()
    });
    self.relay.handler = ServiceProxy({
        channel: self.relay,
        egressNodes: FakeEgressNodes({
            hostPort: opts.type === 'bench-relay' ?
                benchRelayHostPort : opts.type === 'trace-relay' ?
                traceRelayHostPort : null,
            topology: {
                'benchmark': [benchRelayHostPort],
                'tcollector': [traceRelayHostPort]
            }
        })
    });

    self.tcollectorChannel = TChannel({
        trace: false,
        statsd: NullStatsd(),
        logger: self.relay.logger,
        statTags: {
            app: 'relay-server'
        }
    });
    self.reporter = Reporter({
        channel: self.tcollectorChannel.makeSubChannel({
            serviceName: 'tcollector',
            peers: [traceRelayHostPort]
        }),
        logger: self.relay.logger,
        callerName: opts.type
    });

    if (opts.trace) {
        self.relay.tracer.reporter = function report(span) {
            self.reporter.report(span, {
                timeout: 10 * 1000
            });
        };
    }

    if (opts.type === 'bench-relay') {
        self.relay.handler.createServiceChannel('benchmark');
        self.relay.listen(opts.benchRelayPort, '127.0.0.1', onListen);
    } else if (opts.type === 'trace-relay') {
        self.relay.handler.createServiceChannel('tcollector');
        self.relay.listen(opts.traceRelayPort, '127.0.0.1', onListen);
    }

    function onListen() {
        var peer;

        if (opts.type === 'bench-relay') {
            peer = self.relay.handler.getServicePeer(
                'benchmark', benchHostPort
            );
            peer.connect();
        } else if (opts.type === 'trace-relay') {
            peer = self.relay.handler.getServicePeer(
                'tcollector', traceHostPort
            );
            peer.connect();
        }
    }
}
<|endoftext|>


<commit_before>var parsons2d = function(options) {
    this.options = options;
    //
    var feedback_exists = false;
    var modified_lines = [];
    var X_INDENT = options.xIndent || 50;
    var FEEDBACK_STYLES = { 'correctPosition' : 'correctPosition',
            'incorrectPosition' : 'incorrectPosition',
            'correctIndent' : 'correctIndent',
            'incorrectIndent' : 'incorrectIndent'};
    function updateIndent(leftDiff, id) {
        console.log("diff "+leftDiff);
        var code_line = getLineById(id);
        var new_indent = code_line.indent
        + Math.floor(leftDiff / X_INDENT);
        new_indent = Math.max(0, new_indent);
        code_line.indent = new_indent;
        return new_indent;
    };
    function getLineById(id) {
        return modified_lines[getElemIndex(id)];
    }
    function getElemIndex(id) {
        for ( var i = 0; i < modified_lines.length; i++) {
            if (modified_lines[i].id == id) {
                return i;
            }
        }
    };

    function normalizeIndents(lines) {

        var normalized = [];
        var previous_indentation;
        var new_line;

        for ( var i = 0; i < lines.length; i++ ) {
            //create shallow copy from the line object
            new_line = jQuery.extend({}, lines[i]);
            if (i == 0) {
                new_line.indent = 0;
            } else if (lines[i].indent == lines[i-i].indent) {
                new_line.indent = normalized[i-1].indent;
            } else if (lines[i].indent > lines[i-1].indent) {
                new_line.indent = normalized[i-1].indent + 1;
            } else {
                // indentation van be -1 if no matching indentation exists, i.e. IndentationError in Python
                new_line.indent = function(index) {
                    //return line index from the previous lines with matchind indentation
                    for (var i = index-1; i >= 0; i--) {
                        if (lines[i].indent == lines[index].indent) {
                            return i;
                        }
                    }
                    return -1;
                }(i);
            }
            normalized[i] = new_line;
        }
        return normalized;
    };
    function getModifiedCode() {
        //ids of the the modified code
        var users_code_ids = $("#ul-" + this.options.sortableId).sortable('toArray');
        var lines_to_return = [];
        for ( var i = 0; i < users_code_ids.length; i++ ) {
            lines_to_return[i] = getLineById(users_code_ids[i]);
        }
        return lines_to_return;
    }
    function getFeedback() {
        feedback_exists = true;
        var student_code = normalizeIndents(getModifiedCode());

        for (var i = 0; i < student_code.length; i++) {
            var code_line = student_code[i];
            if (code_line.code !== options.codeLines[i][1]) {
                if (this.options.incorrectSound && $.sound) {
                    $.sound.play(this.options.incorrectSound);
                }
                $("#" + code_line.id).addClass("incorrectPosition");
                alert("line " + (i+1) + " is not correct!");
                return;
            }
            if (code_line.indent !== this.options.codeLines[i][0]) {
                if (this.options.incorrectSound && $.sound) {
                    $.sound.play(this.options.incorrectSound);
                }
                $("#" + code_line.id).addClass("incorrectIndent");
                alert("line " + (i+1) + " is not indented correctly");
                return;
            }
        }

        if (this.options.correctSound && $.sound) {
            $.sound.play(this.options.correctSound);
        }

        alert("ok");
    };
    function clearFeedback() {
        var li_elements = $("#ul-" + options.sortableId + " li");
        for (var style in FEEDBACK_STYLES) {
            li_elements.removeClass(FEEDBACK_STYLES[style]);
        }
        feedback_exists = false;
    };
    function init() {
        var codelines = [];
        if (typeof(options.codeLines) === "string") {
            codelines = options.codeLines.split('\n');
            for (var i = 0; i < codelines.length; i++) {
                modified_lines[i] = {
                        'indent' : 0,
                        'code' : codelines[i],
                        'id' : 'codeline' + i
                };
                codelines[i] = '
' + codelines[i] + '<\/li>';
            }
        } else {
            for (var i = 0; i < options.codeLines.length; i++) {
                modified_lines[i] = {
                        'indent' : 0,
                        'code' : options.codeLines[i][1],
                        'id' : 'codeline' + i
                };
                codelines[i] = '
' + options.codeLines[i][1] + '<\/li>';
            }
        }
        var swap1, swap2, tmp;
        for (i = options.codeLines.length*2; i > 0; i--) {
            swap1 = Math.floor(Math.random() * options.codeLines.length);
            swap2 = Math.floor(Math.random() * options.codeLines.length);
            tmp = codelines[swap1];
            codelines[swap1] = codelines[swap2];
            codelines[swap2] = tmp;
        }
        if (this.options.trashId) {
            $("#" + this.options.trashId).html('
Trash

'+codelines.join('')+'
');
            $("#" + this.options.sortableId).html('
Solution

');
        } else {
            $("#" + this.options.sortableId).html('
'+codelines.join('')+'
');
        }
        if (typeof(this.options.prettyPrint) === "undefined" || this.options.prettyPrint) {
            prettyPrint();
        }
    };
    init();
    var sortable = $("#ul-" + this.options.sortableId).sortable({
        start : function(event, ui) {
            if (feedback_exists) {
                clearFeedback();
            }
        },
        stop : function(event, ui) {
            if ($(event.target)[0] != ui.item.parent()[0]) {
                return;
            }
            var ind = updateIndent(ui.position.left - ui.item.parent().offset().left,
                                    ui.item[0].id);
            ui.item.css("margin-left", X_INDENT * ind + "px");
        },
        receive : function(event, ui) {
            var ind = updateIndent(ui.position.left - ui.item.parent().offset().left,
                                    ui.item[0].id);
            ui.item.css("margin-left", X_INDENT * ind + "px");
        },
        grid : [ X_INDENT, 1 ]
    });
    if (this.options.trashId) {
        var trash = $("#ul-" + this.options.trashId).sortable({
            connectWith: sortable,
            receive: function(event, ui) {
                getLineById(ui.item[0].id).indent = 0;
                ui.item.css("margin-left", "0");
            }
        });
        sortable.sortable('option', 'connectWith', trash);
    }
    return {
        getFeedback : function() {
            getFeedback();
        },
        shuffleLines : function() {
            init();
        }
    };
};<commit_msg>check that the the number of code lines in the solution is correct<commit_after>var parsons2d = function(options) {

	var codeLine = function(table_row, id) {

		return {
			id: id,
			code: table_row[1],
			indent: table_row[0]
		};

	};

    this.options = options;
    //
    var feedback_exists = false;
    var modified_lines = [];
    var model_solution = [];
    var extra_lines = [];
    var X_INDENT = options.xIndent || 50;
    var FEEDBACK_STYLES = { 'correctPosition' : 'correctPosition',
            'incorrectPosition' : 'incorrectPosition',
            'correctIndent' : 'correctIndent',
            'incorrectIndent' : 'incorrectIndent'};
    function updateIndent(leftDiff, id) {
        console.log("diff "+leftDiff);
        var code_line = getLineById(id);
        var new_indent = code_line.indent
        + Math.floor(leftDiff / X_INDENT);
        new_indent = Math.max(0, new_indent);
        code_line.indent = new_indent;
        return new_indent;
    };
    function getLineById(id) {
        return modified_lines[getElemIndex(id)];
    }
    function getElemIndex(id) {
        for ( var i = 0; i < modified_lines.length; i++) {
            if (modified_lines[i].id == id) {
                return i;
            }
        }
    };

    function normalizeIndents(lines) {

        var normalized = [];
        var previous_indentation;
        var new_line;

        for ( var i = 0; i < lines.length; i++ ) {
            //create shallow copy from the line object
            new_line = jQuery.extend({}, lines[i]);
            if (i == 0) {
                new_line.indent = 0;
            } else if (lines[i].indent == lines[i-i].indent) {
                new_line.indent = normalized[i-1].indent;
            } else if (lines[i].indent > lines[i-1].indent) {
                new_line.indent = normalized[i-1].indent + 1;
            } else {
                // indentation van be -1 if no matching indentation exists, i.e. IndentationError in Python
                new_line.indent = function(index) {
                    //return line index from the previous lines with matchind indentation
                    for (var i = index-1; i >= 0; i--) {
                        if (lines[i].indent == lines[index].indent) {
                            return i;
                        }
                    }
                    return -1;
                }(i);
            }
            normalized[i] = new_line;
        }
        return normalized;
    };
    function getModifiedCode() {
        //ids of the the modified code
        var users_code_ids = $("#ul-" + this.options.sortableId).sortable('toArray');
        var lines_to_return = [];
        for ( var i = 0; i < users_code_ids.length; i++ ) {
            lines_to_return[i] = getLineById(users_code_ids[i]);
        }
        return lines_to_return;
    };

    function displayError(message) {
    	if (this.options.incorrectSound && $.sound) {
            $.sound.play(this.options.incorrectSound);
        }
    	alert(message);
    };

    function getFeedback() {
        feedback_exists = true;
        var student_code = normalizeIndents(getModifiedCode());
        var lines_to_check = Math.min(student_code.length, model_solution.length)

        for (var i = 0; i < lines_to_check; i++) {
            var code_line = student_code[i];
            var model_line = model_solution[i]
            if (code_line.code !== model_line.code) {
            	displayError("line " + (i+1) + " is not correct!");
                $("#" + code_line.id).addClass("incorrectPosition");
                return;
            }
            if (code_line.indent !== model_line.indent) {
            	displayError("line " + (i+1) + " is not indented correctly");
            	$("#" + code_line.id).addClass("incorrectIndent");
                return;
            }
        }

        if (model_solution.length < student_code.length) {
        	displayError("Too many lines in your solution");
        	return;
        } else if (model_solution.length > student_code-length){
        	displayError("Too few lines in your solution");
        	return;
        }

        if (this.options.correctSound && $.sound) {
            $.sound.play(this.options.correctSound);
        }

        alert("ok");
    };
    function clearFeedback() {
        var li_elements = $("#ul-" + options.sortableId + " li");
        for (var style in FEEDBACK_STYLES) {
            li_elements.removeClass(FEEDBACK_STYLES[style]);
        }
        feedback_exists = false;
    };
    function init() {
        var codelines = [];
        if (typeof(options.codeLines) === "string") {
            codelines = options.codeLines.split('\n');
            for (var i = 0; i < codelines.length; i++) {
                modified_lines[i] = {
                        'indent' : 0,
                        'code' : codelines[i],
                        'id' : 'codeline' + i
                };
                codelines[i] = '
' + codelines[i] + '<\/li>';
            }
        } else {
            for (var i = 0; i < options.codeLines.length; i++) {
            	modified_lines[i] = codeLine(options.codeLines[i], 'codeline' + i);
                if (options.codeLines[i].indent < 0) {
                	extra_lines.push(codeLine(options.codeLines[i]));
                } else {
                	model_solution.push(codeLine(options.codeLines[i]));
                }
                codelines[i] = '
' + options.codeLines[i][1] + '<\/li>';

            }
        }
        var swap1, swap2, tmp;
        for (i = options.codeLines.length*2; i > 0; i--) {
            swap1 = Math.floor(Math.random() * options.codeLines.length);
            swap2 = Math.floor(Math.random() * options.codeLines.length);
            tmp = codelines[swap1];
            codelines[swap1] = codelines[swap2];
            codelines[swap2] = tmp;
        }
        if (this.options.trashId) {
            $("#" + this.options.trashId).html('
Trash

'+codelines.join('')+'
');
            $("#" + this.options.sortableId).html('
Solution

');
        } else {
            $("#" + this.options.sortableId).html('
'+codelines.join('')+'
');
        }
        if (typeof(this.options.prettyPrint) === "undefined" || this.options.prettyPrint) {
            prettyPrint();
        }
    };
    init();
    var sortable = $("#ul-" + this.options.sortableId).sortable({
        start : function(event, ui) {
            if (feedback_exists) {
                clearFeedback();
            }
        },
        stop : function(event, ui) {
            if ($(event.target)[0] != ui.item.parent()[0]) {
                return;
            }
            var ind = updateIndent(ui.position.left - ui.item.parent().offset().left,
                                    ui.item[0].id);
            ui.item.css("margin-left", X_INDENT * ind + "px");
        },
        receive : function(event, ui) {
            var ind = updateIndent(ui.position.left - ui.item.parent().offset().left,
                                    ui.item[0].id);
            ui.item.css("margin-left", X_INDENT * ind + "px");
        },
        grid : [ X_INDENT, 1 ]
    });
    if (this.options.trashId) {
        var trash = $("#ul-" + this.options.trashId).sortable({
            connectWith: sortable,
            receive: function(event, ui) {
                getLineById(ui.item[0].id).indent = 0;
                ui.item.css("margin-left", "0");
            }
        });
        sortable.sortable('option', 'connectWith', trash);
    }
    return {
        getFeedback : function() {
            getFeedback();
        },
        shuffleLines : function() {
            init();
        }
    };
};<|endoftext|>