<commit_before>
var DCPU16 = DCPU16 || {};

(function () {
	var _ = {
			opTable: {
				'SET': 0x1,
				// sugar
				'MOV': 0x1,
				'ADD': 0x2,
				'SUB': 0x3,
				'MUL': 0x4,
				'MLI': 0x5,
				'DIV': 0x6,
				'DVI': 0x7,
				'MOD': 0x8,
				'MDI': 0x9,
				'AND': 0xa,
				'BOR': 0xb,
				'XOR': 0xc,
				'SHR': 0xd,
				'ASR': 0xe,
				'SHL': 0xf,

				'IFB': 0x10,
				'IFC': 0x11,
				'IFE': 0x12,
				'IFN': 0x13,
				'IFG': 0x14,
				'IFA': 0x15,
				'IFL': 0x16,
				'IFU': 0x17,

				'ADX': 0x1a,
				'SBX': 0x1b,

				'STI': 0x1e,
				'STD': 0x1f,

				// special instructions
				// TODO: get rid of the arithmetics
				'JSR': 0x1 << 5,

				'INT': 0x8 << 5,
				'IAG': 0x9 << 5,
				'IAS': 0xa << 5,
				'RFI': 0xb << 5,
				'IAQ': 0xc << 5,

				'HWN': 0x10 << 5,
				'HWQ': 0x11 << 5,
				'HWI': 0x12 << 5
			},

			regTable: {
				'A': 0x0,
				'B': 0x1,
				'C': 0x2,
				'X': 0x3,
				'Y': 0x4,
				'Z': 0x5,
				'I': 0x6,
				'J': 0x7,

				// pseudo registers
				'PUSH': 0x18,
				'POP': 0x18,
				'PEEK': 0x19,

				// special purpose registers
				'SP': 0x1b,
				'PC': 0x1c,
				'EX': 0x1d,
				'IA': 0xff
			},

			preprocess: function (src) {
				// eliminate tabs
				return src.replace(/\t/g, " ");
			},

			isArray: function (val) {
				return typeof val === "object" && 'splice' in val && 'join' in val;
			}
		}, // end of definition of _

		ParserError = function (msg, line) {
			this.name = 'ParserError';
			this.message = msg;
			this.line = line;
		};
		ParserError.prototype = Error.prototype;

	DCPU16.asm = function (src, options) {
		'use strict';

		var i, tokens, pc = 0, oppc = 0, par = 0, tmp,

			// results
			bc = [], listing = [], rom = [],
			addr2line = {}, line2addr = {},

			// constrol structures
			labels = {}, macros = {},

			// second pass
			resolveLabels = [], resolveExpressions = [],

			// errors, warnings, ...
			warnings = [],
			warn = function (msg, line) {
				warnings.push({
					message: msg,
					line: line
				});
			},

			// parsing and generating
			emit = function (value) {
				bc.push(value & DCPU16.maxWord);
				pc++;
			},

			parseTokens = function (node, allowMacros, evalExpressions) {
				var opcode = 0, parameters, i, j, result, tmp = [], parval;

				switch(node.type) {
				case "node_label":
					if (labels[node.value]) {
						warn('Label already defined in line ' + labels[node.value].line + ', ignoring this definition.', node.line);
					} else if (_.regTable[node.value.toUpperCase()] >= 0) {
						warn('"' + node.value + '" is a keyword. This label can not be referenced.', node.line);
					} else {
						labels[node.value] = {
							line: node.line,
							pc: pc
						};
					}
					break;
				case "node_directive":
					switch(node.value.toLowerCase()) {
					case "dat":
					case "dw":
						parameters = node.children[0];

						for (i = 0; i < parameters.length; i++) {
							tmp = parseTokens(parameters[i], false, false);

							if (_.isArray(tmp)) {
								emit(tmp[0]);
							} else if (typeof tmp === 'string'){
								for (j = 0; j < tmp.length; j++) {
									emit(tmp.charCodeAt(j));
								}
							} else {
								throw new ParserError('Unknown parameter "' + tmp + '" for dat.', node.line);
							}
						}
						break;

					// todo :/
					case "equ":
					case "eq":
					case "if":
					case "elseif":
					case "else":
					case "endif":
					case "org":
					case "macro":
					case "nolist":
					case "list":
					case "dir_callmacro":
						throw new ParserError('Not yet implemented.', node.line);
						break;
					default:
						warn('Ignoring unknown directive "' + node.value + '".', node.line);
						break;
					}
					break;
				case "node_op":
					if (_.opTable[node.value] >= 0) {
						opcode = _.opTable[node.value];
						parameters = node.children[0];

						if (((opcode & 0x1f) > 0 && parameters.length !== 2) || ((opcode & 0x1f) === 0 && parameters.length !== 1)) {
							throw new ParserError('Invalid number of parameters.', node.line);
						}

						oppc = pc;
						emit(0);

						if ((opcode & 0x1f) > 0) {
							// basic op
							for (par = 1; par >= 0; par--) {
								tmp = parseTokens(parameters[par], false, false);
								parval = 0;

								if (parameters[par].value === 'val_deref') {
									if (tmp[1] !== 0) {
										parval = _.regTable[tmp[1]];
										if (parval < 0x8) {
											parval += 0x8;
										}
									} else {
										parval = 0x1e;
										emit(tmp[0]);
									}
								} else {
									if (tmp[1] !== 0) {
										parval = _.regTable[tmp[1]];
									} else {
										if (par === 1 && tmp[0] >= -1 && tmp[0] < 30) {
											parval = 0x21 + tmp[0];
										} else {
											parval = 0x1f;
											emit(tmp[0]);
										}
									}
								}
								// write parameter value to opcode
								opcode |= ((parval & ((1 << (5 + par)) - 1)) << (5 + par * 5));
							}
						} else {
							// non basic op
							par = 1;

							tmp = parseTokens(parameters[0], false, false);
							parval = 0;

							if (parameters[0].value === 'val_deref') {
								if (tmp[1] !== 0) {
									parval = _.regTable[tmp[1]];
									if (parval < 0x8) {
										parval += 0x8;
									}
								} else {
									parval = 0x1e;
									emit(tmp[0]);
								}
							} else {
								if (tmp[1] !== 0) {
									parval = _.regTable[tmp[1]];
								} else {
									if (par === 1 && tmp[0] > -1 && tmp[0] < 30) {
										parval = 0x21 + tmp[0];
									} else {
										parval = 0x1f;
										emit(tmp[0]);
									}
								}
							}
							// write parameter value to opcode
							opcode |= ((parval & 0x3f) << 10);
						}

						bc[oppc] = opcode;
					} else {
						throw new ParserError('Unknown operation "' + node.value + '".', node.line);
					}
					break;
				case "node_value":
					switch (node.value) {
					case "val_paramlist":
						result = [];
						for (i = 0; i < node.children.length; i++) {
							result.push(parseTokens(node.children[i], false, false));
						}
						break;
					case "val_deref":
						result = parseTokens(node.children[0], false, false);
						break;
					case "val_literal":
						result = parseTokens(node.children[0], false, false);
						break;
					}
					break;
				case "val_register":
					result = [0, node.value];
					break;
				case "val_identifier":
					if (evalExpressions) {
						result = [labels[node.value].pc, 0];
					} else {
						resolveLabels.push({
							label: node.value,
							pc: pc,
							par: par,
							line: node.line,
							oppc: oppc
						});
						result = [0xDEAD, 0];
					}
					break;
				case "val_number":
					result = [node.value, 0];
					break;
				case "val_string":
					if (evalExpressions) {
						result = [node.value.length > 0 ? node.value.charCodeAt(0) : 0, 0];
					} else {
						result = node.value;
					}
					break;
				case "node_comparison":
					throw new ParserError('Not implemented', node.line);
					break;
				case "node_expression":
					if (!evalExpressions) {
						resolveExpressions.push({
							expression: node,
							pc: pc,
							par: par,
							line: node.line,
							oppc: oppc
						});
						result = [0xDEAD, 0];
					} else {
						tmp.push(parseTokens(node.children[0], false, true));
						tmp.push(parseTokens(node.children[1], false, true));

						if (tmp[0][1] !== 0 && tmp[1][1] !== 0) {
							throw new ParserError('Found multiple registers in one expressions.', node.line);
						}

						if ((tmp[0][1] !== 0 || tmp[1][1] !== 0) && node.value !== '+') {
							throw new ParserError('Registers inside expressions are allowed in sums only.', node.line);
						}

						result = [0, 0];

						if (tmp[0][1] !== 0) {
							result[1] = tmp[0][1];
						}

						if (tmp[1][1] !== 0) {
							result[1] = tmp[1][1];
						}

						switch (node.value) {
						case "+":
							result[0] = tmp[0][0] + tmp[1][0];
							break;
						case "-":
							result[0] = tmp[0][0] - tmp[1][0];
							break;
						case "*":
							result[0] = tmp[0][0] * tmp[1][0];
							break;
						case "/":
							result[0] = tmp[0][0] / tmp[1][0];
							break;
						case "%":
							result[0] = tmp[0][0] % tmp[1][0];
							break;
						case "&":
							result[0] = tmp[0][0] & tmp[1][0];
							break;
						case "|":
							result[0] = tmp[0][0] | tmp[1][0];
							break;
						case "^":
							result[0] = tmp[0][0] ^ tmp[1][0];
							break;
						}
					}
					break;
				}

				return result;
			};

		options = options || {};
		src = _.preprocess(src);

		try {
			tokens = DCPU16.Parser.parse(src);

			for (i = 0; i < tokens.length; i++) {
				if (tokens[i].value !== 'nop') {
					addr2line[pc] = tokens[i].line;
					line2addr[tokens[i].line] = pc;
				}
				parseTokens(tokens[i], true, false);
			}
		} catch (e) {
			throw new ParserError(e.message, e.line);
		}

		// labels and expressions
		for (i = 0; i < resolveLabels.length; i++) {
			tmp = resolveLabels[i];

			if (typeof labels[tmp.label] !== 'undefined') {
				bc[tmp.pc] = labels[tmp.label].pc;
			} else {
				throw new ParserError('Can\'t find definition for label "' + tmp.label + '"', tmp.line);
			}
		}

		for (i = 0; i < resolveExpressions.length; i++) {
			tmp = resolveExpressions[i];

			par = parseTokens(tmp.expression, false, true);
			if (par[1] !== 0) {
				// we have a register in here
				oppc = par[1];
				par[1] = _.regTable[par[1]];

				// we have to delete the old parameter value
				bc[tmp.oppc] &= (((1 << (5 + (1 - tmp.par))) - 1) << (5 + (1 - tmp.par) * 5)) | 0x1f;

				if (par[1] >= 0 && par[1] < 0x8) {
					// it's a standard register
					bc[tmp.oppc] |= (par[1] + 0x10) << (5 + tmp.par * 5);
				} else if (par[1] === 0x1b) {
					// it's SP
					bc[tmp.oppc] |= 0x1b << (5 + tmp.par * 5);
				} else {
					throw new ParserError('The register "' + oppc + '" is not allowed in an expression.', tmp.line);
				}
			}

			bc[tmp.pc] = par[0];
		}

		for (i = 0; i < bc.length; i++) {
			rom.push(bc[i] & 0xff);
			rom.push((bc[i] >> 8) & 0xff);
		}

		return {
			bc: rom,
			base: 0,
			warnings: warnings,
			addr2line: addr2line,
			line2addr: line2addr,
			labels: labels
		};
	}

	if (typeof TestCase !== 'undefined') {
		DCPU16.ParserError = ParserError;
	}

})();
<commit_msg>throw an error if PUSH/POP are used in the wrong places<commit_after>
var DCPU16 = DCPU16 || {};

