<commit_before>var _ = require('underscore');
var fs = require('fs');
var path = require('path');
var async = require('async');
var MailParser = require('mailparser').MailParser;
// var HtmlToText = require('html-to-text');
var EmailSender = require('./EmailSender');
var EmailReceiver = require('./EmailReceiver');
var EmailTemplates = require('./EmailTemplates');

module.exports = (function () {
	'use strict';

	/**
	 * @class EmailInterface
	 * @classdesc `EmailInterface` class that serves as an interface / middleman between the code base and the EmailSender.
	 *
	 * @param {object} [options]					- Options
	 * @param {object} [options.sender]				-  {@link EmailSender} Options for the email sending service
	 * @param {object} [options.receiver]			-  {@link EmailReceiver} Options for the email sending service
	 *
	 * @return {EmailInterface}
	 */
	function EmailInterface (options) {

		options = options || {};

		this.templatesDir = options.templatesDir;

		if (options.sender) {
			this.sender = new EmailSender(options.sender);
			this.templating = new EmailTemplates(options.templating);
		}

		if (options.receiver) {
			this.receiver = new EmailReceiver(options.receiver);
		}

		this.transport = null;

	}

	/**
	 * Small chaining method that sets the transport type for the following send command.
	 *
	 * @function with
	 * @memberof EmailInterface.prototype
	 *
	 * @param {string}	transport	-	Name of the transport method (e.g: 'SES', 'direct', 'sendmail', ...etc.)
	 *
	 * @return {EmailInterface}
	 *
	 * @api public
	 */
	EmailInterface.prototype.with = function (transport) {
		return (this.transport = transport, this);
	};

	/**
	 * Chaining of some RegExps to clean up quotes and email authors.
	 *
	 * @function getCleanEmailBody
	 * @memberof EmailInterface.prototype
	 *
	 * @param {string}	email	-	The fully buffered / streamed email content
	 *
	 * @return {string}
	 *
	 * @api private
	 */
	EmailInterface.prototype.getCleanEmailBody = function (email) {
		// TODO convert from HTML to text and then cleanup if email is HTML
		email = email
			// Remove email signatures
			.replace(/(\r?\n)\-{2} ?(\r?\n)[\w\W]+/, '')
			// Remove Outlook previous message header
			.replace(/(\r?\n)\-+ ?Original Message ?\-+[\w\W]+/i, '')
			// Remove other type of Outlook previous message header
			.replace(/(\r?\n)\_{30,}[\w\W]+/, '')
			.replace(/(\r?\n)\-{30,}[\w\W]+/, '')
			// Mac OSX mail
			.replace(/(\r?\n)On ([^(\r?\n)]*?) wrote:(\r?\n)[\w\W]+/i, '')
			// Forwarded emails
			.replace(/(\r?\n)\-{5,} ?Forwarded by [\w\W]+ ?\-{5,}(\r?\n)/i, '')
			// Outlook and other email clients's reply format with multilingual support
			.replace(/(\r?\n)\*?(From|De)\*?: [\w\W]+/i, '')
			// Hotmail reply format
			.replace(/(\r?\n)Date: [\w\W]+/i, '')
			// Smartphone footer
			.replace(/(\r?\n)Sent from my [\w\W]+/i, '')
			// Sent by signature style
			.replace(/(\r?\n)Sent by:[\w\W]+/i, '')
			// Remove replies
			.replace(/(\r?\n)> [\w\W]+/i, '')
			.trim();

		return email;
	};

	/**
	 * Closure function that return new instances of a mail parser stream to which receiveid emails are piped to.
	 *
	 * @function InstanciateMailParser
	 * @memberof EmailInterface.prototype
	 *
	 * @param {function}	callback	- Callback
	 *
	 * @return {function}
	 *
	 * @api public
	 */
	EmailInterface.prototype.InstanciateMailParser = function (callback) {
		var me = this;
		return function () {
			var mailParser = new MailParser({
				debug: false
				// TODO streamAttachments
				// TODO unescapeSMTP
				// TODO defaultCharset
				// TODO showAttachmentLinks
			});

			mailParser.on('end', function (email) {
				email.text = me.getCleanEmailBody(email.text);
				// TODO clean html bodies too using JSDOM or cheerio
				callback(null, email);
			});

			return mailParser;
		};
	};

	/**
	 * Assembles an object containing all the needed informations to create a valid
	 * envelope and (HTML) email body.
	 *
	 * @function assembleEmail
	 * @memberof EmailInterface.prototype
	 *
	 * @param {object}			settings					- Data use to create the envelop and email body
	 * @param {string}			settings.from				- Sender email
	 * @param {(string|array)}	settings.to					- Destination email address(es)
	 * @param {array}			[settings.cc]				- Recipients in the Cc field
	 * @param {array}			[settings.bcc]				- Recipients in the Bcc field
	 * @param {string}			[settings.replyTo]			- ReplyTo field
	 * @param {string}			[settings.inReplyTo]		- Message Id to which the email replies to
	 * @param {string}			[settings.references]		- Messages Id list
	 * @param {string}			[settings.subject]			- Subject of the email
	 * @param {string}			[settings.text]				- Plaintext body
	 * @param {string}			[settings.html]				- HTML body
	 * @param {object}			[settings.headers]			- HTTP / SMTP headers
	 * @param {array}			[settings.attachments]		- List of attachments files / buffers or strings
	 * @param {array}			[settings.messageId]		- List of attachments files / buffers or strings
	 *
	 * @param {object}			[data]						- Data to feed to the templating engine
	 *
	 * @param {function}		callback					- Callback
	 *
	 * @return {undefined}
	 *
	 * @api private
	 */
	EmailInterface.prototype.assembleEmail = function (settings, data, callback) {
		var accumulator = {};
		var attachments = false;

		var type = settings.type;
		var subject = settings.subject;

		var accumulate = function (templates) {
			var uid = templates.uid;
			templates.uid = null;
			delete templates.uid;

			accumulator[uid] = _.extend(accumulator[uid] || {}, templates);

			var instance = accumulator[uid];

			if(instance.html && instance.subject && attachments !== false) {
				accumulator[uid] = null;
				delete accumulator[uid];
				callback(null, instance);
			}
		}.bind(this);

		var templatesDir = this.templatesDir;
		var templating = this.templating;

		async.auto({
			renderedEmail: function (cb) {
				var contentDir = path.resolve(templatesDir, 'content');

				templating.render({
					templatesDir: contentDir,
					partials: {},
					helper: {},
					items: data,
					type: type
				}, function (e, templates) {
					if(e) {
						return cb(e);
					}

					accumulate(templates);
					cb();
				});
			},
			renderedSubject: function (cb) {
				if(_.isString(subject)) {
					return accumulate({
						subject: subject
					});
				}

				var subjectDir = path.resolve(templatesDir, 'subject');

				templating.render({
					templatesDir: subjectDir,
					partials: {},
					helper: {},
					items: data,
					type: type
				}, function (e, templates) {
					if(e) {
						return cb(e);
					}

					accumulate({
						uid: templates.uid,
						subject: templates.html
					});
					cb();
				});
			},
			attachmentsFiles: function (cb) {
				var attachmentsDir = path.resolve(templatesDir, 'attachments', type);

				fs.readdir(attachmentsDir, cb);
			},
			attachmentsList: ['attachmentsFiles', function (cb, results) {
				attachments = {};
				attachments = _.map(
					results.attachmentsFiles,
					function (attachment) {
						return {
							filename: attachment,
							path: attachment,
							cid: attachment
						};
					}
				);
				cb();
			}]
		}, function (e, results) {
			if(e) {
				return callback(e);
			}

			// _.merge(emailFields, {
			// 	html: results.renderedEmail.html,
			// 	text: results.renderedEmail.text,
			// 	subject: results.renderedSubject,
			// 	attachments: results.attachmentsList
			// });

			// callback(null, emailFields);
		});
	};

	/**
	 * Send an email with wathever transport was setup by EmailSender.
	 *
	 * @function send
	 * @memberof EmailInterface.prototype
	 *
	 * @param {object}		settings	- {@link  EmailInterface#assembleEmail} Data use to create the envelop and email body
	 * @param {object}		data		- Data to feed to the templating engine
	 * @param {function}	callback	- Callback
	 *
	 * @return {undefined}
	 *
	 * @api public
	 */
	EmailInterface.prototype.send = function (settings, data, callback) {
		if(_.isArray(data) === false) {
			data = [data];
		}

		var callbackCount = data.length;

		var transport = this.transport;
		this.assembleEmail(settings, data, function (e, emailContents) {
			if (e) {
				return callback(e);
			}

			_.extend(settings, emailContents);

			var failed = [];
			var succeeded = [];

			this.sender.send(transport, settings, function (e, info) {
				callbackCount -= 1;

				if(e && _.isArray(e.errors)) {
					_.union(
						failed,
						_.map(e.errors, function (error) {
							return error.recipients;
						})
					);
				}

				if (!info || !_.isObject(info)) {
					return;
				}

				if (_.isArray(info.accepted)) {
					_.union(
						succeeded,
						info.accepted
					);
				}
				if (_.isArray(info.rejected)) {
					_.union(
						failed,
						info.rejected
					);
				}
				if (_.isArray(info.pending)) {
					_.union(
						failed,
						info.pending
					);
				}

				if (callbackCount === 0) {
					callback(null, failed, succeeded);
				}
			});
		}.bind(this));

	};

	/**
	 * Receives emails on the local email server, parses and forwards them to a callback.
	 *
	 * @function receive
	 * @memberof EmailInterface.prototype
	 *
	 * @param {function} callback	- Callback function called after the entire email has been streamed and parsed
	 *
	 * @return {undefined}
	 *
	 * @api public
	 */
	EmailInterface.prototype.receive = function (callback) {
		var mailParserInstanciator = this.InstanciateMailParser(callback);
		this.receiver.receive(mailParserInstanciator);
	};

	return EmailInterface;

})();
<commit_msg>Removed results<commit_after>var _ = require('underscore');
var fs = require('fs');
var path = require('path');
var async = require('async');
var MailParser = require('mailparser').MailParser;
// var HtmlToText = require('html-to-text');
var EmailSender = require('./EmailSender');
var EmailReceiver = require('./EmailReceiver');
var EmailTemplates = require('./EmailTemplates');

