<commit_before>'use strict';
var request = require('request');
var fs = require('fs');
var mongoose = require('mongoose');
var HTML = mongoose.model('HTML');
var cheerio = require('cheerio');
var _ = require('lodash');
var Car = mongoose.model('Car');

exports.search = function(args) {
	var url = args.next ? args.next : buildUrl(args);
	if (url  === 'Searching http://www.gumtree.com.au/undefined') {
		process.exit(0);
	}

	var options = {
		url: url,
	    headers: {
	        'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36',
	    }
	}

	if (args.text || args.t) {
		if (args.name) {
			HTML.findOne({name: name})
				.sort('-created')
				.exec(function(err, html) {
					parse(html.body);
				});
		}
	} else if (args.save || args.s) {
		console.log('Saving file: ' + url);
		request(options, function(err, response, body) {
			if (err) throw err;
			var html = new HTML({
				url: url,
				body: body,
			});

			html.save(function(err) {
				if (err) throw err;
				console.log('File has been saved.');
				process.exit(0);
			});
		});
	} else {
		console.log('Searching ' + options.url);
		request(options, function(err, response, body) {
			if (err) throw err;
			nextButton(body);
		});
	}
};

function parse (body) {
	var $ = cheerio.load(body);
	$('li[itemprop=offers]').each(function(index, li) {
		var name = $(this).find('span[itemprop=name]').html();
		var price = $(this).find('div[itemprop=price]').html().split('$');
		if (price[1]) {
			price = price[1].replace(',', '');
		} else {
			price = null;
		}
		var url = $(this).find('a[itemprop=url]').attr('href');
		var urgent = $(this).find('div[title=Urgent]').find('p.text').html();
		var car = new Car({
			name: name,
			price: price,
			url: url,
			urgent: urgent,
		});

		Car.count({url: url}, function(err, count) {
			if (count === 0) {
				car.save(function(err) {
					if (err) throw err;
				});
			};
		});

	});
}

function nextButton(body) {
	var $ = cheerio.load(body);
	parse(body);
	var next = $('a[title=Next]').attr('href');

	setTimeout(function() {
		if (next === 'undefined') {
			process.exit(0);
		} else {
			var args = {
				next: 'http://www.gumtree.com.au/' + next,
			};
			exports.search(args);
		};
	}, Math.random() * (7000 - 3000) + 3000);
}

function buildUrl(args) {
	// price
	// make
	// year
	var base = 'http://www.gumtree.com.au/s-cars-vans-utes/perth/'
	var id = 'c18320l3008303';
	var make = args.make ? 'carmake-' + args.make + '/' : '';
	var min = args.min ? args.min + '.00' : '';
	var max = args.max ? args.max + '.00' : '';
	var price = (min || max) ? '?price=' + min + '__' + max : '';
	var from = args.from ? args.from : '';
	var to = args.to ? args.to : '';
	var year = (from || to) ? 'caryear-' + from + '__' + to + '/' : '';

	var url = base + make + year + id + price;
	return url;
}<commit_msg>ending queries when we have seen cars<commit_after>'use strict';
var request = require('request');
var fs = require('fs');
var mongoose = require('mongoose');
var HTML = mongoose.model('HTML');
var cheerio = require('cheerio');
var _ = require('lodash');
var Car = mongoose.model('Car');

exports.search = function(args) {
	var url = args.next ? args.next : buildUrl(args);
	console.log(url);
	if (url  === 'Searching http://www.gumtree.com.au/undefined') {
		process.exit(0);
	}

	var options = {
		url: url,
	    headers: {
	        'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36',
	    }
	}

	if (args.text || args.t) {
		if (args.name) {
			HTML.findOne({name: name})
				.sort('-created')
				.exec(function(err, html) {
					parse(html.body);
				});
		}
	} else {
		console.log('Searching ' + options.url);
		request(options, function(err, response, body) {
			if (err) throw err;
			nextButton(body);
		});
	}
};

function parse (body) {
	var $ = cheerio.load(body);
	$('li[itemprop=offers]').each(function(index, li) {
		var name = $(this).find('span[itemprop=name]').html();
		var price = $(this).find('div[itemprop=price]').html().split('$');
		if (price[1]) {
			price = price[1].replace(',', '');
		} else {
			price = null;
		}
		var url = $(this).find('a[itemprop=url]').attr('href');
		var urgent = $(this).find('div[title=Urgent]').find('p.text').html();
		var car = new Car({
			name: name,
			price: price,
			url: url,
			urgent: urgent,
		});

		Car.count({url: url}, function(err, count) {
			if (count === 0) {
				car.save(function(err) {
					if (err) throw err;
				});
			} else {
				process.exit(0);
			};
		});

	});
}

function nextButton(body) {
	var $ = cheerio.load(body);
	parse(body);
	var next = $('a[title=Next]').attr('href');

	setTimeout(function() {
		if (next === undefined) {
			process.exit(0);
		} else {
			var args = {
				next: 'http://www.gumtree.com.au/' + next,
			};
			exports.search(args);
		};
	}, Math.random() * (7000 - 3000) + 3000);
}

function buildUrl(args) {
	// price
	// make
	// year
	var base = 'http://www.gumtree.com.au/s-cars-vans-utes/perth/'
	var id = 'c18320l3008303';
	var make = args.make ? 'carmake-' + args.make + '/' : '';
	var min = args.min ? args.min + '.00' : '';
	var max = args.max ? args.max + '.00' : '';
	var price = (min || max) ? '?price=' + min + '__' + max : '';
	var from = args.from ? args.from : '';
	var to = args.to ? args.to : '';
	var year = (from || to) ? 'caryear-' + from + '__' + to + '/' : '';

	var url = base + make + year + id + price;
	return url;
}<|endoftext|>


<commit_before>/**
@class
*/
$.boom.people = {};

/**
@class
@extends $.boom.filter
*/
$.boom.people.group = {};

/**
@class
@extends $.boom.item
*/
$.boom.person = {};

$.extend($.boom.person, $.boom.item, {
	/**
	@lends $.boom.person
	*/

	base_url: '/cms/people/view/',

	/** @function */
	bind: function( context){

		var self = this;

		$.boom.dialog.bind({
			image: $('.boom-asset-preview', context )
		});

		$('.b-people-groups-add', context ).click(function(){
			var rid = $( this ).attr( 'rel' );

			var dialog = $.boom.dialog.open({
				url: '/cms/people/add_group/' + rid,
				title: 'Add group',
				callback: function(){

					var dialog = this;
					var data = $( dialog ).find('form').serialize();
					$.boom.loader.show();

					$.post('/cms/people/add_group/' + rid, data )
					.done( function(){

						$.boom.loader.hide();
					});
				}
			});
		});

		$('.b-people-group-delete', context ).click(function(){
			var elem = $( this );
			var group_id = elem.attr( 'rel' );
			var person_id = elem.closest( 'div' ).attr( 'rel' );

			$.boom.loader.show();

			$.post( '/cms/people/remove_group/' + person_id, {groups: group_id} )
			.done( function(){
				elem.closest( 'li' ).remove();
				$.boom.loader.hide();
			});
		});

		$('.b-people-save', context ).bind('save', function( event ){

			var rid = $( this ).attr( 'rel' );
			var data = $( this ).closest( 'form' ).serialize();

			$.boom.loader.show();

			$.post('/cms/people/save/' + rid, data)
			.done( function(){

				$.boom.loader.hide();
				$.boom.growl.show( "Person saved." );
			});

		}).click(function(){

			$( this ).trigger( 'save' );
		});

		$('#b-delete-person', context ).click(function( event ){

			var rid = $( this ).attr( 'rel' );
			var deleted = new $.Deferred();

			$.boom.dialog.open({
				width: 350,
				msg: 'Are you sure you want to delete this person?',
				title: 'Please confirm',
				deferred: deleted
			});

			deleted
			.pipe( function( event ){

				$.boom.loader.show();

				return $.post('/cms/people/delete', { people: rid });
			})
			.done( function(){

				var items = $.boom.history.getHash().split('/')[1].split(',');

				$.boom.loader.hide();

				if ( items.length > 1 ){

					var segments =
						$.boom.history.getHash().split('/')[0] +
						'/' +
						$.grep(items, function(val){

							return val != rid;

						}).join(',');

					$.boom.history.load( segments );

				} else {

					//self.browser.defaultRoute();
				}
			});
		});
	}
});

$.extend($.boom.people.group, $.boom.filter,  {
	/**
	@lends $.boom.people.group
	*/

	/** @function */
	build_url : function(){

		var self = this;

		params =
			'tag=' + self.rid + '&' +
			'perpage=' + self.options.perpage + '&' +
			'sortby=' + self.options.sortby + '&' +
			'order='  + self.options.order;

		var url =
			'/cms/' + self.options.type + '/list'
			+ '?' + params;

		$.boom.log('Group items get' + self.rid );

		return url;
	},

	/** @function */
	bind : function( context ){

		$('.b-items-thumbs .thumb', context ).captions($.boom.config.captions);

	},

	/** @function */
	edit : function(event, browser){
		event.preventDefault();

		var self = this;
		var item = $( event.target ).closest( 'li' );
		var rid = item.find('a').attr( 'rel' );
		var selected_page = null;

		return browser.main_panel
		.find('.b-items-content')
		.sload( '/cms/groups/edit/' + rid, function(){

			$.boom.loader.hide();

			this
			.ui()
			.on( 'change', '#b-group-roles-general input[type=radio]', function( event ){

				var role_id = this.name;
				var allowed = this.value;

				$.post(
					'/cms/groups/remove_role/' + rid,
					{
						role_id : role_id
					}
				)
				.pipe( function( response ){
					return $.post(
						'/cms/groups/add_role/' + rid,
						{
							role_id : role_id,
							allowed : allowed,
							page_id: 0
						}
					);
				})
				.done( function( response ){
				});
			})
			.on( 'change', '#b-group-roles-pages input[type=radio]', function( event ){

				var role_id = this.name;
				var allowed = parseInt( this.value, 10 );
				var page_id = selected_page;

				$.post(
					'/cms/groups/remove_role/' + rid,
					{
						role_id : role_id,
						page_id : page_id
					}
				)
				.pipe( function( response ){
					if ( allowed == -1 ){
						return this.resolve();
					}
					return $.post(
						'/cms/groups/add_role/' + rid,
						{
							role_id : role_id,
							allowed : allowed,
							page_id: page_id
						}
					);
				})
				.done( function( response ){
				});
			});

			/**
			 * Clicking on a page in the tree.
			 * Should make a GET call to /cms/groups/list_roles/<group ID>?page_id=<page ID>
			 *
			 * This will return a json encoded array of role ID => <value>
			 * Possible values are 1 if the role is allowed and 0 if the role is disallowed.
			 * If nothing is set for a role then that role ID won't be in the returned array.
			 *
			 * The role checkboxes should then be updated if the correct values.
			 */

			$.boom.util.page_tree( this.find( '#b-group-roles-pages .boom-tree' ) )
				.progress( function( page ) {

					selected_page = page.page_id;

					$( '#b-group-roles-pages input[type=radio]')
						.filter( ':checked' )
						.prop( 'checked', false )
						.removeAttr( 'checked' )
						.end()
						.filter( '[value="-1"]' )
						.prop( 'checked', true )
						.attr( 'checked', 'checked' );

					$( '#b-group-roles-pages .boom-tree a[rel=' + page.page_id + ']' )
						.parents( '.boom-tree' )
						.find( 'a.ui-state-active' )
						.removeClass( 'ui-state-active' )
						.end()
						.end()
						.addClass( 'ui-state-active' );

					$.get( '/cms/groups/list_roles/' + rid + '?page_id=' + page.page_id )
					.done( function( data ){
						for ( role in data ) {
							$( 'input[name=' + role + ']' )
								.filter( ':checked' )
								.prop( 'checked', false )
								.removeAttr( 'checked' )
								.end()
								.filter( '[value=' + data[ role ] + ']' )
								.prop( 'checked', true )
								.attr( 'checked', 'checked' );
						}
					});

				});
		} );
	},

	/** @function */
	add: function(event){

		var self = this;

		var url = '/cms/groups/add';

		var dialog = $.boom.dialog.open({
			url: url,
			title: 'Add group',
			callback: function(){
				$.post(url, {name: $('#b-people-group-name').val()} )
				.done( function(response){

					$.boom.growl.show('Group successfully saved.');

					top.location.reload();
				});
			}
		});
	},

	/** @function */
	save: function(group_id, data){
		$.boom.loader.show();

		return $.post( '/cms/groups/save/' + group_id, data )
		.done( function(response){

			$.boom.loader.hide();

		});
	},

	/** @function */
	remove : function(event){

		event.preventDefault();

		var item = $( event.target ).closest( 'li' );
		var rid = item.find('a')[0].rel;

		$.boom.dialog.confirm(
			'Please confirm',
			'Are you sure you want to remove this group?

 This will delete the group from the database and cannot be undone!'
		)
		.done( function(){

			$.boom.loader.show();

			$.post( '/cms/groups/delete/' + rid )
			.done( function(){

				$.boom.loader.hide();

				$.boom.growl.show( 'Group successfully removed.' );
				item.remove();
			});
		});
	},

	/** @function */
	update_tree : function( selector, permission ) {
		$.boom.log( 'updating permissions ' + selector );

		var new_item = '
' + permission.label + '
';

		$( selector )
		.tree( 'add_item', new_item );

	}
});