(function () {
	var _ = {
			opTable: {
				'SET': 0x1,
				// sugar
				'MOV': 0x1,
				'ADD': 0x2,
				'SUB': 0x3,
				'MUL': 0x4,
				'MLI': 0x5,
				'DIV': 0x6,
				'DVI': 0x7,
				'MOD': 0x8,
				'MDI': 0x9,
				'AND': 0xa,
				'BOR': 0xb,
				'XOR': 0xc,
				'SHR': 0xd,
				'ASR': 0xe,
				'SHL': 0xf,

				'IFB': 0x10,
				'IFC': 0x11,
				'IFE': 0x12,
				'IFN': 0x13,
				'IFG': 0x14,
				'IFA': 0x15,
				'IFL': 0x16,
				'IFU': 0x17,

				'ADX': 0x1a,
				'SBX': 0x1b,

				'STI': 0x1e,
				'STD': 0x1f,

				// special instructions
				// TODO: get rid of the arithmetics
				'JSR': 0x1 << 5,

				'INT': 0x8 << 5,
				'IAG': 0x9 << 5,
				'IAS': 0xa << 5,
				'RFI': 0xb << 5,
				'IAQ': 0xc << 5,

				'HWN': 0x10 << 5,
				'HWQ': 0x11 << 5,
				'HWI': 0x12 << 5
			},

			regTable: {
				'A': 0x0,
				'B': 0x1,
				'C': 0x2,
				'X': 0x3,
				'Y': 0x4,
				'Z': 0x5,
				'I': 0x6,
				'J': 0x7,

				// pseudo registers
				'PUSH': 0x18,
				'POP': 0x18,
				'PEEK': 0x19,

				// special purpose registers
				'SP': 0x1b,
				'PC': 0x1c,
				'EX': 0x1d,
				'IA': 0xff
			},

			preprocess: function (src) {
				// eliminate tabs
				return src.replace(/\t/g, " ");
			},

			isArray: function (val) {
				return typeof val === "object" && 'splice' in val && 'join' in val;
			}
		}, // end of definition of _

		ParserError = function (msg, line) {
			this.name = 'ParserError';
			this.message = msg;
			this.line = line;
		};
		ParserError.prototype = Error.prototype;

	DCPU16.asm = function (src, options) {
		'use strict';

		var i, tokens, pc = 0, oppc = 0, par = 0, tmp,

			// results
			bc = [], listing = [], rom = [],
			addr2line = {}, line2addr = {},

			// constrol structures
			labels = {}, macros = {},

			// second pass
			resolveLabels = [], resolveExpressions = [],

			// errors, warnings, ...
			warnings = [],
			warn = function (msg, line) {
				warnings.push({
					message: msg,
					line: line
				});
			},

			// parsing and generating
			emit = function (value) {
				bc.push(value & DCPU16.maxWord);
				pc++;
			},

			parseTokens = function (node, allowMacros, evalExpressions) {
				var opcode = 0, parameters, i, j, result, tmp = [], parval;

				switch(node.type) {
				case "node_label":
					if (labels[node.value]) {
						warn('Label already defined in line ' + labels[node.value].line + ', ignoring this definition.', node.line);
					} else if (_.regTable[node.value.toUpperCase()] >= 0) {
						warn('"' + node.value + '" is a keyword. This label can not be referenced.', node.line);
					} else {
						labels[node.value] = {
							line: node.line,
							pc: pc
						};
					}
					break;
				case "node_directive":
					switch(node.value.toLowerCase()) {
					case "dat":
					case "dw":
						parameters = node.children[0];

						for (i = 0; i < parameters.length; i++) {
							tmp = parseTokens(parameters[i], false, false);

							if (_.isArray(tmp)) {
								emit(tmp[0]);
							} else if (typeof tmp === 'string'){
								for (j = 0; j < tmp.length; j++) {
									emit(tmp.charCodeAt(j));
								}
							} else {
								throw new ParserError('Unknown parameter "' + tmp + '" for dat.', node.line);
							}
						}
						break;

					// todo :/
					case "equ":
					case "eq":
					case "if":
					case "elseif":
					case "else":
					case "endif":
					case "org":
					case "macro":
					case "nolist":
					case "list":
					case "dir_callmacro":
						throw new ParserError('Not yet implemented.', node.line);
						break;
					default:
						warn('Ignoring unknown directive "' + node.value + '".', node.line);
						break;
					}
					break;
				case "node_op":
					if (_.opTable[node.value] >= 0) {
						opcode = _.opTable[node.value];
						parameters = node.children[0];

						if (((opcode & 0x1f) > 0 && parameters.length !== 2) || ((opcode & 0x1f) === 0 && parameters.length !== 1)) {
							throw new ParserError('Invalid number of parameters.', node.line);
						}

						oppc = pc;
						emit(0);

						if ((opcode & 0x1f) > 0) {
							// basic op
							for (par = 1; par >= 0; par--) {
								tmp = parseTokens(parameters[par], false, false);
								parval = 0;

								if (parameters[par].value === 'val_deref') {
									if (tmp[1] !== 0) {
										parval = _.regTable[tmp[1]];
										if (parval < 0x8) {
											parval += 0x8;
										}
									} else {
										parval = 0x1e;
										emit(tmp[0]);
									}
								} else {
									if (tmp[1] !== 0) {
										if (par === 1 && tmp[1] === 'PUSH') {
											throw new ParserError('PUSH is not allowed in this context.', node.line);
										} else if (par === 0 && tmp[1] === 'POP') {
											throw new ParserError('POP is not allowed in this context.', node.line);
										}

										parval = _.regTable[tmp[1]];
									} else {
										if (par === 1 && tmp[0] >= -1 && tmp[0] < 30) {
											parval = 0x21 + tmp[0];
										} else {
											parval = 0x1f;
											emit(tmp[0]);
										}
									}
								}
								// write parameter value to opcode
								opcode |= ((parval & ((1 << (5 + par)) - 1)) << (5 + par * 5));
							}
						} else {
							// non basic op
							par = 1;

							tmp = parseTokens(parameters[0], false, false);
							parval = 0;

							if (parameters[0].value === 'val_deref') {
								if (tmp[1] !== 0) {
									parval = _.regTable[tmp[1]];
									if (parval < 0x8) {
										parval += 0x8;
									}
								} else {
									parval = 0x1e;
									emit(tmp[0]);
								}
							} else {
								if (tmp[1] !== 0) {
									parval = _.regTable[tmp[1]];
								} else {
									if (par === 1 && tmp[0] > -1 && tmp[0] < 30) {
										parval = 0x21 + tmp[0];
									} else {
										parval = 0x1f;
										emit(tmp[0]);
									}
								}
							}
							// write parameter value to opcode
							opcode |= ((parval & 0x3f) << 10);
						}

						bc[oppc] = opcode;
					} else {
						throw new ParserError('Unknown operation "' + node.value + '".', node.line);
					}
					break;
				case "node_value":
					switch (node.value) {
					case "val_paramlist":
						result = [];
						for (i = 0; i < node.children.length; i++) {
							result.push(parseTokens(node.children[i], false, false));
						}
						break;
					case "val_deref":
						result = parseTokens(node.children[0], false, false);
						break;
					case "val_literal":
						result = parseTokens(node.children[0], false, false);
						break;
					}
					break;
				case "val_register":
					result = [0, node.value];
					break;
				case "val_identifier":
					if (evalExpressions) {
						result = [labels[node.value].pc, 0];
					} else {
						resolveLabels.push({
							label: node.value,
							pc: pc,
							par: par,
							line: node.line,
							oppc: oppc
						});
						result = [0xDEAD, 0];
					}
					break;
				case "val_number":
					result = [node.value, 0];
					break;
				case "val_string":
					if (evalExpressions) {
						result = [node.value.length > 0 ? node.value.charCodeAt(0) : 0, 0];
					} else {
						result = node.value;
					}
					break;
				case "node_comparison":
					throw new ParserError('Not implemented', node.line);
					break;
				case "node_expression":
					if (!evalExpressions) {
						resolveExpressions.push({
							expression: node,
							pc: pc,
							par: par,
							line: node.line,
							oppc: oppc
						});
						result = [0xDEAD, 0];
					} else {
						tmp.push(parseTokens(node.children[0], false, true));
						tmp.push(parseTokens(node.children[1], false, true));

						if (tmp[0][1] !== 0 && tmp[1][1] !== 0) {
							throw new ParserError('Found multiple registers in one expressions.', node.line);
						}

						if ((tmp[0][1] !== 0 || tmp[1][1] !== 0) && node.value !== '+') {
							throw new ParserError('Registers inside expressions are allowed in sums only.', node.line);
						}

						result = [0, 0];

						if (tmp[0][1] !== 0) {
							result[1] = tmp[0][1];
						}

						if (tmp[1][1] !== 0) {
							result[1] = tmp[1][1];
						}

						switch (node.value) {
						case "+":
							result[0] = tmp[0][0] + tmp[1][0];
							break;
						case "-":
							result[0] = tmp[0][0] - tmp[1][0];
							break;
						case "*":
							result[0] = tmp[0][0] * tmp[1][0];
							break;
						case "/":
							result[0] = tmp[0][0] / tmp[1][0];
							break;
						case "%":
							result[0] = tmp[0][0] % tmp[1][0];
							break;
						case "&":
							result[0] = tmp[0][0] & tmp[1][0];
							break;
						case "|":
							result[0] = tmp[0][0] | tmp[1][0];
							break;
						case "^":
							result[0] = tmp[0][0] ^ tmp[1][0];
							break;
						}
					}
					break;
				}

				return result;
			};

		options = options || {};
		src = _.preprocess(src);

		try {
			tokens = DCPU16.Parser.parse(src);

			for (i = 0; i < tokens.length; i++) {
				if (tokens[i].value !== 'nop') {
					addr2line[pc] = tokens[i].line;
					line2addr[tokens[i].line] = pc;
				}
				parseTokens(tokens[i], true, false);
			}
		} catch (e) {
			throw new ParserError(e.message, e.line);
		}

		// labels and expressions
		for (i = 0; i < resolveLabels.length; i++) {
			tmp = resolveLabels[i];

			if (typeof labels[tmp.label] !== 'undefined') {
				bc[tmp.pc] = labels[tmp.label].pc;
			} else {
				throw new ParserError('Can\'t find definition for label "' + tmp.label + '"', tmp.line);
			}
		}

		for (i = 0; i < resolveExpressions.length; i++) {
			tmp = resolveExpressions[i];

			par = parseTokens(tmp.expression, false, true);
			if (par[1] !== 0) {
				// we have a register in here
				oppc = par[1];
				par[1] = _.regTable[par[1]];

				// we have to delete the old parameter value
				bc[tmp.oppc] &= (((1 << (5 + (1 - tmp.par))) - 1) << (5 + (1 - tmp.par) * 5)) | 0x1f;

				if (par[1] >= 0 && par[1] < 0x8) {
					// it's a standard register
					bc[tmp.oppc] |= (par[1] + 0x10) << (5 + tmp.par * 5);
				} else if (par[1] === 0x1b) {
					// it's SP
					bc[tmp.oppc] |= 0x1b << (5 + tmp.par * 5);
				} else {
					throw new ParserError('The register "' + oppc + '" is not allowed in an expression.', tmp.line);
				}
			}

			bc[tmp.pc] = par[0];
		}

		for (i = 0; i < bc.length; i++) {
			rom.push(bc[i] & 0xff);
			rom.push((bc[i] >> 8) & 0xff);
		}

		return {
			bc: rom,
			base: 0,
			warnings: warnings,
			addr2line: addr2line,
			line2addr: line2addr,
			labels: labels
		};
	}

	if (typeof TestCase !== 'undefined') {
		DCPU16.ParserError = ParserError;
	}

})();
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.INTERFACE({
  package: 'foam.dao',
  name: 'Journal',
  extends: 'foam.dao.Sink',

  methods: [
    function replay(dao) {}
  ]
});