module.exports = (function () {
	'use strict';

	/**
	 * @class EmailInterface
	 * @classdesc `EmailInterface` class that serves as an interface / middleman between the code base and the EmailSender.
	 *
	 * @param {object} [options]					- Options
	 * @param {object} [options.sender]				-  {@link EmailSender} Options for the email sending service
	 * @param {object} [options.receiver]			-  {@link EmailReceiver} Options for the email sending service
	 *
	 * @return {EmailInterface}
	 */
	function EmailInterface (options) {

		options = options || {};

		this.templatesDir = options.templatesDir;

		if (options.sender) {
			this.sender = new EmailSender(options.sender);
			this.templating = new EmailTemplates(options.templating);
		}

		if (options.receiver) {
			this.receiver = new EmailReceiver(options.receiver);
		}

		this.transport = null;

	}

	/**
	 * Small chaining method that sets the transport type for the following send command.
	 *
	 * @function with
	 * @memberof EmailInterface.prototype
	 *
	 * @param {string}	transport	-	Name of the transport method (e.g: 'SES', 'direct', 'sendmail', ...etc.)
	 *
	 * @return {EmailInterface}
	 *
	 * @api public
	 */
	EmailInterface.prototype.with = function (transport) {
		return (this.transport = transport, this);
	};

	/**
	 * Chaining of some RegExps to clean up quotes and email authors.
	 *
	 * @function getCleanEmailBody
	 * @memberof EmailInterface.prototype
	 *
	 * @param {string}	email	-	The fully buffered / streamed email content
	 *
	 * @return {string}
	 *
	 * @api private
	 */
	EmailInterface.prototype.getCleanEmailBody = function (email) {
		// TODO convert from HTML to text and then cleanup if email is HTML
		email = email
			// Remove email signatures
			.replace(/(\r?\n)\-{2} ?(\r?\n)[\w\W]+/, '')
			// Remove Outlook previous message header
			.replace(/(\r?\n)\-+ ?Original Message ?\-+[\w\W]+/i, '')
			// Remove other type of Outlook previous message header
			.replace(/(\r?\n)\_{30,}[\w\W]+/, '')
			.replace(/(\r?\n)\-{30,}[\w\W]+/, '')
			// Mac OSX mail
			.replace(/(\r?\n)On ([^(\r?\n)]*?) wrote:(\r?\n)[\w\W]+/i, '')
			// Forwarded emails
			.replace(/(\r?\n)\-{5,} ?Forwarded by [\w\W]+ ?\-{5,}(\r?\n)/i, '')
			// Outlook and other email clients's reply format with multilingual support
			.replace(/(\r?\n)\*?(From|De)\*?: [\w\W]+/i, '')
			// Hotmail reply format
			.replace(/(\r?\n)Date: [\w\W]+/i, '')
			// Smartphone footer
			.replace(/(\r?\n)Sent from my [\w\W]+/i, '')
			// Sent by signature style
			.replace(/(\r?\n)Sent by:[\w\W]+/i, '')
			// Remove replies
			.replace(/(\r?\n)> [\w\W]+/i, '')
			.trim();

		return email;
	};

	/**
	 * Closure function that return new instances of a mail parser stream to which receiveid emails are piped to.
	 *
	 * @function InstanciateMailParser
	 * @memberof EmailInterface.prototype
	 *
	 * @param {function}	callback	- Callback
	 *
	 * @return {function}
	 *
	 * @api public
	 */
	EmailInterface.prototype.InstanciateMailParser = function (callback) {
		var me = this;
		return function () {
			var mailParser = new MailParser({
				debug: false
				// TODO streamAttachments
				// TODO unescapeSMTP
				// TODO defaultCharset
				// TODO showAttachmentLinks
			});

			mailParser.on('end', function (email) {
				email.text = me.getCleanEmailBody(email.text);
				// TODO clean html bodies too using JSDOM or cheerio
				callback(null, email);
			});

			return mailParser;
		};
	};

	/**
	 * Assembles an object containing all the needed informations to create a valid
	 * envelope and (HTML) email body.
	 *
	 * @function assembleEmail
	 * @memberof EmailInterface.prototype
	 *
	 * @param {object}			settings					- Data use to create the envelop and email body
	 * @param {string}			settings.from				- Sender email
	 * @param {(string|array)}	settings.to					- Destination email address(es)
	 * @param {array}			[settings.cc]				- Recipients in the Cc field
	 * @param {array}			[settings.bcc]				- Recipients in the Bcc field
	 * @param {string}			[settings.replyTo]			- ReplyTo field
	 * @param {string}			[settings.inReplyTo]		- Message Id to which the email replies to
	 * @param {string}			[settings.references]		- Messages Id list
	 * @param {string}			[settings.subject]			- Subject of the email
	 * @param {string}			[settings.text]				- Plaintext body
	 * @param {string}			[settings.html]				- HTML body
	 * @param {object}			[settings.headers]			- HTTP / SMTP headers
	 * @param {array}			[settings.attachments]		- List of attachments files / buffers or strings
	 * @param {array}			[settings.messageId]		- List of attachments files / buffers or strings
	 *
	 * @param {object}			[data]						- Data to feed to the templating engine
	 *
	 * @param {function}		callback					- Callback
	 *
	 * @return {undefined}
	 *
	 * @api private
	 */
	EmailInterface.prototype.assembleEmail = function (settings, data, callback) {
		var accumulator = {};
		var attachments = false;

		var type = settings.type;
		var subject = settings.subject;

		var accumulate = function (templates) {
			var uid = templates.uid;
			templates.uid = null;
			delete templates.uid;

			accumulator[uid] = _.extend(accumulator[uid] || {}, templates);

			var instance = accumulator[uid];

			if(instance.html && instance.subject && attachments !== false) {
				accumulator[uid] = null;
				delete accumulator[uid];
				callback(null, instance);
			}
		}.bind(this);

		var templatesDir = this.templatesDir;
		var templating = this.templating;

		async.auto({
			renderedEmail: function (cb) {
				var contentDir = path.resolve(templatesDir, 'content');

				templating.render({
					templatesDir: contentDir,
					partials: {},
					helper: {},
					items: data,
					type: type
				}, function (e, templates) {
					if(e) {
						return cb(e);
					}

					accumulate(templates);
					cb();
				});
			},
			renderedSubject: function (cb) {
				if(_.isString(subject)) {
					return accumulate({
						subject: subject
					});
				}

				var subjectDir = path.resolve(templatesDir, 'subject');

				templating.render({
					templatesDir: subjectDir,
					partials: {},
					helper: {},
					items: data,
					type: type
				}, function (e, templates) {
					if(e) {
						return cb(e);
					}

					accumulate({
						uid: templates.uid,
						subject: templates.html
					});
					cb();
				});
			},
			attachmentsFiles: function (cb) {
				var attachmentsDir = path.resolve(templatesDir, 'attachments', type);

				fs.readdir(attachmentsDir, cb);
			},
			attachmentsList: ['attachmentsFiles', function (cb, results) {
				attachments = {};
				attachments = _.map(
					results.attachmentsFiles,
					function (attachment) {
						return {
							filename: attachment,
							path: attachment,
							cid: attachment
						};
					}
				);
				cb();
			}]
		}, function (e) {
			if(e) {
				return callback(e);
			}

			// _.merge(emailFields, {
			// 	html: results.renderedEmail.html,
			// 	text: results.renderedEmail.text,
			// 	subject: results.renderedSubject,
			// 	attachments: results.attachmentsList
			// });

			// callback(null, emailFields);
		});
	};

	/**
	 * Send an email with wathever transport was setup by EmailSender.
	 *
	 * @function send
	 * @memberof EmailInterface.prototype
	 *
	 * @param {object}		settings	- {@link  EmailInterface#assembleEmail} Data use to create the envelop and email body
	 * @param {object}		data		- Data to feed to the templating engine
	 * @param {function}	callback	- Callback
	 *
	 * @return {undefined}
	 *
	 * @api public
	 */
	EmailInterface.prototype.send = function (settings, data, callback) {
		if(_.isArray(data) === false) {
			data = [data];
		}

		var callbackCount = data.length;

		var transport = this.transport;
		this.assembleEmail(settings, data, function (e, emailContents) {
			if (e) {
				return callback(e);
			}

			_.extend(settings, emailContents);

			var failed = [];
			var succeeded = [];

			this.sender.send(transport, settings, function (e, info) {
				callbackCount -= 1;

				if(e && _.isArray(e.errors)) {
					_.union(
						failed,
						_.map(e.errors, function (error) {
							return error.recipients;
						})
					);
				}

				if (!info || !_.isObject(info)) {
					return;
				}

				if (_.isArray(info.accepted)) {
					_.union(
						succeeded,
						info.accepted
					);
				}
				if (_.isArray(info.rejected)) {
					_.union(
						failed,
						info.rejected
					);
				}
				if (_.isArray(info.pending)) {
					_.union(
						failed,
						info.pending
					);
				}

				if (callbackCount === 0) {
					callback(null, failed, succeeded);
				}
			});
		}.bind(this));

	};

	/**
	 * Receives emails on the local email server, parses and forwards them to a callback.
	 *
	 * @function receive
	 * @memberof EmailInterface.prototype
	 *
	 * @param {function} callback	- Callback function called after the entire email has been streamed and parsed
	 *
	 * @return {undefined}
	 *
	 * @api public
	 */
	EmailInterface.prototype.receive = function (callback) {
		var mailParserInstanciator = this.InstanciateMailParser(callback);
		this.receiver.receive(mailParserInstanciator);
	};

	return EmailInterface;

})();
<|endoftext|>


<commit_before>const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const getAlias = require('proton-pack/webpack/alias');
const { getJsLoader } = require('proton-pack/webpack/js.loader');
const getCssLoaders = require('proton-pack/webpack/css.loader');
const getAssetsLoaders = require('proton-pack/webpack/assets.loader');

module.exports = {
    webpackFinal: async (config, { configType }) => {
        const isProduction = configType === 'PRODUCTION';

        const options = {
            isProduction,
            hasReactRefresh: false
        };

        return {
            ...config,
            resolve: {
                ...config.resolve,
                alias: {
                    ...config.resolve.alias,
                    ...getAlias(),
                }
            },
            module: {
                ...config.module,
                rules: [
                    ...config.module.rules.filter((rule) => {
                        return rule.test.toString().includes('mdx');
                    }),
                    ...[getJsLoader(options), ...getCssLoaders(options), ...getAssetsLoaders(options)],
                ],
            },
            plugins: [
                ...config.plugins,
                new MiniCssExtractPlugin({
                    filename: isProduction ? '[name].[contenthash:8].css' : '[name].css',
                    chunkFilename: isProduction ? '[id].[contenthash:8].css' : '[id].css'
                }),
            ]
        };
    },
    module: {
        rules: [
            {
                test: /\.stories\.tsx?$/,
                loaders: [
                    {
                        loader: require.resolve('@storybook/source-loader'),
                        options: { parser: 'typescript' },
                    },
                ],
                enforce: 'pre',
            },
        ],
    },
    stories: ['../src/stories/*.stories.*'],
    addons: [
        {
            name: '@storybook/addon-docs',
            options: {
                sourceLoaderOptions: {
                    parser: 'typescript',
                    injectStoryParameters: true,
                },
            },
        },
        '@storybook/addon-essentials',
        {

            name: '@storybook/addon-storysource',
            options: {
                sourceLoaderOptions: {
                    parser: 'typescript',
                    injectStoryParameters: true,
                },
            },
        }
    ],
    typescript: {
        check: false,
        checkOptions: {},
        reactDocgen: 'react-docgen-typescript',
        reactDocgenTypescriptOptions: {
        shouldExtractLiteralValuesFromEnum: true,
        propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
        },
    },
};
<commit_msg>Storysource working yay!<commit_after>const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const getAlias = require('proton-pack/webpack/alias');
const { getJsLoader } = require('proton-pack/webpack/js.loader');
const getCssLoaders = require('proton-pack/webpack/css.loader');
const getAssetsLoaders = require('proton-pack/webpack/assets.loader');