/**
* User interface for browsing and managing people.
* @class
* @name $.boom.browser_people
*/
$.widget( 'boom.browser_people', $.boom.browser, {
	/** @lends $.boom.browser_people */

	/**
	map url fragments to objects
	@property
	*/
	url_map : {
		person: $.boom.person,
		group: $.boom.people.group
	},

	options: {
		sortby: 'name',
		order: 'asc',
		defaultRoute: 'group/0',
		type: 'people',
		treeConfig : {
			showEdit: true,
			showRemove: true
		}
	},

	_create : function(){

		$.boom.log( 'people browser init' );

		var self = this;

		this.tag = this.url_map.group;

		$.boom.browser.prototype._create.call( this );

		$('.b-people-group-add').click(function(event){
			$.boom.people.group.add( this );
		});

		$('#boom-tagmanager-create-person').click(function(){
			var dialog = $.boom.dialog.open({
				url: '/cms/people/add',
				title: 'Create new person',
				onLoad: function(){

					$('#boom-tagmanager-create-person-form input[name="name"]').focus();
				},
				callback: function(){
					self
						.savePerson('/cms/people/add')
						.done( function(){
							window.location.reload();
						});
				}
			});
		});

		$('#boom-topbar')
			.on('click', '#b-button-multiaction-edit', function(){

				var ids = [];

				$('.b-items-select-checkbox:checked').each(function(){

					var id = this.id.replace(/person-(thumb|list)-/, '');

					if ( $.inArray(id, ids) === -1 ) {

						ids.push( id );
					}
				});

				$.boom.history.load('person/' + ids.join('-'));
			})
			.on('click', '#b-button-multiaction-delete', function(){

				var msg = 'Are you sure you want to send the selected people to the rubbish bin?';

				$.boom.dialog
					.confirm('Confirm deletion', msg)
					.done( function(){

						var people = [];

						$('.b-items-select-checkbox:checked').each(function(i){

							people.push( $( this ).attr( 'id' ).replace(/person-(thumb|list)-/, '') );
						});

						$.boom.loader.show();

						$.post('/cms/people/delete', {people: people}, function(){

							$.boom.loader.hide();

							$.boom.history.refresh();
						});
					});
			});
	},

	/** @function */
	savePerson: function(url){

		// TODO: validation

		var data = $('#boom-tagmanager-create-person-form').serialize();

		$.boom.loader.show();

		return $.post(url, data)
		.done( function(id){

			$.boom.loader.hide();

		});
	}
});
<commit_msg>refactor select checkboxes<commit_after>/**
@class
*/
$.boom.people = {};

/**
@class
@extends $.boom.filter
*/
$.boom.people.group = {};

/**
@class
@extends $.boom.item
*/
$.boom.person = {};

$.extend($.boom.person, $.boom.item, {
	/**
	@lends $.boom.person
	*/

	base_url: '/cms/people/view/',

	/** @function */
	select : function( rid, selected ){

		var thumb = '#person-thumb-' + rid;
		var list = '#person-list-' + rid;

		var checkbox = $( thumb );
		checkbox.prop( 'checked', selected );

		if ( selected ) {

			checkbox.attr('checked', 'checked');

			checkbox.parents( 'div.thumb' ).addClass( 'ui-state-active' );
			$( list ).parents( 'tr' ).addClass( 'ui-state-active' );

		} else {

			checkbox.removeAttr('checked');

			checkbox.parents( 'div.thumb' ).removeClass( 'ui-state-active' );
			$( list ).parents( 'tr' ).removeClass( 'ui-state-active' );
		}

	},

	/** @function */
	bind: function( context){

		var self = this;

		$.boom.dialog.bind({
			image: $('.boom-asset-preview', context )
		});

		$('.b-people-groups-add', context ).click(function(){
			var rid = $( this ).attr( 'rel' );

			var dialog = $.boom.dialog.open({
				url: '/cms/people/add_group/' + rid,
				title: 'Add group',
				callback: function(){

					var dialog = this;
					var data = $( dialog ).find('form').serialize();
					$.boom.loader.show();

					$.post('/cms/people/add_group/' + rid, data )
					.done( function(){

						$.boom.loader.hide();
					});
				}
			});
		});

		$('.b-people-group-delete', context ).click(function(){
			var elem = $( this );
			var group_id = elem.attr( 'rel' );
			var person_id = elem.closest( 'div' ).attr( 'rel' );

			$.boom.loader.show();

			$.post( '/cms/people/remove_group/' + person_id, {groups: group_id} )
			.done( function(){
				elem.closest( 'li' ).remove();
				$.boom.loader.hide();
			});
		});

		$('.b-people-save', context ).bind('save', function( event ){

			var rid = $( this ).attr( 'rel' );
			var data = $( this ).closest( 'form' ).serialize();

			$.boom.loader.show();

			$.post('/cms/people/save/' + rid, data)
			.done( function(){

				$.boom.loader.hide();
				$.boom.growl.show( "Person saved." );
			});

		}).click(function(){

			$( this ).trigger( 'save' );
		});

		$('#b-delete-person', context ).click(function( event ){

			var rid = $( this ).attr( 'rel' );
			var deleted = new $.Deferred();

			$.boom.dialog.open({
				width: 350,
				msg: 'Are you sure you want to delete this person?',
				title: 'Please confirm',
				deferred: deleted
			});

			deleted
			.pipe( function( event ){

				$.boom.loader.show();

				return $.post('/cms/people/delete', { people: rid });
			})
			.done( function(){

				var items = $.boom.history.getHash().split('/')[1].split(',');

				$.boom.loader.hide();

				if ( items.length > 1 ){

					var segments =
						$.boom.history.getHash().split('/')[0] +
						'/' +
						$.grep(items, function(val){

							return val != rid;

						}).join(',');

					$.boom.history.load( segments );

				} else {

					//self.browser.defaultRoute();
				}
			});
		});
	}
});

$.extend($.boom.people.group, $.boom.filter,  {
	/**
	@lends $.boom.people.group
	*/

	/** @function */
	build_url : function(){

		var self = this;

		params =
			'tag=' + self.rid + '&' +
			'perpage=' + self.options.perpage + '&' +
			'sortby=' + self.options.sortby + '&' +
			'order='  + self.options.order;

		var url =
			'/cms/' + self.options.type + '/list'
			+ '?' + params;

		$.boom.log('Group items get' + self.rid );

		return url;
	},

	/** @function */
	bind : function( context ){

		$('.b-items-thumbs .thumb', context ).captions($.boom.config.captions);

	},

	/** @function */
	edit : function(event, browser){
		event.preventDefault();

		var self = this;
		var item = $( event.target ).closest( 'li' );
		var rid = item.find('a').attr( 'rel' );
		var selected_page = null;

		return browser.main_panel
		.find('.b-items-content')
		.sload( '/cms/groups/edit/' + rid, function(){

			$.boom.loader.hide();

			this
			.ui()
			.on( 'change', '#b-group-roles-general input[type=radio]', function( event ){

				var role_id = this.name;
				var allowed = this.value;

				$.post(
					'/cms/groups/remove_role/' + rid,
					{
						role_id : role_id
					}
				)
				.pipe( function( response ){
					return $.post(
						'/cms/groups/add_role/' + rid,
						{
							role_id : role_id,
							allowed : allowed,
							page_id: 0
						}
					);
				})
				.done( function( response ){
				});
			})
			.on( 'change', '#b-group-roles-pages input[type=radio]', function( event ){

				var role_id = this.name;
				var allowed = parseInt( this.value, 10 );
				var page_id = selected_page;

				$.post(
					'/cms/groups/remove_role/' + rid,
					{
						role_id : role_id,
						page_id : page_id
					}
				)
				.pipe( function( response ){
					if ( allowed == -1 ){
						return this.resolve();
					}
					return $.post(
						'/cms/groups/add_role/' + rid,
						{
							role_id : role_id,
							allowed : allowed,
							page_id: page_id
						}
					);
				})
				.done( function( response ){
				});
			});

			/**
			 * Clicking on a page in the tree.
			 * Should make a GET call to /cms/groups/list_roles/<group ID>?page_id=<page ID>
			 *
			 * This will return a json encoded array of role ID => <value>
			 * Possible values are 1 if the role is allowed and 0 if the role is disallowed.
			 * If nothing is set for a role then that role ID won't be in the returned array.
			 *
			 * The role checkboxes should then be updated if the correct values.
			 */

			$.boom.util.page_tree( this.find( '#b-group-roles-pages .boom-tree' ) )
				.progress( function( page ) {

					selected_page = page.page_id;

					$( '#b-group-roles-pages input[type=radio]')
						.filter( ':checked' )
						.prop( 'checked', false )
						.removeAttr( 'checked' )
						.end()
						.filter( '[value="-1"]' )
						.prop( 'checked', true )
						.attr( 'checked', 'checked' );

					$( '#b-group-roles-pages .boom-tree a[rel=' + page.page_id + ']' )
						.parents( '.boom-tree' )
						.find( 'a.ui-state-active' )
						.removeClass( 'ui-state-active' )
						.end()
						.end()
						.addClass( 'ui-state-active' );

					$.get( '/cms/groups/list_roles/' + rid + '?page_id=' + page.page_id )
					.done( function( data ){
						for ( role in data ) {
							$( 'input[name=' + role + ']' )
								.filter( ':checked' )
								.prop( 'checked', false )
								.removeAttr( 'checked' )
								.end()
								.filter( '[value=' + data[ role ] + ']' )
								.prop( 'checked', true )
								.attr( 'checked', 'checked' );
						}
					});

				});
		} );
	},

	/** @function */
	add: function(event){

		var self = this;

		var url = '/cms/groups/add';

		var dialog = $.boom.dialog.open({
			url: url,
			title: 'Add group',
			callback: function(){
				$.post(url, {name: $('#b-people-group-name').val()} )
				.done( function(response){

					$.boom.growl.show('Group successfully saved.');

					top.location.reload();
				});
			}
		});
	},

	/** @function */
	save: function(group_id, data){
		$.boom.loader.show();

		return $.post( '/cms/groups/save/' + group_id, data )
		.done( function(response){

			$.boom.loader.hide();

		});
	},

	/** @function */
	remove : function(event){

		event.preventDefault();

		var item = $( event.target ).closest( 'li' );
		var rid = item.find('a')[0].rel;

		$.boom.dialog.confirm(
			'Please confirm',
			'Are you sure you want to remove this group?

 This will delete the group from the database and cannot be undone!'
		)
		.done( function(){

			$.boom.loader.show();

			$.post( '/cms/groups/delete/' + rid )
			.done( function(){

				$.boom.loader.hide();

				$.boom.growl.show( 'Group successfully removed.' );
				item.remove();
			});
		});
	},

	/** @function */
	update_tree : function( selector, permission ) {
		$.boom.log( 'updating permissions ' + selector );

		var new_item = '
' + permission.label + '
';

		$( selector )
		.tree( 'add_item', new_item );

	}
});