if ( foam.isServer ) {
  foam.CLASS({
    package: 'foam.dao',
    name: 'NodeFileJournal',
    implements: ['foam.dao.Journal'],
    properties: [
      {
        name: 'fd',
        required: true
      },
      {
        name: 'offset',
        factory: function() {
          var stat = this.fs.fstatSync(this.fd);
          return stat.size;
        }
      },
      {
        name: 'fs',
        factory: function() { return require('fs'); }
      },
      {
        name: 'writePromise',
        value: Promise.resolve()
      }
    ],

    methods: [
      function put(obj) {
        return this.write_(Buffer.from(
            "put(foam.json.parse(" + foam.json.Storage.stringify(obj) +
              "));\n"));
      },

      function remove(obj) {
        return this.write_(Buffer.from(
            "remove(foam.json.parse(" + foam.json.Storage.stringify(obj) +
              "));\n"));
      },

      function write_(data) {
        var self = this;
        var offset = self.offset;
        self.offset += data.length;
        return self.writePromise = self.writePromise.then(function() {
          return new Promise(function(resolve, reject) {
            self.fs.write(
                self.fd, data, 0, data.length, offset,
                function(err, written, buffer) {
                  if ( err ) reject(err);
                  if ( written != data.length )
                    reject(new Error('foam.dao.NodeFileJournal: Incomplete write'));
                  resolve();
                });
          });
        });
      },

      function replay(dao) {
        var self = this;
        return new Promise(function(resolve, reject) {
          self.fs.readFile(self.fd, 'utf8', function(err, data_) {
            if ( err ) {
              reject(err);
              return;
            }

            var context = {
              put: function(o) { return dao.put(o); },
              remove: function(o) { return dao.remove(o); },
              foam: {
                json: {
                  parse: function(obj) {
                    return foam.json.parse(obj, null, dao.__context__);
                  }
                }
              }
            };

            with(context) eval(data_);

            resolve(dao);
          });
        });
      },
      function eof() {}
    ]
  });
}

foam.CLASS({
  package: 'foam.dao',
  name: 'JDAO',
  extends: 'foam.dao.PromisedDAO',

  properties: [
    'delegate',
    'journal',
    {
      name: 'promise',
      factory: function() {
        var self = this;
        return this.journal.replay(this.delegate).then(function(dao) {
          dao.listen(self.journal);
          return dao;
        });
      }
    },
    {
      name: 'synced',
      getter: function() {
        return Promise.all([ this.promise, this.journal.writePromise ]);
      }
    }
  ]
});
<commit_msg>JDAO/js: Support default class name<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.INTERFACE({
  package: 'foam.dao',
  name: 'Journal',
  extends: 'foam.dao.Sink',

  methods: [
    function replay(dao) {}
  ]
});

if ( foam.isServer ) {
  foam.CLASS({
    package: 'foam.dao',
    name: 'NodeFileJournal',
    implements: ['foam.dao.Journal'],
    properties: [
      {
        class: 'Class',
        name: 'of',
        value: 'foam.core.FObject'
      },
      {
        name: 'fd',
        required: true
      },
      {
        name: 'offset',
        factory: function() {
          var stat = this.fs.fstatSync(this.fd);
          return stat.size;
        }
      },
      {
        name: 'fs',
        factory: function() { return require('fs'); }
      },
      {
        name: 'writePromise',
        value: Promise.resolve()
      }
    ],

    methods: [
      function put(obj) {
        return this.write_(Buffer.from(
            "put(foam.json.parse(" + foam.json.Storage.stringify(obj, this.of) +
              "));\n"));
      },

      function remove(obj) {
        return this.write_(Buffer.from(
            "remove(foam.json.parse(" +
              foam.json.Storage.stringify(obj, this.of) +
              "));\n"));
      },

      function write_(data) {
        var self = this;
        var offset = self.offset;
        self.offset += data.length;
        return self.writePromise = self.writePromise.then(function() {
          return new Promise(function(resolve, reject) {
            self.fs.write(
                self.fd, data, 0, data.length, offset,
                function(err, written, buffer) {
                  if ( err ) reject(err);
                  if ( written != data.length )
                    reject(new Error('foam.dao.NodeFileJournal: Incomplete write'));
                  resolve();
                });
          });
        });
      },

      function replay(dao) {
        var self = this;
        return new Promise(function(resolve, reject) {
          self.fs.readFile(self.fd, 'utf8', function(err, data_) {
            if ( err ) {
              reject(err);
              return;
            }

            var context = {
              put: function(o) { return dao.put(o); },
              remove: function(o) { return dao.remove(o); },
              foam: {
                json: {
                  parse: function(obj) {
                    return foam.json.parse(obj, self.of, dao.__context__);
                  }
                }
              }
            };

            with(context) eval(data_);

            resolve(dao);
          });
        });
      },
      function eof() {}
    ]
  });
}

foam.CLASS({
  package: 'foam.dao',
  name: 'JDAO',
  extends: 'foam.dao.PromisedDAO',

  properties: [
    'delegate',
    'journal',
    {
      name: 'promise',
      factory: function() {
        var self = this;
        return this.journal.replay(this.delegate).then(function(dao) {
          dao.listen(self.journal);
          return dao;
        });
      }
    },
    {
      name: 'synced',
      getter: function() {
        return Promise.all([ this.promise, this.journal.writePromise ]);
      }
    }
  ]
});
<|endoftext|>


<commit_before>'use strict'

import { client as WebSocketClient } from 'websocket'
import { EventEmitter } from 'events'
import util from 'util'
import { Logger, transports } from 'winston'
import tunnel from 'tunnel'
import SocksProxyAgent from 'socks-proxy-agent'

import Packet from './lib/packet'
import Snake from './snake'
import * as parser from './lib/parser'

import { PROTOCOL_VERSION } from './constants/slither'
import * as messages from './constants/messages'

// Bot
class Bot extends EventEmitter {
  // Options
  // name - snake name
  // server - server address to connect to
  // reconnect - whether to reconnect or not after death or disconnect
  constructor(options) {
    super()

    const { name, server, skin } = options

    this.logger = new Logger({
      level: options.logLevel || 'info',
      transports: [new transports.Console()]
    })

    this.options = options
    this.name = name
    this.server = server
    this.skin = skin

    this.conn = null
    this.connected = false

    this.leaderboard = []
    this.snakes = {}
    this.myId = null
  }

  connect(proxyServer) {
    this.logger.debug(`Connecting bot ${this.name} (${this.server})`.yellow)
    this.proxyServer = proxyServer

    const client = new WebSocketClient()
    const requestOptions = {}

    // Tunnel through proxy server if the option is there
    if(typeof proxyServer === 'string') {
      const AUTH = process.env.PROXY_AUTH || null
      let mode = 'http'
      if(proxyServer.indexOf('socks') === 0) {
        mode = 'socks'
      }

      if(mode === 'http') {
        const proxy = {
          host: proxyServer,
          port: 80
        }

        let idx = proxy.host.indexOf(':')
        if(idx > 0) {
          proxy.port = proxy.host.substring(idx + 1)
          proxy.host = proxy.host.substring(0, idx)
        }

        if(AUTH) {
          proxy.proxyAuth = AUTH
        }

        requestOptions.agent = tunnel.httpOverHttp({
          proxy
        })
      } else if(mode === 'socks') {
        // if(AUTH) {
        //   const idx = proxyServer.indexOf('socks://')
        //   proxyServer = `socks://${AUTH}@${proxyServer.substring(idx + 8)}`
        // }
        //
        // requestOptions.agent = new SocksProxyAgent(proxyServer)
        // this.logger.debug('[%s] Using %s proxy server', this.name, mode)
      }
    } else if(typeof proxyServer === 'object') {
      requestOptions.agent = proxyServer
    }

    // connectFailed
    client.on('connectFailed', err => {
      this.logger.debug('[%s] %s', this.name, err)

      this.emit('error', err)
      this.emit('errorConnect', err)
    })

    client.on('connect', this.onConnect.bind(this))
    client.connect(`ws://${this.server}/slither`, null, 'http://slither.io', null, requestOptions)
  }

  // me will return the snake that belongs to you
  me() {
    return this.snakes[this.myId]
  }

  // onConnect gets called once we successfully connect to the slither.io
  // game server
  onConnect(connection) {
    this.logger.debug(`[${this.name}] has successfully connected`.rainbow)
    this.conn = connection
    this.connected = true

    connection.on('error', error => {
      this.logger.debug('[%s] Error - %s', this.name, error)
      this.emit('error', error)
    })

    connection.on('close', this.onClose.bind(this))
    connection.on('message', this.onMessage.bind(this))

    // Send the initial packet
    // SetUsernameAndSkin
    // https://github.com/ClitherProject/Slither.io-Protocol/blob/master/Protocol.md#packet-setusernameandskin
    const initialPacket = new Packet(3 + this.name.length)
    initialPacket.put(115)
    initialPacket.put(PROTOCOL_VERSION - 1)
    initialPacket.put(this.skin || 44)
    initialPacket.putString(this.name)
    initialPacket.send(this.conn)
  }

  // onMessage
  onMessage(message) {
    if(message.type !== 'binary') {
      return
    }

    const parsedMessage = parser.parse(message.binaryData)
    if(!parsedMessage) {
      return
    }

    let snake;

    switch(parsedMessage.messageType) {
      case messages.INITIAL:
        // Make sure the protocol version matches
        if(parsedMessage.protocolVersion !== PROTOCOL_VERSION) {
          this.logger.error('[%s] Protocol version mismatch. %d > %d', this.name,
            PROTOCOL_VERSION, parsedMessage.protocolVersion)
          this.conn.close()
        }
        break

      case messages.SNAKE:
        if(parsedMessage.removing) {
          if(typeof this.snakes[parsedMessage.id] !== 'undefined') {
            const snake = this.snakes[parsedMessage.id]

            this.logger.debug('[%s] Removing snake %s', this.name,
              snake.name)
            this.emit('snakeLeft', snake, (snake.id === this.myId))

            delete this.snakes[parsedMessage.id]
          }
          return
        }

        snake = new Snake(this, parsedMessage)

        // The first snake in our view will be us
        if(!this.myId) {
          this.myId = parsedMessage.id
          this.emit('spawn', snake)
        }

        this.snakes[parsedMessage.id] = snake
        this.emit('snakeEnter', snake, (parsedMessage.id === this.myId))
        break

      case messages.LEADERBOARD:
        this.leaderboard = parsedMessage.snakes
        this.emit('leaderboard', this.leaderboard)
        break

      case messages.DEAD:
        this.logger.debug('[%s] Just died', this.name)
        this.emit('dead', parsedMessage)
        break

      case messages.EAT:
        this.emit('ate')
        break;

      case messages.POSITION:
        snake = this.snakes[parsedMessage.id]
        if(typeof snake !== 'undefined') {
          snake.x = parsedMessage.x
          snake.y = parsedMessage.y

          this.emit('snakePosition', parsedMessage, snake)

          if(snake.id === this.myId) {
            this.emit('position', parsedMessage, snake)
          }
        }
        break
    }
  }

  // onClose
  onClose(reason) {
    this.logger.debug(`[${this.name}] Disconnected (${reason})`.red)
    this.connected = false
    this.conn = null
    this.leaderboard = []
    this.snakes = {}
    this.myId = null

    this.emit('disconnected')

    // Reconnect after we close (probably died)
    if(this.options.reconnect) {
      setTimeout(() => {
        this.connect(this.proxyServer)
      }, 1000) // TODO: Make this a configuration
    }
  }

  // close
  close() {
    if(this.conn !== null) {
      this.conn.close()
    }
  }

  // toJSON
  toJSON() {
    const { id, name, server, connected, leaderboard } = this
    return {
      id,
      name,
      server,
      connected,
      leaderboard,

      // Will deal with this later
      enabled: true
    }
  }
}