module.exports = {
    webpackFinal: async (config, { configType }) => {
        const isProduction = configType === 'PRODUCTION';

        const options = {
            isProduction,
            hasReactRefresh: false
        };

        return {
            ...config,
            resolve: {
                ...config.resolve,
                alias: {
                    ...config.resolve.alias,
                    ...getAlias(),
                }
            },
            module: {
                ...config.module,
                rules: [
                    ...config.module.rules.filter((rule) => {
                        return rule.test.toString().includes('mdx');
                    }),
                    {
                        test: /\.stories\.tsx?$/,
                        loaders: [
                            {
                                loader: require.resolve('@storybook/source-loader'),
                                options: { parser: 'typescript' },
                            },
                        ],
                        enforce: 'pre',
                    },
                    ...[getJsLoader(options), ...getCssLoaders(options), ...getAssetsLoaders(options)],
                ],
            },
            plugins: [
                ...config.plugins,
                new MiniCssExtractPlugin({
                    filename: isProduction ? '[name].[contenthash:8].css' : '[name].css',
                    chunkFilename: isProduction ? '[id].[contenthash:8].css' : '[id].css'
                }),
            ]
        };
    },
    stories: ['../src/stories/*.stories.*'],
    addons: [
        '@storybook/addon-docs',
        '@storybook/addon-essentials',
        '@storybook/addon-storysource',
    ],
    typescript: {
        check: false,
        checkOptions: {},
        reactDocgen: 'react-docgen-typescript',
        reactDocgenTypescriptOptions: {
        shouldExtractLiteralValuesFromEnum: true,
        propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
        },
    },
};
<|endoftext|>


<commit_before>var	_            = require('lodash-contrib'),
	readWordList = require('./readWordList'),
	siblingGraph = require('./siblingGraph'),
	longest = require('./algorithms/longest/leastSiblingsFirst');

var longestChain = { chain: ['NOTHING'] };

var search = function(index) {
	readWordList('en.txt', 4).then(siblingGraph.create).then(function(words) {

		words = _.sortBy(words, function(word) { return 0 - word.siblings.length; });
		var wordsLength = words.length;
		var currWord = words[index].word;

		var result = longest([words[index]]);

		process.stdout.write('\rWord: ' + currWord + ' (' + index + ') ' + ' chain: ' + result.chain.length + '. Longest so far is ' + longestChain.chain[0] + ' with ' + longestChain.chain.length + '\n\r');

		if (result.chain.length > longestChain.chain.length) { longestChain = _.cloneDeep(result); }

		if (++index >= wordsLength) {
			console.log('\n\rLongest chain: ' + longestChain.chain.length + '\n\r');
			console.log(longestChain.chain.join(', '));
			console.log('REMAINDER: ' + longestChain.remainder.length);
			console.log(longestChain.remainder.join(', '));
			return longestChain;
		}

		search(index);
	});
};

search(0);
<commit_msg>hooked process exit to display current max chain on ctrl-c<commit_after>var	_            = require('lodash-contrib'),
	readWordList = require('./readWordList'),
	siblingGraph = require('./siblingGraph'),
	longest = require('./algorithms/longest/leastSiblingsFirst');

var longestChain = { chain: ['NOTHING'] };

process.on('SIGINT', function() {
	console.log('\n\rLongest chain: ' + longestChain.chain.length + '\n\r');
	console.log(longestChain.chain.join(', '));
	console.log('REMAINDER: ' + longestChain.remainder.length);
	console.log(longestChain.remainder.join(', '));

	process.exit();
});

var search = function(index) {
	readWordList('en.txt', 4).then(siblingGraph.create).then(function(words) {

		words = _.sortBy(words, function(word) { return 0 - word.siblings.length; });
		var wordsLength = words.length;
		var currWord = words[index].word;

		var result = longest([words[index]]);

		process.stdout.write('\rWord: ' + currWord + ' (' + index + ') ' + ' chain: ' + result.chain.length + '. Longest so far is ' + longestChain.chain[0] + ' with ' + longestChain.chain.length + '\n\r');

		if (result.chain.length > longestChain.chain.length) { longestChain = _.cloneDeep(result); }

		if (++index >= wordsLength) {
			console.log('\n\rLongest chain: ' + longestChain.chain.length + '\n\r');
			console.log(longestChain.chain.join(', '));
			console.log('REMAINDER: ' + longestChain.remainder.length);
			console.log(longestChain.remainder.join(', '));
			return longestChain;
		}

		search(index);
	});
};

search(0);
<|endoftext|>


<commit_before>'use strict';

goog.provide('Blockly.JavaScript.Sendto');

goog.require('Blockly.JavaScript');

// --- SayIt --------------------------------------------------
Blockly.Words['sayit']               = {'en': 'say text',                    'de': 'aussprechen',                        'ru': 'произнести'};
Blockly.Words['sayit_message']       = {'en': 'message',                     'de': 'Meldung',                            'ru': 'сообщение'};
Blockly.Words['sayit_volume']        = {'en': 'volume (optional)',           'de': 'Lautstärke (optional)',              'ru': 'громкость (не обяз.)'};
Blockly.Words['sayit_tooltip']       = {'en': 'Text to speech',              'de': 'Text zu Sprache',                    'ru': 'Произнести сообщение'};
Blockly.Words['sayit_help']          = {'en': 'https://github.com/ioBroker/ioBroker.sayit/blob/master/README.md', 'de': 'http://www.iobroker.net/?page_id=178&lang=de', 'ru': 'http://www.iobroker.net/?page_id=4262&lang=ru'};

// Blockly.Sendto is global variable and defined in javascript/admin/google-blockly/own/blocks_sendto.js

Blockly.Sendto.blocks['sayit'] =
    '<block type="sayit">'
    + '     <value name="INSTANCE">'
    + '     </value>'
    + '     <value name="LANGUAGE">'
    + '     </value>'
    + '     <value name="VOLUME">'
    + '     </value>'
    + '     <value name="MESSAGE">'
    + '         <shadow type="text">'
    + '             <field name="TEXT">text</field>'
    + '         </shadow>'
    + '     </value>'
    + '     <value name="LOG">'
    + '     </value>'
    + '</block>';

Blockly.Blocks['sayit'] = {
    init: function() {
        this.appendDummyInput('INSTANCE')
            .appendField(Blockly.Words['sayit'][systemLang])
            .appendField(new Blockly.FieldDropdown([['sayit.0', '.0'], ['sayit.1', '.1'], ['sayit.2', '.2'], ['sayit.3', '.3'], ['sayit.4', '.4']]), 'INSTANCE');

        var languages;
        if (systemLang === 'en') {
            languages = [['english', 'en'], ['deutsch', 'de'], ['русский', 'ru']];
        } else if (systemLang === 'de') {
            languages = [['deutsch', 'de'], ['english', 'en'], ['русский', 'ru']];
        } else if (systemLang === 'ru') {
            languages = [['русский', 'ru'], ['english', 'en'], ['deutsch', 'de']];
        } else {
            languages = [['english', 'en'], ['deutsch', 'de'], ['русский', 'ru']];
        }

        this.appendDummyInput('LANGUAGE')
            .appendField(new Blockly.FieldDropdown(languages), 'LANGUAGE');

        this.appendValueInput('VOLUME')
            .setCheck('Number')
            .appendField(Blockly.Words['sayit_volume'][systemLang]);

        this.appendValueInput('MESSAGE')
            .appendField(Blockly.Words['sayit_message'][systemLang]);

        this.appendDummyInput('LOG')
            .appendField(Blockly.Words['telegram_log'][systemLang])
            .appendField(new Blockly.FieldDropdown([
                [Blockly.Words['telegram_log_none'][systemLang],  ''],
                [Blockly.Words['telegram_log_info'][systemLang],  'log'],
                [Blockly.Words['telegram_log_debug'][systemLang], 'debug'],
                [Blockly.Words['telegram_log_warn'][systemLang],  'warn'],
                [Blockly.Words['telegram_log_error'][systemLang], 'error']
            ]), 'LOG');

        this.setInputsInline(false);
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);

        this.setColour(Blockly.Sendto.HUE);
        this.setTooltip(Blockly.Words['sayit_tooltip'][systemLang]);
        this.setHelpUrl(Blockly.Words['sayit_help'][systemLang]);
    }
};

Blockly.JavaScript['sayit'] = function(block) {
    var dropdown_instance = block.getFieldValue('INSTANCE');
    var dropdown_language = block.getFieldValue('LANGUAGE');
    var value_message = Blockly.JavaScript.valueToCode(block, 'MESSAGE', Blockly.JavaScript.ORDER_ATOMIC);
    var value_volume  = Blockly.JavaScript.valueToCode(block, 'VOLUME', Blockly.JavaScript.ORDER_ATOMIC);
    var logLevel = block.getFieldValue('LOG');

    var logText;
    if (logLevel) {
        logText = 'console.' + logLevel + '("sayIt' + (dropdown_language ? '[' + dropdown_language + ']' : '') + (value_volume ? '[Volume - ' + value_volume + ']' : '') + ': " + ' + value_message + ');\n'
    } else {
        logText = '';
    }

    return 'setState("sayit' + dropdown_instance + '.tts.text", "' + dropdown_language + ';' + (value_volume !== null && value_volume !== '' ? value_volume + ';' : '') + '" + ' + value_message  + ');\n' +
        logText;
};
<commit_msg>(bluefox) translations<commit_after>'use strict';

goog.provide('Blockly.JavaScript.Sendto');

goog.require('Blockly.JavaScript');

// --- SayIt --------------------------------------------------
Blockly.Words['sayit']               = {'en': 'say text',                    'de': 'aussprechen',                        'ru': 'произнести'};
Blockly.Words['sayit_message']       = {'en': 'message',                     'de': 'Meldung',                            'ru': 'сообщение'};
Blockly.Words['sayit_volume']        = {'en': 'volume (optional)',           'de': 'Lautstärke (optional)',              'ru': 'громкость (не обяз.)'};
Blockly.Words['sayit_tooltip']       = {'en': 'Text to speech',              'de': 'Text zu Sprache',                    'ru': 'Произнести сообщение'};
Blockly.Words['sayit_help']          = {'en': 'https://github.com/ioBroker/ioBroker.sayit/blob/master/README.md', 'de': 'http://www.iobroker.net/?page_id=178&lang=de', 'ru': 'http://www.iobroker.net/?page_id=4262&lang=ru'};

Blockly.Words['sayit_log']           = {'en': 'log level',                   'de': 'Loglevel',                           'ru': 'Протокол'};
Blockly.Words['sayit_log_none']      = {'en': 'none',                        'de': 'keins',                              'ru': 'нет'};
Blockly.Words['sayit_log_info']      = {'en': 'info',                        'de': 'info',                               'ru': 'инфо'};
Blockly.Words['sayit_log_debug']     = {'en': 'debug',                       'de': 'debug',                              'ru': 'debug'};
Blockly.Words['sayit_log_warn']      = {'en': 'warning',                     'de': 'warning',                            'ru': 'warning'};
Blockly.Words['sayit_log_error']     = {'en': 'error',                       'de': 'error',                              'ru': 'ошибка'};

// Blockly.Sendto is global variable and defined in javascript/admin/google-blockly/own/blocks_sendto.js