/**
* User interface for browsing and managing people.
* @class
* @name $.boom.browser_people
*/
$.widget( 'boom.browser_people', $.boom.browser, {
	/** @lends $.boom.browser_people */

	/**
	map url fragments to objects
	@property
	*/
	url_map : {
		person: $.boom.person,
		group: $.boom.people.group
	},

	options: {
		sortby: 'name',
		order: 'asc',
		defaultRoute: 'group/0',
		type: 'people',
		treeConfig : {
			showEdit: true,
			showRemove: true
		}
	},

	_create : function(){

		$.boom.log( 'people browser init' );

		var self = this;

		this.tag = this.url_map.group;

		$.boom.browser.prototype._create.call( this );

		$('.b-people-group-add').click(function(event){
			$.boom.people.group.add( this );
		});

		$('#boom-tagmanager-create-person').click(function(){
			var dialog = $.boom.dialog.open({
				url: '/cms/people/add',
				title: 'Create new person',
				onLoad: function(){

					$('#boom-tagmanager-create-person-form input[name="name"]').focus();
				},
				callback: function(){
					self
						.savePerson('/cms/people/add')
						.done( function(){
							window.location.reload();
						});
				}
			});
		});

		$('#boom-topbar')
			.on('click', '#b-button-multiaction-edit', function(){

				var ids = [];

				$('.b-items-select-checkbox:checked').each(function(){

					var id = this.id.replace(/person-(thumb|list)-/, '');

					if ( $.inArray(id, ids) === -1 ) {

						ids.push( id );
					}
				});

				$.boom.history.load('person/' + ids.join('-'));
			})
			.on('click', '#b-button-multiaction-delete', function(){

				var msg = 'Are you sure you want to send the selected people to the rubbish bin?';

				$.boom.dialog
					.confirm('Confirm deletion', msg)
					.done( function(){

						var people = [];

						$('.b-items-select-checkbox:checked').each(function(i){

							people.push( $( this ).attr( 'id' ).replace(/person-(thumb|list)-/, '') );
						});

						$.boom.loader.show();

						$.post('/cms/people/delete', {people: people}, function(){

							$.boom.loader.hide();

							$.boom.history.refresh();
						});
					});
			});

		self.main_panel
			.on( 'change', '.b-items-select-checkbox', function( event ){
				// checkbox IDs are of the form type-view-id.
				var item = this.id.split( '-' );
				var view = item[ 1 ];
				var type = item[ 0 ];
				var item_id = item[ 2 ];

				$.boom.person.select( item_id, $( this ).is(':checked') );

				var amount = $('.b-items-select-checkbox:checked').length;

				var buttons = $( '[id|=b-button-multiaction]' ).not( '#b-button-multiaction-edit' );

				$( '#b-button-multiaction-edit' ).button( (  amount && amount < 3) ? 'enable' : 'disable' );

				buttons.button( amount > 0 ? 'enable' : 'disable' );
			})
			.on( 'mouseenter focus', '#b-items-view-list tbody tr, #b-items-view-thumbs a', function( event ){
				$( this ).addClass( 'ui-state-hover' );
			})
			.on( 'mouseleave blur', '#b-items-view-list tbody tr, #b-items-view-thumbs a', function( event ){
				$( this ).removeClass( 'ui-state-hover' );
			})
			.on( 'click', '.boom-pagination a', function( e ){
				e.preventDefault();

				//$.boom.history.load( '/cms/assets/list?' + $( this ).attr( 'href' ).split( '?' )[ 1 ] );
				$.get( '/cms/people/list?' + $( this ).attr( 'href' ).split( '?' )[ 1 ])
				.done( function( data ){
					var $data = $( data );
					var pagination = $data.find( '.boom-pagination' ).html();
					var list = $data.find( '#b-items-view-list' ).html();
					var thumbs = $data.find( '#b-items-view-thumbs' ).html();
					$( self.main_panel )
						.find( '.boom-pagination' )
						.html( pagination )
						.end()
						.find( '#b-items-view-list' )
						.html( list )
						.end()
						.find( '#b-items-view-thumbs' )
						.html( thumbs );
				});

				return false;
			});

	},

	/** @function */
	savePerson: function(url){

		// TODO: validation

		var data = $('#boom-tagmanager-create-person-form').serialize();

		$.boom.loader.show();

		return $.post(url, data)
		.done( function(id){

			$.boom.loader.hide();

		});
	}
});
<|endoftext|>


<commit_before>/**
 * Provides a user interface to create the planning action.
 */
var PlanningPanel = React.createClass(
{
    getInitialState: function()
    {
        return {tokenToManeuver: {}};
    },

    cancel: function()
    {
        callback(undefined);
    },

    ok: function()
    {
        var environment = this.props.environment;
        var agent = this.props.agent;
        var tokenToManeuver = this.state.tokenToManeuver;
        var callback = this.props.callback;

        var answer = new PlanningAction(environment, agent, tokenToManeuver);

        callback(answer);
    },

    render: function()
    {
        var tokens = this.props.tokens;
        var imageUtils = this.props.imageUtils;
        var self = this;
        var myHtml = [];

        for (var i = 0; i < tokens.length; i++)
        {
            var token = tokens[i];
            myHtml[myHtml.length] =
                <ManeuverChooser
                    token={token}
                    imageUtils={imageUtils}
                    callback={self.selectionChanged}
                />
                	;
        }

        return (<OptionPane panelClass="optionPane"
            title="Planning: Select Maneuvers" titleClass="optionPaneTitle"
            initialInput={

{myHtml}

}
            buttons={<button onClick={self.cancel}>Cancel</button>
                <button onClick={self.ok}>OK</button>}
            buttonsClass="optionPaneButtons"
        />);
    },

    selectionChanged: function(token, maneuver)
    {
        LOGGER.debug("selectionChanged() token = " + token + " maneuver = " + maneuver);
        var tokenToManeuver = this.state.tokenToManeuver;
        tokenToManeuver[token] = maneuver;
    },
});
<commit_msg>Removed the Cancel button.<commit_after>/**
 * Provides a user interface to create the planning action.
 */
var PlanningPanel = React.createClass(
{
    getInitialState: function()
    {
        return {tokenToManeuver: {}};
    },

    ok: function()
    {
        var environment = this.props.environment;
        var agent = this.props.agent;
        var tokenToManeuver = this.state.tokenToManeuver;
        var callback = this.props.callback;

        var answer = new PlanningAction(environment, agent, tokenToManeuver);

        callback(answer);
    },

    render: function()
    {
        var tokens = this.props.tokens;
        var imageUtils = this.props.imageUtils;
        var self = this;
        var myHtml = [];

        for (var i = 0; i < tokens.length; i++)
        {
            var token = tokens[i];
            myHtml[myHtml.length] =
                <ManeuverChooser
                    token={token}
                    imageUtils={imageUtils}
                    callback={self.selectionChanged}
                />
                	;
        }

        return (<OptionPane panelClass="optionPane"
            title="Planning: Select Maneuvers" titleClass="optionPaneTitle"
            initialInput={

{myHtml}

}
            buttons={<button onClick={self.ok}>OK</button>}
            buttonsClass="optionPaneButtons"
        />);
    },

    selectionChanged: function(token, maneuver)
    {
        LOGGER.debug("selectionChanged() token = " + token + " maneuver = " + maneuver);
        var tokenToManeuver = this.state.tokenToManeuver;
        tokenToManeuver[token] = maneuver;
    },
});
<|endoftext|>


<commit_before>// ==UserScript==
// @name vultaire.net CookieBot
// @namespace http://vultaire.net/gmscripts
// @description A very simple clickslave and AI bot for Cookie Clicker.
// @include http://orteil.dashnet.org/cookieclicker/*
// @version 0.16
// ==/UserScript==

// Changes:
//
// 0.16: Added new auto-purchase logic: uses a simple algorithm for
//   deciding a purchase based upon the ratio of cookies-per-minute
//   gain against the cost of the upgrade.
//
// 0.15: Fixed the purchase rule list: it now gets re-initialized
//   after resetting.
//
// 0.14: Updated soft reset to consider total cookies made across all
//   resets.
//
// 0.13: Changed "hold buffer" lower bound to 1 billion CPS.
//
// 0.12: Added a tweak: the cookie "hold buffer" only takes effect if
//   you are making at least a million cookies per second.
//
// 0.11: Fixed auto-soft-reset comparison.
//
// 0.10: Added auto-soft-reset when enough cookies have been made to
//   double the end-game income.  (Based upon current max multiplier
//   of 470% @ 0 prestige and 570% at 4+ prestige.)
//
// 0.9: Minor fix on a check for a possibly defined variable; should
//   work in Chrome again.  (I don't *think* it was affecting FireFox,
//   but not sure.)
//
// 0.8: Embarassing error.  Put the click parameter in the wrong
//   place.  Oops.
//
// 0.7: PhantomJS testing support: can effectively parameterize
//   startup by injecting a variable before loading the main script.
//   Added single parameter, phantomJsClickRate, for controlling the
//   autoclick rate.
//
// 0.6: Fixed cookies-on-hand logic: CPS variable reflected Frenzy; we
//   don't want that.
//
// 0.5: Added minimum cookies-on-hand buffer for gaming the Golden
//   Cookies.