// For some reason a ton of slither.io servers don't return the expected WebSocket
// accept key during handshake. This causes the bot to terminate the connection.
//
// This "Hack" will stop it from closing
//
// TODO: Figure out the cause of this
WebSocketClient.prototype.failHandshake = function(reason) {
  if(reason.indexOf('Sec-WebSocket-Accept header from server didn\'t match') >= 0) {
    // Ignore it and accept
    this.succeedHandshake()
  }
}
export default Bot
<commit_msg>Proxy Support<commit_after>'use strict'

import { client as WebSocketClient } from 'websocket'
import { EventEmitter } from 'events'
import util from 'util'
import { Logger, transports } from 'winston'
import tunnel from 'tunnel'
import SocksProxyAgent from 'socks-proxy-agent'

import Packet from './lib/packet'
import Snake from './snake'
import * as parser from './lib/parser'

import { PROTOCOL_VERSION } from './constants/slither'
import * as messages from './constants/messages'

// Bot
class Bot extends EventEmitter {
  // Options
  // name - snake name
  // server - server address to connect to
  // reconnect - whether to reconnect or not after death or disconnect
  constructor(options) {
    super()

    const { name, server, skin } = options

    this.logger = new Logger({
      level: options.logLevel || 'info',
      transports: [new transports.Console()]
    })

    this.options = options
    this.name = name
    this.server = server
    this.skin = skin

    this.conn = null
    this.connected = false

    this.leaderboard = []
    this.snakes = {}
    this.myId = null
  }

  connect(proxyServer) {
    this.logger.debug(`Connecting bot ${this.name} (${this.server})`.yellow)
    this.proxyServer = proxyServer

    const client = new WebSocketClient()
    const requestOptions = {}

    // Tunnel through proxy server if the option is there
    if(typeof proxyServer === 'string') {
      const AUTH = process.env.PROXY_AUTH || null
      let mode = 'http'
      if(proxyServer.indexOf('socks') === 0) {
        mode = 'socks'
      }

      if(mode === 'http') {
        const proxy = {
          host: proxyServer,
          port: 80
        }

        let idx = proxy.host.indexOf(':')
        if(idx > 0) {
          proxy.port = proxy.host.substring(idx + 1)
          proxy.host = proxy.host.substring(0, idx)
        }

        if(AUTH) {
          proxy.proxyAuth = AUTH
        }

        requestOptions.agent = tunnel.httpOverHttp({
          proxy
        })
      } else if (mode === 'socks5') {
                    console.log('Mode socks5, proxy', proxyServer);
                    let temp = proxyServer.split(':');
                    let socksIp = temp[0]
                    let socksPort = temp[1];
                    requestOptions.agent = new Socks.Agent({
                        proxy: {
                            ipaddress: socksIp,
                            port: socksPort,
                            type: 5
                        }
                    });
                } else if (mode === 'socks4') {
                    console.log('Mode socks4, proxy', proxyServer);
                    let temp = proxyServer.split(':');
                    let socksIp = temp[0]
                    let socksPort = temp[1];
                    requestOptions.agent = new Socks.Agent({
                        proxy: {
                            ipaddress: socksIp,
                            port: socksPort,
                            type: 4
                        }
                    });
                }
    } else if(typeof proxyServer === 'object') {
      requestOptions.agent = proxyServer
    }

    // connectFailed
    client.on('connectFailed', err => {
      this.logger.debug('[%s] %s', this.name, err)

      this.emit('error', err)
      this.emit('errorConnect', err)
    })

    client.on('connect', this.onConnect.bind(this))
    client.connect(`ws://${this.server}/slither`, null, 'http://slither.io', null, requestOptions)
  }

  // me will return the snake that belongs to you
  me() {
    return this.snakes[this.myId]
  }

  // onConnect gets called once we successfully connect to the slither.io
  // game server
  onConnect(connection) {
    this.logger.debug(`[${this.name}] has successfully connected`.rainbow)
    this.conn = connection
    this.connected = true

    connection.on('error', error => {
      this.logger.debug('[%s] Error - %s', this.name, error)
      this.emit('error', error)
    })

    connection.on('close', this.onClose.bind(this))
    connection.on('message', this.onMessage.bind(this))

    // Send the initial packet
    // SetUsernameAndSkin
    // https://github.com/ClitherProject/Slither.io-Protocol/blob/master/Protocol.md#packet-setusernameandskin
    const initialPacket = new Packet(3 + this.name.length)
    initialPacket.put(115)
    initialPacket.put(PROTOCOL_VERSION - 1)
    initialPacket.put(this.skin || 44)
    initialPacket.putString(this.name)
    initialPacket.send(this.conn)
  }

  // onMessage
  onMessage(message) {
    if(message.type !== 'binary') {
      return
    }

    const parsedMessage = parser.parse(message.binaryData)
    if(!parsedMessage) {
      return
    }

    let snake;

    switch(parsedMessage.messageType) {
      case messages.INITIAL:
        // Make sure the protocol version matches
        if(parsedMessage.protocolVersion !== PROTOCOL_VERSION) {
          this.logger.error('[%s] Protocol version mismatch. %d > %d', this.name,
            PROTOCOL_VERSION, parsedMessage.protocolVersion)
          this.conn.close()
        }
        break

      case messages.SNAKE:
        if(parsedMessage.removing) {
          if(typeof this.snakes[parsedMessage.id] !== 'undefined') {
            const snake = this.snakes[parsedMessage.id]

            this.logger.debug('[%s] Removing snake %s', this.name,
              snake.name)
            this.emit('snakeLeft', snake, (snake.id === this.myId))

            delete this.snakes[parsedMessage.id]
          }
          return
        }

        snake = new Snake(this, parsedMessage)

        // The first snake in our view will be us
        if(!this.myId) {
          this.myId = parsedMessage.id
          this.emit('spawn', snake)
        }

        this.snakes[parsedMessage.id] = snake
        this.emit('snakeEnter', snake, (parsedMessage.id === this.myId))
        break

      case messages.LEADERBOARD:
        this.leaderboard = parsedMessage.snakes
        this.emit('leaderboard', this.leaderboard)
        break

      case messages.DEAD:
        this.logger.debug('[%s] Just died', this.name)
        this.emit('dead', parsedMessage)
        break

      case messages.EAT:
        this.emit('ate')
        break;

      case messages.POSITION:
        snake = this.snakes[parsedMessage.id]
        if(typeof snake !== 'undefined') {
          snake.x = parsedMessage.x
          snake.y = parsedMessage.y

          this.emit('snakePosition', parsedMessage, snake)

          if(snake.id === this.myId) {
            this.emit('position', parsedMessage, snake)
          }
        }
        break
    }
  }

  // onClose
  onClose(reason) {
    this.logger.debug(`[${this.name}] Disconnected (${reason})`.red)
    this.connected = false
    this.conn = null
    this.leaderboard = []
    this.snakes = {}
    this.myId = null

    this.emit('disconnected')

    // Reconnect after we close (probably died)
    if(this.options.reconnect) {
      setTimeout(() => {
        this.connect(this.proxyServer)
      }, 1000) // TODO: Make this a configuration
    }
  }

  // close
  close() {
    if(this.conn !== null) {
      this.conn.close()
    }
  }

  // toJSON
  toJSON() {
    const { id, name, server, connected, leaderboard } = this
    return {
      id,
      name,
      server,
      connected,
      leaderboard,

      // Will deal with this later
      enabled: true
    }
  }
}

// For some reason a ton of slither.io servers don't return the expected WebSocket
// accept key during handshake. This causes the bot to terminate the connection.
//
// This "Hack" will stop it from closing
//
// TODO: Figure out the cause of this
WebSocketClient.prototype.failHandshake = function(reason) {
  if(reason.indexOf('Sec-WebSocket-Accept header from server didn\'t match') >= 0) {
    // Ignore it and accept
    this.succeedHandshake()
  }
}
export default Bot
<|endoftext|>


<commit_before>import debug from 'debug'
import TelegramBot from 'node-telegram-bot-api'
import { TapIfRepository } from './repositories'

const logTap = debug('tap-if-bot:bot')

/**
 * @class TapIfBot
 */
export class TapIfBot {

    static async build({ token, telegramBotOptions, database }) {
        const conf = Object.assign({
            polling: { autoStart: false }
        }, telegramBotOptions)
        const bot = new TelegramBot(token, conf)
        const db = await new TapIfRepository.build(database)
        return new TapIfBot({ bot, db })
    }

    constructor({ bot, db }) {
        this.bot = bot
        this.db = db
        // Setup listeners
        this.bot.onText(/^\/tapif([a-z0-9\s]+)/i, (...args) => this.recordTap(...args))
        this.bot.onText(/^\/taps/i, (...args) => this.sendReport(...args))
        this.bot.onText(/^\/reset/, (...args) => this.resetTaps(...args))
        this.bot.onText(/^\/help/, (...args) => this.sendHelp(...args))
    }

    start() {
        if (!this.bot.isPolling())
            this.bot.initPolling()
    }

    async stop() {
        if (this.bot.isPolling())
            await this.bot.stopPolling()
    }

    async recordTap(msg, match) {
        const { from: { id: userId }, chat: { id: chatId } } = msg
        let [ , tapMessage ] = match
        tapMessage = tapMessage.trim().replace(/\s+/g, ' ')
        logTap(`got tap ${ tapMessage } from ${ userId } at ${ chatId }`)
        await this.db.storeTap(chatId, userId, tapMessage)
    }

    async sendReport(msg) {
        const { chat: { id: chatId } } = msg
        const taps = await this.db.getTaps(chatId)
        const report = taps.reduce((rep, tapRep) => {
            const { message, taps, uniqueTaps } = tapRep
            rep += `${ message }: *${ uniqueTaps }*/${ taps }  \n`
            return rep
        }, `Taps report:  \n`)
        logTap(`sending report for ${ chatId }, taps in record: ${ taps.length }`)
        await this.bot.sendMessage(chatId, report, { parse_mode: 'Markdown' })
    }

    async sendHelp(msg) {
        const { chat: { id: chatId } } = msg
        logTap(`sending report for ${ chatId }, length: ${ report.length }`)
        await this.bot.sendMessage(chatId, `I'll keep count of any time a /TapIfSomething is sent on the chat!`)
    }

    async resetTaps(msg) {
        const { chat: { id: chatId } } = msg
        await this.sendReport(msg)
        await this.db.deleteTaps(chatId)
        await this.bot.sendMessage(`Deleted all recorded taps!`)
    }
}
<commit_msg>Inform when there are no taps on record<commit_after>import debug from 'debug'
import TelegramBot from 'node-telegram-bot-api'
import { TapIfRepository } from './repositories'

const logTap = debug('tap-if-bot:bot')

/**
 * @class TapIfBot
 */
export class TapIfBot {

    static async build({ token, telegramBotOptions, database }) {
        const conf = Object.assign({
            polling: { autoStart: false }
        }, telegramBotOptions)
        const bot = new TelegramBot(token, conf)
        const db = await new TapIfRepository.build(database)
        return new TapIfBot({ bot, db })
    }

    constructor({ bot, db }) {
        this.bot = bot
        this.db = db
        // Setup listeners
        this.bot.onText(/^\/tapif([a-z0-9\s]+)/i, (...args) => this.recordTap(...args))
        this.bot.onText(/^\/taps/i, (...args) => this.sendReport(...args))
        this.bot.onText(/^\/reset/, (...args) => this.resetTaps(...args))
        this.bot.onText(/^\/help/, (...args) => this.sendHelp(...args))
    }

    start() {
        if (!this.bot.isPolling())
            this.bot.initPolling()
    }

    async stop() {
        if (this.bot.isPolling())
            await this.bot.stopPolling()
    }