Blockly.Sendto.blocks['sayit'] =
    '<block type="sayit">'
    + '     <value name="INSTANCE">'
    + '     </value>'
    + '     <value name="LANGUAGE">'
    + '     </value>'
    + '     <value name="VOLUME">'
    + '     </value>'
    + '     <value name="MESSAGE">'
    + '         <shadow type="text">'
    + '             <field name="TEXT">text</field>'
    + '         </shadow>'
    + '     </value>'
    + '     <value name="LOG">'
    + '     </value>'
    + '</block>';

Blockly.Blocks['sayit'] = {
    init: function() {
        this.appendDummyInput('INSTANCE')
            .appendField(Blockly.Words['sayit'][systemLang])
            .appendField(new Blockly.FieldDropdown([['sayit.0', '.0'], ['sayit.1', '.1'], ['sayit.2', '.2'], ['sayit.3', '.3'], ['sayit.4', '.4']]), 'INSTANCE');

        var languages;
        if (systemLang === 'en') {
            languages = [['english', 'en'], ['deutsch', 'de'], ['русский', 'ru']];
        } else if (systemLang === 'de') {
            languages = [['deutsch', 'de'], ['english', 'en'], ['русский', 'ru']];
        } else if (systemLang === 'ru') {
            languages = [['русский', 'ru'], ['english', 'en'], ['deutsch', 'de']];
        } else {
            languages = [['english', 'en'], ['deutsch', 'de'], ['русский', 'ru']];
        }

        this.appendDummyInput('LANGUAGE')
            .appendField(new Blockly.FieldDropdown(languages), 'LANGUAGE');

        this.appendValueInput('VOLUME')
            .setCheck('Number')
            .appendField(Blockly.Words['sayit_volume'][systemLang]);

        this.appendValueInput('MESSAGE')
            .appendField(Blockly.Words['sayit_message'][systemLang]);

        this.appendDummyInput('LOG')
            .appendField(Blockly.Words['sayit_log'][systemLang])
            .appendField(new Blockly.FieldDropdown([
                [Blockly.Words['sayit_log_none'][systemLang],  ''],
                [Blockly.Words['sayit_log_info'][systemLang],  'log'],
                [Blockly.Words['sayit_log_debug'][systemLang], 'debug'],
                [Blockly.Words['sayit_log_warn'][systemLang],  'warn'],
                [Blockly.Words['sayit_log_error'][systemLang], 'error']
            ]), 'LOG');

        this.setInputsInline(false);
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);

        this.setColour(Blockly.Sendto.HUE);
        this.setTooltip(Blockly.Words['sayit_tooltip'][systemLang]);
        this.setHelpUrl(Blockly.Words['sayit_help'][systemLang]);
    }
};

Blockly.JavaScript['sayit'] = function(block) {
    var dropdown_instance = block.getFieldValue('INSTANCE');
    var dropdown_language = block.getFieldValue('LANGUAGE');
    var value_message = Blockly.JavaScript.valueToCode(block, 'MESSAGE', Blockly.JavaScript.ORDER_ATOMIC);
    var value_volume  = Blockly.JavaScript.valueToCode(block, 'VOLUME', Blockly.JavaScript.ORDER_ATOMIC);
    var logLevel = block.getFieldValue('LOG');

    var logText;
    if (logLevel) {
        logText = 'console.' + logLevel + '("sayIt' + (dropdown_language ? '[' + dropdown_language + ']' : '') + (value_volume ? '[Volume - ' + value_volume + ']' : '') + ': " + ' + value_message + ');\n'
    } else {
        logText = '';
    }

    return 'setState("sayit' + dropdown_instance + '.tts.text", "' + dropdown_language + ';' + (value_volume !== null && value_volume !== '' ? value_volume + ';' : '') + '" + ' + value_message  + ');\n' +
        logText;
};
<|endoftext|>