var CookieBot = function () {
    var autoClicker = null;
    var realConfirm = window.confirm;

    function injectScript(src) {
        var text = document.createTextNode(src);
        var script = document.createElement("script");
        script.appendChild(text);
        document.body.appendChild(script);
    }

    function hijackFunctions() {
        hijackConfirm();
        hijackGameParticlesAdd();
    }

    function hijackConfirm() {
        // Automatically hit "yes" for any confirm dialogs.
        // In order to work with TamperMonkey, need to inject into the
        // page directly; can't just override.
        injectScript([
            "window.confirm = function (message) {",
            "    console.log('Automatically hitting \"yes\" for: ' + message);",
            "    return true;",
            "}",
        ].join(""))
    }

    function hijackGameParticlesAdd() {
        var fn = Game.particlesAdd;
        Game.particlesAdd = function (text, el) {
            console.log("Popup: " + text)
            return fn(text, el);
        }
    }

    function enableAutoClick() {
        if (autoClicker === null) {
            var clickInterval = 200;
            if (typeof phantomJsClickRate !== "undefined") {
                console.log("PhantomJS click rate detected; setting to "
                            + phantomJsClickRate + " clicks per second.");
                clickInterval = 1000 / phantomJsClickRate;
            }
            autoClicker = setInterval(Game.ClickCookie, clickInterval);
        }
    }
    function disableAutoClick() {
        if (autoClicker !== null) {
            clearInterval(autoClicker);
            autoClicker = null;
        }
    }

    var objectShoppingOrder = null;

    function initPurchaseRules() {
        objectShoppingOrder = [
            // Syntax: [object, buy-up-to]
            // i.e. if I have 20 cursors and buy-up-to is 50, I buy 30 cursors.
            // If buy-up-to is null, means to just keep buying.
            ["Cursor", 5],
            ["Grandma", 3],
            ["Farm", 3],
            ["Cursor", 20],
            ["Factory", 3],
            ["Mine", 3],
            ["Cursor", 50],
            ["Grandma", 10],
            ["Farm", 10],
            ["Shipment", 5],
            ["Factory", 10],
            ["Mine", 10],
            ["Shipment", 10],
            ["Alchemy lab", 5],
            ["Portal", 10],
            ["Alchemy lab", 10],
            ["Time machine", 20],
            ["Cursor", 100],
            ["Antimatter condenser", 30],
            ["Grandma", 50],
            ["Cursor", 130],
            ["Antimatter condenser", 40],
            ["Farm", 50],
            ["Factory", 50],
            ["Mine", 50],
            ["Shipment", 50],
            ["Cursor", 150],
            ["Antimatter condenser", 50],
            ["Alchemy lab", 50],
            ["Portal", 50],
            ["Time machine", 30],
            ["Cursor", 200],
            ["Antimatter condenser", 60],
            ["Grandma", 128],
            ["Farm", 128],
            ["Factory", 100],
            ["Mine", 100],
            ["Shipment", 100],
            ["Alchemy lab", 100],
            ["Portal", 100],
            ["Time machine", 50],
            ["Antimatter condenser", 70],
            ["Grandma", 150],
            ["Time machine", 80],
            ["Antimatter condenser", 80],
            ["Grandma", 175],
            ["Time machine", 100],
            ["Antimatter condenser", 90],
            ["Grandma", 200],
            ["Antimatter condenser", null],
        ];
    }

    function hasGetLucky() {
        return Game.UpgradesById.filter(function (u) {
            return u.name === "Get lucky";
        })[0].bought;
    }

    function cookiesToHold() {
        // Computes an adjustment factor, such that Golden Cookies are
        // as effective as possible.

        // Early game, this just gets in the way, so skip unless our
        // CPS is at a certain level.  Let's say... 1 billion.
        if (Game.cookiesPs < 1000000000) {
            return 0;
        }

        // Get base cookies-per-second, i.e. accomodating for any Frenzy.
        var realCps = Game.cookiesPs;
        if (Game.frenzy > 0) {
            realCps /= Game.frenzyPower;
        }

        // Compute potential CPS multiplier for Lucky.
        var multiplier = 60 * 20;  // Represents 20 minutes of cookies
        if (hasGetLucky()) {
            multiplier *= 7;  // Potential stacked multiplier with "Get Lucky" upgrade.
        }

        var bonusCookies = realCps * multiplier;
        var bonusCap = bonusCookies * 10;
        return bonusCap;
    }

    function autoBuyUpgrades() {
        var neverBuy = ["Elder Covenant"];
        var bought = false;
        Game.UpgradesInStore.filter(function (upgrade) {
            return upgrade.unlocked && (neverBuy.indexOf(upgrade.name) === -1);
        }).map(function (upgrade) {
            var price;
            if (!bought && (Game.cookies - cookiesToHold() >= upgrade.basePrice)) {
                price = upgrade.basePrice;
                bought = true;
                upgrade.buy();
                console.log("Purchased " + upgrade.name
                            + " for " + Beautify(price));
            }
        });
    }
    function pricePerCps(o) {
        // Returns price/CPS ratio.
        return o.price/o.cps();
    }
    function autoBuyObjects() {
        var cookiesInFiveMinutes = Game.cookies + (Game.cookiesPs * 60 * 5);
        var candidates = Game.ObjectsById.sort(function (a, b) {
            return pricePerCps(a) - pricePerCps(b);
        }).filter(function (o) {
            return cookiesInFiveMinutes > o.price + cookiesToHold();
        });
        // candidates.map(function (o) {
        //     console.log("Candidate: " + o.name
        //                 + " (" + pricePerCps(o) + " price/CPS)");
        // });
        if (candidates.length > 0) {
            var object = candidates[0];
            if (Game.cookies - cookiesToHold() >= object.price) {
                object.buy();
                console.log(">>> Purchased " + object.name
                            + " for " + Beautify(object.price)
                            + ", current count: " + object.amount);
            } // else {
            //     console.log("Waiting on " + object.name
            //                 + ", price: " + Beautify(object.price)
            //                 + ", price/CPS: " + pricePerCps(object)
            //                 + ", will buy at: "
            //                 + Beautify(object.price + cookiesToHold()));
            // }
        }
    }

    function buyObjectsByRules() {
        while (true) {
            var name = objectShoppingOrder[0][0];
            var target = objectShoppingOrder[0][1];
            var object = Game.ObjectsById.filter(function (object) {
                return object.name === name;
            })[0];
            var price;
            if (target === null || object.amount < target) {
                if (Game.cookies - cookiesToHold() >= object.price) {
                    object.buy();
                    console.log("Purchased " + object.name
                                + " for " + Beautify(object.price)
                                + ", current count: " + object.amount);
                } else {
                    // Don't do anything this time.
                }
                return;
            }
            objectShoppingOrder.shift();
        }
    }
    function clickGoldenCookies() {
        if (Game.goldenCookie.life > 0) {
            Game.goldenCookie.click();
        }
    }
    function autoSoftReset() {
        // Exceptions go here...  i.e. don't auto-reset unless you
        // have purchased these items...  For now: don't bother.

        // Begin check for whether we can double our end-game income
        // by resetting.

        var currentPrestige = Game.prestige['Heavenly chips'];
        var base = 470;   // Using 100 (instead of 1.00) as 100%
        // Adjust for cookie requirements which require prestige;
        // these will be available on subsequent runs through.
        base += (25 * Math.min(4, currentPrestige));
        current = base + (2*currentPrestige);  // Current raw multiplier

        // Next: 2*current
        // Next base: 570 (for sure)
        // next: 570 + 2p = 2(current)
        //       2(285 + p) = 2(current)
        //          285 + p = current
        //                p = current - 285
        var targetPrestige = current - 285;
        if (Game.HowMuchPrestige(Game.cookiesEarned + Game.cookiesReset)
            >= targetPrestige) {
            Game.Reset();
            initPurchaseRules();
        }
    }
    function tick() {
        autoBuyUpgrades();
        autoBuyObjects();
        //buyObjectsByRules();
        clickGoldenCookies();
        autoSoftReset();
    }
    function init() {
        hijackFunctions();
        enableAutoClick();
        initPurchaseRules();
        setInterval(tick, 500);
    }
    return {
        init: init,
        enableAutoClick: enableAutoClick,
        disableAutoClick: disableAutoClick,
        cookiesToHold: cookiesToHold,
    };
}();

function bootStrap() {
    // Since not everything gets loaded right away... wait a bit.
    if (Game.ClickCookie) {
        CookieBot.init();
    } else {
        setTimeout(bootStrap, 200);
    }
}

bootStrap();
<commit_msg>Added priority upgrade purchases.<commit_after>// ==UserScript==
// @name vultaire.net CookieBot
// @namespace http://vultaire.net/gmscripts
// @description A very simple clickslave and AI bot for Cookie Clicker.
// @include http://orteil.dashnet.org/cookieclicker/*
// @version 0.17
// ==/UserScript==

// Changes:
//
// 0.17: Added special case upgrade purchases where the cookie buffer
//   is ignored for particularly high-value purchases, such as kitten
//   and heavenly chip related upgrades.
//
// 0.16: Added new auto-purchase logic: uses a simple algorithm for
//   deciding a purchase based upon the ratio of cookies-per-minute
//   gain against the cost of the upgrade.
//
// 0.15: Fixed the purchase rule list: it now gets re-initialized
//   after resetting.
//
// 0.14: Updated soft reset to consider total cookies made across all
//   resets.
//
// 0.13: Changed "hold buffer" lower bound to 1 billion CPS.
//
// 0.12: Added a tweak: the cookie "hold buffer" only takes effect if
//   you are making at least a million cookies per second.
//
// 0.11: Fixed auto-soft-reset comparison.
//
// 0.10: Added auto-soft-reset when enough cookies have been made to
//   double the end-game income.  (Based upon current max multiplier
//   of 470% @ 0 prestige and 570% at 4+ prestige.)
//
// 0.9: Minor fix on a check for a possibly defined variable; should
//   work in Chrome again.  (I don't *think* it was affecting FireFox,
//   but not sure.)
//
// 0.8: Embarassing error.  Put the click parameter in the wrong
//   place.  Oops.
//
// 0.7: PhantomJS testing support: can effectively parameterize
//   startup by injecting a variable before loading the main script.
//   Added single parameter, phantomJsClickRate, for controlling the
//   autoclick rate.
//
// 0.6: Fixed cookies-on-hand logic: CPS variable reflected Frenzy; we
//   don't want that.
//
// 0.5: Added minimum cookies-on-hand buffer for gaming the Golden
//   Cookies.

var CookieBot = function () {
    var autoClicker = null;
    var realConfirm = window.confirm;

    function injectScript(src) {
        var text = document.createTextNode(src);
        var script = document.createElement("script");
        script.appendChild(text);
        document.body.appendChild(script);
    }

    function hijackFunctions() {
        hijackConfirm();
        hijackGameParticlesAdd();
    }

    function hijackConfirm() {
        // Automatically hit "yes" for any confirm dialogs.
        // In order to work with TamperMonkey, need to inject into the
        // page directly; can't just override.
        injectScript([
            "window.confirm = function (message) {",
            "    console.log('Automatically hitting \"yes\" for: ' + message);",
            "    return true;",
            "}",
        ].join(""))
    }

    function hijackGameParticlesAdd() {
        var fn = Game.particlesAdd;
        Game.particlesAdd = function (text, el) {
            console.log("Popup: " + text)
            return fn(text, el);
        }
    }

    function enableAutoClick() {
        if (autoClicker === null) {
            var clickInterval = 200;
            if (typeof phantomJsClickRate !== "undefined") {
                console.log("PhantomJS click rate detected; setting to "
                            + phantomJsClickRate + " clicks per second.");
                clickInterval = 1000 / phantomJsClickRate;
            }
            autoClicker = setInterval(Game.ClickCookie, clickInterval);
        }
    }
    function disableAutoClick() {
        if (autoClicker !== null) {
            clearInterval(autoClicker);
            autoClicker = null;
        }
    }

    var objectShoppingOrder = null;

    function initPurchaseRules() {
        objectShoppingOrder = [
            // Syntax: [object, buy-up-to]
            // i.e. if I have 20 cursors and buy-up-to is 50, I buy 30 cursors.
            // If buy-up-to is null, means to just keep buying.
            ["Cursor", 5],
            ["Grandma", 3],
            ["Farm", 3],
            ["Cursor", 20],
            ["Factory", 3],
            ["Mine", 3],
            ["Cursor", 50],
            ["Grandma", 10],
            ["Farm", 10],
            ["Shipment", 5],
            ["Factory", 10],
            ["Mine", 10],
            ["Shipment", 10],
            ["Alchemy lab", 5],
            ["Portal", 10],
            ["Alchemy lab", 10],
            ["Time machine", 20],
            ["Cursor", 100],
            ["Antimatter condenser", 30],
            ["Grandma", 50],
            ["Cursor", 130],
            ["Antimatter condenser", 40],
            ["Farm", 50],
            ["Factory", 50],
            ["Mine", 50],
            ["Shipment", 50],
            ["Cursor", 150],
            ["Antimatter condenser", 50],
            ["Alchemy lab", 50],
            ["Portal", 50],
            ["Time machine", 30],
            ["Cursor", 200],
            ["Antimatter condenser", 60],
            ["Grandma", 128],
            ["Farm", 128],
            ["Factory", 100],
            ["Mine", 100],
            ["Shipment", 100],
            ["Alchemy lab", 100],
            ["Portal", 100],
            ["Time machine", 50],
            ["Antimatter condenser", 70],
            ["Grandma", 150],
            ["Time machine", 80],
            ["Antimatter condenser", 80],
            ["Grandma", 175],
            ["Time machine", 100],
            ["Antimatter condenser", 90],
            ["Grandma", 200],
            ["Antimatter condenser", null],
        ];
    }

    function hasGetLucky() {
        return Game.UpgradesById.filter(function (u) {
            return u.name === "Get lucky";
        })[0].bought;
    }

    function cookiesToHold() {
        // Computes an adjustment factor, such that Golden Cookies are
        // as effective as possible.

        // Early game, this just gets in the way, so skip unless our
        // CPS is at a certain level.  Let's say... 1 billion.
        if (Game.cookiesPs < 1000000000) {
            return 0;
        }

        // Get base cookies-per-second, i.e. accomodating for any Frenzy.
        var realCps = Game.cookiesPs;
        if (Game.frenzy > 0) {
            realCps /= Game.frenzyPower;
        }

        // Compute potential CPS multiplier for Lucky.
        var multiplier = 60 * 20;  // Represents 20 minutes of cookies
        if (hasGetLucky()) {
            multiplier *= 7;  // Potential stacked multiplier with "Get Lucky" upgrade.
        }

        var bonusCookies = realCps * multiplier;
        var bonusCap = bonusCookies * 10;
        return bonusCap;
    }

    var neverBuy = ["Elder Covenant"];
    var buyEarly = [
        "Kitten helpers",
        "Kitten workers",
        "Kitten engineers",
        "Kitten overseers",
        "Heavenly chip secret",
        "Heavenly cookie stand",
        "Heavenly bakery",
        "Heavenly confectionery",
        "Heavenly key",
    ];

    function autoBuyPriorityUpgrades() {
        var bought = false;
        Game.UpgradesInStore.filter(function (upgrade) {
            return upgrade.unlocked && (buyEarly.indexOf(upgrade.name) !== -1);
        }).map(function (upgrade) {
            if (!bought && (Game.cookies - cookiesToHold() >= upgrade.basePrice)) {
                bought = true;
                upgrade.buy();
                console.log("Purchased " + upgrade.name
                            + " for " + Beautify(upgrade.basePrice));
            }
        });
        return bought;
    }

    function autoBuyGeneralUpgrades() {
        var bought = false;
        Game.UpgradesInStore.filter(function (upgrade) {
            return upgrade.unlocked && (neverBuy.indexOf(upgrade.name) === -1);
        }).map(function (upgrade) {
            if (!bought && (Game.cookies - cookiesToHold() >= upgrade.basePrice)) {
                bought = true;
                upgrade.buy();
                console.log("Purchased " + upgrade.name
                            + " for " + Beautify(upgrade.basePrice));
            }
        });
        return bought;
    }

    function autoBuyUpgrades() {
        if (!autoBuyPriorityUpgrades()) {
            autoBuyGeneralUpgrades();
        }
    }

    function pricePerCps(o) {
        // Returns price/CPS ratio.
        return o.price/o.cps();
    }
    function autoBuyObjects() {
        var cookiesInFiveMinutes = Game.cookies + (Game.cookiesPs * 60 * 5);
        var candidates = Game.ObjectsById.sort(function (a, b) {
            return pricePerCps(a) - pricePerCps(b);
        }).filter(function (o) {
            return cookiesInFiveMinutes > o.price + cookiesToHold();
        });
        // candidates.map(function (o) {
        //     console.log("Candidate: " + o.name
        //                 + " (" + pricePerCps(o) + " price/CPS)");
        // });
        if (candidates.length > 0) {
            var object = candidates[0];
            if (Game.cookies - cookiesToHold() >= object.price) {
                object.buy();
                console.log(">>> Purchased " + object.name
                            + " for " + Beautify(object.price)
                            + ", current count: " + object.amount);
            } // else {
            //     console.log("Waiting on " + object.name
            //                 + ", price: " + Beautify(object.price)
            //                 + ", price/CPS: " + pricePerCps(object)
            //                 + ", will buy at: "
            //                 + Beautify(object.price + cookiesToHold()));
            // }
        }
    }

    function buyObjectsByRules() {
        while (true) {
            var name = objectShoppingOrder[0][0];
            var target = objectShoppingOrder[0][1];
            var object = Game.ObjectsById.filter(function (object) {
                return object.name === name;
            })[0];
            var price;
            if (target === null || object.amount < target) {
                if (Game.cookies - cookiesToHold() >= object.price) {
                    object.buy();
                    console.log("Purchased " + object.name
                                + " for " + Beautify(object.price)
                                + ", current count: " + object.amount);
                } else {
                    // Don't do anything this time.
                }
                return;
            }
            objectShoppingOrder.shift();
        }
    }
    function clickGoldenCookies() {
        if (Game.goldenCookie.life > 0) {
            Game.goldenCookie.click();
        }
    }
    function autoSoftReset() {
        // Exceptions go here...  i.e. don't auto-reset unless you
        // have purchased these items...  For now: don't bother.

        // Begin check for whether we can double our end-game income
        // by resetting.

        var currentPrestige = Game.prestige['Heavenly chips'];
        var base = 470;   // Using 100 (instead of 1.00) as 100%
        // Adjust for cookie requirements which require prestige;
        // these will be available on subsequent runs through.
        base += (25 * Math.min(4, currentPrestige));
        current = base + (2*currentPrestige);  // Current raw multiplier

        // Next: 2*current
        // Next base: 570 (for sure)
        // next: 570 + 2p = 2(current)
        //       2(285 + p) = 2(current)
        //          285 + p = current
        //                p = current - 285
        var targetPrestige = current - 285;
        if (Game.HowMuchPrestige(Game.cookiesEarned + Game.cookiesReset)
            >= targetPrestige) {
            Game.Reset();
            initPurchaseRules();
        }
    }
    function tick() {
        autoBuyUpgrades();
        autoBuyObjects();
        //buyObjectsByRules();
        clickGoldenCookies();
        autoSoftReset();
    }
    function init() {
        hijackFunctions();
        enableAutoClick();
        initPurchaseRules();
        setInterval(tick, 500);
    }
    return {
        init: init,
        enableAutoClick: enableAutoClick,
        disableAutoClick: disableAutoClick,
        cookiesToHold: cookiesToHold,
    };
}();