    async recordTap(msg, match) {
        const { from: { id: userId }, chat: { id: chatId } } = msg
        let [ , tapMessage ] = match
        tapMessage = tapMessage.trim().replace(/\s+/g, ' ')
        logTap(`got tap ${ tapMessage } from ${ userId } at ${ chatId }`)
        await this.db.storeTap(chatId, userId, tapMessage)
    }

    async sendReport(msg) {
        const { chat: { id: chatId } } = msg
        logTap(`sending report for ${ chatId }, taps in record: ${ taps.length }`)
        const taps = await this.db.getTaps(chatId)
        if (taps.lenght > 0) {
            const report = taps.reduce((rep, tapRep) => {
                const { message, taps, uniqueTaps } = tapRep
                rep += `${ message }: *${ uniqueTaps }*/${ taps }  \n`
                return rep
            }, `Taps report:  \n`)
            await this.bot.sendMessage(chatId, report, { parse_mode: 'Markdown' })
        } else
            await this.bot.sendMessage(chatId, `No taps recorded for this chat`, { parse_mode: 'Markdown' })

    }

    async sendHelp(msg) {
        const { chat: { id: chatId } } = msg
        logTap(`sending report for ${ chatId }, length: ${ report.length }`)
        await this.bot.sendMessage(chatId, `I'll keep count of any time a /TapIfSomething is sent on the chat!`)
    }

    async resetTaps(msg) {
        const { chat: { id: chatId } } = msg
        await this.sendReport(msg)
        await this.db.deleteTaps(chatId)
        await this.bot.sendMessage(`Deleted all recorded taps!`)
    }
}
<|endoftext|>


<commit_before>// Dependencies =========================
var Twit = require('twit');
var ura = require('unique-random-array');
var config = require('./config');
var strings = require('./helpers/strings');
var sentiment = require('./helpers/sentiment');

var Twitter = new Twit(config);

// Frequency in minutes
var retweetFrequency = 93;
var favoriteFrequency = 56;

// RANDOM QUERY STRING  =========================

var qs = ura(strings.queryString);
var qsSq = ura(strings.queryStringSubQuery);
var rt = ura(strings.resultType);
//var rs = ura(strings.responseString);

// https://dev.twitter.com/rest/reference/get/search/tweets
// A UTF-8, URL-encoded search query of 500 characters maximum, including operators.
// Queries may additionally be limited by complexity.

// RETWEET BOT ==========================

// find latest tweet according the query 'q' in params

// result_type: options, mixed, recent, popular
// * mixed : Include both popular and real time results in the response.
// * recent : return only the most recent results in the response
// * popular : return only the most popular results in the response.

var retweet = function () {
  var paramQS = qs();
  paramQS += qsSq();
  var paramRT = rt();
  var params = {
    q: paramQS,
    result_type: paramRT,
    lang: 'en'
  };

  Twitter.get('search/tweets', params, function (err, data) {
        // if there no errors
    if (!err) {
            // grab ID of tweet to retweet
      try {
                // run sentiment check ==========
        var tweets = data.statuses;
        var randomTweet = ranDom(tweets);
        var retweetId = randomTweet.id_str;
        var retweetText = randomTweet.text;

                // setup http call
        var httpCall = sentiment.init();

        httpCall.send('txt=' + retweetText).end(function (result) {
          var sentim = result.body.result.sentiment;
          var confidence = parseFloat(result.body.result.confidence);
          console.log(confidence, sentim);
          // if sentiment is Negative and the confidence is above 75%
          if (sentim === 'Negative' && confidence >= 75) {
            console.log('RETWEET NEG NEG NEG', sentim, retweetText)
            return
          }
        })
      } catch (e) {
        console.log('retweetId DERP!', e.message, 'Query String:', paramQS + ' TweetId: ' + retweetId + ' Tweet: ' + retweetText);
        return
      }
            // Tell TWITTER to retweet
      Twitter.post('statuses/retweet/:id', {
        id: retweetId
      }, function (err, response) {
        if (response) {
          console.log('RETWEETED!', ' Query String:', paramQS + ' TweetId: ' + retweetId + ' Tweet: ' + retweetText)
        }
                // if there was an error while tweeting
        if (err) {
          console.log('RETWEET ERROR! Duplication maybe...:', err, 'Query String:', paramQS + ' TweetId: ' + retweetId + ' Tweet: ' + retweetText);
        }
      })
    } else { console.log('Something went wrong while SEARCHING... ' + err.message) }
  })
}

// retweet on bot start
retweet();
    // retweet in every x minutes
setInterval(retweet, 1000 * 60 * retweetFrequency);

// FAVORITE BOT====================

// find a random tweet and 'favorite' it
var favoriteTweet = function () {
  var paramQS = qs();
  paramQS += qsSq();
  var paramRT = rt();
  var params = {
    q: paramQS + paramBls(),
    result_type: paramRT,
    lang: 'en'
  };

    // find the tweet
  Twitter.get('search/tweets', params, function (err, data) {
        // find tweets
    var tweet = data.statuses;
    var randomTweet = ranDom(tweet); // pick a random tweet

        // if random tweet exists
    if (typeof randomTweet !== 'undefined') {
            // run sentiment check ==========
            // setup http call
      var httpCall = sentiment.init();
      var favoriteText = randomTweet['text'];

      httpCall.send('txt=' + favoriteText).end(function (result) {
        var sentim = result.body.result.sentiment;
        var confidence = parseFloat(result.body.result.confidence);
        console.log(confidence, sentim)
        // if sentiment is Negative and the confidence is above 75%
        if (sentim === 'Negative' && confidence >= 75) {
          console.log('FAVORITE NEG NEG NEG', sentim, favoriteText)
          return
        }
      })

            // Tell TWITTER to 'favorite'
      Twitter.post('favorites/create', {
        id: randomTweet.id_str
      }, function (err, response) {
                // if there was an error while 'favorite'
        if (err) {
          console.log('CANNOT BE FAVORITED... Error: ', err, ' Query String: ' + paramQS + ' TweetId: ' + randomTweet.id_str + ' TweetText: ' + randomTweet.text);
        } else {
          console.log('FAVORITED... Success!!!', ' Query String: ' + paramQS + ' TweetId: ' + randomTweet.id_str + ' TweetText: ' + randomTweet.text);
        }
      })
    }
  })
}

// favorite on bot start
favoriteTweet();
    // favorite in every x minutes
setInterval(favoriteTweet, 1000 * 60 * favoriteFrequency);

// STREAM API for interacting with a USER =======
// set up a user stream
//var stream = Twitter.stream('user');

// REPLY-FOLLOW BOT ============================

// what to do when someone follows you?
//stream.on('follow', followed)

// ...trigger the callback
// function followed (event) {
//   console.log('Follow Event now RUNNING')
//         // get USER's twitter handle (screen name)
//   var screenName = event.source.screen_name

//     // CREATE RANDOM RESPONSE  ============================
//   // var responseString = rs()
//   // var find = 'screenName'
//   // var regex = new RegExp(find, 'g')
//   // responseString = responseString.replace(regex, screenName)

//   // function that replies back to every USER who followed for the first time
//   //console.log(responseString)
//   // Don't want to send these messages out
//   //tweetNow(responseString)
// }

// function definition to tweet back to USER who followed
function tweetNow (tweetTxt) {
  var tweet = {
    status: tweetTxt
  }

    // HARCODE user name in and check before RT
  var n = tweetTxt.search(/@DesignPuddle/i)

  if (n !== -1) {
    console.log('TWEET SELF! Skipped!!')
  } else {
    Twitter.post('statuses/update', tweet, function (err, data, response) {
      if (err) {
        console.log('Cannot Reply to Follower. ERROR!: ' + err)
      } else {
        console.log('Reply to follower. SUCCESS!')
      }
    })
  }
}

// function to generate a random tweet tweet
function ranDom (arr) {
  var index = Math.floor(Math.random() * arr.length);
  console.log('Random Value:' + index + " of ArraySize " + arr.length);
  return arr[index];
}

function paramBls () {
  var ret = '';
  var arr = strings.blockedStrings;
  var i;
  var n;
  for (i = 0, n = arr.length; i < n; i++) {
    ret += ' -' + arr[i];
  }
  return ret;
}
<commit_msg>Test Commit to branch Please enter the commit message for your changes. Lines starting<commit_after>// Dependencies =========================
var Twit = require('twit');
var ura = require('unique-random-array');
var config = require('./config');
var strings = require('./helpers/strings');
var sentiment = require('./helpers/sentiment');

var Twitter = new Twit(config);

// Frequency in minutes
var retweetFrequency = 93; // Change to random value
var favoriteFrequency = 56;

// RANDOM QUERY STRING  =========================

var qs = ura(strings.queryString);
var qsSq = ura(strings.queryStringSubQuery);
var rt = ura(strings.resultType);
//var rs = ura(strings.responseString);

// https://dev.twitter.com/rest/reference/get/search/tweets
// A UTF-8, URL-encoded search query of 500 characters maximum, including operators.
// Queries may additionally be limited by complexity.

// RETWEET BOT ==========================

// find latest tweet according the query 'q' in params

// result_type: options, mixed, recent, popular
// * mixed : Include both popular and real time results in the response.
// * recent : return only the most recent results in the response
// * popular : return only the most popular results in the response.

var retweet = function () {
  var paramQS = qs();
  paramQS += qsSq();
  var paramRT = rt();
  var params = {
    q: paramQS,
    result_type: paramRT,
    lang: 'en'
  };

  Twitter.get('search/tweets', params, function (err, data) {
        // if there no errors
    if (!err) {
            // grab ID of tweet to retweet
      try {
                // run sentiment check ==========
        var tweets = data.statuses;
        var randomTweet = ranDom(tweets);
        var retweetId = randomTweet.id_str;
        var retweetText = randomTweet.text;

                // setup http call
        var httpCall = sentiment.init();

        httpCall.send('txt=' + retweetText).end(function (result) {
          var sentim = result.body.result.sentiment;
          var confidence = parseFloat(result.body.result.confidence);
          console.log(confidence, sentim);
          // if sentiment is Negative and the confidence is above 75%
          if (sentim === 'Negative' && confidence >= 75) {
            console.log('RETWEET NEG NEG NEG', sentim, retweetText)
            return
          }
        })
      } catch (e) {
        console.log('retweetId DERP!', e.message, 'Query String:', paramQS + ' TweetId: ' + retweetId + ' Tweet: ' + retweetText);
        return
      }
            // Tell TWITTER to retweet
      Twitter.post('statuses/retweet/:id', {
        id: retweetId
      }, function (err, response) {
        if (response) {
          console.log('RETWEETED!', ' Query String:', paramQS + ' TweetId: ' + retweetId + ' Tweet: ' + retweetText)
        }
                // if there was an error while tweeting
        if (err) {
          console.log('RETWEET ERROR! Duplication maybe...:', err, 'Query String:', paramQS + ' TweetId: ' + retweetId + ' Tweet: ' + retweetText);
        }
      })
    } else { console.log('Something went wrong while SEARCHING... ' + err.message) }
  })
}

// retweet on bot start
retweet();
    // retweet in every x minutes
setInterval(retweet, 1000 * 60 * retweetFrequency);

// FAVORITE BOT====================