<commit_before>define([
    "jquery",
    "pat-parser",
    "pat-registry",
    "pat-utils",
    "pat-inject"
], function($, Parser, registry, utils, inject) {
    var parser = new Parser("modal");

    parser.add_argument("class");

    var modal = {
        name: "modal",
        jquery_plugin: true,
        // div's are turned into modals
        // links and forms inject modals
        trigger: "div.pat-modal, a.pat-modal, form.pat-modal",
        init: function($el, opts) {
            if ($el.length > 1) {
                // We enforce a one-to-one mapping between modal objects and
                // DOM elements, so here we recurse and instantiate a new modal
                // for each $el
                $el.each(function() {
                    modal.init($(this));
                });
            } else if ($el.length === 1) {
                var cfg = parser.parse($el, opts);
                this.$el = $el;
                if ($el.is("div"))
                    modal._init_div1($el, cfg);
                else
                    modal._init_inject1($el, cfg);
            }
        },

        _init_inject1: function($el, cfg) {
            var opts = {
                target: "#pat-modal",
                "class": "pat-modal" + (cfg["class"] ? " " + cfg["class"] : "")
            };
            // if $el is already inside a modal, do not detach #pat-modal,
            // because this would unnecessarily close the modal itself
            if (!$el.closest("#pat-modal")) {
                $("#pat-modal").detach();
            }
            inject.init($el, opts);
        },

        _init_div1: function($el) {
            var $header = $("
"),
                activeElement = document.activeElement;

            $("<button type='button' class='close-panel'>Close</button>").appendTo($header);

            // We cannot handle text nodes here
            $el.children(":last, :not(:first)")
                .wrapAll("
");
            $(".panel-content", $el).before($header);
            $el.children(":first:not(.header)").prependTo($header);

            // Restore focus in case the active element was a child of $el and
            // the focus was lost during the wrapping.
            activeElement.focus();

            // event handlers remove modal - first arg to bind is ``this``
            $(document).on("click.pat-modal", ".close-panel",
                           modal.destroy.bind($el, $el));
            // remove on ESC
            $(document).on("keyup.pat-modal",
                           modal.destroy.bind($el, $el));

            modal.setPosition();
        },

        setPosition: function() {
            if ((this.$el === undefined) || (this.$el.length === 0)) {
                return;
            }

            var $oldClone = $("#pat-modal-clone");
            if ($oldClone.length > 0) {
                $oldClone.remove();
            }

            var $clone = this.$el.clone();

            $clone
                .attr("id", "pat-modal-clone")
                .css({
                    "visibility": "hidden",
                    "position": "absolute",
                    "height": ""
                }).appendTo("body");

            // wait for browser to update DOM
            setTimeout($.proxy(modal.measure, this), 0);
        },

        measure: function() {
            var $clone = $("#pat-modal-clone");
            if ($clone.length === 0) {
                return;
            }

            var maxHeight = $(window).innerHeight() - $clone.outerHeight(true) +
                            $clone.outerHeight(),
                height = $clone.outerHeight();

            $clone.remove();

            if (maxHeight - height < 0) {
                this.$el.addClass("max-height").css("height", maxHeight);
            } else {
                this.$el.removeClass("max-height").css("height", height);
            }

            var top = ($(window).innerHeight() - this.$el.outerHeight(true)) / 2;
            this.$el.css("top", top);
        },

        destroy: function($el, ev) {
            if (ev && ev.type === "keyup" && ev.which !== 27)
                return;
            $(document).off(".pat-modal");
            $el.remove();
        }
    };

    $(window).on("resize.pat-modal-position", $.proxy(modal.setPosition, modal));
    $(window).on("pat-inject-content-loaded.pat-modal-position", "#pat-modal",
        $.proxy(modal.setPosition, modal));
    $(document).on("patterns-injected.pat-modal-position", "#pat-modal,div.pat-modal",
        $.proxy(modal.setPosition, modal));

    registry.register(modal);
    return modal;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<commit_msg>Fix modal resize on content load.<commit_after>define([
    "jquery",
    "pat-parser",
    "pat-registry",
    "pat-utils",
    "pat-inject"
], function($, Parser, registry, utils, inject) {
    var parser = new Parser("modal");

    parser.add_argument("class");

    var modal = {
        name: "modal",
        jquery_plugin: true,
        // div's are turned into modals
        // links and forms inject modals
        trigger: "div.pat-modal, a.pat-modal, form.pat-modal",
        init: function($el, opts) {
            if ($el.length > 1) {
                // We enforce a one-to-one mapping between modal objects and
                // DOM elements, so here we recurse and instantiate a new modal
                // for each $el
                $el.each(function() {
                    modal.init($(this));
                });
            } else if ($el.length === 1) {
                var cfg = parser.parse($el, opts);
                this.$el = $el;
                if ($el.is("div"))
                    modal._init_div1($el, cfg);
                else
                    modal._init_inject1($el, cfg);
            }
        },

        _init_inject1: function($el, cfg) {
            var opts = {
                target: "#pat-modal",
                "class": "pat-modal" + (cfg["class"] ? " " + cfg["class"] : "")
            };
            // if $el is already inside a modal, do not detach #pat-modal,
            // because this would unnecessarily close the modal itself
            if (!$el.closest("#pat-modal")) {
                $("#pat-modal").detach();
            }
            inject.init($el, opts);
        },

        _init_div1: function($el) {
            var $header = $("
"),
                activeElement = document.activeElement;

            $("<button type='button' class='close-panel'>Close</button>").appendTo($header);

            // We cannot handle text nodes here
            $el.children(":last, :not(:first)")
                .wrapAll("
");
            $(".panel-content", $el).before($header);
            $el.children(":first:not(.header)").prependTo($header);

            // Restore focus in case the active element was a child of $el and
            // the focus was lost during the wrapping.
            activeElement.focus();

            // event handlers remove modal - first arg to bind is ``this``
            $(document).on("click.pat-modal", ".close-panel",
                           modal.destroy.bind($el, $el));
            // remove on ESC
            $(document).on("keyup.pat-modal",
                           modal.destroy.bind($el, $el));

            modal.setPosition();
        },

        setPosition: function() {
            if ((this.$el === undefined) || (this.$el.length === 0)) {
                return;
            }

            var $oldClone = $("#pat-modal-clone");
            if ($oldClone.length > 0) {
                $oldClone.remove();
            }

            var $clone = this.$el.clone();

            $clone
                .attr("id", "pat-modal-clone")
                .css({
                    "visibility": "hidden",
                    "position": "absolute",
                    "height": ""
                }).appendTo("body");

            // wait for browser to update DOM
            setTimeout($.proxy(modal.measure, this), 0);
        },

        measure: function() {
            var $clone = $("#pat-modal-clone");
            if ($clone.length === 0) {
                return;
            }

            var maxHeight = $(window).innerHeight() - $clone.outerHeight(true) +
                            $clone.outerHeight(),
                height = $clone.outerHeight();

            $clone.remove();

            if (maxHeight - height < 0) {
                this.$el.addClass("max-height").css("height", maxHeight);
            } else {
                this.$el.removeClass("max-height").css("height", height);
            }

            var top = ($(window).innerHeight() - this.$el.outerHeight(true)) / 2;
            this.$el.css("top", top);
        },

        destroy: function($el, ev) {
            if (ev && ev.type === "keyup" && ev.which !== 27)
                return;
            $(document).off(".pat-modal");
            $el.remove();
        }
    };

    $(window).on("resize.pat-modal-position", $.proxy(modal.setPosition, modal));
    $(document).on("pat-inject-content-loaded.pat-modal-position", "#pat-modal",
        $.proxy(modal.setPosition, modal));
    $(document).on("patterns-injected.pat-modal-position", "#pat-modal,div.pat-modal",
        $.proxy(modal.setPosition, modal));

    registry.register(modal);
    return modal;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<|endoftext|>


<commit_before>// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

var async = require('async');
var fs = require('fs');
var _ = require('underscore');
var grpc = require('..');
var examples = grpc.load(__dirname + '/route_guide.proto').examples;
var client = new examples.RouteGuide('localhost:50051');

var COORD_FACTOR = 1e7;

function runGetFeature(callback) {
  var next = _.after(2, callback);
  function featureCallback(error, feature) {
    if (error) {
      callback(error);
    }
    if (feature.name === '') {
      console.log('Found no feature at ' +
          feature.location.latitude/COORD_FACTOR + ', ' +
          feature.location.longitude/COORD_FACTOR);
    } else {
      console.log('Found feature called "' + feature.name + '" at ' +
          feature.location.latitude/COORD_FACTOR + ', ' +
          feature.location.longitude/COORD_FACTOR);
    }
    next();
  }
  var point1 = {
    latitude: 409146138,
    longitude: -746188906
  };
  var point2 = {
    latitude: 0,
    longitude: 0
  };
  client.getFeature(point1, featureCallback);
  client.getFeature(point2, featureCallback);
}

function runListFeatures(callback) {
  var rectangle = {
    lo: {
      latitude: 400000000,
      longitude: -750000000
    },
    hi: {
      latitude: 420000000,
      longitude: -730000000
    }
  };
  console.log('Looking for features between 40, -75 and 42, -73');
  var call = client.listFeatures(rectangle);
  call.on('data', function(feature) {
      console.log('Found feature called "' + feature.name + '" at ' +
          feature.location.latitude/COORD_FACTOR + ', ' +
          feature.location.longitude/COORD_FACTOR);
  });
  call.on('end', callback);
}

function runRecordRoute(callback) {
  fs.readFile(__dirname + '/route_guide_db.json', function(err, data) {
    if (err) callback(err);
    var feature_list = JSON.parse(data);

    var num_points = 10;
    var call = client.recordRoute(function(error, stats) {
      if (error) {
        callback(error);
      }
      console.log('Finished trip with', stats.point_count, 'points');
      console.log('Passed', stats.feature_count, 'features');
      console.log('Travelled', stats.distance, 'meters');
      console.log('It took', stats.elapsed_time, 'seconds');
      callback();
    });
    function pointSender(lat, lng) {
      return function(callback) {
        console.log('Visiting point ' + lat/COORD_FACTOR + ', ' +
            lng/COORD_FACTOR);
        call.write({
          latitude: lat,
          longitude: lng
        });
        _.delay(callback, _.random(500, 1500));
      };
    }
    var point_senders = [];
    for (var i = 0; i < num_points; i++) {
      var rand_point = feature_list[_.random(0, feature_list.length - 1)];
      point_senders[i] = pointSender(rand_point.location.latitude,
                                     rand_point.location.longitude);
    }
    async.series(point_senders, function() {
      call.end();
    });
  });
}

function runRouteChat(callback) {
  var call = client.routeChat();
  call.on('data', function(note) {
    console.log('Got message "' + note.message + '" at ' +
        note.location.latitude + ', ' + note.location.longitude);
  });

  call.on('end', callback);

  var notes = [{
    location: {
      latitude: 0,
      longitude: 0
    },
    message: 'First message'
  }, {
    location: {
      latitude: 0,
      longitude: 1
    },
    message: 'Second message'
  }, {
    location: {
      latitude: 1,
      longitude: 0
    },
    message: 'Third message'
  }, {
    location: {
      latitude: 0,
      longitude: 0
    },
    message: 'Fourth message'
  }];
  for (var i = 0; i < notes.length; i++) {
    var note = notes[i];
    console.log('Sending message "' + note.message + '" at ' +
        note.location.latitude + ', ' + note.location.longitude);
    call.write(note);
  }
  call.end();
}

function main() {
  async.series([
    runGetFeature,
    runListFeatures,
    runRecordRoute,
    runRouteChat
  ]);
}

if (require.main === module) {
  main();
}

exports.runGetFeature = runGetFeature;

exports.runListFeatures = runListFeatures;

exports.runRecordRoute = runRecordRoute;

exports.runRouteChat = runRouteChat;
<commit_msg>Added comments to route_guide_client.js<commit_after>// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

var async = require('async');
var fs = require('fs');
var _ = require('underscore');
var grpc = require('..');
var examples = grpc.load(__dirname + '/route_guide.proto').examples;
var client = new examples.RouteGuide('localhost:50051');

var COORD_FACTOR = 1e7;

/**
 * Run the getFeature demo. Calls getFeature with a point known to have a
 * feature and a point known not to have a feature.
 * @param {function} callback Called when this demo is complete
 */
function runGetFeature(callback) {
  var next = _.after(2, callback);
  function featureCallback(error, feature) {
    if (error) {
      callback(error);
    }
    if (feature.name === '') {
      console.log('Found no feature at ' +
          feature.location.latitude/COORD_FACTOR + ', ' +
          feature.location.longitude/COORD_FACTOR);
    } else {
      console.log('Found feature called "' + feature.name + '" at ' +
          feature.location.latitude/COORD_FACTOR + ', ' +
          feature.location.longitude/COORD_FACTOR);
    }
    next();
  }
  var point1 = {
    latitude: 409146138,
    longitude: -746188906
  };
  var point2 = {
    latitude: 0,
    longitude: 0
  };
  client.getFeature(point1, featureCallback);
  client.getFeature(point2, featureCallback);
}

/**
 * Run the listFeatures demo. Calls listFeatures with a rectangle containing all
 * of the features in the pre-generated database. Prints each response as it
 * comes in.
 * @param {function} callback Called when this demo is complete
 */
function runListFeatures(callback) {
  var rectangle = {
    lo: {
      latitude: 400000000,
      longitude: -750000000
    },
    hi: {
      latitude: 420000000,
      longitude: -730000000
    }
  };
  console.log('Looking for features between 40, -75 and 42, -73');
  var call = client.listFeatures(rectangle);
  call.on('data', function(feature) {
      console.log('Found feature called "' + feature.name + '" at ' +
          feature.location.latitude/COORD_FACTOR + ', ' +
          feature.location.longitude/COORD_FACTOR);
  });
  call.on('end', callback);
}

/**
 * Run the recordRoute demo. Sends several randomly chosen points from the
 * pre-generated feature database with a variable delay in between. Prints the
 * statistics when they are sent from the server.
 * @param {function} callback Called when this demo is complete
 */
function runRecordRoute(callback) {
  fs.readFile(__dirname + '/route_guide_db.json', function(err, data) {
    if (err) callback(err);
    var feature_list = JSON.parse(data);

    var num_points = 10;
    var call = client.recordRoute(function(error, stats) {
      if (error) {
        callback(error);
      }
      console.log('Finished trip with', stats.point_count, 'points');
      console.log('Passed', stats.feature_count, 'features');
      console.log('Travelled', stats.distance, 'meters');
      console.log('It took', stats.elapsed_time, 'seconds');
      callback();
    });
    /**
     * Constructs a function that asynchronously sends the given point and then
     * delays sending its callback
     * @param {number} lat The latitude to send
     * @param {number} lng The longitude to send
     * @return {function(function)} The function that sends the point
     */
    function pointSender(lat, lng) {
      /**
       * Sends the point, then calls the callback after a delay
       * @param {function} callback Called when complete
       */
      return function(callback) {
        console.log('Visiting point ' + lat/COORD_FACTOR + ', ' +
            lng/COORD_FACTOR);
        call.write({
          latitude: lat,
          longitude: lng
        });
        _.delay(callback, _.random(500, 1500));
      };
    }
    var point_senders = [];
    for (var i = 0; i < num_points; i++) {
      var rand_point = feature_list[_.random(0, feature_list.length - 1)];
      point_senders[i] = pointSender(rand_point.location.latitude,
                                     rand_point.location.longitude);
    }
    async.series(point_senders, function() {
      call.end();
    });
  });
}

/**
 * Run the routeChat demo. Send some chat messages, and print any chat messages
 * that are sent from the server.
 * @param {function} callback Called when the demo is complete
 */
function runRouteChat(callback) {
  var call = client.routeChat();
  call.on('data', function(note) {
    console.log('Got message "' + note.message + '" at ' +
        note.location.latitude + ', ' + note.location.longitude);
  });

  call.on('end', callback);

  var notes = [{
    location: {
      latitude: 0,
      longitude: 0
    },
    message: 'First message'
  }, {
    location: {
      latitude: 0,
      longitude: 1
    },
    message: 'Second message'
  }, {
    location: {
      latitude: 1,
      longitude: 0
    },
    message: 'Third message'
  }, {
    location: {
      latitude: 0,
      longitude: 0
    },
    message: 'Fourth message'
  }];
  for (var i = 0; i < notes.length; i++) {
    var note = notes[i];
    console.log('Sending message "' + note.message + '" at ' +
        note.location.latitude + ', ' + note.location.longitude);
    call.write(note);
  }
  call.end();
}

/**
 * Run all of the demos in order
 */
function main() {
  async.series([
    runGetFeature,
    runListFeatures,
    runRecordRoute,
    runRouteChat
  ]);
}

if (require.main === module) {
  main();
}

exports.runGetFeature = runGetFeature;

exports.runListFeatures = runListFeatures;

exports.runRecordRoute = runRecordRoute;

exports.runRouteChat = runRouteChat;
<|endoftext|>


<commit_before><commit_msg>cant change session<commit_after><|endoftext|>


<commit_before>function ComponentTable( id ) {
	var self = new Component( id );

	self.setState('ignore-list', {});

	self.setColumns = function( columns ) {
		var real_columns = [];
		for( i = 0; i < (columns.length - 1); i++ ) {
			var column = columns[i];
			real_columns.push(column);
		}
		self.setState('columns', real_columns);
	};
	self.setColumnMap = function( map ) {
		self.setState('columns.map', map);
	};
	self.setSortColumn = function( id, direction ) {
		var map = self.getState('columns.map');
		self.setState('columns.sort', id);
		self.setState('columns.sort-mapped', (map[id] ? map[id] : ''));
		self.setState('columns.sort-direction', direction);
	};
	self._setSortColumn = function( id ) {
		var currentColumn = self.getState('columns.sort');
		var currentDirection = self.getState('columns.sort-direction');
		var direction = 'asc';

		if( currentColumn == id ) {
			direction = (currentDirection == 'asc' ? 'desc' : 'asc');
		}
		self.setSortColumn( id, direction );
		self.setState('columns.sort-active', true);
		self.action('sort-changed', id, direction);
	};

	self.setRows = function( rows, order ) {
		self.setState('rows.map', rows);
		self.setState('rows.order', order);
		self.stopNavigationIfFocusGone();
	};
	self.setRowDefaultStyle = function( style ) {
		self.setState('rows.default-style', style);
	};
	self.registerColumnCallback = function( column, functor ) {
		var callbacks = self.getState('columns.callbacks');

		if( !callbacks )
			callbacks = {};

		callbacks[column] = functor;

		self.setState('columns.callbacks', callbacks);
	};
	self.addIgnore = function( id ) {
		var list = self.getState('ignore-list');
		list['' + id] = true;
	};
	self.resetIgnores = function() {
		self.setState('ignore-list', {});
	};
	self.updateHeaders = function() {
		var columns = self.getState('columns');
		var map = self.getState('columns.map');

		var sortedColumn = self.getState('columns.sort');
		var sortedColumnDirection = self.getState('columns.sort-direction');

		columns.each(function(column){
			var label = column.label;
			if( sortedColumn == column.id ) {
				if( sortedColumnDirection == 'asc' ) {
					label += '';
				} else {
					label += '';
				}
			}
			$(column.id).innerHTML = label;
			$(column.id).style.backgroundColor = (sortedColumn == column.id ? '#FFC' : '#EEF');
			$(column.id).style.textAlign = column.align;
		});
	};
	self.forceUpdate = function() {
		var columns = self.getState('columns');
		var map = self.getState('columns.map');
		var callbacks = self.getState('columns.callbacks');
		var rows = self.getState('rows.map');
		var rowsOrder = self.getState('rows.order');
		var defaultStyle = self.getState('rows.default-style');
		var sortActive = self.getState('columns.sort-active');
		var ignoreList = self.getState('ignore-list');

		self.updateHeaders();

		var node = $(self.identifier());
		var body = null;
		var keptRows = {};
		var keptCount = 0;

		for( i = 0; i < node.childNodes.length; i++ ) {
			var childNode = node.childNodes[i];
			if( childNode.tagName && childNode.tagName.toLowerCase() == 'tbody' ) {
				body = childNode;
				break;
			}
		}

		if( !body ) {
			alert(self.identifier() + ': Unable to update table as it had no body');
		}

		for( i = 0; i < body.childNodes.length; i++ ) {
			var row = body.childNodes[i];
			if( row && row.tagName && row.tagName.toLowerCase() == 'tr' && row.id != (self.identifier() + '.Headers') ){
				if( sortActive || ignoreList['' + row.sourceObjectID] || (!sortActive && !rows['' + row.sourceObjectID]) ) {
					body.removeChild(row);
					i--;
				} else {
					keptRows['' + row.sourceObjectID] = row;
					keptCount++;
				}
			}
		}

		var previousRow = null;
		rowsOrder.each(function(rowid){
			if( !ignoreList['' + rowid] ) {
				if( !keptRows['' + rowid] ) {
					var row = rows['' + rowid];
					var html = '';
					var id = row.id;
					var rowStyle = {};
					var styles = '';

					[ 'fg', 'bg', 'bold', 'underline', 'italic', 'strike', 'smallcaps' ].each(function( attr ){
						if( defaultStyle[attr] ) rowStyle[attr] = defaultStyle[attr];
						if( row.style && row.style[attr] ) rowStyle[attr] = row.style[attr];
					});

					if( rowStyle.fg ) styles += "color:" + rowStyle.fg + ";";
					if( rowStyle.bg ) styles += "background-color:" + rowStyle.bg + ";";
					if( rowStyle.bold ) style += "font-weight:bold;";
					if( rowStyle.italic ) style += "font-style:italic;";
					if( rowStyle.underline ) style += "text-decoration:underline;";
					if( rowStyle.strike ) style += "text-decoration:line-through;";
					if( rowStyle.smallcaps ) style += "font-variant:small-caps;";

					if( styles ) {
						styles = ' style="' + styles + ';padding:2px;padding-left:4px;padding-right:4px;" nowrap="nowrap"';
					}

					for( j = 0; j < columns.length; j++ ) {
						var cancelClickEvent = '';
						var column = columns[j];
						var item;

						if( callbacks[column.id] ) {
							item = callbacks[column.id](row.data, column);
						} else {
							item = row.data[map[column.id]]
							if( column.maxlength && item.length > column.maxlength ) {
								item = item.substr(0, column.maxlength) + '...';
							}
						}

						if( column.ignoreClicks ) {
							cancelClickEvent = ' onclick="CancelEvent(event); return false"';
						}

						html += '' + (item ? item : '') + '	';
					}

					var div = document.createElement('div');
					div.innerHTML = '

' + html + '

';
					var newTableRow = div.childNodes[0].childNodes[0].childNodes[0];
					newTableRow.sourceObjectID = row.id;

					if( previousRow == null ) {
						if( body.childNodes.length == 1 ) {
							body.appendChild(newTableRow);
						} else {
							body.insertBefore(newTableRow,body.firstChild.nextSibling);
						}
					} else {
						if (previousRow.nextSibling)
							previousRow.parentNode.insertBefore(newTableRow,previousRow.nextSibling);
						else
							previousRow.parentNode.appendChild(newTableRow);
					}
					if( keptCount ) {
						newTableRow.appear({duration:1});
					} else {
						newTableRow.style.display = '';
					}

					newTableRow.onclick = function(event) {
						self.action('row-clicked', row.id);
					};
					previousRow = newTableRow;
				} else {
					previousRow = keptRows[''+rowid];
				}
			}
		});

		self.setState('columns.sort-active', false);
	};

	self.setState('keyboard-navigation', false);
	self.setState('keyboard-navigation.focus', 0);

	self._highlightRow = function( id ) {
		var node = $(self.identifier() + '.row.' + id);
		if( node ) {
			var i = 0;
			for( i = 0; i < node.childNodes.length; i++ ) {
				node.childNodes[i].style.backgroundColor = '#FFFF33';
				node.childNodes[i].style.color = '#000';
			}
		}
	};
	self._lowlightRow = function( id ) {
		var node = $(self.identifier() + '.row.' + id);
		if( node ) {
			var rows = self.getState('rows.map');
			var defaultStyle = self.getState('rows.default-style');
			var rowStyle = {};
			var row = rows['' + id];

			[ 'fg', 'bg' ].each(function( attr ){
				if( defaultStyle[attr] ) rowStyle[attr] = defaultStyle[attr];
				if( row && row.style && row.style[attr] ) rowStyle[attr] = row.style[attr];
			});

			var i = 0;
			for( i = 0; i < node.childNodes.length; i++ ) {
				node.childNodes[i].style.backgroundColor = rowStyle.bg;
				node.childNodes[i].style.color = rowStyle.fg;
			}
		}
	};

	self.stopNavigationIfFocusGone = function() {
		if( self.getState('keyboard-navigation') ) {
			var ignores = self.getState('ignore-list');
			var rows = self.getState('rows.map');
			var current_focus = self.getState('keyboard-navigation.focus');

			if( ignores['' + current_focus] || !rows['' + current_focus] ) {
				self.stopNavigation();
			}
		}
	};
	self.navigationActive = function() {
		return self.getState('keyboard-navigation.active');
	};
	self.stopNavigation = function() {
		if( self.getState('keyboard-navigation') ) {

			if( self.getState('keyboard-navigation.active') ) {
				self.setState('keyboard-navigation.active', false);
				self._lowlightRow(self.getState('keyboard-navigation.focus'));
				Hotkeys.remove(self.getState('keyboard-navigation.escape'));
				Hotkeys.remove(self.getState('keyboard-navigation.navigate'));
				Hotkeys.remove('Shift+' + self.getState('keyboard-navigation.navigate'));
				Hotkeys.remove(self.getState('keyboard-navigation.select'));
				Hotkeys.remove(self.getState('keyboard-navigation.custom'));
			} else {
				if( self.getState('keyboard-navigation.enter') ) {
					Hotkeys.remove(self.getState('keyboard-navigation.enter'));
				}
			}

			if( self.getState('keyboard-navigation.enter') ) {
				Hotkeys.add(self.getState('keyboard-navigation.enter'), function() {
					self.startNavigation();
				});
			}
		}
	};
	self.startNavigation = function() {
		var order = self.getState('rows.order');

		if( self.navigationActive() ) {
			self.stopNavigation();
		}

		if( order.length > 0 ) {
			self.setState('keyboard-navigation.active', true);

			Hotkeys.remove(self.getState('keyboard-navigation.enter'));

			Hotkeys.add(self.getState('keyboard-navigation.escape'), function() {
				self.stopNavigation();
			});

			Hotkeys.add(self.getState('keyboard-navigation.navigate'), function() {
				var order = self.getState('rows.order');
				var ignores = self.getState('ignore-list');
				var current_focus = self.getState('keyboard-navigation.focus');
				var new_focus = 0;
				var i = 0;

				for( i = 0; i < (order.length - 1); i++ ) {
					if( order[i] == current_focus && !ignores['' + order[i]] ) {
						new_focus = order[i+1];
					}
				}

				if( new_focus == 0 ) {
					new_focus = order[0];
				}

				self.setState('keyboard-navigation.focus', new_focus);

				self._lowlightRow(current_focus);
				self._highlightRow(new_focus);
			}, {'disable_in_input': true} );

			Hotkeys.add('Shift+' + self.getState('keyboard-navigation.navigate'), function() {
				var order = self.getState('rows.order');
				var ignores = self.getState('ignore-list');
				var current_focus = self.getState('keyboard-navigation.focus');
				var new_focus = 0;
				var i = 0;

				for( i = (order.length - 1); i > 0; i-- ) {
					if( order[i] == current_focus && !ignores['' + order[i]] ) {
						new_focus = order[i-1];
					}
				}

				if( new_focus == 0 ) {
					new_focus = order[order.length - 1];
				}

				self.setState('keyboard-navigation.focus', new_focus);

				self._lowlightRow(current_focus);
				self._highlightRow(new_focus);
			}, {'disable_in_input': true} );

			Hotkeys.add(self.getState('keyboard-navigation.select'), function() {
				self.action('row-clicked', self.getState('keyboard-navigation.focus'));
			}, {'disable_in_input': true} );

			Hotkeys.add(self.getState('keyboard-navigation.custom'), function() {
				var id = self.getState('keyboard-navigation.focus');
				var callback = self.getState('keyboard-navigation.custom-callback');
				callback(id);
			}, {'disable_in_input': true} );

			self.setState('keyboard-navigation.focus', order[0]);
			self._highlightRow(self.getState('keyboard-navigation.focus'));
		}
	};
	self.enableKeyboardNavigation = function( enter, escape, navigate, select, custom, callback ) {
		self.setState('keyboard-navigation', true);
		self.setState('keyboard-navigation.enter', enter);
		self.setState('keyboard-navigation.escape', escape);
		self.setState('keyboard-navigation.navigate', navigate);
		self.setState('keyboard-navigation.select', select);
		self.setState('keyboard-navigation.custom', custom);
		self.setState('keyboard-navigation.custom-callback', callback);
		self.setState('keyboard-navigation.active', false);
		self.stopNavigation();
	};

	return self;
}

<commit_msg>Fix the table<commit_after>function ComponentTable( id ) {
	var self = new Component( id );

	self.setState('ignore-list', {});

	self.setColumns = function( columns ) {
		var real_columns = [];
		for( i = 0; i < (columns.length - 1); i++ ) {
			var column = columns[i];
			real_columns.push(column);
		}
		self.setState('columns', real_columns);
	};
	self.setColumnMap = function( map ) {
		self.setState('columns.map', map);
	};
	self.setSortColumn = function( id, direction ) {
		var map = self.getState('columns.map');
		self.setState('columns.sort', id);
		self.setState('columns.sort-mapped', (map[id] ? map[id] : ''));
		self.setState('columns.sort-direction', direction);
	};
	self._setSortColumn = function( id ) {
		var currentColumn = self.getState('columns.sort');
		var currentDirection = self.getState('columns.sort-direction');
		var direction = 'asc';

		if( currentColumn == id ) {
			direction = (currentDirection == 'asc' ? 'desc' : 'asc');
		}
		self.setSortColumn( id, direction );
		self.setState('columns.sort-active', true);
		self.action('sort-changed', id, direction);
	};

	self.setRows = function( rows, order ) {
		self.setState('rows.map', rows);
		self.setState('rows.order', order);
		self.stopNavigationIfFocusGone();
	};
	self.setRowDefaultStyle = function( style ) {
		self.setState('rows.default-style', style);
	};
	self.registerColumnCallback = function( column, functor ) {
		var callbacks = self.getState('columns.callbacks');

		if( !callbacks )
			callbacks = {};

		callbacks[column] = functor;

		self.setState('columns.callbacks', callbacks);
	};
	self.addIgnore = function( id ) {
		var list = self.getState('ignore-list');
		list['' + id] = true;
	};
	self.resetIgnores = function() {
		self.setState('ignore-list', {});
	};
	self.updateHeaders = function() {
		var columns = self.getState('columns');
		var map = self.getState('columns.map');

		var sortedColumn = self.getState('columns.sort');
		var sortedColumnDirection = self.getState('columns.sort-direction');

		columns.each(function(column){
			var label = column.label;
			if( sortedColumn == column.id ) {
				if( sortedColumnDirection == 'asc' ) {
					label += '';
				} else {
					label += '';
				}
			}
			$(column.id).innerHTML = label;
			$(column.id).style.backgroundColor = (sortedColumn == column.id ? '#FFC' : '#EEF');
			$(column.id).style.textAlign = column.align;
		});
	};
	self.forceUpdate = function() {
		var columns = self.getState('columns');
		var map = self.getState('columns.map');
		var callbacks = self.getState('columns.callbacks');
		var rows = self.getState('rows.map');
		var rowsOrder = self.getState('rows.order');
		var defaultStyle = self.getState('rows.default-style');
		var sortActive = self.getState('columns.sort-active');
		var ignoreList = self.getState('ignore-list');

		self.updateHeaders();

		var node = $(self.identifier());
		var body = null;
		var keptRows = {};
		var keptCount = 0;

		for( i = 0; i < node.childNodes.length; i++ ) {
			var childNode = node.childNodes[i];
			if( childNode.tagName && childNode.tagName.toLowerCase() == 'tbody' ) {
				body = childNode;
				break;
			}
		}

		if( !body ) {
			alert(self.identifier() + ': Unable to update table as it had no body');
		}

		for( i = 0; i < body.childNodes.length; i++ ) {
			var row = body.childNodes[i];
			if( row && row.tagName && row.tagName.toLowerCase() == 'tr' && row.id != (self.identifier() + '.Headers') ){
				if( sortActive || ignoreList['' + row.sourceObjectID] || (!sortActive && !rows['' + row.sourceObjectID]) ) {
					body.removeChild(row);
					i--;
				} else {
					keptRows['' + row.sourceObjectID] = row;
					keptCount++;
				}
			}
		}

		var previousRow = null;
		rowsOrder.each(function(rowid){
			if( !ignoreList['' + rowid] ) {
				if( !keptRows['' + rowid] ) {
					var row = rows['' + rowid];
					var html = '';
					var id = row.id;
					var rowStyle = {};
					var styles = '';

					[ 'fg', 'bg', 'bold', 'underline', 'italic', 'strike', 'smallcaps' ].each(function( attr ){
						if( defaultStyle[attr] ) rowStyle[attr] = defaultStyle[attr];
						if( row.style && row.style[attr] ) rowStyle[attr] = row.style[attr];
					});

					if( rowStyle.fg ) styles += "color:" + rowStyle.fg + ";";
					if( rowStyle.bg ) styles += "background-color:" + rowStyle.bg + ";";
					if( rowStyle.bold ) style += "font-weight:bold;";
					if( rowStyle.italic ) style += "font-style:italic;";
					if( rowStyle.underline ) style += "text-decoration:underline;";
					if( rowStyle.strike ) style += "text-decoration:line-through;";
					if( rowStyle.smallcaps ) style += "font-variant:small-caps;";

					if( styles ) {
						styles = ' style="' + styles + ';padding:2px;padding-left:4px;padding-right:4px;" nowrap="nowrap"';
					}

					for( j = 0; j < columns.length; j++ ) {
						var cancelClickEvent = '';
						var column = columns[j];
						var item;

						if( callbacks[column.id] ) {
							item = callbacks[column.id](row.data, column);
						} else {
							item = row.data[map[column.id]]
							if( column.maxlength && item.length > column.maxlength ) {
								item = item.substr(0, column.maxlength) + '...';
							}
						}

						if( column.ignoreClicks ) {
							cancelClickEvent = ' onclick="CancelEvent(event); return false"';
						}

						html += '' + (item ? item : '') + '	';
					}

					var div = document.createElement('div');
					div.innerHTML = '

' + html + '

';
					var newTableRow = div.childNodes[0].childNodes[0].childNodes[0];
					newTableRow.sourceObjectID = row.id;

					if( previousRow == null ) {
						if( body.childNodes.length == 1 ) {
							body.appendChild(newTableRow);
						} else {
							body.insertBefore(newTableRow,body.firstChild.nextSibling);
						}
					} else {
						if (previousRow.nextSibling)
							previousRow.parentNode.insertBefore(newTableRow,previousRow.nextSibling);
						else
							previousRow.parentNode.appendChild(newTableRow);
					}
					if( keptCount ) {
						newTableRow.appear({duration:1});
					} else {
						newTableRow.style.display = '';
					}

					newTableRow.onclick = function(event) {
						self.action('row-clicked', row.id);
					};
					previousRow = newTableRow;
				} else {
					previousRow = keptRows[''+rowid];
				}
			}
		});

		self.setState('columns.sort-active', false);
	};

	self.setState('keyboard-navigation', false);
	self.setState('keyboard-navigation.focus', 0);

	self._highlightRow = function( id ) {
		var node = $(self.identifier() + '.row.' + id);
		if( node ) {
			var i = 0;
			for( i = 0; i < node.childNodes.length; i++ ) {
				node.childNodes[i].style.backgroundColor = '#FFFF33';
				node.childNodes[i].style.color = '#000';
			}
		}
	};
	self._lowlightRow = function( id ) {
		var node = $(self.identifier() + '.row.' + id);
		if( node ) {
			var rows = self.getState('rows.map');
			var defaultStyle = self.getState('rows.default-style');
			var rowStyle = {};
			var row = rows['' + id];

			[ 'fg', 'bg' ].each(function( attr ){
				if( defaultStyle[attr] ) rowStyle[attr] = defaultStyle[attr];
				if( row && row.style && row.style[attr] ) rowStyle[attr] = row.style[attr];
			});

			var i = 0;
			for( i = 0; i < node.childNodes.length; i++ ) {
				node.childNodes[i].style.backgroundColor = rowStyle.bg;
				node.childNodes[i].style.color = rowStyle.fg;
			}
		}
	};

	self.stopNavigationIfFocusGone = function() {
		if( self.getState('keyboard-navigation') ) {
			var ignores = self.getState('ignore-list');
			var rows = self.getState('rows.map');
			var current_focus = self.getState('keyboard-navigation.focus');

			if( ignores['' + current_focus] || !rows['' + current_focus] ) {
				self.stopNavigation();
			}
		}
	};
	self.navigationActive = function() {
		return self.getState('keyboard-navigation.active');
	};
	self.stopNavigation = function() {
		if( self.getState('keyboard-navigation') ) {

			if( self.getState('keyboard-navigation.active') ) {
				self.setState('keyboard-navigation.active', false);
				self._lowlightRow(self.getState('keyboard-navigation.focus'));
				Hotkeys.remove(self.getState('keyboard-navigation.escape'));
				Hotkeys.remove(self.getState('keyboard-navigation.navigate'));
				Hotkeys.remove('Shift+' + self.getState('keyboard-navigation.navigate'));
				Hotkeys.remove(self.getState('keyboard-navigation.select'));
				Hotkeys.remove(self.getState('keyboard-navigation.custom'));
			} else {
				if( self.getState('keyboard-navigation.enter') ) {
					Hotkeys.remove(self.getState('keyboard-navigation.enter'));
				}
			}

			if( self.getState('keyboard-navigation.enter') ) {
				Hotkeys.add(self.getState('keyboard-navigation.enter'), function() {
					self.startNavigation();
				});
			}
		}
	};
	self.startNavigation = function() {
		var order = self.getState('rows.order');

		if( self.navigationActive() ) {
			self.stopNavigation();
		}

		if( order.length > 0 ) {
			self.setState('keyboard-navigation.active', true);

			Hotkeys.remove(self.getState('keyboard-navigation.enter'));

			Hotkeys.add(self.getState('keyboard-navigation.escape'), function() {
				self.stopNavigation();
			});

			Hotkeys.add(self.getState('keyboard-navigation.navigate'), function() {
				var order = self.getState('rows.order');
				var ignores = self.getState('ignore-list');
				var current_focus = self.getState('keyboard-navigation.focus');
				var new_focus = 0;
				var i = 0;

				for( i = 0; i < (order.length - 1); i++ ) {
					if( order[i] == current_focus && !ignores['' + order[i]] ) {
						new_focus = order[i+1];
					}
				}

				if( new_focus == 0 ) {
					new_focus = order[0];
				}

				self.setState('keyboard-navigation.focus', new_focus);

				self._lowlightRow(current_focus);
				self._highlightRow(new_focus);
			}, {'disable_in_input': true} );

			Hotkeys.add('Shift+' + self.getState('keyboard-navigation.navigate'), function() {
				var order = self.getState('rows.order');
				var ignores = self.getState('ignore-list');
				var current_focus = self.getState('keyboard-navigation.focus');
				var new_focus = 0;
				var i = 0;

				for( i = (order.length - 1); i > 0; i-- ) {
					if( order[i] == current_focus && !ignores['' + order[i]] ) {
						new_focus = order[i-1];
					}
				}

				if( new_focus == 0 ) {
					new_focus = order[order.length - 1];
				}

				self.setState('keyboard-navigation.focus', new_focus);

				self._lowlightRow(current_focus);
				self._highlightRow(new_focus);
			}, {'disable_in_input': true} );

			Hotkeys.add(self.getState('keyboard-navigation.select'), function() {
				self.action('row-clicked', self.getState('keyboard-navigation.focus'));
			}, {'disable_in_input': true} );

			Hotkeys.add(self.getState('keyboard-navigation.custom'), function() {
				var id = self.getState('keyboard-navigation.focus');
				var callback = self.getState('keyboard-navigation.custom-callback');
				callback(id);
			}, {'disable_in_input': true} );

			self.setState('keyboard-navigation.focus', order[0]);
			self._highlightRow(self.getState('keyboard-navigation.focus'));
		}
	};
	self.enableKeyboardNavigation = function( enter, escape, navigate, select, custom, callback ) {
		self.setState('keyboard-navigation', true);
		self.setState('keyboard-navigation.enter', enter);
		self.setState('keyboard-navigation.escape', escape);
		self.setState('keyboard-navigation.navigate', navigate);
		self.setState('keyboard-navigation.select', select);
		self.setState('keyboard-navigation.custom', custom);
		self.setState('keyboard-navigation.custom-callback', callback);
		self.setState('keyboard-navigation.active', false);
		self.stopNavigation();
	};

	return self;
}

<|endoftext|>


<commit_before>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule DOMChildrenOperations
 * @typechecks static-only
 */

'use strict';

var Danger = require('Danger');
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');

var setTextContent = require('setTextContent');
var invariant = require('invariant');

/**
 * Inserts `childNode` as a child of `parentNode` at the `index`.
 *
 * @param {DOMElement} parentNode Parent node in which to insert.
 * @param {DOMElement} childNode Child node to insert.
 * @param {number} index Index at which to insert the child.
 * @internal
 */
function insertChildAt(parentNode, childNode, index) {
  // By exploiting arrays returning `undefined` for an undefined index, we can
  // rely exclusively on `insertBefore(node, null)` instead of also using
  // `appendChild(node)`. However, using `undefined` is not allowed by all
  // browsers so we must replace it with `null`.
  parentNode.insertBefore(
    childNode,
    parentNode.childNodes[index] || null
  );
}

/**
 * Operations for updating with DOM children.
 */
var DOMChildrenOperations = {

  dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,

  updateTextContent: setTextContent,

  /**
   * Updates a component's children by processing a series of updates. The
   * update configurations are each expected to have a `parentNode` property.
   *
   * @param {array<object>} updates List of update configurations.
   * @param {array<string>} markupList List of markup strings.
   * @internal
   */
  processUpdates: function(updates, markupList) {
    var update;
    // Mapping from parent IDs to initial child orderings.
    var initialChildren = null;
    // List of children that will be moved or removed.
    var updatedChildren = null;

    for (var i = 0; i < updates.length; i++) {
      update = updates[i];
      if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING ||
          update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {
        var updatedIndex = update.fromIndex;
        var updatedChild = update.parentNode.childNodes[updatedIndex];
        var parentID = update.parentID;

        invariant(
          updatedChild,
          'processUpdates(): Unable to find child %s of element. This ' +
          'probably means the DOM was unexpectedly mutated (e.g., by the ' +
          'browser), usually due to forgetting a <tbody> when using tables, ' +
          'nesting tags like <form>, <p>, or <a>, or using non-SVG elements ' +
          'in an <svg> parent. Try inspecting the child nodes of the element ' +
          'with React ID `%s`.',
          updatedIndex,
          parentID
        );

        initialChildren = initialChildren || {};
        initialChildren[parentID] = initialChildren[parentID] || [];
        initialChildren[parentID][updatedIndex] = updatedChild;

        updatedChildren = updatedChildren || [];
        updatedChildren.push(updatedChild);
      }
    }

    var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);

    // Remove updated children first so that `toIndex` is consistent.
    if (updatedChildren) {
      for (var j = 0; j < updatedChildren.length; j++) {
        updatedChildren[j].parentNode.removeChild(updatedChildren[j]);
      }
    }

    for (var k = 0; k < updates.length; k++) {
      update = updates[k];
      switch (update.type) {
        case ReactMultiChildUpdateTypes.INSERT_MARKUP:
          insertChildAt(
            update.parentNode,
            renderedMarkup[update.markupIndex],
            update.toIndex
          );
          break;
        case ReactMultiChildUpdateTypes.MOVE_EXISTING:
          insertChildAt(
            update.parentNode,
            initialChildren[update.parentID][update.fromIndex],
            update.toIndex
          );
          break;
        case ReactMultiChildUpdateTypes.TEXT_CONTENT:
          setTextContent(
            update.parentNode,
            update.textContent
          );
          break;
        case ReactMultiChildUpdateTypes.REMOVE_NODE:
          // Already removed by the for-loop above.
          break;
      }
    }
  }

};

module.exports = DOMChildrenOperations;
<commit_msg>fix render order error in safari<commit_after>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule DOMChildrenOperations
 * @typechecks static-only
 */

'use strict';

var Danger = require('Danger');
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');

var setTextContent = require('setTextContent');
var invariant = require('invariant');

/**
 * Inserts `childNode` as a child of `parentNode` at the `index`.
 *
 * @param {DOMElement} parentNode Parent node in which to insert.
 * @param {DOMElement} childNode Child node to insert.
 * @param {number} index Index at which to insert the child.
 * @internal
 */
function insertChildAt(parentNode, childNode, index) {
  // By exploiting arrays returning `undefined` for an undefined index, we can
  // rely exclusively on `insertBefore(node, null)` instead of also using
  // `appendChild(node)`. However, using `undefined` is not allowed by all
  // browsers so we must replace it with `null`.

  // fix render order error in safari
  try {
    parentNode.insertBefore(
      childNode,
      parentNode.childNodes.item(index) || null
    );
  } catch (e) {
    //IE8 can't use `item` when childNodes is empty.
    parentNode.insertBefore(
      childNode,
      parentNode.childNodes[index] || null
    );
  }
}

/**
 * Operations for updating with DOM children.
 */
var DOMChildrenOperations = {

  dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,

  updateTextContent: setTextContent,

  /**
   * Updates a component's children by processing a series of updates. The
   * update configurations are each expected to have a `parentNode` property.
   *
   * @param {array<object>} updates List of update configurations.
   * @param {array<string>} markupList List of markup strings.
   * @internal
   */
  processUpdates: function(updates, markupList) {
    var update;
    // Mapping from parent IDs to initial child orderings.
    var initialChildren = null;
    // List of children that will be moved or removed.
    var updatedChildren = null;

    for (var i = 0; i < updates.length; i++) {
      update = updates[i];
      if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING ||
          update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {
        var updatedIndex = update.fromIndex;
        var updatedChild = update.parentNode.childNodes[updatedIndex];
        var parentID = update.parentID;

        invariant(
          updatedChild,
          'processUpdates(): Unable to find child %s of element. This ' +
          'probably means the DOM was unexpectedly mutated (e.g., by the ' +
          'browser), usually due to forgetting a <tbody> when using tables, ' +
          'nesting tags like <form>, <p>, or <a>, or using non-SVG elements ' +
          'in an <svg> parent. Try inspecting the child nodes of the element ' +
          'with React ID `%s`.',
          updatedIndex,
          parentID
        );

        initialChildren = initialChildren || {};
        initialChildren[parentID] = initialChildren[parentID] || [];
        initialChildren[parentID][updatedIndex] = updatedChild;

        updatedChildren = updatedChildren || [];
        updatedChildren.push(updatedChild);
      }
    }

    var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);

    // Remove updated children first so that `toIndex` is consistent.
    if (updatedChildren) {
      for (var j = 0; j < updatedChildren.length; j++) {
        updatedChildren[j].parentNode.removeChild(updatedChildren[j]);
      }
    }

    for (var k = 0; k < updates.length; k++) {
      update = updates[k];
      switch (update.type) {
        case ReactMultiChildUpdateTypes.INSERT_MARKUP:
          insertChildAt(
            update.parentNode,
            renderedMarkup[update.markupIndex],
            update.toIndex
          );
          break;
        case ReactMultiChildUpdateTypes.MOVE_EXISTING:
          insertChildAt(
            update.parentNode,
            initialChildren[update.parentID][update.fromIndex],
            update.toIndex
          );
          break;
        case ReactMultiChildUpdateTypes.TEXT_CONTENT:
          setTextContent(
            update.parentNode,
            update.textContent
          );
          break;
        case ReactMultiChildUpdateTypes.REMOVE_NODE:
          // Already removed by the for-loop above.
          break;
      }
    }
  }

};

module.exports = DOMChildrenOperations;
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { Provider } from 'react-redux';
import Helmet from 'react-helmet';

import url from 'url';
import _ from 'lodash';
import { parse } from 'qs';

import createStore from './../../src/client/app/store/index';
import prepareData from './../../src/client/app/helpers/prepareData';

import { Switch, StaticRouter, matchPath } from 'react-router-dom';
import createRoutes from './../../src/client/app/routes/index';
import RouteWithSubRoutes from './../../src/client/app/helpers/routes/RouteWithSubRoutes';
import MainLayout from './../../src/client/app/components/layouts/MainLayout';

const store = createStore();
const routes = createRoutes();

function historyCb(location) {
  const routeState = { location, params: {}, routes: [], query: {}};
  routes.some(route => {
    const match = matchPath(location.pathname, route);

    if (match) {
      routeState.routes.push(route);
      _.assign(routeState.params, match.params);
      const query = location.search ? parse(location.searh.substr(1)) : {};
      _.assign(routeState.query, query);
    }
    return match;
  });

  return routeState;
}

export default (req, res) => {
  const location = url.parse(req.url);
  const routeState = historyCb(location);

  if (routeState.routes.length == 0) {
    res.status(404);
    res.render('views/not_found');
  } else {
    Promise.all(
      _.compact(prepareData(store, routeState))
    ).then(() => {
      const initialState = JSON.stringify(store.getState());
      const context = {};

      const content = ReactDOMServer.renderToString(
        <Provider store={store}>
          <StaticRouter location={req.url} context={context}>
            <MainLayout>
              <Switch>
                {routes.map((route, i) => (
                  <RouteWithSubRoutes key={i} {...route}/>
                ))}
              </Switch>
            </MainLayout>
          </StaticRouter>
        </Provider>
      );

      const head = Helmet.rewind();

      res.status(200);
      res.render(
        'views/index',
        { initialState, content, head }
      );
    });
  }
};
<commit_msg>lesson-8 | fix store<commit_after>import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { Provider } from 'react-redux';
import Helmet from 'react-helmet';

import url from 'url';
import _ from 'lodash';
import { parse } from 'qs';

import createStore from './../../src/client/app/store/index';
import prepareData from './../../src/client/app/helpers/prepareData';

import { Switch, StaticRouter, matchPath } from 'react-router-dom';
import createRoutes from './../../src/client/app/routes/index';
import RouteWithSubRoutes from './../../src/client/app/helpers/routes/RouteWithSubRoutes';
import MainLayout from './../../src/client/app/components/layouts/MainLayout';

const routes = createRoutes();

function historyCb(location) {
  const routeState = { location, params: {}, routes: [], query: {}};
  routes.some(route => {
    const match = matchPath(location.pathname, route);

    if (match) {
      routeState.routes.push(route);
      _.assign(routeState.params, match.params);
      const query = location.search ? parse(location.searh.substr(1)) : {};
      _.assign(routeState.query, query);
    }
    return match;
  });

  return routeState;
}

export default (req, res) => {
  const store = createStore();
  const location = url.parse(req.url);
  const routeState = historyCb(location);

  if (routeState.routes.length == 0) {
    res.status(404);
    res.render('views/not_found');
  } else {
    Promise.all(
      _.compact(prepareData(store, routeState))
    ).then(() => {
      const initialState = JSON.stringify(store.getState());
      const context = {};

      const content = ReactDOMServer.renderToString(
        <Provider store={store}>
          <StaticRouter location={req.url} context={context}>
            <MainLayout>
              <Switch>
                {routes.map((route, i) => (
                  <RouteWithSubRoutes key={i} {...route}/>
                ))}
              </Switch>
            </MainLayout>
          </StaticRouter>
        </Provider>
      );

      const head = Helmet.rewind();

      res.status(200);
      res.render(
        'views/index',
        { initialState, content, head }
      );
    });
  }
};
<|endoftext|>