function bootStrap() {
    // Since not everything gets loaded right away... wait a bit.
    if (Game.ClickCookie) {
        CookieBot.init();
    } else {
        setTimeout(bootStrap, 200);
    }
}

bootStrap();
<|endoftext|>


<commit_before>import h from 'react-hyperscript'
import PropTypes from 'prop-types'
import { compose } from 'recompose'
import { connect as connectStyles } from 'react-fela'
import { isNil, not, and, either, isEmpty } from 'ramda'
import MuiAvatar from 'material-ui/Avatar'
import FontIcon from 'material-ui/FontIcon'

import styles from '../styles/ProfileIcon'

// (mw) these values are _arbitrary_!
// TODO make them more legit
const sizeInPx = {
  small: 40,
  medium: 60,
  large: 80
}

export default compose(
  connectStyles(styles)
)(Avatar)

function Avatar (props) {
  const {
    styles,
    agent,
    size,
    icon,
    dirtyAvatar = ''
  } = props

  const hasDirtyAvatar = not(isEmpty(dirtyAvatar))

  const hasIcon = not(isNil(icon))

  if (isNil(agent)) return null

  const { profile } = agent

  if (isNil(profile)) return null

  const { name, avatar } = profile

  const hasName = not(isNil(name))
  const hasAvatar = not(isNil(avatar))

  console.log('hasAvatar', hasAvatar)
  console.log('hasDirtyAvatar', hasDirtyAvatar)
  console.log('dirtyAvatar', dirtyAvatar)
  console.log('dirtyAvatar isNil?', isNil(dirtyAvatar))
  console.log('dirtyAvatar isEmpty?', isEmpty(dirtyAvatar))
  console.log('hasName', hasName)
  console.log('hasIcon', hasIcon)

  // debugger

  // GK: when accessing profile, dirtyAvatar shows up as empty string
  // GK: i suspect it may be undefined or null when coming from orders page

  const shouldDisplayIcon = and(not(hasAvatar), not(hasDirtyAvatar), not(hasName), hasIcon)

  const src = hasDirtyAvatar ? dirtyAvatar : hasAvatar ? avatar : null

  return (
    h('div', {
      className: styles.container
    }, [
      h(MuiAvatar, {
        className: styles.avatar,
        size: sizeInPx[size],
        icon: (
          and(and(not(hasAvatar), not(hasDirtyAvatar), not(hasName)), hasIcon)
            ? h(FontIcon, {
                className: `fa fa-${icon}`
              })
            : null
        ),
        src: src
      }, [
        and(not(hasAvatar), hasName)
          ? name.substring(0, 1)
          : null
      ])
    ])
  )
}

Avatar.propTypes = {
  avatar: PropTypes.string,
  size: PropTypes.oneOf(['small', 'medium', 'large'])
}

Avatar.defaultProps = {
  size: 'small'
}
<commit_msg>chore(refactor): get rid of logs and debugger<commit_after>import h from 'react-hyperscript'
import PropTypes from 'prop-types'
import { compose } from 'recompose'
import { connect as connectStyles } from 'react-fela'
import { isNil, not, and, either, isEmpty } from 'ramda'
import MuiAvatar from 'material-ui/Avatar'
import FontIcon from 'material-ui/FontIcon'

import styles from '../styles/ProfileIcon'

// (mw) these values are _arbitrary_!
// TODO make them more legit
const sizeInPx = {
  small: 40,
  medium: 60,
  large: 80
}

export default compose(
  connectStyles(styles)
)(Avatar)

function Avatar (props) {
  const {
    styles,
    agent,
    size,
    icon,
    dirtyAvatar = ''
  } = props

  const hasDirtyAvatar = not(isEmpty(dirtyAvatar))

  const hasIcon = not(isNil(icon))

  if (isNil(agent)) return null

  const { profile } = agent

  if (isNil(profile)) return null

  const { name, avatar } = profile

  const hasName = not(isNil(name))
  const hasAvatar = not(isNil(avatar))

  const shouldDisplayIcon = and(not(hasAvatar), not(hasDirtyAvatar), not(hasName), hasIcon)

  const src = hasDirtyAvatar ? dirtyAvatar : hasAvatar ? avatar : null

  return (
    h('div', {
      className: styles.container
    }, [
      h(MuiAvatar, {
        className: styles.avatar,
        size: sizeInPx[size],
        icon: (
          and(and(not(hasAvatar), not(hasDirtyAvatar), not(hasName)), hasIcon)
            ? h(FontIcon, {
                className: `fa fa-${icon}`
              })
            : null
        ),
        src: src
      }, [
        and(not(hasAvatar), hasName)
          ? name.substring(0, 1)
          : null
      ])
    ])
  )
}

Avatar.propTypes = {
  avatar: PropTypes.string,
  size: PropTypes.oneOf(['small', 'medium', 'large'])
}

Avatar.defaultProps = {
  size: 'small'
}
<|endoftext|>


<commit_before>var connect = require('connect'),
    express = require('express');

function workhorse(args) {
  // initialize the app and fire it up
  var app = express.createServer(
      connect.logger(),      // logs all requests
      connect.bodyDecoder()); // makes the POST body available using req.body

  app.configure(function() {
      app.set('views', __dirname + '/views');
      app.use('/static', connect.staticProvider(__dirname + '/static'));
      app.use('/solvers', connect.staticProvider(__dirname + '/solvers'));
    });

  // routing
  app.get('/', function(req, res){
      res.render('index.html.ejs');
    });
  app.get('/problem', function(req,res){
      args.problem(function(problem) {
          res.send(problem);
        });
    });
  app.post('/solution', function(req,res){
      var solution = req.body.solution;
      var problem_id = req.body.problem_id;
      args.solution(solution, problem_id, function(text) {
          res.send(text);
        });
    });

  return app;
}

module.exports = workhorse;
<commit_msg>Added argument validation.<commit_after>var connect = require('connect'),
    express = require('express');

function workhorse(args) {
  validateArgs(args);

  // initialize the app
  var app = express.createServer(
      connect.logger(),       // log all requests
      connect.bodyDecoder()); // make the POST body available using req.body

  app.configure(function() {
      app.set('views', __dirname + '/views');
      app.use('/static', connect.staticProvider(__dirname + '/static'));
      app.use('/solvers', connect.staticProvider(__dirname + '/solvers'));
    });

  // routing
  app.get('/', function(req, res){
      res.render('index.html.ejs');
    });
  app.get('/problem', function(req,res){
      args.problem(function(problem) {
          res.send(problem);
        });
    });
  app.post('/solution', function(req,res){
      var solution = req.body.solution;
      var problem_id = req.body.problem_id;
      args.solution(solution, problem_id, function(text) {
          res.send(text);
        });
    });

  return app;
}

function validateArgs(args) {
  function validateFunctionArgument(args, name) {
    if(!args[name] || (typeof args[name] != 'function'))
      throw "Initialization error. Was expecting an argument '" + name + "' of type 'function'";
  }
  validateFunctionArgument(args, 'solution');
  validateFunctionArgument(args, 'problem');
}

module.exports = workhorse;
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

import { Cache } from './Cache.js';
import { DefaultLoadingManager } from './LoadingManager.js';

function ImageLoader( manager ) {

	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

}

Object.assign( ImageLoader.prototype, {

	crossOrigin: 'Anonymous',

	load: function ( url, onLoad, onProgress, onError ) {

		if ( url === undefined ) url = '';

		if ( this.path !== undefined ) url = this.path + url;

		url = this.manager.resolveURL( url );

		var scope = this;

		var cached = Cache.get( url );

		if ( cached !== undefined ) {

			scope.manager.itemStart( url );

			setTimeout( function () {

				if ( onLoad ) onLoad( cached );

				scope.manager.itemEnd( url );

			}, 0 );

			return cached;

		}

		var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );

		image.addEventListener( 'load', function () {

			Cache.add( url, this );

			if ( onLoad ) onLoad( this );

			scope.manager.itemEnd( url );

		}, false );

		/*
		image.addEventListener( 'progress', function ( event ) {

			if ( onProgress ) onProgress( event );

		}, false );
		*/

		image.addEventListener( 'error', function ( event ) {

			if ( onError ) onError( event );

			scope.manager.itemEnd( url );
			scope.manager.itemError( url );

		}, false );

		if ( url.substr( 0, 5 ) !== 'data:' ) {

			if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;

		}

		scope.manager.itemStart( url );

		image.src = url;

		return image;

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;
		return this;

	},

	setPath: function ( value ) {

		this.path = value;
		return this;

	}

} );

export { ImageLoader };
<commit_msg>ImageLoader: remove both 'load' and 'error' listeners immediately after either of load or error completes, prevents undesired GC references<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

import { Cache } from './Cache.js';
import { DefaultLoadingManager } from './LoadingManager.js';

function ImageLoader( manager ) {

	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

}