// find a random tweet and 'favorite' it
var favoriteTweet = function () {
  var paramQS = qs();
  paramQS += qsSq();
  var paramRT = rt();
  var params = {
    q: paramQS + paramBls(),
    result_type: paramRT,
    lang: 'en'
  };

    // find the tweet
  Twitter.get('search/tweets', params, function (err, data) {
        // find tweets
    var tweet = data.statuses;
    var randomTweet = ranDom(tweet); // pick a random tweet

        // if random tweet exists
    if (typeof randomTweet !== 'undefined') {
            // run sentiment check ==========
            // setup http call
      var httpCall = sentiment.init();
      var favoriteText = randomTweet['text'];

      httpCall.send('txt=' + favoriteText).end(function (result) {
        var sentim = result.body.result.sentiment;
        var confidence = parseFloat(result.body.result.confidence);
        console.log(confidence, sentim)
        // if sentiment is Negative and the confidence is above 75%
        if (sentim === 'Negative' && confidence >= 75) {
          console.log('FAVORITE NEG NEG NEG', sentim, favoriteText)
          return
        }
      })

            // Tell TWITTER to 'favorite'
      Twitter.post('favorites/create', {
        id: randomTweet.id_str
      }, function (err, response) {
                // if there was an error while 'favorite'
        if (err) {
          console.log('CANNOT BE FAVORITED... Error: ', err, ' Query String: ' + paramQS + ' TweetId: ' + randomTweet.id_str + ' TweetText: ' + randomTweet.text);
        } else {
          console.log('FAVORITED... Success!!!', ' Query String: ' + paramQS + ' TweetId: ' + randomTweet.id_str + ' TweetText: ' + randomTweet.text);
        }
      })
    }
  })
}

// favorite on bot start
favoriteTweet();
    // favorite in every x minutes
setInterval(favoriteTweet, 1000 * 60 * favoriteFrequency);

// function definition to tweet back to USER who followed
function tweetNow (tweetTxt) {
  var tweet = {
    status: tweetTxt
  }

    // HARCODE user name in and check before RT
  var n = tweetTxt.search(/@DesignPuddle/i)

  if (n !== -1) {
    console.log('TWEET SELF! Skipped!!')
  } else {
    Twitter.post('statuses/update', tweet, function (err, data, response) {
      if (err) {
        console.log('Cannot Reply to Follower. ERROR!: ' + err)
      } else {
        console.log('Reply to follower. SUCCESS!')
      }
    })
  }
}

// function to generate a random tweet tweet
function ranDom (arr) {
  var index = Math.floor(Math.random() * arr.length);
  console.log('Random Value:' + index + " of ArraySize " + arr.length);
  return arr[index];
}

function paramBls () {
  var ret = '';
  var arr = strings.blockedStrings;
  var i;
  var n;
  for (i = 0, n = arr.length; i < n; i++) {
    ret += ' -' + arr[i];
  }
  return ret;
}
<|endoftext|>


<commit_before>/*
    Flan ES6 by Capuccino
    Original ES5 code by Ovyerus and MokouFujiwara
    Licensed under MIT.
    Copyright (c) 2016-2016 Capuccino, Ovyerus, MokouFujiwara, et al.
*/

//Framework imports
const { Discord } = require("discord.js");
const { fs } = require("fs");
const { util } = require("util");
const { JsonDB } = require("node-json-db");

//Constants
const config = require('./config.json');
const bot = new Discord.Client();
const data = new JsonDB('data', true, true);

//Init
bot.on('ready', () => {
    require('./init_commands.js').init();
    console.log("Auth token: " + config.auth);
    if (!data.data.admins) data.push('/', { admins: [] }, false);
    if (!data.data.blacklist) data.push('/', { blacklist: [] }, false);
    bot.config = config;
    bot.data = data;
});
//Don't place anything here, commands have their own JS files.
var commands = {};
// Synchronously works with init_commands.js. After init_commands checks for deps and returns a functioning command,
// this exports the following functioning command. Obsolete/broken commands aren't exported for a reason.
// We like to keep it that way.
export function addCommand(commandName, commandObject) {
    try {
        commands[commandName] = commandObject;
    } catch (err) {
        console.log(err);
    }
}
export function commandCount() {
    return Object.keys(commands).length;
};
bot.on("message", () => {
    //giant ass CMD thing CP'ed from flan-chanbot.
    if (msg.content.startsWith(config.prefix)) {
        const args = msg.content.substring(config.prefix.length, msg.content.length).split(' ');
        const cmd = args.shift();
        const suffix = args.join(' ');
        if (commands[cmd] !== undefined) {
            if (data.getData('/blacklist').indexOf(msg.author.id) !== -1) return;
            try {
                if (commands[cmd].adminOnly && data.getData('/admins').indexOf(msg.author.id) !== -1) {
                    commands[cmd].main(bot, { msg: msg, args: args, suffix: suffix });
                } else if (commands[cmd].adminOnly && data.data.getData('/admins').indexOf(msg.author.id) === -1) {
                    msg.channel.sendMessage('That command is restricted to the bot owner/s.');
                } else {
                    commands[cmd].main(bot, { msg: msg, args: args, suffix: suffix });
                }
            } catch (err) {
                console.log(err);
                var errMsg = `Unexpected error while executing commmand \`${cmd}\`\n`;
                errMsg += '```js\n';
                errMsg += err + '\n';
                errMsg += '```';
                msg.channel.sendMessage(errMsg);
            }
        }
    }

    if (msg.content.startsWith("<@" + bot.user.id + "> prefix")) {
        bot.reply(msg.channel.id, "***My prefix is *** `" + coinfig.prefix + "`!");
    }
});

!config.useEmail ? bot.login(config.token) : bot.login(config.email, config.password);<commit_msg>revert export command function to ES5<commit_after>/*
    Flan ES6 by Capuccino
    Original ES5 code by Ovyerus and MokouFujiwara
    Licensed under MIT.
    Copyright (c) 2016-2016 Capuccino, Ovyerus, MokouFujiwara, et al.
*/

//Framework imports
const { Discord } = require("discord.js");
const { fs } = require("fs");
const { util } = require("util");
const { JsonDB } = require("node-json-db");

//Constants
const config = require('./config.json');
const bot = new Discord.Client();
const data = new JsonDB('data', true, true);

//Init
bot.on('ready', () => {
    require('./init_commands.js').init();
    console.log("Auth token: " + config.auth);
    if (!data.data.admins) data.push('/', { admins: [] }, false);
    if (!data.data.blacklist) data.push('/', { blacklist: [] }, false);
    bot.config = config;
    bot.data = data;
});
//Don't place anything here, commands have their own JS files.
var commands = {};
// Synchronously works with init_commands.js. After init_commands checks for deps and returns a functioning command,
// this exports the following functioning command. Obsolete/broken commands aren't exported for a reason.
// We like to keep it that way.
exports.addCommand = function(commandName, commandObject) {
    try {
        commands[commandName] = commandObject;
    } catch (err) {
        console.log(err);
    }
}
exports.commandCount = function() {
    return Object.keys(commands).length;
};
bot.on("message", () => {
    //giant ass CMD thing CP'ed from flan-chanbot.
    if (msg.content.startsWith(config.prefix)) {
        const args = msg.content.substring(config.prefix.length, msg.content.length).split(' ');
        const cmd = args.shift();
        const suffix = args.join(' ');
        if (commands[cmd] !== undefined) {
            if (data.getData('/blacklist').indexOf(msg.author.id) !== -1) return;
            try {
                if (commands[cmd].adminOnly && data.getData('/admins').indexOf(msg.author.id) !== -1) {
                    commands[cmd].main(bot, { msg: msg, args: args, suffix: suffix });
                } else if (commands[cmd].adminOnly && data.data.getData('/admins').indexOf(msg.author.id) === -1) {
                    msg.channel.sendMessage('That command is restricted to the bot owner/s.');
                } else {
                    commands[cmd].main(bot, { msg: msg, args: args, suffix: suffix });
                }
            } catch (err) {
                console.log(err);
                var errMsg = `Unexpected error while executing commmand \`${cmd}\`\n`;
                errMsg += '```js\n';
                errMsg += err + '\n';
                errMsg += '```';
                msg.channel.sendMessage(errMsg);
            }
        }
    }

    if (msg.content.startsWith("<@" + bot.user.id + "> prefix")) {
        bot.reply(msg.channel.id, "***My prefix is *** `" + coinfig.prefix + "`!");
    }
});

!config.useEmail ? bot.login(config.token) : bot.login(config.email, config.password);<|endoftext|>


<commit_before>'use strict';
import Promise from "native-promise-only";
import FormioForm from './formio.form';
import Formio from './formio';
import FormioUtils from './utils';
import each from 'lodash/each';
import clone from 'lodash/clone';
export class FormioWizard extends FormioForm {
  constructor(element, options) {
    super(element, options);
    this.wizard = null;
    this.pages = [];
    this.globalComponents = [];
    this.page = 0;
    this.history = [];
    this._nextPage = 0;
  }

  setPage(num) {
    if (!this.wizard.full && num >= 0 && num < this.pages.length) {
      this.page = num;
      return super.setForm(this.currentPage());
    }
    else if (this.wizard.full) {
      return super.setForm(this.getWizard());
    }
    return Promise.reject('Page not found');
  }

  getNextPage(data, currentPage) {
    let form = this.pages[currentPage];
    // Check conditional nextPage
    if (form) {
      let page = ++currentPage;
      if (form.nextPage) {
        // Allow for script execution.
        if (typeof form.nextPage === 'string') {
          try {
            let next = page;
            eval('(function(data) {' + form.nextPage.toString() + '})(data)');
            page = next;
            if (!isNaN(parseInt(page, 10)) && isFinite(page)) {
              return page;
            }
            if (typeof page !== 'string') {
              return page;
            }

            // Assume they passed back the key of the page to go to.
            return this.getPageIndexByKey(page);
          }
          catch (e) {
            console.warn('An error occurred in a custom nextPage function statement for component ' + form.key, e);
            return page;
          }
        }
        // Or use JSON Logic.
        else {
          let result = FormioUtils.jsonLogic.apply(form.nextPage, {
            data: data,
            page: page,
            form: form
          });
          let newPage = parseInt(result, 10);
          if (!isNaN(parseInt(newPage, 10)) && isFinite(newPage)) {
            return newPage;
          }

          return this.getPageIndexByKey(result);
        }
      }

      return page;
    }

    return null;
  }

  getPreviousPage() {
    let prev = this.history.pop();
    if(typeof prev !== 'undefined') {
      return prev;
    }

    return this.page - 1;
  }

  nextPage() {
    // Validate the form builed, before go to the next page
    if (this.checkValidity(this.submission.data, true)) {
      this.checkData(this.submission.data, {
        noValidate: true
      });
      return this.beforeNext().then(() => {
        this.history.push(this.page);
        return this.setPage(this.getNextPage(this.submission.data, this.page)).then(() => {
          this._nextPage = this.getNextPage(this.submission.data, this.page);
          this.emit('nextPage', {page: this.page, submission: this.submission});
        });
      });
    }
    else {
      return Promise.reject(this.showErrors());
    }
  }

  prevPage() {
    let prevPage = this.getPreviousPage();
    return this.setPage(prevPage).then(() => {
      this.emit('prevPage', {page: this.page, submission: this.submission});
    });
  }

  cancel() {
    super.cancel();
    this.history = [];
    return this.setPage(0);
  }

  getPageIndexByKey(key) {
    let pageIndex = 0;
    each(this.pages, (_page, index) => {
      if (_page.key === key) {
        pageIndex = index;
        return false;
      }
    });
    return pageIndex;
  }

  addGlobalComponents(page) {
    // If there are non-page components, then add them here. This is helpful to allow for hidden fields that
    // can propogate between pages.
    if (this.globalComponents.length) {
      page.components = this.globalComponents.concat(page.components);
    }
    return page;
  }

  getPage(pageNum) {
    if ((pageNum >= 0) && (pageNum < this.pages.length)) {
      return this.addGlobalComponents(this.pages[pageNum]);
    }
    return null;
  }

  getWizard() {
    let pageIndex = 0;
    let page = null;
    let wizard = clone(this.wizard);
    wizard.components = [];
    do {
      page = this.getPage(pageIndex);
      if (page) {
        wizard.components.push(page);
      }
    } while (pageIndex = this.getNextPage(this.submission.data, pageIndex));

    // Add all other components.
    each(this.wizard.components, (component) => {
      if (component.type !== 'panel') {
        wizard.components.push(component);
      }
    });

    return wizard;
  }

  currentPage() {
    return this.getPage(this.page);
  }

  buildPages(form) {
    this.pages = [];
    each(form.components, (component) => {
      if (component.type === 'panel') {
        // Ensure that this page can be seen.
        if (FormioUtils.checkCondition(component, this.data, this.data)) {
          this.pages.push(component);
        }
      }
      else if (component.type === 'hidden') {
        // Global components are hidden components that can propagate between pages.
        this.globalComponents.push(component);
      }
    });
    this.buildWizardHeader();
    this.buildWizardNav();
  }

  setForm(form) {
    if (!form) {
      return;
    }
    this.wizard = form;
    this.buildPages(this.wizard);
    return this.setPage(this.page);
  }

  build() {
    super.build();
    this.formReady.then(() => {
      this.buildWizardHeader();
      this.buildWizardNav();
    });
  }

  hasButton(name, nextPage) {
    if (name === 'previous') {
      return (this.page > 0);
    }
    nextPage = (nextPage === undefined) ? this.getNextPage(this.submission.data, this.page) : nextPage;
    if (name === 'next') {
      return (nextPage !== null) && (nextPage < this.pages.length);
    }
    if (name === 'submit') {
      return (nextPage === null) || (this.page === (this.pages.length - 1));
    }
    return true;
  }

  buildWizardHeader() {
    if (this.wizardHeader) {
      this.wizardHeader.innerHTML = '';
    }

    let currentPage = this.currentPage();
    if (!currentPage || this.wizard.full) {
      return;
    }

    currentPage.breadcrumb = currentPage.breadcrumb || 'default';
    if (currentPage.breadcrumb.toLowerCase() === 'none') {
      return;
    }

    this.wizardHeader = this.ce('ul', {
      class: 'pagination'
    });

    // Add the header to the beginning.
    this.prepend(this.wizardHeader);

    let showHistory = (currentPage.breadcrumb.toLowerCase() === 'history');
    each(this.pages, (page, i) => {
      // See if this page is in our history.
      if (showHistory && ((this.page !== i) && !this.history.includes(i))) {
        return;
      }

      let pageButton = this.ce('li', {
        class: (i === this.page) ? 'active' : '',
        style: (i === this.page) ? '' : 'cursor: pointer;'
      });

      // Navigate to the page as they click on it.
      if (this.page !== i) {
        this.addEventListener(pageButton, 'click', (event) => {
          event.preventDefault();
          this.setPage(i);
        });
      }

      let pageLabel = this.ce('span');
      let pageTitle = page.title;
      if (currentPage.breadcrumb.toLowerCase() === 'condensed') {
        pageTitle = ((i === this.page) || showHistory) ? page.title : (i + 1);
        if (!pageTitle) {
          pageTitle = (i + 1);
        }
      }

      pageLabel.appendChild(this.text(pageTitle));
      pageButton.appendChild(pageLabel);
      this.wizardHeader.appendChild(pageButton);
    });
  }

  pageId(page) {
    if (page.key) {
      return page.key;
    }
    else if (
      page.components &&
      page.components.length > 0
    ) {
      return this.pageId(page.components[0]);
    }
    else {
      return page.title;
    }
  }

  onChange(flags, changed) {
    super.onChange(flags, changed);

    // Only rebuild if there is a page change.
    let pageIndex = 0;
    let rebuild = false;
    each(this.wizard.components, (component) => {
      if (component.type !== 'panel') {
        return;
      }

      if (FormioUtils.hasCondition(component)) {
        let hasPage = this.pages && this.pages[pageIndex] && (this.pageId(this.pages[pageIndex]) === this.pageId(component));
        let shouldShow = FormioUtils.checkCondition(component, this.data, this.data);
        if ((shouldShow && !hasPage) || (!shouldShow && hasPage)) {
          rebuild = true;
          return false;
        }
        if (shouldShow) {
          pageIndex++;
        }
      }
      else {
        pageIndex++;
      }
    });

    if (rebuild) {
      this.setForm(this.wizard);
    }

    // Update Wizard Nav
    let nextPage = this.getNextPage(this.submission.data, this.page);
    if (this._nextPage != nextPage) {
      this.buildWizardNav(nextPage);
      this.emit('updateWizardNav', {oldpage: this._nextPage, newpage: nextPage, submission: this.submission});
      this._nextPage = nextPage;
    }
  }

  buildWizardNav(nextPage) {
    if (this.wizardNav) {
      this.wizardNav.innerHTML = '';
      if (this.element.contains(this.wizardNav)) {
        this.element.removeChild(this.wizardNav);
      }
    }
    if (this.wizard.full) {
      return;
    }
    this.wizardNav = this.ce('ul', {
      class: 'list-inline'
    });
    this.element.appendChild(this.wizardNav);
    each([
      {name: 'cancel',    method: 'cancel',   class: 'btn btn-default'},
      {name: 'previous',  method: 'prevPage', class: 'btn btn-primary'},
      {name: 'next',      method: 'nextPage', class: 'btn btn-primary'},
      {name: 'submit',    method: 'submit',   class: 'btn btn-primary'}
    ], (button) => {
      if (!this.hasButton(button.name, nextPage)) {
        return;
      }
      let buttonWrapper = this.ce('li');
      let buttonProp = button.name + 'Button';
      this[buttonProp] = this.ce('button', {
        class: button.class + ' btn-wizard-nav-' + button.name
      });
      this[buttonProp].appendChild(this.text(this.t(button.name)));
      this.addEventListener(this[buttonProp], 'click', (event) => {
        event.preventDefault();
        this[button.method]();
      });
      buttonWrapper.appendChild(this[buttonProp]);
      this.wizardNav.appendChild(buttonWrapper);
    });
  }
}

FormioWizard.setBaseUrl = Formio.setBaseUrl;
FormioWizard.setApiUrl = Formio.setApiUrl;
FormioWizard.setAppUrl = Formio.setAppUrl;

module.exports = global.FormioWizard = FormioWizard;
<commit_msg>Adding Optional "BreadcrumbSettings" to options<commit_after>'use strict';
import Promise from "native-promise-only";
import FormioForm from './formio.form';
import Formio from './formio';
import FormioUtils from './utils';
import each from 'lodash/each';
import clone from 'lodash/clone';
export class FormioWizard extends FormioForm {
  constructor(element, options) {
    super(element, options);
    this.wizard = null;
    this.pages = [];
    this.globalComponents = [];
    this.page = 0;
    this.history = [];
    this._nextPage = 0;
  }

  setPage(num) {
    if (!this.wizard.full && num >= 0 && num < this.pages.length) {
      this.page = num;
      return super.setForm(this.currentPage());
    }
    else if (this.wizard.full) {
      return super.setForm(this.getWizard());
    }
    return Promise.reject('Page not found');
  }

  getNextPage(data, currentPage) {
    let form = this.pages[currentPage];
    // Check conditional nextPage
    if (form) {
      let page = ++currentPage;
      if (form.nextPage) {
        // Allow for script execution.
        if (typeof form.nextPage === 'string') {
          try {
            let next = page;
            eval('(function(data) {' + form.nextPage.toString() + '})(data)');
            page = next;
            if (!isNaN(parseInt(page, 10)) && isFinite(page)) {
              return page;
            }
            if (typeof page !== 'string') {
              return page;
            }

            // Assume they passed back the key of the page to go to.
            return this.getPageIndexByKey(page);
          }
          catch (e) {
            console.warn('An error occurred in a custom nextPage function statement for component ' + form.key, e);
            return page;
          }
        }
        // Or use JSON Logic.
        else {
          let result = FormioUtils.jsonLogic.apply(form.nextPage, {
            data: data,
            page: page,
            form: form
          });
          let newPage = parseInt(result, 10);
          if (!isNaN(parseInt(newPage, 10)) && isFinite(newPage)) {
            return newPage;
          }

          return this.getPageIndexByKey(result);
        }
      }

      return page;
    }

    return null;
  }

  getPreviousPage() {
    let prev = this.history.pop();
    if(typeof prev !== 'undefined') {
      return prev;
    }

    return this.page - 1;
  }

  nextPage() {
    // Validate the form builed, before go to the next page
    if (this.checkValidity(this.submission.data, true)) {
      this.checkData(this.submission.data, {
        noValidate: true
      });
      return this.beforeNext().then(() => {
        this.history.push(this.page);
        return this.setPage(this.getNextPage(this.submission.data, this.page)).then(() => {
          this._nextPage = this.getNextPage(this.submission.data, this.page);
          this.emit('nextPage', {page: this.page, submission: this.submission});
        });
      });
    }
    else {
      return Promise.reject(this.showErrors());
    }
  }

  prevPage() {
    let prevPage = this.getPreviousPage();
    return this.setPage(prevPage).then(() => {
      this.emit('prevPage', {page: this.page, submission: this.submission});
    });
  }

  cancel() {
    super.cancel();
    this.history = [];
    return this.setPage(0);
  }

  getPageIndexByKey(key) {
    let pageIndex = 0;
    each(this.pages, (_page, index) => {
      if (_page.key === key) {
        pageIndex = index;
        return false;
      }
    });
    return pageIndex;
  }

  addGlobalComponents(page) {
    // If there are non-page components, then add them here. This is helpful to allow for hidden fields that
    // can propogate between pages.
    if (this.globalComponents.length) {
      page.components = this.globalComponents.concat(page.components);
    }
    return page;
  }

  getPage(pageNum) {
    if ((pageNum >= 0) && (pageNum < this.pages.length)) {
      return this.addGlobalComponents(this.pages[pageNum]);
    }
    return null;
  }

  getWizard() {
    let pageIndex = 0;
    let page = null;
    let wizard = clone(this.wizard);
    wizard.components = [];
    do {
      page = this.getPage(pageIndex);
      if (page) {
        wizard.components.push(page);
      }
    } while (pageIndex = this.getNextPage(this.submission.data, pageIndex));

    // Add all other components.
    each(this.wizard.components, (component) => {
      if (component.type !== 'panel') {
        wizard.components.push(component);
      }
    });

    return wizard;
  }

  currentPage() {
    return this.getPage(this.page);
  }

  buildPages(form) {
    this.pages = [];
    each(form.components, (component) => {
      if (component.type === 'panel') {
        // Ensure that this page can be seen.
        if (FormioUtils.checkCondition(component, this.data, this.data)) {
          this.pages.push(component);
        }
      }
      else if (component.type === 'hidden') {
        // Global components are hidden components that can propagate between pages.
        this.globalComponents.push(component);
      }
    });
    this.buildWizardHeader();
    this.buildWizardNav();
  }

  setForm(form) {
    if (!form) {
      return;
    }
    this.wizard = form;
    this.buildPages(this.wizard);
    return this.setPage(this.page);
  }

  build() {
    super.build();
    this.formReady.then(() => {
      this.buildWizardHeader();
      this.buildWizardNav();
    });
  }

  hasButton(name, nextPage) {
    if (name === 'previous') {
      return (this.page > 0);
    }
    nextPage = (nextPage === undefined) ? this.getNextPage(this.submission.data, this.page) : nextPage;
    if (name === 'next') {
      return (nextPage !== null) && (nextPage < this.pages.length);
    }
    if (name === 'submit') {
      return (nextPage === null) || (this.page === (this.pages.length - 1));
    }
    return true;
  }