Object.assign( ImageLoader.prototype, {

	crossOrigin: 'Anonymous',

	load: function ( url, onLoad, onProgress, onError ) {

		if ( url === undefined ) url = '';

		if ( this.path !== undefined ) url = this.path + url;

		url = this.manager.resolveURL( url );

		var scope = this;

		var cached = Cache.get( url );

		if ( cached !== undefined ) {

			scope.manager.itemStart( url );

			setTimeout( function () {

				if ( onLoad ) onLoad( cached );

				scope.manager.itemEnd( url );

			}, 0 );

			return cached;

		}

		var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );

		var loadListener, errorListener;

		loadListener = function () {

			image.removeEventListener( 'load', loadListener, false );
			image.removeEventListener( 'error', errorListener, false );

			Cache.add( url, this );

			if ( onLoad ) onLoad( this );

			scope.manager.itemEnd( url );

		};

		errorListener = function ( event ) {

			image.removeEventListener( 'load', loadListener, false );
			image.removeEventListener( 'error', errorListener, false );

			if ( onError ) onError( event );

			scope.manager.itemEnd( url );
			scope.manager.itemError( url );

		};

		image.addEventListener( 'load', loadListener, false );

		/*
		image.addEventListener( 'progress', function ( event ) {

			if ( onProgress ) onProgress( event );

		}, false );
		*/

		image.addEventListener( 'error', errorListener, false );

		if ( url.substr( 0, 5 ) !== 'data:' ) {

			if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;

		}

		scope.manager.itemStart( url );

		image.src = url;

		return image;

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;
		return this;

	},

	setPath: function ( value ) {

		this.path = value;
		return this;

	}

} );

export { ImageLoader };
<|endoftext|>


<commit_before>const { MessageEmbed: Embed } = require('discord.js');
const ReactionHandler = require('./ReactionHandler');

/**
 * Klasa's RichDisplay, for helping paginated embeds with reaction buttons
 */
class RichDisplay {

	/**
	 * A single unicode character
	 * @typedef {string} emoji
	 * @memberof RichDisplay
	 */

	/**
	 * @typedef {object} RichDisplayEmojisObject
	 * @memberof RichDisplay
	 * @property {emoji} first
	 * @property {emoji} back
	 * @property {emoji} forward
	 * @property {emoji} last
	 * @property {emoji} jump
	 * @property {emoji} info
	 * @property {emoji} stop
	 */

	/**
	 * @typedef {object} RichDisplayRunOptions
	 * @memberof RichDisplay
	 * @property {Function} [filter] A filter function to add to the ReactionHandler
	 * @property {boolean} [stop = true] If a stop reaction should be included
	 * @property {boolean} [jump = true] If a jump reaction should be included
	 * @property {boolean} [firstLast = true] If a first and last reaction should be included
	 * @property {string} [prompt = 'Which page would you like to jump to?'] The prompt to be used when awaiting user input on a page to jump to
	 * @property {number} [startPage = 0] The page to start the RichDisplay on
	 * @property {number} [max] The maximum total amount of reactions to collect
	 * @property {number} [maxEmojis] The maximum number of emojis to collect
	 * @property {number} [maxUsers] The maximum number of users to react
	 * @property {number} [time] The maximum amount of time before this RichDisplay should expire
	 */

	/**
	 * Constructs our RichDisplay instance
	 * @since 0.4.0
	 * @param  {external:MessageEmbed} [embed=new MessageEmbed()] A Template embed to apply to all pages
	 */
	constructor(embed = new Embed()) {
		/**
		 * The embed template
		 * @since 0.4.0
		 * @type {external:MessageEmbed}
		 */
		this.embedTemplate = embed;

		/**
		 * The stored pages of the display
		 * @since 0.4.0
		 * @type {external:MessageEmbed[]}
		 */
		this.pages = [];

		/**
		 * An optional Info page/embed
		 * @since 0.4.0
		 * @type {?external:MessageEmbed}
		 */
		this.infoPage = null;

		/**
		 * The default emojis to use for this display
		 * @since 0.4.0
		 * @type {RichDisplayEmojisObject}
		 */
		this.emojis = {
			first: '⏮',
			back: '◀',
			forward: '▶',
			last: '⏭',
			jump: '🔢',
			info: 'ℹ',
			stop: '⏹'
		};

		/**
		 * If footers have been applied to all pages
		 * @since 0.4.0
		 * @type {boolean}
		 */
		this.footered = false;
	}

	/**
	 * A new instance of the template embed
	 * @since 0.4.0
	 * @type {external:MessageEmbed}
	 * @readonly
	 */
	get template() {
		return new Embed(this.embedTemplate);
	}

	/**
	 * Sets emojis to a new set of emojis
	 * @since 0.4.0
	 * @param {RichDisplayEmojisObject} emojis An object containing replacement emojis to use instead.
	 * @returns {RichDisplay} this RichDisplay
	 */
	setEmojis(emojis) {
		Object.assign(this.emojis, emojis);
		return this;
	}

	/**
	 * Adds a page to the RichDisplay
	 * @since 0.4.0
	 * @param {(Function|external:MessageEmbed)} embed A callback with the embed template passed and the embed returned, or an embed.
	 * @returns {RichDisplay} this RichDisplay
	 */
	addPage(embed) {
		this.pages.push(this._handlePageGeneration(embed));
		return this;
	}

	/**
	 * Adds an info page to the RichDisplay
	 * @since 0.4.0
	 * @param {(Function|external:MessageEmbed)} embed A callback with the embed template passed and the embed returned, or an embed.
	 * @returns {RichDisplay} this RichDisplay
	 */
	setInfoPage(embed) {
		this.infoPage = this._handlePageGeneration(embed);
		return this;
	}

	/**
	 * Runs the RichDisplay
	 * @since 0.4.0
	 * @param {external:Message} msg A message to either edit, or use to send a new message for this RichDisplay
	 * @param {RichDisplayRunOptions} [options={}] The options to use while running this RichDisplay
	 * @returns {ReactionHandler}
	 */
	async run(msg, options = {}) {
		if (!this.footered) this._footer();
		if (!options.filter) options.filter = () => true;
		const emojis = this._determineEmojis(
			[],
			!('stop' in options) || ('stop' in options && options.stop),
			!('jump' in options) || ('jump' in options && options.jump),
			!('firstLast' in options) || ('firstLast' in options && options.firstLast),
		);
		const message = msg.editable ? await msg.edit('', { embed: this.pages[options.startPage || 0] }) : await msg.channel.send(this.pages[options.startPage || 0]);
		return new ReactionHandler(
			message,
			(reaction, user) => emojis.includes(reaction.emoji.name) && user !== msg.client.user && options.filter(reaction, user),
			options,
			this,
			emojis
		);
	}

	/**
	 * Adds page of pages footers to all pages
	 * @since 0.4.0
	 * @returns {void}
	 * @private
	 */
	async _footer() {
		for (let i = 1; i <= this.pages.length; i++) this.pages[i - 1].setFooter(`${i}/${this.pages.length}`);
		if (this.infoPage) this.infoPage.setFooter('ℹ');
	}

	/**
	 * Determins the emojis to use in this display
	 * @since 0.4.0
	 * @param {emoji[]} emojis An array of emojis to use
	 * @param {boolean} stop Whether the stop emoji should be included
	 * @param {boolean} jump Whether the jump emoji should be included
	 * @param {boolean} firstLast Whether the first & last emojis should be included
	 * @returns {emoji[]}
	 * @private
	 */
	_determineEmojis(emojis, stop, jump, firstLast) {
		if (this.pages.length > 1 || this.infoPage) {
			if (firstLast) emojis.push(this.emojis.first, this.emojis.back, this.emojis.forward, this.emojis.last);
			else emojis.push(this.emojis.back, this.emojis.forward);
		}
		if (this.infoPage) emojis.push(this.emojis.info);
		if (stop) emojis.push(this.emojis.stop);
		if (jump) emojis.push(this.emojis.jump);
		return emojis;
	}

	/**
	 * Resolves the callback or MessageEmbed into a MessageEmbed
	 * @since 0.4.0
	 * @param {(Function|external:MessageEmbed)} cb The callback or embed
	 * @returns {external:MessageEmbed}
	 * @private
	 */
	_handlePageGeneration(cb) {
		if (typeof cb === 'function') {
			// eslint-disable-next-line callback-return
			const page = cb(this.template);
			if (page instanceof Embed) return page;
		} else if (cb instanceof Embed) {
			return cb;
		}
		throw new Error('Expected a MessageEmbed or Function returning a MessageEmbed');
	}

}

module.exports = RichDisplay;
<commit_msg>update filter docs on RichDisplayRunOptions<commit_after>const { MessageEmbed: Embed } = require('discord.js');
const ReactionHandler = require('./ReactionHandler');

/**
 * Klasa's RichDisplay, for helping paginated embeds with reaction buttons
 */
class RichDisplay {

	/**
	 * A single unicode character
	 * @typedef {string} emoji
	 * @memberof RichDisplay
	 */

	/**
	 * @typedef {object} RichDisplayEmojisObject
	 * @memberof RichDisplay
	 * @property {emoji} first
	 * @property {emoji} back
	 * @property {emoji} forward
	 * @property {emoji} last
	 * @property {emoji} jump
	 * @property {emoji} info
	 * @property {emoji} stop
	 */

	/**
	 * @typedef {object} RichDisplayRunOptions
	 * @memberof RichDisplay
	 * @property {Function} [filter] A filter function to add to the ReactionHandler (Recieves: Reaction, User)
	 * @property {boolean} [stop = true] If a stop reaction should be included
	 * @property {boolean} [jump = true] If a jump reaction should be included
	 * @property {boolean} [firstLast = true] If a first and last reaction should be included
	 * @property {string} [prompt = 'Which page would you like to jump to?'] The prompt to be used when awaiting user input on a page to jump to
	 * @property {number} [startPage = 0] The page to start the RichDisplay on
	 * @property {number} [max] The maximum total amount of reactions to collect
	 * @property {number} [maxEmojis] The maximum number of emojis to collect
	 * @property {number} [maxUsers] The maximum number of users to react
	 * @property {number} [time] The maximum amount of time before this RichDisplay should expire
	 */

	/**
	 * Constructs our RichDisplay instance
	 * @since 0.4.0
	 * @param  {external:MessageEmbed} [embed=new MessageEmbed()] A Template embed to apply to all pages
	 */
	constructor(embed = new Embed()) {
		/**
		 * The embed template
		 * @since 0.4.0
		 * @type {external:MessageEmbed}
		 */
		this.embedTemplate = embed;

		/**
		 * The stored pages of the display
		 * @since 0.4.0
		 * @type {external:MessageEmbed[]}
		 */
		this.pages = [];

		/**
		 * An optional Info page/embed
		 * @since 0.4.0
		 * @type {?external:MessageEmbed}
		 */
		this.infoPage = null;

		/**
		 * The default emojis to use for this display
		 * @since 0.4.0
		 * @type {RichDisplayEmojisObject}
		 */
		this.emojis = {
			first: '⏮',
			back: '◀',
			forward: '▶',
			last: '⏭',
			jump: '🔢',
			info: 'ℹ',
			stop: '⏹'
		};

		/**
		 * If footers have been applied to all pages
		 * @since 0.4.0
		 * @type {boolean}
		 */
		this.footered = false;
	}

	/**
	 * A new instance of the template embed
	 * @since 0.4.0
	 * @type {external:MessageEmbed}
	 * @readonly
	 */
	get template() {
		return new Embed(this.embedTemplate);
	}

	/**
	 * Sets emojis to a new set of emojis
	 * @since 0.4.0
	 * @param {RichDisplayEmojisObject} emojis An object containing replacement emojis to use instead.
	 * @returns {RichDisplay} this RichDisplay
	 */
	setEmojis(emojis) {
		Object.assign(this.emojis, emojis);
		return this;
	}

	/**
	 * Adds a page to the RichDisplay
	 * @since 0.4.0
	 * @param {(Function|external:MessageEmbed)} embed A callback with the embed template passed and the embed returned, or an embed.
	 * @returns {RichDisplay} this RichDisplay
	 */
	addPage(embed) {
		this.pages.push(this._handlePageGeneration(embed));
		return this;
	}

	/**
	 * Adds an info page to the RichDisplay
	 * @since 0.4.0
	 * @param {(Function|external:MessageEmbed)} embed A callback with the embed template passed and the embed returned, or an embed.
	 * @returns {RichDisplay} this RichDisplay
	 */
	setInfoPage(embed) {
		this.infoPage = this._handlePageGeneration(embed);
		return this;
	}

	/**
	 * Runs the RichDisplay
	 * @since 0.4.0
	 * @param {external:Message} msg A message to either edit, or use to send a new message for this RichDisplay
	 * @param {RichDisplayRunOptions} [options={}] The options to use while running this RichDisplay
	 * @returns {ReactionHandler}
	 */
	async run(msg, options = {}) {
		if (!this.footered) this._footer();
		if (!options.filter) options.filter = () => true;
		const emojis = this._determineEmojis(
			[],
			!('stop' in options) || ('stop' in options && options.stop),
			!('jump' in options) || ('jump' in options && options.jump),
			!('firstLast' in options) || ('firstLast' in options && options.firstLast),
		);
		const message = msg.editable ? await msg.edit('', { embed: this.pages[options.startPage || 0] }) : await msg.channel.send(this.pages[options.startPage || 0]);
		return new ReactionHandler(
			message,
			(reaction, user) => emojis.includes(reaction.emoji.name) && user !== msg.client.user && options.filter(reaction, user),
			options,
			this,
			emojis
		);
	}

	/**
	 * Adds page of pages footers to all pages
	 * @since 0.4.0
	 * @returns {void}
	 * @private
	 */
	async _footer() {
		for (let i = 1; i <= this.pages.length; i++) this.pages[i - 1].setFooter(`${i}/${this.pages.length}`);
		if (this.infoPage) this.infoPage.setFooter('ℹ');
	}

	/**
	 * Determins the emojis to use in this display
	 * @since 0.4.0
	 * @param {emoji[]} emojis An array of emojis to use
	 * @param {boolean} stop Whether the stop emoji should be included
	 * @param {boolean} jump Whether the jump emoji should be included
	 * @param {boolean} firstLast Whether the first & last emojis should be included
	 * @returns {emoji[]}
	 * @private
	 */
	_determineEmojis(emojis, stop, jump, firstLast) {
		if (this.pages.length > 1 || this.infoPage) {
			if (firstLast) emojis.push(this.emojis.first, this.emojis.back, this.emojis.forward, this.emojis.last);
			else emojis.push(this.emojis.back, this.emojis.forward);
		}
		if (this.infoPage) emojis.push(this.emojis.info);
		if (stop) emojis.push(this.emojis.stop);
		if (jump) emojis.push(this.emojis.jump);
		return emojis;
	}

	/**
	 * Resolves the callback or MessageEmbed into a MessageEmbed
	 * @since 0.4.0
	 * @param {(Function|external:MessageEmbed)} cb The callback or embed
	 * @returns {external:MessageEmbed}
	 * @private
	 */
	_handlePageGeneration(cb) {
		if (typeof cb === 'function') {
			// eslint-disable-next-line callback-return
			const page = cb(this.template);
			if (page instanceof Embed) return page;
		} else if (cb instanceof Embed) {
			return cb;
		}
		throw new Error('Expected a MessageEmbed or Function returning a MessageEmbed');
	}

}

module.exports = RichDisplay;
<|endoftext|>


<commit_before>var Trie = require('./trie').Trie;

var isEmpty = function(ob) {
  for(var i in ob){ return false; }
  return true;
}

var root = new Trie();
// Test Create
console.log("Create:", '\t\t\t\t', typeof(root) !== 'undefined' && root.name === '' && root.isWord === false && isEmpty(root.children));
if (!(typeof(root) !== 'undefined' && root.name === '' && root.isWord === false && isEmpty(root.children))) process.exit(-1);

// Test Add Word
root.set('and')
var test_root = typeof(root) !== 'undefined' && root.name === '' && root.isWord === false && !isEmpty(root.children);
var test = root.children['a'];
var test_a = typeof(test) !== 'undefined' && test.name === 'a' && test.isWord === false && !isEmpty(test.children);
test = test.children['n'];
var test_an = typeof(test) !== 'undefined' && test.name === 'n' && test.isWord === false && !isEmpty(test.children);
test = test.children['d'];
var test_and = typeof(test) !== 'undefined' && test.name === 'd' && test.isWord === true && isEmpty(test.children);
console.log("Set:", '\t\t\t\t\t', test_root && test_a && test_an && test_and);
if (!(test_root && test_a && test_an && test_and)) process.exit(-1);

// Test Add Word for a second word
root.set('an')
test_root = typeof(root) !== 'undefined' && root.name === '' && root.isWord === false && !isEmpty(root.children);
test = root.children['a'];
test_a = typeof(test) !== 'undefined' && test.name === 'a' && test.isWord === false && !isEmpty(test.children);
test = test.children['n'];
test_an = typeof(test) !== 'undefined' && test.name === 'n' && test.isWord === true && !isEmpty(test.children);
test = test.children['d'];
test_and = typeof(test) !== 'undefined' && test.name === 'd' && test.isWord === true && isEmpty(test.children);
console.log("Set (second word):", '\t\t\t', test_root && test_a && test_an && test_and);
if (!(test_root && test_a && test_an && test_and)) process.exit(-1);

// Test Remove Word
root.del('and');
test_root = typeof(root) !== 'undefined' && root.name === ''  && root.isWord === false && !isEmpty(root.children);
test = root.children['a'];
test_a    = typeof(test) !== 'undefined' && test.name === 'a' && test.isWord === false && !isEmpty(test.children);
test = test.children['n'];
test_an   = typeof(test) !== 'undefined' && test.name === 'n' && test.isWord === true  &&  isEmpty(test.children);
test = test.children['d'];
test_and  = typeof(test) === 'undefined';
console.log("Del:", '\t\t\t\t\t', test_root && test_a && test_an && test_and);
if (!(test_root && test_a && test_an && test_and)) process.exit(-1);

root.set('Hello');
var non_existing_short = root.exists('Hell') === false;
var non_existing_long = root.exists('Helloo') === false;
var existing = root.exists('Hello')  ===  true;
console.log("Exists (non-existing word short):", '\t', non_existing_short);
console.log("Exists (non-existing word long):", '\t', non_existing_long);
console.log("Exists (existing word):", '\t\t', existing);
if (!(non_existing_short && non_existing_long && existing)) process.exit(-1);

var words = ['a', 'b', 'and', 'an', 'as', 'ant', 'andy', 'art'];
root.sets(words);
var match = root.match('a').join('') == [ 'a', 'an', 'and', 'andy', 'ant', 'as', 'art' ].join('');
console.log("Match:", '\t\t\t\t\t', match);
if (!(match)) process.exit(-1);

<commit_msg>Moved all unit tests to use the assert module. Significantly reduced complexity.<commit_after>var Trie = require('./trie').Trie;
var assert = require('assert');

// Test Create
var root = new Trie();
var expected = {
  root: { name: '' , isWord: false, children: {} },
  a   : { name: 'a', isWord: false, children: {} },
  an  : { name: 'n', isWord: false, children: {} },
  and : { name: 'd', isWord: false, children: {} }
};
assert.deepEqual( root, expected.root, "Failed root was not correctly initialized." );

// Test Add Word
root.set('and');
expected.root.children['a'] = expected.a;
expected.a.children['n']    = expected.an;
expected.an.children['d']   = expected.and;
expected.and.isWord = true;
assert.deepEqual(root, expected.root, "Failed root was not correctly modified by set('and').");

// Test Add Word, for a second word
root.set('an')
expected.an.isWord = true;
assert.deepEqual(root, expected.root, "Failed root was not correctly modified by set('an').");

// Test Remove Word
root.del('and');
delete expected.and;
delete expected.an.children['d'];
assert.deepEqual(root, expected.root, "Failed root was not correctly modified by del('and').");

root.set('Hello');
assert.strictEqual(false, root.exists('Hell'), "Non existing short word 'exists'" );
assert.strictEqual(false, root.exists('Helloo'), "Non existing long word 'exists'" );
assert.strictEqual(true, root.exists('Hello'), "Existing short word doesn't 'exists'" );

var words = [ 'b', 'a', 'an', 'and', 'andy', 'as', 'art'];
root.sets(words);
assert.deepEqual( root.match('a'), words.slice(1));
<|endoftext|>


<commit_before>/**
 * @file xsdwebform.parser.log.js
 * XSD Schema to HTML5 Web Form
 * @author George Bouris <gb@eworx.gr>
 * @copyright Copyright (C) 2017 EEA, Eworx, George Bouris. All rights reserved.
 */

'use strict';

/**
 * Class XSDWebFormParserLog
 * Parser for XSD Schema Tags
 * Static
 */
class XSDWebFormParserLog {
	/**
	 * Class constructor
	 */
	constructor() {
		this.htmlOutput = `<!DOCTYPE html>

`;
	}
	/**
	 * showLog
	 */
	showLogs(sender) {
		if (!sender.verbose)
			console.log("");

		// process.stdout.write(sender.htmlOutput.HTMLObjects[0]);
		if (sender.verbose) {
			console.log("\n\n\x1b[0m\x1b[32mHTML OBJECTS: \x1b[0m\x1b[36m");
			this.htmlOutput  += `<BR><BR><h2>HTML OBJECTS: </h2>\n`;

			console.log("\x1b[0m\x1b[2m");
			this.htmlOutput  += `<div style="/*background-color: rgb(0, 51, 153);*/padding: 8px;font-size:13px;color: #fff;">\n<ul>\n`;
			sender.htmlOutput.HTMLObjects.forEach( (item) => {
				item.itemObject.groups.forEach( (gitem) => {
					gitem.itemObject.items.forEach( (eitem) => {
						console.log(eitem.toString().substring(0, 40) + "...");
						this.htmlOutput  += `<li style="padding: 8px;">${eitem.toString().substring(0, 80) .replace(/</g, '<').replace(/>/g, '>')}..</li>\n`;
					});
				});
			});
			this.htmlOutput  += `</ul>\n</div>\n`;
		} else {
			console.log("");
		}
		console.log("\x1b[0m");
		console.log(new Date());

		this.htmlOutput  += `\n<BR><BR><div style="font-size:14px;color:#777">${new Date()}</div>\n`;

		console.log("\n\x1b[2m\x1b[33m==================================================================================================================================================\n\x1b[0m");
	}

	/**
	 * logXSD
	 * @param xObject
	 */
	logXSD(xObject) {
		console.log("\n\n\x1b[2m\x1b[36m__________________________________________________________________________________________________________________________________________________\n\x1b[0m");
		console.log(`                                                             \x1b[1m\x1b[36mFILE : ${xObject.xfile} \x1b[0m\n`);
		console.log("\x1b[2m\x1b[36m__________________________________________________________________________________________________________________________________________________\n\x1b[0m\n\n");

		this.htmlOutput  += `<h2><span style="color:#777">XSD File:</span> ${xObject.xfile}</h2>\n`;
	}

	/**
	 * logHTML
	 * @param xObject
	 */
	logHTML(xObject) {
		console.log("\n\n\x1b[2m\x1b[33m__________________________________________________________________________________________________________________________________________________\n\x1b[0m");
		console.log(`                                                             \x1b[1m\x1b[33mFILE : ${xObject.hfile} \x1b[0m\n`);
		console.log("\x1b[2m\x1b[33m__________________________________________________________________________________________________________________________________________________\n\x1b[0m\n\n");

		this.htmlOutput  += `<BR><BR><h2><span style="color:#777">XML File:</span> ${xObject.hfile}</h2>\n`;
	}