  buildWizardHeader() {
    if (this.wizardHeader) {
      this.wizardHeader.innerHTML = '';
    }

    let currentPage = this.currentPage();
    if (!currentPage || this.wizard.full) {
      return;
    }

    currentPage.breadcrumb = currentPage.breadcrumb || 'default';
    if (currentPage.breadcrumb.toLowerCase() === 'none') {
      return;
    }

    // Check for and initlize breadcrumb settings object
    this.options.breadcrumbSettings = this.options.breadcrumbSettings || {};
    if(this.options.breadcrumbSettings.clickable === undefined) {
      this.options.breadcrumbSettings.clickable = true;
    }

    this.wizardHeader = this.ce('ul', {
      class: 'pagination'
    });

    // Add the header to the beginning.
    this.prepend(this.wizardHeader);

    let showHistory = (currentPage.breadcrumb.toLowerCase() === 'history');
    each(this.pages, (page, i) => {
      // See if this page is in our history.
      if (showHistory && ((this.page !== i) && !this.history.includes(i))) {
        return;
      }

      // Set clickable based on breadcrumb settings
      let clickable = this.page === i && this.options.breadcrumbSettings.clickable

      let pageButton = this.ce('li', {
        class: (i === this.page) ? 'active' : (clickable ? '' : 'disabled'),
        style: (clickable) ? 'cursor: pointer;' : ''
      });

      // Navigate to the page as they click on it.

      if (clickable) {
        this.addEventListener(pageButton, 'click', (event) => {
          event.preventDefault();
          this.setPage(i);
        });
      }

      let pageLabel = this.ce('span');
      let pageTitle = page.title;
      if (currentPage.breadcrumb.toLowerCase() === 'condensed') {
        pageTitle = ((i === this.page) || showHistory) ? page.title : (i + 1);
        if (!pageTitle) {
          pageTitle = (i + 1);
        }
      }

      pageLabel.appendChild(this.text(pageTitle));
      pageButton.appendChild(pageLabel);
      this.wizardHeader.appendChild(pageButton);
    });
  }

  pageId(page) {
    if (page.key) {
      return page.key;
    }
    else if (
      page.components &&
      page.components.length > 0
    ) {
      return this.pageId(page.components[0]);
    }
    else {
      return page.title;
    }
  }

  onChange(flags, changed) {
    super.onChange(flags, changed);

    // Only rebuild if there is a page change.
    let pageIndex = 0;
    let rebuild = false;
    each(this.wizard.components, (component) => {
      if (component.type !== 'panel') {
        return;
      }

      if (FormioUtils.hasCondition(component)) {
        let hasPage = this.pages && this.pages[pageIndex] && (this.pageId(this.pages[pageIndex]) === this.pageId(component));
        let shouldShow = FormioUtils.checkCondition(component, this.data, this.data);
        if ((shouldShow && !hasPage) || (!shouldShow && hasPage)) {
          rebuild = true;
          return false;
        }
        if (shouldShow) {
          pageIndex++;
        }
      }
      else {
        pageIndex++;
      }
    });

    if (rebuild) {
      this.setForm(this.wizard);
    }

    // Update Wizard Nav
    let nextPage = this.getNextPage(this.submission.data, this.page);
    if (this._nextPage != nextPage) {
      this.buildWizardNav(nextPage);
      this.emit('updateWizardNav', {oldpage: this._nextPage, newpage: nextPage, submission: this.submission});
      this._nextPage = nextPage;
    }
  }

  buildWizardNav(nextPage) {
    if (this.wizardNav) {
      this.wizardNav.innerHTML = '';
      if (this.element.contains(this.wizardNav)) {
        this.element.removeChild(this.wizardNav);
      }
    }
    if (this.wizard.full) {
      return;
    }
    this.wizardNav = this.ce('ul', {
      class: 'list-inline'
    });
    this.element.appendChild(this.wizardNav);
    each([
      {name: 'cancel',    method: 'cancel',   class: 'btn btn-default'},
      {name: 'previous',  method: 'prevPage', class: 'btn btn-primary'},
      {name: 'next',      method: 'nextPage', class: 'btn btn-primary'},
      {name: 'submit',    method: 'submit',   class: 'btn btn-primary'}
    ], (button) => {
      if (!this.hasButton(button.name, nextPage)) {
        return;
      }
      let buttonWrapper = this.ce('li');
      let buttonProp = button.name + 'Button';
      this[buttonProp] = this.ce('button', {
        class: button.class + ' btn-wizard-nav-' + button.name
      });
      this[buttonProp].appendChild(this.text(this.t(button.name)));
      this.addEventListener(this[buttonProp], 'click', (event) => {
        event.preventDefault();
        this[button.method]();
      });
      buttonWrapper.appendChild(this[buttonProp]);
      this.wizardNav.appendChild(buttonWrapper);
    });
  }
}

FormioWizard.setBaseUrl = Formio.setBaseUrl;
FormioWizard.setApiUrl = Formio.setApiUrl;
FormioWizard.setAppUrl = Formio.setAppUrl;

module.exports = global.FormioWizard = FormioWizard;
<|endoftext|>


<commit_before>/*	VCO.Date
	Date object
	MONTHS are 1-BASED, not 0-BASED (different from Javascript date objects)
================================================== */
VCO.Date = VCO.Class.extend({

	initialize: function (data, format) {
		if (typeof(data) == 'number' || Date == data.constructor) {
			var date = null;
			if (Date == data.constructor) {
				date = data;
			} else {
				date = new Date(data);
			}
			this.data = {
				format: 		"yyyy mmmm",
				display_type: 	"",
				date_obj: 		date
			}

		} else {
			this.data = {
				year: 			"",
				month: 			"",
				day: 			"",
				hour: 			"",
				minute: 		"",
				second: 		"",
				millisecond: 	"",
				format: 		"yyyy mmmm",
				display_type: 	"",
				date_obj: 		{}
			};

			// Merge Data
			VCO.Util.mergeData(this.data, data);

			// Create Date Object
			this._createDateObj();
		}

		if (format) {
			this.data.format = format;
		} else {
			this.data.format = VCO.DateUtil.findBestFormat(this.data);
		}

		this._createDisplayType();

	},

	/*	Private Methods
	================================================== */

	/*	Create Display Type
	================================================== */
	setDateFormat: function(format) {
		// Set display type format
		this.data.format = format;
		this._createDisplayType();
	},

	getDisplayDate: function() {
		return this.data.display_type;
	},

	getMillisecond: function() {
		return this.getTime();
	},

	getTime: function() {
		return this.data.date_obj.getTime();
	},

	/*	Create Display Type
	================================================== */
	_createDisplayType: function() {
		this.data.display_type = VCO.DateFormat(this.data.date_obj, this.data.format);
	},

	isBefore: function(other_date) {
		if (!(VCO.Date == other_date.constructor)) { throw("Can only compare to VCO.Date")}
		if (this.data.date_obj) {
			if (!(Date == other_date.data.date_obj.constructor)) {
				throw("Can't compare VCO.Dates on different scales") // but should be able to compare 'cosmological scale' dates once we get to that...
			}
			return this.data.date_obj < other_date.data.date_obj
		}
		throw("Can't compare");
	},

	isAfter: function(other_date) {
		if (!(VCO.Date == other_date.constructor)) { throw("Can only compare to VCO.Date")}
		if (this.data.date_obj) {
			if (!(Date == other_date.data.date_obj.constructor)) {
				throw("Can't compare VCO.Dates on different scales") // but should be able to compare 'cosmological scale' dates once we get to that...
			}
			return this.data.date_obj > other_date.data.date_obj
		}
		throw("Can't compare");

	},

	/*	Create JavaScript date object
	================================================== */
	_createDateObj: function() {
		var _date = {
			year: 			0,
			month: 			1, // stupid JS dates
			day: 			0,
			hour: 			0,
			minute: 		0,
			second: 		0,
			millisecond: 	0
		};

		// Merge dates
		VCO.Util.mergeData(_date, this.data);
		DATE_PARTS = ['year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond'];

		// Make strings into numbers
		for (var ix in DATE_PARTS) {
			var parsed = parseInt(_date[DATE_PARTS[ix]]);
			if (isNaN(parsed)) parsed = 0;
			_date[DATE_PARTS[ix]] = parsed;
		}

		if (_date.month > 0 && _date.month <= 12) {
			_date.month = _date.month - 1;
		}
		trace(_date);
		// Create Javascript date object
		this.data.date_obj = new Date(_date.year, _date.month, _date.day, _date.hour, _date.minute, _date.second, _date.millisecond);
		trace(this.data.date_obj);
	}

});

<commit_msg>Removed console log from VCO.Date<commit_after>/*	VCO.Date
	Date object
	MONTHS are 1-BASED, not 0-BASED (different from Javascript date objects)
================================================== */
VCO.Date = VCO.Class.extend({

	initialize: function (data, format) {
		if (typeof(data) == 'number' || Date == data.constructor) {
			var date = null;
			if (Date == data.constructor) {
				date = data;
			} else {
				date = new Date(data);
			}
			this.data = {
				format: 		"yyyy mmmm",
				display_type: 	"",
				date_obj: 		date
			}

		} else {
			this.data = {
				year: 			"",
				month: 			"",
				day: 			"",
				hour: 			"",
				minute: 		"",
				second: 		"",
				millisecond: 	"",
				format: 		"yyyy mmmm",
				display_type: 	"",
				date_obj: 		{}
			};

			// Merge Data
			VCO.Util.mergeData(this.data, data);

			// Create Date Object
			this._createDateObj();
		}

		if (format) {
			this.data.format = format;
		} else {
			this.data.format = VCO.DateUtil.findBestFormat(this.data);
		}

		this._createDisplayType();

	},

	/*	Private Methods
	================================================== */

	/*	Create Display Type
	================================================== */
	setDateFormat: function(format) {
		// Set display type format
		this.data.format = format;
		this._createDisplayType();
	},

	getDisplayDate: function() {
		return this.data.display_type;
	},

	getMillisecond: function() {
		return this.getTime();
	},

	getTime: function() {
		return this.data.date_obj.getTime();
	},

	/*	Create Display Type
	================================================== */
	_createDisplayType: function() {
		this.data.display_type = VCO.DateFormat(this.data.date_obj, this.data.format);
	},

	isBefore: function(other_date) {
		if (!(VCO.Date == other_date.constructor)) { throw("Can only compare to VCO.Date")}
		if (this.data.date_obj) {
			if (!(Date == other_date.data.date_obj.constructor)) {
				throw("Can't compare VCO.Dates on different scales") // but should be able to compare 'cosmological scale' dates once we get to that...
			}
			return this.data.date_obj < other_date.data.date_obj
		}
		throw("Can't compare");
	},

	isAfter: function(other_date) {
		if (!(VCO.Date == other_date.constructor)) { throw("Can only compare to VCO.Date")}
		if (this.data.date_obj) {
			if (!(Date == other_date.data.date_obj.constructor)) {
				throw("Can't compare VCO.Dates on different scales") // but should be able to compare 'cosmological scale' dates once we get to that...
			}
			return this.data.date_obj > other_date.data.date_obj
		}
		throw("Can't compare");

	},

	/*	Create JavaScript date object
	================================================== */
	_createDateObj: function() {
		var _date = {
			year: 			0,
			month: 			1, // stupid JS dates
			day: 			0,
			hour: 			0,
			minute: 		0,
			second: 		0,
			millisecond: 	0
		};

		// Merge dates
		VCO.Util.mergeData(_date, this.data);
		DATE_PARTS = ['year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond'];

		// Make strings into numbers
		for (var ix in DATE_PARTS) {
			var parsed = parseInt(_date[DATE_PARTS[ix]]);
			if (isNaN(parsed)) parsed = 0;
			_date[DATE_PARTS[ix]] = parsed;
		}

		if (_date.month > 0 && _date.month <= 12) {
			_date.month = _date.month - 1;
		}
		// Create Javascript date object
		this.data.date_obj = new Date(_date.year, _date.month, _date.day, _date.hour, _date.minute, _date.second, _date.millisecond);
	}

});

<|endoftext|>