	/**
	 * showItemLog - ShowLog
	 * @param xsdItem
	 */
	showItemLog(xsdItem, verbose) {

		let xspace = "  ";
		for (let i = 0; i < xsdItem.level; i++) {
			xspace += "\t";
		}

		console.log(`${xspace}\x1b[0m\x1b[31m▓▓▓▓▓▓▓▓▓▓▓▓▓\x1b[0m`);
		process.stdout.write(`${xspace}\x1b[2m▓▓▓▓ \x1b[0m\x1b[2mL:${xsdItem.level} \x1b[2m▓▓▓▓\x1b[0m\x1b[31m⇢\x1b[0m `);
		this.htmlOutput  += `

Level ${xsdItem.level}
`;

		if (xsdItem.children) {
			process.stdout.write(`\x1b[1m${xsdItem.name}`);
			this.htmlOutput  += `<li class="xsdc" style="width:200px;color:rgb(0, 51, 153);background-color:#fff;">${xsdItem.name}\t<span>line ${xsdItem.line}</span></li>\n`;

			if (xsdItem.attr.name) {
				process.stdout.write(` - ${xsdItem.attr.name}`);
				this.htmlOutput  += `<li class="xsdc" style="border-radius:0;width:300px;font-size:14px;color:rgb(204, 0, 0);background-color:#fafafa;"><b>${xsdItem.attr.name}</b></li>\n`;

				if (verbose) {
					if (xsdItem.name === "xs:element") {
						let txmlItem = xsdItem.toString();
						txmlItem = txmlItem.split("\n").join("");
						txmlItem = txmlItem.split("<").join(xspace + `\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m<`);

						let pos1 = txmlItem.indexOf("<xs:documentation>");
						if (pos1 > 0) {
							let pos2 = txmlItem.indexOf("</xs:documentation>");
							txmlItem = txmlItem.substring(0, pos1) + "<xs:documentation> ..." + txmlItem.substring(pos2);
						}
						process.stdout.write(`\x1b[2m${txmlItem}`);
					}
				}
			} else if (xsdItem.attr.value) {
				process.stdout.write(`\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m${xsdItem.attr.value}\x1b[0m`);
				this.htmlOutput  += `<li class="xsdc"style="border-radius:0;width:300px;font-size:12px;color:#333;background-color:#dee6f7;"><b>${xsdItem.attr.value}</b></li>\n`;
			} else if (xsdItem.attr.ref) {
				process.stdout.write(`\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m\x1b[36mRef: \x1b[1m\x1b[36m${xsdItem.attr.ref}\x1b[0m`);
				this.htmlOutput  += `<li class="xsdc"style="border-radius:0;width:300px;font-size:12px;color:#333;background-color:#dee6f7;">Ref: ${xsdItem.attr.ref}</li>\n`;
			}

			process.stdout.write(`\n\x1b[2m${xspace}▓▓▓▓▓▓▓▓▓▓▓▓▓`);

			if (xsdItem.name === "xs:documentation" && xsdItem.xparent.name === "xs:annotation") {
				let txmlItem = xsdItem.val.toString().trim();
				if (txmlItem.length > 60)
					txmlItem = txmlItem.substring(0, 60) + "...";
				process.stdout.write(` \x1b[2m\x1b[37m ${txmlItem}\x1b[0m\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓`);
			}

			if (xsdItem.xparent) {
				console.log(`\x1b[2m\x1b[32m  parent ::\x1b[1m ${xsdItem.xparent.name}\x1b[0m`);
				if (xsdItem.xparent.attr.name) {
					console.log(`${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓ \x1b[2m\x1b[32m par.name ::\x1b[1m ${xsdItem.xparent.attr.name}\x1b[0m`);
				}
			}
		}

		if (xsdItem.level === 0)
			console.log(" ");

		this.htmlOutput  += `</ul>\n`;

		process.stdout.write(`\x1b[2m${xspace}         ▒▒`);
	}

	/**
	 * logXsdTag - Log XSD Element Tag
	 * @param item
	 */
	logXsdTag(item) {
		console.log(`\x1b[0m\x1b[31m⇣\x1b[2m Found Tag \x1b[33m${item}\x1b[0m`);
		this.htmlOutput  += `<div class="ftag"># ${item}</div>\n`;
	}

	/**
	 * logTODO - Log XSD Element Tag
	 * @param msg
	 */
	logTODO(msg) {
		console.log(`\x1b[1m\x1b[31mTODO: \x1b[0m${msg}\x1b[0m`);
	}

	/**
	 * logHtmlTag - Log HTML Element Tag
	 * @param item
	 */
	logHtmlTag(item, sender) {
		if (sender.verbose) {
			console.log(`\x1b[0m\x1b[31m⇣\n\x1b[2mParsing HTML Tag ⇢ \x1b[33m${item.name}\x1b[0m\n`);
			this.htmlOutput  += `<div class="phtmlt"># <b>${item.name}</b> :: <b>${item.attr.element  || item.attr.name || ' '}</b></div>\n`;
		}
	}

	/**
	 * getHtmlLog
	 */
	getHtmlLog() {
		return this.htmlOutput  + `

		 `;
	}

}

module.exports = XSDWebFormParserLog;<commit_msg>Updated LOG files<commit_after>/**
 * @file xsdwebform.parser.log.js
 * XSD Schema to HTML5 Web Form
 * @author George Bouris <gb@eworx.gr>
 * @copyright Copyright (C) 2017 EEA, Eworx, George Bouris. All rights reserved.
 */

'use strict';

/**
 * Class XSDWebFormParserLog
 * Parser for XSD Schema Tags
 * Static
 */
class XSDWebFormParserLog {
	/**
	 * Class constructor
	 */
	constructor() {
		this.htmlOutput = `<!DOCTYPE html>

0

1

2

3

4

5

6

7

8

9

`;
	}
	/**
	 * showLog
	 */
	showLogs(sender) {
		if (!sender.verbose)
			console.log("");

		// process.stdout.write(sender.htmlOutput.HTMLObjects[0]);
		if (sender.verbose) {
			console.log("\n\n\x1b[0m\x1b[32mHTML OBJECTS: \x1b[0m\x1b[36m");
			this.htmlOutput  += `<BR><BR><h2>HTML OBJECTS: </h2>\n`;

			console.log("\x1b[0m\x1b[2m");
			this.htmlOutput  += `<div style="/*background-color: rgb(0, 51, 153);*/padding: 8px;font-size:13px;color: #fff;">\n<ul>\n`;
			sender.htmlOutput.HTMLObjects.forEach( (item) => {
				item.itemObject.groups.forEach( (gitem) => {
					gitem.itemObject.items.forEach( (eitem) => {
						console.log(eitem.toString().substring(0, 40) + "...");
						this.htmlOutput  += `<li style="padding: 8px;">${eitem.toString().substring(0, 80) .replace(/</g, '<').replace(/>/g, '>')}..</li>\n`;
					});
				});
			});
			this.htmlOutput  += `</ul>\n</div>\n`;
		} else {
			console.log("");
		}
		console.log("\x1b[0m");
		console.log(new Date());

		this.htmlOutput  += `\n<BR><BR><div style="font-size:14px;color:#777">${new Date()}</div>\n`;

		console.log("\n\x1b[2m\x1b[33m==================================================================================================================================================\n\x1b[0m");
	}

	/**
	 * logXSD
	 * @param xObject
	 */
	logXSD(xObject) {
		console.log("\n\n\x1b[2m\x1b[36m__________________________________________________________________________________________________________________________________________________\n\x1b[0m");
		console.log(`                                                             \x1b[1m\x1b[36mFILE : ${xObject.xfile} \x1b[0m\n`);
		console.log("\x1b[2m\x1b[36m__________________________________________________________________________________________________________________________________________________\n\x1b[0m\n\n");

		this.htmlOutput  += `<h2><span style="color:#777">XSD File:</span> ${xObject.xfile}</h2>\n`;
	}

	/**
	 * logHTML
	 * @param xObject
	 */
	logHTML(xObject) {
		console.log("\n\n\x1b[2m\x1b[33m__________________________________________________________________________________________________________________________________________________\n\x1b[0m");
		console.log(`                                                             \x1b[1m\x1b[33mFILE : ${xObject.hfile} \x1b[0m\n`);
		console.log("\x1b[2m\x1b[33m__________________________________________________________________________________________________________________________________________________\n\x1b[0m\n\n");

		this.htmlOutput  += `<BR><BR><h2><span style="color:#777">XML File:</span> ${xObject.hfile}</h2>\n`;
	}

	/**
	 * showItemLog - ShowLog
	 * @param xsdItem
	 */
	showItemLog(xsdItem, verbose) {

		let xspace = "  ";
		for (let i = 0; i < xsdItem.level; i++) {
			xspace += "\t";
		}

		console.log(`${xspace}\x1b[0m\x1b[31m▓▓▓▓▓▓▓▓▓▓▓▓▓\x1b[0m`);
		process.stdout.write(`${xspace}\x1b[2m▓▓▓▓ \x1b[0m\x1b[2mL:${xsdItem.level} \x1b[2m▓▓▓▓\x1b[0m\x1b[31m⇢\x1b[0m `);
		this.htmlOutput  += `

Level ${xsdItem.level}
`;

		if (xsdItem.children) {
			process.stdout.write(`\x1b[1m${xsdItem.name}`);
			this.htmlOutput  += `<li class="xsdc" style="width:200px;color:rgb(0, 51, 153);background-color:#fff;">${xsdItem.name}\t<span>line ${xsdItem.line}</span></li>\n`;

			if (xsdItem.attr.name) {
				process.stdout.write(` - ${xsdItem.attr.name}`);
				this.htmlOutput  += `<li class="xsdc" style="border-radius:0;width:300px;font-size:14px;color:rgb(204, 0, 0);background-color:#fafafa;"><b>${xsdItem.attr.name}</b></li>\n`;

				if (verbose) {
					if (xsdItem.name === "xs:element") {
						let txmlItem = xsdItem.toString();
						txmlItem = txmlItem.split("\n").join("");
						txmlItem = txmlItem.split("<").join(xspace + `\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m<`);

						let pos1 = txmlItem.indexOf("<xs:documentation>");
						if (pos1 > 0) {
							let pos2 = txmlItem.indexOf("</xs:documentation>");
							txmlItem = txmlItem.substring(0, pos1) + "<xs:documentation> ..." + txmlItem.substring(pos2);
						}
						process.stdout.write(`\x1b[2m${txmlItem}`);
					}
				}
			} else if (xsdItem.attr.value) {
				process.stdout.write(`\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m${xsdItem.attr.value}\x1b[0m`);
				this.htmlOutput  += `<li class="xsdc"style="border-radius:0;width:300px;font-size:12px;color:#333;background-color:#dee6f7;"><b>${xsdItem.attr.value}</b></li>\n`;
			} else if (xsdItem.attr.ref) {
				process.stdout.write(`\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m\x1b[36mRef: \x1b[1m\x1b[36m${xsdItem.attr.ref}\x1b[0m`);
				this.htmlOutput  += `<li class="xsdc"style="border-radius:0;width:300px;font-size:12px;color:#333;background-color:#dee6f7;">Ref: ${xsdItem.attr.ref}</li>\n`;
			}

			process.stdout.write(`\n\x1b[2m${xspace}▓▓▓▓▓▓▓▓▓▓▓▓▓`);

			if (xsdItem.name === "xs:documentation" && xsdItem.xparent.name === "xs:annotation") {
				let txmlItem = xsdItem.val.toString().trim();
				if (txmlItem.length > 60)
					txmlItem = txmlItem.substring(0, 60) + "...";
				process.stdout.write(` \x1b[2m\x1b[37m ${txmlItem}\x1b[0m\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓`);
			}

			if (xsdItem.xparent) {
				console.log(`\x1b[2m\x1b[32m  parent ::\x1b[1m ${xsdItem.xparent.name}\x1b[0m`);
				if (xsdItem.xparent.attr.name) {
					console.log(`${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓ \x1b[2m\x1b[32m par.name ::\x1b[1m ${xsdItem.xparent.attr.name}\x1b[0m`);
				}
			}
		}

		if (xsdItem.level === 0)
			console.log(" ");

		this.htmlOutput  += `</ul>\n`;

		process.stdout.write(`\x1b[2m${xspace}         ▒▒`);
	}

	/**
	 * logXsdTag - Log XSD Element Tag
	 * @param item
	 */
	logXsdTag(item) {
		console.log(`\x1b[0m\x1b[31m⇣\x1b[2m Found Tag \x1b[33m${item}\x1b[0m`);
		this.htmlOutput  += `<div class="ftag"># ${item}</div>\n`;
	}

	/**
	 * logTODO - Log XSD Element Tag
	 * @param msg
	 */
	logTODO(msg) {
		console.log(`\x1b[1m\x1b[31mTODO: \x1b[0m${msg}\x1b[0m`);
	}

	/**
	 * logHtmlTag - Log HTML Element Tag
	 * @param item
	 */
	logHtmlTag(item, sender) {
		if (sender.verbose) {
			console.log(`\x1b[0m\x1b[31m⇣\n\x1b[2mParsing HTML Tag ⇢ \x1b[33m${item.name}\x1b[0m\n`);
			this.htmlOutput  += `<div class="phtmlt"># <b>${item.name}</b> :: <b>${item.attr.element  || item.attr.name || ' '}</b></div>\n`;
		}
	}

	/**
	 * getHtmlLog
	 */
	getHtmlLog() {
		return this.htmlOutput  + `

 `;
	}

}

module.exports = XSDWebFormParserLog;<|endoftext|>


<commit_before><commit_msg>Update project angucomplete-alt to 2.0.3<commit_after><|endoftext|>