<commit_before>(function($) {
	//there should be 2 input elements - 1 for text and one for textarea
	$.fn.typingtutor = function(options) {
		//todo: validate input
		var settings = $.extend({
			speedInterval: 4,
			focus: false,
			textBackgroundColor: '#ffffff'
		}, options);
		//todo: make order independent
		var text = this[0];
		var textarea = this[1];
		$(textarea).css('resize', 'none');
		$(textarea).attr('onpaste', 'return false;');
		$(textarea).attr('oncut', 'return false;');
		//hopefully the browser will support HTML5
		$(textarea).attr('spellcheck', 'false');

		var currentLinePosition = 0;
		var lines = $(text).find('p');
		var originalTexts = [];
		var lineLetters = [];
		var totalCharacters = 0;
		for (var i = 0; i < lines.length; i++) {
			lines[i] = $(lines[i]);
			var lineText = $.trim(lines[i].text()).replace(/\t/g, ' ');
			totalCharacters += lineText.length;
			lines[i][0].innerHTML = '';
			originalTexts[i] = lineText;
			lineLetters[i] = [];
			for (var j = 0; j < lineText.length; j++) {
				var letter = $('' + lineText.charAt(j) + '');
				lines[i].append(letter);
				lineLetters[i][j] = letter;
			}
			//append a whitespace to the end of each line
			var lastLetter = $(' ');
			lineLetters[i][j] = lastLetter;
			lines[i].append(lastLetter);
			originalTexts[i] += ' ';
		}
		totalCharacters -= 1; //substracting 1 for the very first hit

		$(text).css('font-family', '"Courier New", Courier, monospace');

		var textBgColor = '#c9ffe0';

		var cursorColor = '#c6dea2';
		var errorColor = '#ff6188';

		//resulting object
		var res = {};

		function drawTextBackground(line, position) {
			if (lineLetters[line] && lineLetters[line][position]) {
				lineLetters[line][position].css('background-color', textBgColor);
			}
		}
		function clearTextBackground(line, position) {
			if (lineLetters[line] && lineLetters[line][position]) {
				lineLetters[line][position].css('background-color', settings.textBackgroundColor);
			}
		}
		function drawCursor(line, position) {
			if (lineLetters[line] && lineLetters[line][position]) {
				lineLetters[line][position].css('background-color', cursorColor);
				//next key callback
				nextKeyCallback(line, position-1);
			}
		}
		function increaseErrorCount(){
			isError = true;
			ec++;
			if (eh) {
				eh.call(this, ec);
			}
			if(settings.nextKeyCallback){
				settings.nextKeyCallback.call(this, 8);
			}
		}
		function highlightError(line, position) {
			if (lineLetters[line] && lineLetters[line][position]) {
				lineLetters[line][position].css('background-color', errorColor);
			}
			clearSpeed();
			increaseErrorCount();
			res.nextKeys = 8;
		}
		function endsWith(str, suffix) {
			return str.indexOf(suffix, str.length - suffix.length) !== -1;
		}
		function getLines() {
			var currentText = textarea.value;
			var allLines = currentText.split(/\n/g);
			if ($.browser.name === 'msie' && endsWith(currentText, '\n')) {
				//todo test for ie > 8
				allLines.push('');
			}
			return allLines;
		}
		function getLinesCount() {
			return getLines().length;
		}
		function getLastLine() {
			var allLines = getLines();
			return allLines[allLines.length - 1];
		}

		//speed interval
		var si = settings.speedInterval;
		//last correct date
		var lcd;
		//times
		var tms = [];
		//speed callback
		var scb = settings.speedTrackCallback;
		//finish callback
		var fcb = settings.finishCallback;
		function clearSpeed() {
			lcd = null;
			tms.length = 0;
		}
		var millisInMinute = 1000 * 60;
		var startTime = null;

		//error count
		var ec = 0;
		//error handler
		var eh = settings.errorCallback;

		var isError = false;

		function nextKeyCallback(currentLinePosition, currentTypingPosition) {
			if(settings.nextKeyCallback){
				var currentLineText = originalTexts[currentLinePosition];
				//next typing position
				var ntp = currentTypingPosition + 1;
				if(currentLineText.length > ntp) {
					if(currentLineText.charAt(ntp) === ' ' && ntp === currentLineText.length - 1) {
						//either whitespace or enter are allowed to move to the next line
						res.nextKeys = [13, 32];
					} else {
						res.nextKeys = [currentLineText.charCodeAt(ntp)];
					}
					settings.nextKeyCallback.call(this, res.nextKeys);
				}
			}
		}

		var keyPress = function(e) {
			if (!startTime) {
				startTime = new Date().getTime();
			}
			if (e.keyCode === 8 || e.keyCode === 13) {
				return;
			}

			//a letter has been typed
			var lastTypedLine = getLastLine();
			var currentTypingPosition = lastTypedLine.length;
			if (!originalTexts[currentLinePosition]) {
				return;
			}
			if (currentTypingPosition >= originalTexts[currentLinePosition].length - 1) {
				//at the end of the line
				if (!isError && e.which === 32) {
					//trigger enter event
					e.preventDefault();
					e = new jQuery.Event('keydown');
					e.which = e.keyCode = 13;
					$(textarea).trigger(e);

					$(textarea).val($(textarea).val() + '\n');
					//hack for IE: move cursor to the end:
					if($.browser.name === 'msie'){
						var range = $(textarea)[0].createTextRange();
						range.collapse(false);
						range.select();
					}
					return;
				}
			}
			if (currentTypingPosition > originalTexts[currentLinePosition].length - 1) {
				increaseErrorCount();
				return;
			}
			if (originalTexts[currentLinePosition].substring(0, currentTypingPosition + 1) === lastTypedLine + String.fromCharCode(e.which)) {
				//a correct letter is about to be pressed
				isError = false;
				drawTextBackground(currentLinePosition, currentTypingPosition);
				drawCursor(currentLinePosition, currentTypingPosition + 1);
				if (scb) {
					//correct date
					var cd = new Date().getTime();
					if (lcd) {
						//recording current time
						var t = cd - lcd;
						tms.push(t);
						if (tms.length === si) {
							//calculate average and call speed feedback
							var tot = 0;
							$.each(tms, function(i, val) {
								tot += val;
							});
							//average speed of typing one character
							var avg = tot / (tms.length);

							var speed = millisInMinute / avg;
							scb.call(this, parseInt(speed));

							tms.length = 0;
						}
					}

					lcd = cd;
				}
				//check if the whole text is typed
				//at this point we are sure that the typed symbol was correct
				//if we're at the end of last line - fire 'finishedcallback'
				if (fcb) {
					if (!isError && originalTexts.length - 1 === currentLinePosition && originalTexts[originalTexts.length - 1].length - 2/*substracting last whitespace*/ === currentTypingPosition) {
						var time = new Date().getTime() - startTime;
						var overallSpeed = (totalCharacters / time) * millisInMinute;
						fcb.call(this, parseInt(overallSpeed));
						//append last typed char to the textarea before disabling it
						$(textarea).val($(textarea).val() + String.fromCharCode(e.which));
						$(textarea).attr('disabled', true);
						$(textarea).unbind('keypress');
						$(textarea).unbind('keydown');
						$(textarea).unbind('keyup');
					}
				}
			} else {
				highlightError(currentLinePosition, currentTypingPosition);
			}
		};
		var keyDown = function(e) {
			console.log(e.which)
			//skip arrow keys
			if($.inArray(e.keyCode, [37, 38, 39, 40]) !== -1){
				e.preventDefault();
				return;
			}
			//disable home key, allow only shift+home combo
			if(e.keyCode === 36 && !e.shiftKey){
			    e.preventDefault();
			    return;
			}
			if (e.keyCode === 8) {
				//backspace - unstyle last styled character
				var lastLine = getLastLine();
				var currentTypingPosition = lastLine.length;
				if (currentTypingPosition > 0) {
					if (!originalTexts[currentLinePosition]) {
						return;
					}

					if (currentTypingPosition < originalTexts[currentLinePosition].length) {
						clearTextBackground(currentLinePosition, currentTypingPosition);
					}
					if (currentTypingPosition > 1) {
						if (currentTypingPosition - 1 < originalTexts[currentLinePosition].length) {
							clearTextBackground(currentLinePosition, currentTypingPosition - 1);
							if (originalTexts[currentLinePosition].substring(0, currentTypingPosition - 1) === lastLine.substring(0, currentTypingPosition - 1)) {
								drawCursor(currentLinePosition, currentTypingPosition - 1);
							}
						}
					} else {
						drawCursor(currentLinePosition, 0);
					}
				} else {
					//we may have jumped to a previous line
					//Remove cursor from previous line
					if (currentLinePosition === 0) {
						//we're at the beginning of the first line
						return;
					}
					if(! originalTexts[currentLinePosition]){
						return;
					}

					clearTextBackground(currentLinePosition, 0);
					currentLinePosition--;
					var currentTypedLine = getLines()[currentLinePosition];
					currentTypingPosition = currentTypedLine.length + 1; //adding one for space at the end
					if (checkInput(currentTypedLine, currentLinePosition, currentTypingPosition)) {
						drawCursor(currentLinePosition, currentTypingPosition - 1);
					} else {
						highlightError(currentLinePosition, currentTypingPosition - 2);
					}
				}
			} else if (e.keyCode === 13) {
				//enter
				//validate current line
				var lastLine = getLastLine();
				if ($.trim(originalTexts[currentLinePosition]) !== lastLine) {
					highlightError(currentLinePosition, lastLine.length);
					e.preventDefault();
					return;
				} else {
					drawTextBackground(currentLinePosition, lastLine.length);
				}
				currentLinePosition++;
				drawCursor(currentLinePosition, 0);
			}
		};
		var keyUp = function(e){
			//var t1 = new Date().getTime();
			//clear backgrounds of of all characters which are beyond current typing point
			var lastLine = getLastLine();
			var currentTypingPosition = lastLine.length;
			if(currentTypingPosition >= lineLetters[currentLinePosition].length){
				return;
			}
			//adding one for cursor
			for(var i = currentTypingPosition + 1; i < lineLetters[currentLinePosition].length; i++){
				clearTextBackground(currentLinePosition, i);
			}
			//we don't want to replace errors with cursor
			if ((e.ctrlKey || e.shiftKey || e.keyCode === 46) && checkInput(lastLine, currentLinePosition, currentTypingPosition)) {
				drawCursor(currentLinePosition, currentTypingPosition);
			}
			//console.log('KeyUp in: ' + (new Date().getTime() - t1));
		};

		$(textarea).keypress(keyPress);
		$(textarea).keydown(keyDown);
		$(textarea).keyup(keyUp);

		function moveToEnd() {
			var text = $(textarea).val();
			$(textarea).focus().val('').val(text);
		}
		$(textarea).mouseup(moveToEnd);

		/**
		 * Checks if last line was correct up to currentTypingPosition
		 */
		function checkInput(lastLine, currentLinePosition, currentTypingPosition){
			return $.trim(originalTexts[currentLinePosition]).substring(0, currentTypingPosition - 1) === $.trim(lastLine).substring(0, currentTypingPosition - 1);
		}
		if(settings.focus){
			$(textarea).focus();
		}
		drawCursor(0, 0);

		res.restart = function(){
			$(textarea).unbind('keypress');
			$(textarea).unbind('keydown');
			$(textarea).unbind('keyup');
			//clear backgrounds of all texts
			$.each(lineLetters, function(i, line){
				$.each(line, function(j, letter){
					letter.css('background-color', settings.textBackgroundColor);
				});
			});
			drawCursor(0, 0);

			currentLinePosition = 0;

			$(textarea).val('').attr('disabled', false);

			ec = 0;

			if (eh) {
				eh.call(this, ec);
			}

			isError = false;

			if (scb) {
				scb.call(this, 0);
			}
			clearSpeed();
			startTime = null;

			$(textarea).keypress(keyPress);
			$(textarea).keydown(keyDown);
			$(textarea).keyup(keyUp);
		};

		return res;
	};
}(jQuery));<commit_msg>minor refactonigns<commit_after>(function($) {
	//there should be 2 input elements - 1 for text and one for textarea
	$.fn.typingtutor = function(options) {
		//todo: validate input
		var settings = $.extend({
			speedInterval: 4,
			focus: false,
			textBackgroundColor: '#ffffff'
		}, options);
		//todo: make order independent
		var text = this[0];
		var textarea = this[1];
		$(textarea).css('resize', 'none');
		$(textarea).attr('onpaste', 'return false;');
		$(textarea).attr('oncut', 'return false;');
		//hopefully the browser will support HTML5
		$(textarea).attr('spellcheck', 'false');

		var currentLinePosition = 0;
		var lines = $(text).find('p');
		var originalTexts = [];
		var lineLetters = [];
		var totalCharacters = 0;
		for (var i = 0; i < lines.length; i++) {
			lines[i] = $(lines[i]);
			var lineText = $.trim(lines[i].text()).replace(/\t/g, ' ');
			totalCharacters += lineText.length;
			lines[i][0].innerHTML = '';
			originalTexts[i] = lineText;
			lineLetters[i] = [];
			for (var j = 0; j < lineText.length; j++) {
				var letter = $('' + lineText.charAt(j) + '');
				lines[i].append(letter);
				lineLetters[i][j] = letter;
			}
			//append a whitespace to the end of each line
			var lastLetter = $(' ');
			lineLetters[i][j] = lastLetter;
			lines[i].append(lastLetter);
			originalTexts[i] += ' ';
		}
		totalCharacters -= 1; //substracting 1 for the very first hit

		$(text).css('font-family', '"Courier New", Courier, monospace');

		var textBgColor = '#c9ffe0';

		var cursorColor = '#c6dea2';
		var errorColor = '#ff6188';

		//resulting object
		var res = {};

		function drawTextBackground(line, position) {
			if (lineLetters[line] && lineLetters[line][position]) {
				lineLetters[line][position].css('background-color', textBgColor);
			}
		}
		function clearTextBackground(line, position) {
			if (lineLetters[line] && lineLetters[line][position]) {
				lineLetters[line][position].css('background-color', settings.textBackgroundColor);
			}
		}
		function drawCursor(line, position) {
			if (lineLetters[line] && lineLetters[line][position]) {
				lineLetters[line][position].css('background-color', cursorColor);
				//next key callback
				nextKeyCallback(line, position-1);
			}
		}
		function increaseErrorCount(){
			isError = true;
			ec++;
			if (eh) {
				eh.call(this, ec);
			}
			if(settings.nextKeyCallback){
				settings.nextKeyCallback.call(this, 8);
			}
		}
		function highlightError(line, position) {
			if (lineLetters[line] && lineLetters[line][position]) {
				lineLetters[line][position].css('background-color', errorColor);
			}
			clearSpeed();
			increaseErrorCount();
			res.nextKeys = 8;
		}
		function endsWith(str, suffix) {
			return str.indexOf(suffix, str.length - suffix.length) !== -1;
		}
		function getLines() {
			var currentText = textarea.value;
			var allLines = currentText.split(/\n/g);
			if ($.browser.name === 'msie' && endsWith(currentText, '\n')) {
				//todo test for ie > 8
				allLines.push('');
			}
			return allLines;
		}
		function getLinesCount() {
			return getLines().length;
		}
		function getLastLine() {
			var allLines = getLines();
			return allLines[allLines.length - 1];
		}

		//speed interval
		var si = settings.speedInterval;
		//last correct date
		var lcd;
		//times
		var tms = [];
		//speed callback
		var scb = settings.speedTrackCallback;
		//finish callback
		var fcb = settings.finishCallback;
		function clearSpeed() {
			lcd = null;
			tms.length = 0;
		}
		var millisInMinute = 1000 * 60;
		var startTime = null;

		//error count
		var ec = 0;
		//error handler
		var eh = settings.errorCallback;

		var isError = false;

		function nextKeyCallback(currentLinePosition, currentTypingPosition) {
			if(settings.nextKeyCallback){
				var currentLineText = originalTexts[currentLinePosition];
				//next typing position
				var ntp = currentTypingPosition + 1;
				if(currentLineText.length > ntp) {
					if(currentLineText.charAt(ntp) === ' ' && ntp === currentLineText.length - 1) {
						//either whitespace or enter are allowed to move to the next line
						res.nextKeys = [13, 32];
					} else {
						res.nextKeys = [currentLineText.charCodeAt(ntp)];
					}
					settings.nextKeyCallback.call(this, res.nextKeys);
				}
			}
		}

		var keyPress = function(e) {
			if (!startTime) {
				startTime = new Date().getTime();
			}
			if (e.keyCode === 8 || e.keyCode === 13) {
				return;
			}

			//a letter has been typed
			var lastTypedLine = getLastLine();
			var currentTypingPosition = lastTypedLine.length;
			if (!originalTexts[currentLinePosition]) {
				return;
			}
			if (currentTypingPosition >= originalTexts[currentLinePosition].length - 1) {
				//at the end of the line
				if (!isError && e.which === 32) {
					//trigger enter event
					e.preventDefault();
					e = new jQuery.Event('keydown');
					e.which = e.keyCode = 13;
					$(textarea).trigger(e);

					$(textarea).val($(textarea).val() + '\n');
					//hack for IE: move cursor to the end:
					if($.browser.name === 'msie'){
						var range = $(textarea)[0].createTextRange();
						range.collapse(false);
						range.select();
					}
					return;
				}
			}
			if (currentTypingPosition > originalTexts[currentLinePosition].length - 1) {
				increaseErrorCount();
				return;
			}
			if (originalTexts[currentLinePosition].substring(0, currentTypingPosition + 1) === lastTypedLine + String.fromCharCode(e.which)) {
				//a correct letter is about to be pressed
				isError = false;
				drawTextBackground(currentLinePosition, currentTypingPosition);
				drawCursor(currentLinePosition, currentTypingPosition + 1);
				if (scb) {
					//correct date
					var cd = new Date().getTime();
					if (lcd) {
						//recording current time
						var t = cd - lcd;
						tms.push(t);
						if (tms.length === si) {
							//calculate average and call speed feedback
							var tot = 0;
							$.each(tms, function(i, val) {
								tot += val;
							});
							//average speed of typing one character
							var avg = tot / (tms.length);

							var speed = millisInMinute / avg;
							scb.call(this, parseInt(speed));

							tms.length = 0;
						}
					}

					lcd = cd;
				}
				//check if the whole text is typed
				//at this point we are sure that the typed symbol was correct
				//if we're at the end of last line - fire 'finishedcallback'
				if (fcb) {
					if (!isError && originalTexts.length - 1 === currentLinePosition && originalTexts[originalTexts.length - 1].length - 2/*substracting last whitespace*/ === currentTypingPosition) {
						var time = new Date().getTime() - startTime;
						var overallSpeed = (totalCharacters / time) * millisInMinute;
						fcb.call(this, parseInt(overallSpeed));
						//append last typed char to the textarea before disabling it
						$(textarea).val($(textarea).val() + String.fromCharCode(e.which));
						$(textarea).attr('disabled', true);
						$(textarea).unbind('keypress');
						$(textarea).unbind('keydown');
						$(textarea).unbind('keyup');
					}
				}
			} else {
				highlightError(currentLinePosition, currentTypingPosition);
			}
		};
		var keyDown = function(e) {
			//skip arrow keys
			if($.inArray(e.keyCode, [37, 38, 39, 40]) !== -1){
				e.preventDefault();
				return;
			}
			//disable home key, allow only shift+home combo
			if(e.keyCode === 36 && !e.shiftKey){
			    e.preventDefault();
			    return;
			}
			if (e.keyCode === 8) {
				//backspace - unstyle last styled character
				var lastLine = getLastLine();
				var currentTypingPosition = lastLine.length;
				if (currentTypingPosition > 0) {
					if (!originalTexts[currentLinePosition]) {
						return;
					}

					if (currentTypingPosition < originalTexts[currentLinePosition].length) {
						clearTextBackground(currentLinePosition, currentTypingPosition);
					}
					if (currentTypingPosition > 1) {
						if (currentTypingPosition - 1 < originalTexts[currentLinePosition].length) {
							clearTextBackground(currentLinePosition, currentTypingPosition - 1);
							if (originalTexts[currentLinePosition].substring(0, currentTypingPosition - 1) === lastLine.substring(0, currentTypingPosition - 1)) {
								drawCursor(currentLinePosition, currentTypingPosition - 1);
							}
						}
					} else {
						drawCursor(currentLinePosition, 0);
					}
				} else {
					//we may have jumped to a previous line
					//Remove cursor from previous line
					if (currentLinePosition === 0) {
						//we're at the beginning of the first line
						return;
					}
					if(! originalTexts[currentLinePosition]){
						return;
					}

					clearTextBackground(currentLinePosition, 0);
					currentLinePosition--;
					var currentTypedLine = getLines()[currentLinePosition];
					currentTypingPosition = currentTypedLine.length + 1; //adding one for space at the end
					if (checkInput(currentTypedLine, currentLinePosition, currentTypingPosition)) {
						drawCursor(currentLinePosition, currentTypingPosition - 1);
					} else {
						highlightError(currentLinePosition, currentTypingPosition - 2);
					}
				}
			} else if (e.keyCode === 13) {
				//enter
				//validate current line
				var lastLine = getLastLine();
				if ($.trim(originalTexts[currentLinePosition]) !== lastLine) {
					highlightError(currentLinePosition, lastLine.length);
					e.preventDefault();
					return;
				} else {
					drawTextBackground(currentLinePosition, lastLine.length);
				}
				currentLinePosition++;
				drawCursor(currentLinePosition, 0);
			}
		};
		var keyUp = function(e){
			//var t1 = new Date().getTime();
			//clear backgrounds of of all characters which are beyond current typing point
			var lastLine = getLastLine();
			var currentTypingPosition = lastLine.length;
			if(currentTypingPosition >= lineLetters[currentLinePosition].length){
				return;
			}
			//adding one for cursor
			for(var i = currentTypingPosition + 1; i < lineLetters[currentLinePosition].length; i++){
				clearTextBackground(currentLinePosition, i);
			}
			//we don't want to replace errors with cursor
			if ((e.ctrlKey || e.shiftKey || e.keyCode === 46) && checkInput(lastLine, currentLinePosition, currentTypingPosition)) {
				drawCursor(currentLinePosition, currentTypingPosition);
			}
			//console.log('KeyUp in: ' + (new Date().getTime() - t1));
		};

		$(textarea).keypress(keyPress);
		$(textarea).keydown(keyDown);
		$(textarea).keyup(keyUp);

		function moveToEnd() {
			var text = $(textarea).val();
			$(textarea).focus().val('').val(text);
		}
		$(textarea).mouseup(moveToEnd);

		/**
		 * Checks if last line was correct up to currentTypingPosition
		 */
		function checkInput(lastLine, currentLinePosition, currentTypingPosition){
			return $.trim(originalTexts[currentLinePosition]).substring(0, currentTypingPosition - 1) === $.trim(lastLine).substring(0, currentTypingPosition - 1);
		}
		if(settings.focus){
			$(textarea).focus();
		}
		drawCursor(0, 0);

		res.restart = function(){
			$(textarea).unbind('keypress');
			$(textarea).unbind('keydown');
			$(textarea).unbind('keyup');
			//clear backgrounds of all texts
			$.each(lineLetters, function(i, line){
				$.each(line, function(j, letter){
					letter.css('background-color', settings.textBackgroundColor);
				});
			});
			drawCursor(0, 0);

			currentLinePosition = 0;

			$(textarea).val('').attr('disabled', false);

			ec = 0;

			if (eh) {
				eh.call(this, ec);
			}

			isError = false;

			if (scb) {
				scb.call(this, 0);
			}
			clearSpeed();
			startTime = null;

			$(textarea).keypress(keyPress);
			$(textarea).keydown(keyDown);
			$(textarea).keyup(keyUp);
		};

		return res;
	};
}(jQuery));<|endoftext|>


<commit_before>(function($){
	var iframe;
	//there should be 2 input elements - 1 for text and one for textarea
	$.fn.typingtutor = function(options){
		//todo: validate input
		var settings = $.extend({}, options);
		//todo: make order independent
		var text = this[0];
		var textarea = this[1];
		var textFrame = document.createElement('iframe');
		var typingFrame = document.createElement('iframe');
		$(text).replaceWith(textFrame);
		$(textarea).replaceWith(typingFrame);

		$(textFrame).contents().find('body').append($(text).text());
		$(typingFrame).contents()[0].designMode="on";
		$(textFrame).contents()[0].designMode="on";
		//hopefully this works even though I don't obtain selection from window, but rather from document
		var textSelection = $(textFrame).contents()[0].getSelection();
		//todo will need error range too
		var textRange = $(textFrame).contents()[0].createRange();

		var textRangeEnd = 0;

		var typingText = $(textFrame).contents().find('body')[0].firstChild;
		//hopefully this works in all browsers too...
		$(typingFrame).contents().find('body').keypress(function(){
			//todo for testing only
			textRange.setStart(typingText, textRangeEnd);
			textRange.setEnd(typingText, textRangeEnd + 1);
			//textRangeEnd++;
			//applying the range
			textSelection.addRange(textRange);
			//coloring the range
			$(textFrame).contents()[0].execCommand('bold');
			textSelection.removeAllRanges();
		});
	};
}(jQuery));
jQuery.fn.selectText = function() {
    var range, selection;
    if (document.body.createTextRange) {
        range = document.body.createTextRange();
        range.moveToElementText(this[0]);
        range.select();
    } else if (window.getSelection) {
        selection = window.getSelection();
        range = document.createRange();
        range.selectNodeContents(this[0]);
//        range.setStart(this[0], 2);
//        range.setEnd(this[0],4);
        selection.removeAllRanges();
        selection.addRange(range);
    }
};<commit_msg>backspace deletion works<commit_after>(function($){
	var iframe;
	//there should be 2 input elements - 1 for text and one for textarea
	$.fn.typingtutor = function(options) {
		//todo: validate input
		var settings = $.extend({}, options);
		//todo: make order independent
		var text = this[0];
		var textarea = this[1];
		var textFrame = document.createElement('iframe');
		var typingFrame = document.createElement('iframe');
		$(text).replaceWith(textFrame);
		$(textarea).replaceWith(typingFrame);

		var textBody = $(textFrame).contents().find('body');
		var typingBody = $(typingFrame).contents().find('body');

		var originalText = $(text).text();

		textBody.append(originalText);
		$(typingFrame).contents()[0].designMode="on";
		$(textFrame).contents()[0].designMode="on";
		//hopefully this works even though I don't obtain selection from window, but rather from document
		//todo: IE?
		var textSelection = $(textFrame).contents()[0].getSelection();
		//todo will need error range too
		//todo: IE?
		var textRange = $(textFrame).contents()[0].createRange();

		var textRangeEnd = 0;

		var typingText = textBody[0].firstChild;

		typingBody.keydown(function(event){
			if(event.keyCode === 8) {
				//backspace - unstyle last styled character

				//todo: WARN: this does not take into account current line
				var currentTypingPosition = typingBody.text().length;
				if(currentTypingPosition > 0) {
					textBody[0].innerHTML = "";
					textBody.text(originalText);

					typingText = textBody[0].firstChild;

					textRange.setStart(typingText, 0);
					textRange.setEnd(typingText, currentTypingPosition-1);
					textSelection.addRange(textRange);
					$(textFrame).contents()[0].execCommand('bold');
				}
			} else {
				//a letter has been typed
				//todo for testing only
				//todo: IE?
				textRange.setStart(typingText, 0);
				textRange.setEnd(typingText, 1);
				//applying the range
				//todo: IE?
				textSelection.addRange(textRange);
				//color the range
				$(textFrame).contents()[0].execCommand('bold');
			}
			textSelection.removeAllRanges();
		});

	};
}(jQuery));
jQuery.fn.selectText = function() {
    var range, selection;
    if (document.body.createTextRange) {
        range = document.body.createTextRange();
        range.moveToElementText(this[0]);
        range.select();
    } else if (window.getSelection) {
        selection = window.getSelection();
        range = document.createRange();
        range.selectNodeContents(this[0]);
//        range.setStart(this[0], 2);
//        range.setEnd(this[0],4);
        selection.removeAllRanges();
        selection.addRange(range);
    }
};<|endoftext|>


<commit_before>/*
This module takes a website formatted for a regular computer screen
and, via configuration, mobilizes it by zooming in on specific sections
of the page and providing user interface elements for scaling/translating
between components.
*/

CT.mobile = {
    "options": { // true/false for ALLNODE._mobile
        "mobile": ["mobile", "stretched"],
        "normal": ["normal", "stretched"],
        "tablet": ["stretched", "mobile"]
    },
    _dur: 0,
    "fitNode": function(n, t, o, cb) {
        var tline, w = CT.align.width() - 10,
            toff = n && CT.align.offset(n), ready;
        CT.dom.ALLNODE.mobileNode = n;
        if (CT.dom.ALLNODE._mode == "mobile")
            tline = "scale(" + (w / n.clientWidth) + ") translate(-"
                + toff.left + "px,-" + toff.top + "px)";
        else // stretched
            tline = "scale(" + (w / CT.dom.ALLNODE.clientWidth) + ")";
        CT.trans.setVenderPrefixed(CT.dom.ALLNODE, "transform-origin",
            o ? o : (w < CT.dom.ALLNODE.clientWidth ? "0% 0%" : "50% 0%"));
        CT.trans.trans({
            node: CT.dom.ALLNODE,
            property: "transform",
            value: t && t || tline,
            duration: CT.mobile._dur,
            prefix: true,
            cb: function() {
                ready && n && n.scrollIntoView(true, { "behavior": "smooth" });
                ready = true;
                cb && cb();
            }
        });
        if (!CT.mobile._dur) {
            CT.mobile._dur = 1000;
            n && n.scrollIntoView(true, { "block": "start", "behavior": "auto" }); // for initial load
        }
    },
    "fitAndSnap": function(n, cb) {
        if (CT.dom.ALLNODE.mobileNode) // smoothest way once we're loaded
            CT.dom.ALLNODE.mobileNode.scrollIntoView(true, { "behavior": "smooth" });
        CT.mobile.fitNode(n, null, null, cb);
    },
    "mobileSnap": function(cb) {
        if (CT.dom.ALLNODE && CT.dom.ALLNODE._mode == "mobile")
            CT.mobile.fitAndSnap(CT.dom.ALLNODE._mobileDefault, cb);
    },
    "getMobileNode": function(bdata) {
        if (bdata.id)
            return document.getElementById(bdata.id);
        else {
            var cname = (CT.mobile.page && CT.mobile.page[bdata.name])
                ? CT.mobile.page[bdata.name] : bdata.firstClass;
            return document.getElementsByClassName(cname)[0];
        }
    },
    "mobileMenuLink": function(bdata) {
        var pref = "/img/" + (bdata.section && bdata.page || "icons") + "/",
            name = bdata.name || (bdata.section && bdata.icon) || bdata.page || bdata.icon,
            url = !bdata.clickChild && bdata.page && (bdata.page + ".html");
        if (url && bdata.section)
            url += "#!" + bdata.section;
        return CT.dom.labeledImage(pref + bdata.icon + ".png", url,
            name, name, "centeredimg", "round bordered padded",
            "centered nowrap small", false, (bdata.id || bdata.firstClass || bdata.clickChild)
                && function() {
                    CT.dom.ALLNODE.toggleMobileMenu();
                    if (bdata.clickChild)
                        CT.dom.id(bdata.clickChild).firstElementChild.onclick();
                    else
                        CT.mobile.fitAndSnap(CT.mobile.getMobileNode(bdata));
                }, true);
    },
    "initMobileMenus": function(mmbtn, loggedin, searchcb) {
        mmbtn.tops = CT.dom.node(null, null,
            "button_row top_out", "top_buttons");
        mmbtn.bottoms = CT.dom.node(null, null,
            "button_row bottom_out", "bottom_buttons");

        var mobile_search = CT.dom.field("mobile_search");
        mmbtn.tops.appendChild(CT.dom.node(CT.dom.node(
            [CT.dom.node("CAN Smart Search"), mobile_search], "div",
            "round bordered padded", "mobile_search_node"), "label", null,
            null, {"for": "mobile_search", "htmlFor": "mobile_search"}));
        (CT.mobile.page && CT.mobile.page.top || CT.mobile.menus.top).forEach(function(bdata) {
            mmbtn.tops.appendChild(CT.mobile.mobileMenuLink(bdata));
        });
        CT.mobile.menus.bottom.forEach(function(bdata) {
            mmbtn.bottoms.appendChild(CT.mobile.mobileMenuLink(bdata));
        });
        mmbtn.bottoms.appendChild(CT.mobile.mobileMenuLink(
            CT.mobile.menus.alternatives[loggedin ? "participate" : "login"]));
        CT.dom.inputEnterCallback(mobile_search, searchcb);
        CT.dom.blurField(mobile_search);

        document.body.appendChild(mmbtn.tops);
        document.body.appendChild(mmbtn.bottoms);

        var lefts = CT.mobile.page && CT.mobile.page.left || CT.mobile.menus.left;
        if (!lefts) return
        mmbtn.lefts = CT.dom.node(null, null,
            "button_row_side left_out", "left_buttons");
        lefts.forEach(function(bdata) {
            mmbtn.lefts.appendChild(CT.mobile.mobileMenuLink(bdata));
        });
        document.body.appendChild(mmbtn.lefts);
    },
    "_mset": function() {
        var _a = CT.dom.ALLNODE, i, m,
            modes = ["mobile", "tablet"];
        for (i = 0; i < modes.length; i++) {
            m = modes[i];
            if (_a["_" + m])
                return CT.mobile.options[m];
        }
        return CT.mobile.options.normal;
    },
    "isMobile": function() {
        return CT.dom.ALLNODE._mobile;
    },
    "initResizer": function(loggedin, resdata, menus, page, searchcb) {
        CT.mobile.menus = menus;
        CT.mobile.page = page;

        // for compiler
        var curd, btn, mmbtn, _a = CT.dom.ALLNODE, zMode = function() {
            return CT.mobile._mset()[_a._mindex];
        };
        var setScroll = function() {
            var _doscroll = function(e) {
                var n = _a.mobileNode || _a;
                if (n.getBoundingClientRect().bottom < CT.align.height())
                    n.scrollIntoView(false, { "behavior": "smooth" });
            };
            window.onscroll = function(e) {
                setTimeout(_doscroll, 500);
//                setTimeout(_doscroll, 1000);
  //              setTimeout(_doscroll, 2000);
    //            setTimeout(_doscroll, 3000);
            };
            var firstMove;
            window.addEventListener('touchstart', function (e) {
                firstMove = true;
            });
            window.addEventListener('touchmove', function (e) {
                if (firstMove) {
                    e.preventDefault();
                    firstMove = false;
                } else
                    window.onscroll && window.onscroll();
            });
        };
        _a._mobileDefault = _a.mobileNode =
            CT.mobile.getMobileNode((page && page.top || menus.top)[1]);
        _a._mode = zMode();
        _a._mindex = 0;
        _a._otherMode = function() {
            return CT.mobile._mset()[(_a._mindex + 1) % 2];
        };
        _a._swapMode = function() {
            _a._mindex = _a._mindex ? 0 : 1;
            setTimeout(function() {
                var vp = document.getElementsByTagName("meta");
                for (var i = 0; i < vp.length; i++) {
                    if (vp[i].name == "viewport") {
                        vp[i].content = "width=device-width, initial-scale=1.0"
                            + ((_a._mode == "mobile")
                            ? ", min-scale=1.0, max-scale=1.0, user-scalable=no" : "");
                        break;
                    }
                }
            }, 200);
            _a.resize();
        };
        _a.toggleMobileMenu = function() {
            if (mmbtn._on) {
                mmbtn.tops.className = "button_row top_out";
                mmbtn.bottoms.className = "button_row bottom_out";
                if (mmbtn.lefts)
                    mmbtn.lefts.className = "button_row_side left_out";
            } else {
                mmbtn.tops.className = "button_row";
                mmbtn.bottoms.className = "button_row";
                if (mmbtn.lefts)
                    mmbtn.lefts.className = "button_row_side";
            }
            mmbtn._on = !mmbtn._on;
        };
        curd = resdata[_a._otherMode()];
        btn = CT.dom.img(curd.img, null, _a._swapMode, null,
            null, curd.alt, "resize_btn", "round bordered padded");
        mmbtn = CT.dom.img("/img/mobile-menu.png", null, _a.toggleMobileMenu,
            null, null, "Mobile Menu", "mobile_menu_btn", "round bordered padded");
        _a.resize = function() {
            _a._mobile = CT.info.mobile || CT.align.width() <= 720;
            _a._tablet = CT.info.tablet || CT.align.width() <= 980;
            _a._mode = zMode();
            if (_a._mode == "normal")
                CT.mobile.fitNode(null, "scale(1)", "50% 0%");
            else if (_a._mode == "stretched")
                CT.mobile.fitAndSnap(_a);
            else
                CT.mobile.fitAndSnap(_a._mobileDefault);
            if (_a._mode == "mobile") {
                mmbtn.style.display = "block";
                _a.chatBlock && _a.chatBlock();
            } else {
                mmbtn.style.display = "none";
                if (mmbtn._on)
                    mmbtn.onclick();
            }
            var toggleMode = _a._otherMode();
            btn.title = btn.alt = resdata[toggleMode].alt;
            btn.firstChild.firstChild.src = resdata[toggleMode].img;
        };
        document.body.appendChild(btn);
        document.body.appendChild(mmbtn);
        CT.mobile.initMobileMenus(mmbtn, loggedin, searchcb);
        _a.resize();
        setScroll();
    }
};<commit_msg>mobile: support right menu, className (suffix), and bdata.click()<commit_after>/*
This module takes a website formatted for a regular computer screen
and, via configuration, mobilizes it by zooming in on specific sections
of the page and providing user interface elements for scaling/translating
between components.
*/

CT.mobile = {
    "options": { // true/false for ALLNODE._mobile
        "mobile": ["mobile", "stretched"],
        "normal": ["normal", "stretched"],
        "tablet": ["stretched", "mobile"]
    },
    _dur: 0,
    "fitNode": function(n, t, o, cb) {
        var tline, w = CT.align.width() - 10,
            toff = n && CT.align.offset(n), ready;
        CT.dom.ALLNODE.mobileNode = n;
        if (CT.dom.ALLNODE._mode == "mobile")
            tline = "scale(" + (w / n.clientWidth) + ") translate(-"
                + toff.left + "px,-" + toff.top + "px)";
        else // stretched
            tline = "scale(" + (w / CT.dom.ALLNODE.clientWidth) + ")";
        CT.trans.setVenderPrefixed(CT.dom.ALLNODE, "transform-origin",
            o ? o : (w < CT.dom.ALLNODE.clientWidth ? "0% 0%" : "50% 0%"));
        CT.trans.trans({
            node: CT.dom.ALLNODE,
            property: "transform",
            value: t && t || tline,
            duration: CT.mobile._dur,
            prefix: true,
            cb: function() {
                ready && n && n.scrollIntoView(true, { "behavior": "smooth" });
                ready = true;
                cb && cb();
            }
        });
        if (!CT.mobile._dur) {
            CT.mobile._dur = 1000;
            n && n.scrollIntoView(true, { "block": "start", "behavior": "auto" }); // for initial load
        }
    },
    "fitAndSnap": function(n, cb) {
        if (CT.dom.ALLNODE.mobileNode) // smoothest way once we're loaded
            CT.dom.ALLNODE.mobileNode.scrollIntoView(true, { "behavior": "smooth" });
        CT.mobile.fitNode(n, null, null, cb);
    },
    "mobileSnap": function(cb) {
        if (CT.dom.ALLNODE && CT.dom.ALLNODE._mode == "mobile")
            CT.mobile.fitAndSnap(CT.dom.ALLNODE._mobileDefault, cb);
    },
    "getMobileNode": function(bdata) {
        if (bdata.id)
            return document.getElementById(bdata.id);
        else {
            var cname = (CT.mobile.page && CT.mobile.page[bdata.name])
                ? CT.mobile.page[bdata.name] : bdata.firstClass;
            return document.getElementsByClassName(cname)[0];
        }
    },
    "mobileMenuLink": function(bdata) {
        var pref = "/img/" + (bdata.section ? (bdata.page || bdata.section) : "icons") + "/",
            name = bdata.name || (bdata.section && bdata.icon) || bdata.page || bdata.icon,
            url = !(bdata.click || bdata.clickChild) && bdata.page && (bdata.page + ".html"),
            cname = "round bordered padded";
        if (url && bdata.section)
            url += "#!" + bdata.section;
        if (bdata.className)
            cname += " " + bdata.className;
        return CT.dom.labeledImage(pref + bdata.icon + ".png", url,
            name, name, "centeredimg", cname, "centered nowrap small", false,
            (bdata.id || bdata.firstClass || bdata.click || bdata.clickChild) && function() {
                CT.dom.ALLNODE.toggleMobileMenu();
                if (bdata.click)
                    CT.dom.id(bdata.click).onclick();
                else if (bdata.clickChild)
                    CT.dom.id(bdata.clickChild).firstElementChild.onclick();
                else
                    CT.mobile.fitAndSnap(CT.mobile.getMobileNode(bdata));
            }, true, "mm" + name);
    },
    "initMobileMenus": function(mmbtn, loggedin, searchcb) {
        mmbtn.tops = CT.dom.node(null, null,
            "button_row top_out", "top_buttons");
        mmbtn.bottoms = CT.dom.node(null, null,
            "button_row bottom_out", "bottom_buttons");

        var mobile_search = CT.dom.field("mobile_search");
        mmbtn.tops.appendChild(CT.dom.node(CT.dom.node(
            [CT.dom.node("CAN Smart Search"), mobile_search], "div",
            "round bordered padded", "mobile_search_node"), "label", null,
            null, {"for": "mobile_search", "htmlFor": "mobile_search"}));
        (CT.mobile.page && CT.mobile.page.top || CT.mobile.menus.top).forEach(function(bdata) {
            mmbtn.tops.appendChild(CT.mobile.mobileMenuLink(bdata));
        });
        CT.mobile.menus.bottom.forEach(function(bdata) {
            mmbtn.bottoms.appendChild(CT.mobile.mobileMenuLink(bdata));
        });
        mmbtn.bottoms.appendChild(CT.mobile.mobileMenuLink(
            CT.mobile.menus.alternatives[loggedin ? "participate" : "login"]));
        CT.dom.inputEnterCallback(mobile_search, searchcb);
        CT.dom.blurField(mobile_search);

        document.body.appendChild(mmbtn.tops);
        document.body.appendChild(mmbtn.bottoms);

        var lefts = CT.mobile.page && CT.mobile.page.left || CT.mobile.menus.left;
        if (lefts) {
            mmbtn.lefts = CT.dom.node(null, null,
                "button_row_side left_out", "left_buttons");
            lefts.forEach(function(bdata) {
                mmbtn.lefts.appendChild(CT.mobile.mobileMenuLink(bdata));
            });
            document.body.appendChild(mmbtn.lefts);
        }

        var rights = CT.mobile.page && CT.mobile.page.right || CT.mobile.menus.right;
        if (rights) {
            mmbtn.rights = CT.dom.node(null, null,
                "button_row_side right_out", "right_buttons");
            rights.forEach(function(bdata) {
                mmbtn.rights.appendChild(CT.mobile.mobileMenuLink(bdata));
            });
            document.body.appendChild(mmbtn.rights);
        }
    },
    "_mset": function() {
        var _a = CT.dom.ALLNODE, i, m,
            modes = ["mobile", "tablet"];
        for (i = 0; i < modes.length; i++) {
            m = modes[i];
            if (_a["_" + m])
                return CT.mobile.options[m];
        }
        return CT.mobile.options.normal;
    },
    "isMobile": function() {
        return CT.dom.ALLNODE._mobile;
    },
    "initResizer": function(loggedin, resdata, menus, page, searchcb) {
        CT.mobile.menus = menus;
        CT.mobile.page = page;

        // for compiler
        var curd, btn, mmbtn, _a = CT.dom.ALLNODE, zMode = function() {
            return CT.mobile._mset()[_a._mindex];
        };
        var setScroll = function() {
            var _doscroll = function(e) {
                var n = _a.mobileNode || _a;
                if (n.getBoundingClientRect().bottom < CT.align.height())
                    n.scrollIntoView(false, { "behavior": "smooth" });
            };
            window.onscroll = function(e) {
                setTimeout(_doscroll, 500);
//                setTimeout(_doscroll, 1000);
  //              setTimeout(_doscroll, 2000);
    //            setTimeout(_doscroll, 3000);
            };
            var firstMove;
            window.addEventListener('touchstart', function (e) {
                firstMove = true;
            });
            window.addEventListener('touchmove', function (e) {
                if (firstMove) {
                    e.preventDefault();
                    firstMove = false;
                } else
                    window.onscroll && window.onscroll();
            });
        };
        _a._mobileDefault = _a.mobileNode =
            CT.mobile.getMobileNode((page && page.top || menus.top)[1]);
        _a._mode = zMode();
        _a._mindex = 0;
        _a._otherMode = function() {
            return CT.mobile._mset()[(_a._mindex + 1) % 2];
        };
        _a._swapMode = function() {
            _a._mindex = _a._mindex ? 0 : 1;
            setTimeout(function() {
                var vp = document.getElementsByTagName("meta");
                for (var i = 0; i < vp.length; i++) {
                    if (vp[i].name == "viewport") {
                        vp[i].content = "width=device-width, initial-scale=1.0"
                            + ((_a._mode == "mobile")
                            ? ", min-scale=1.0, max-scale=1.0, user-scalable=no" : "");
                        break;
                    }
                }
            }, 200);
            _a.resize();
        };
        _a.toggleMobileMenu = function() {
            if (mmbtn._on) {
                mmbtn.tops.className = "button_row top_out";
                mmbtn.bottoms.className = "button_row bottom_out";
                if (mmbtn.lefts)
                    mmbtn.lefts.className = "button_row_side left_out";
                if (mmbtn.rights)
                    mmbtn.rights.className = "button_row_side right_out";
            } else {
                mmbtn.tops.className = "button_row";
                mmbtn.bottoms.className = "button_row";
                if (mmbtn.lefts)
                    mmbtn.lefts.className = "button_row_side";
                if (mmbtn.rights)
                    mmbtn.rights.className = "button_row_side";
            }
            mmbtn._on = !mmbtn._on;
        };
        curd = resdata[_a._otherMode()];
        btn = CT.dom.img(curd.img, null, _a._swapMode, null,
            null, curd.alt, "resize_btn", "round bordered padded");
        mmbtn = CT.dom.img("/img/mobile-menu.png", null, _a.toggleMobileMenu,
            null, null, "Mobile Menu", "mobile_menu_btn", "round bordered padded");
        _a.resize = function() {
            _a._mobile = CT.info.mobile || CT.align.width() <= 720;
            _a._tablet = CT.info.tablet || CT.align.width() <= 980;
            _a._mode = zMode();
            if (_a._mode == "normal")
                CT.mobile.fitNode(null, "scale(1)", "50% 0%");
            else if (_a._mode == "stretched")
                CT.mobile.fitAndSnap(_a);
            else
                CT.mobile.fitAndSnap(_a._mobileDefault);
            if (_a._mode == "mobile") {
                mmbtn.style.display = "block";
                _a.chatBlock && _a.chatBlock();
            } else {
                mmbtn.style.display = "none";
                if (mmbtn._on)
                    mmbtn.onclick();
            }
            var toggleMode = _a._otherMode();
            btn.title = btn.alt = resdata[toggleMode].alt;
            btn.firstChild.firstChild.src = resdata[toggleMode].img;
        };
        document.body.appendChild(btn);
        document.body.appendChild(mmbtn);
        CT.mobile.initMobileMenus(mmbtn, loggedin, searchcb);
        _a.resize();
        setScroll();
    }
};<|endoftext|>


<commit_before>var validateEditForm = function (formObject) {
    var error = false;

    // check room number
    if (formObject['room-number'].length < 1) {
        toastr.error("You did not enter a room number");
        error = true;
    }

    return !error;
};

var validateCreateForm = function (formObject) {
    var error = false;

	// check room number
    if (formObject['room-number'].length < 1) {
        toastr.error("You did not enter a room number");
        error = true;
    }

    return !error;
};<commit_msg>Trim added to verifications done by Mark<commit_after>var validateEditForm = function (formObject) {
    var error = false;

    // check room number
    if (formObject['room-number'].trim().length < 1) {
        toastr.error("You did not enter a room number");
        error = true;
    }

    return !error;
};

var validateCreateForm = function (formObject) {
    var error = false;

	// check room number
    if (formObject['room-number'].trim().length < 1) {
        toastr.error("You did not enter a room number");
        error = true;
    }

    return !error;
};<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 Vanderbilt University, All rights reserved.
 *
 * Author: Miklos Maroti
 */

define([ "util/assert", "storage/mongo", "storage/cache", "storage/commit", "core/tasync", "util/sax", "fs", "bin/getconfig", "storage/socketioclient", "core/newcore" ], function (ASSERT, Mongo, Cache, Commit, TASYNC, SAX, FS, CONFIG, Client, Core) {
	function getParameters (option) {
		ASSERT(option === null || typeof option === "string" && option.charAt(0) !== "-");

		var i, j, argv = process.argv.slice(2);

		if (option === null) {
			for (i = 0; i < argv.length && argv[i].charAt(0) !== "-"; ++i) {
			}
			return argv.slice(0, i);
		}

		var option1 = "-" + option;
		var option2 = "--" + option;

		for (i = 0; i < argv.length; ++i) {
			if (argv[i] === option1 || argv[i] === option2) {
				for (j = i + 1; j < argv.length && argv[j].charAt(0) !== "-"; ++j) {
				}
				return argv.slice(i + 1, j);
			}
		}

		return null;
	}

	// --- database

	var database;

	function openDatabase () {
		var paramsMongo = getParameters("mongo");
        var paramsSIO = getParameters("socketio");
        var isSIO = paramsMongo === null && paramsSIO !== null && paramsSIO.length > 0;
        paramsMongo = paramsMongo || [];
        paramsSIO = paramsSIO || [];

		var opt = {
			database: paramsMongo[0] || CONFIG.mongodatabase || "webgme",
			host: paramsMongo[1] || paramsSIO[0] || CONFIG.mongoip || "localhost",
			port: paramsMongo[2] || paramsSIO[1] || CONFIG.mongoport || 27017
		};

        var database = null;
        if(isSIO){
            opt.type = "node";
            console.log("Opening database through socket.io connection on " + opt.host + (opt.port ? ":" + opt.port : ""));
            database = new Commit(new Cache(new Client(opt), {}));
        } else {
            console.log("Opening mongo database " + opt.database + " on " + opt.host + (opt.port ? ":" + opt.port : ""));
            database = new Commit(new Cache(new Mongo(opt), {}));
        }

		database.openDatabase = TASYNC.wrap(database.openDatabase);
		database.openProject = TASYNC.wrap(database.openProject);
		database.closeDatabase = TASYNC.wrap(database.closeDatabase);
		database.getProjectNames = TASYNC.wrap(database.getProjectNames);

		return TASYNC.call(openDatabase2, database, database.openDatabase());
	}

	function openDatabase2 (d) {
		database = d;
	}

	function closeDatabase () {
		if (database) {
			console.log("Closing database");

			var d = database;
			database = null;

			return d.closeDatabase();
		}
	}

	function getDatabase () {
		return database;
	}

	// --- project

	var project, core;

	function openProject (overRideName) {
		ASSERT(database);

		var params = getParameters("proj") || [];
		var name = params[0] || "test";
        if(typeof overRideName === 'string'){
            name = overRideName;
        }

		console.log("Opening project " + name);

		TASYNC.call(openProject2, database.openProject(name));
	}

	function openProject2 (p) {
		p.closeProject = TASYNC.wrap(p.closeProject);
		p.dumpObjects = TASYNC.wrap(p.dumpObjects);
		p.loadObject = TASYNC.wrap(p.loadObject);
		p.insertObject = TASYNC.wrap(p.insertObject);
		p.findHash = TASYNC.wrap(p.findHash);
		p.getBranchNames = TASYNC.wrap(p.getBranchNames);
		p.setBranchHash = TASYNC.wrap(p.setBranchHash);
		p.getBranchHash = TASYNC.wrap(p.getBranchHash);
		p.makeCommit = TASYNC.wrap(p.makeCommit);

		project = p;

        core = Core(project,{autopersist:true,usertype:'tasync'});
	}

	function closeProject () {
		if (project) {
			console.log("Closing project");

			var p = project;
			project = null;
			core = null;

			return p.closeProject();
		}
	}

	function getProject () {
		return project;
	}

	function getCore () {
		return core;
	}

	// --- progress

	var progress;

	function setProgress (func) {
		if (progress) {
			clearInterval(progress);
		}

		if (func) {
			progress = setInterval(func, 2000);
		}
	}

	// --- sax parsing

	var saxParse = TASYNC.wrap(function (xmlfile, handler, callback) {
		ASSERT(typeof handler.opentag === "function");
		ASSERT(typeof handler.closetag === "function");
		ASSERT(typeof handler.text === "function");
		ASSERT(typeof handler.getstat === "function");

		var parser = SAX.createStream(true, {
			trim: true
		});

		parser.on("opentag", handler.opentag);
		parser.on("closetag", handler.closetag);
		parser.on("text", handler.text);

		parser.on("error", function (error) {
			setProgress(null);
			callback(error);
		});

		parser.on("end", function () {
			console.log("Parsing done");
			setProgress(null);
			callback(null);
		});

		var stream = FS.createReadStream(xmlfile);

		stream.on("error", function (err) {
			setProgress(null);
			callback(new Error(err.code === "ENOENT" ? "File not found: " + xmlfile : "Unknown file error: " + JSON.stringify(err)));
		});

		stream.on("open", function () {
			console.log("Parsing " + xmlfile + " ...");
			stream.pipe(parser);
		});

		setProgress(function () {
			var stat = handler.getstat();
			console.log("  at line " + parser._parser.line + (typeof stat === "string" ? " (" + stat + ")" : ""));
		});
	});

	// --- export

	return {
		getParameters: getParameters,
		openDatabase: openDatabase,
		closeDatabase: closeDatabase,
		getDatabase: getDatabase,
		openProject: openProject,
		closeProject: closeProject,
		getProject: getProject,
		getCore: getCore,
		setProgress: setProgress,
		saxParse: saxParse
	};
});
<commit_msg>bugfix - old includes in common<commit_after>/*
 * Copyright (C) 2012 Vanderbilt University, All rights reserved.
 *
 * Author: Miklos Maroti
 */

define([ "util/assert", "storage/mongo", "storage/cache", "storage/commit", "core/tasync", "util/sax", "fs", "bin/getconfig", "storage/client", "core/core" ], function (ASSERT, Mongo, Cache, Commit, TASYNC, SAX, FS, CONFIG, Client, Core) {
	function getParameters (option) {
		ASSERT(option === null || typeof option === "string" && option.charAt(0) !== "-");

		var i, j, argv = process.argv.slice(2);

		if (option === null) {
			for (i = 0; i < argv.length && argv[i].charAt(0) !== "-"; ++i) {
			}
			return argv.slice(0, i);
		}

		var option1 = "-" + option;
		var option2 = "--" + option;

		for (i = 0; i < argv.length; ++i) {
			if (argv[i] === option1 || argv[i] === option2) {
				for (j = i + 1; j < argv.length && argv[j].charAt(0) !== "-"; ++j) {
				}
				return argv.slice(i + 1, j);
			}
		}

		return null;
	}

	// --- database

	var database;

	function openDatabase () {
		var paramsMongo = getParameters("mongo");
        var paramsSIO = getParameters("socketio");
        var isSIO = paramsMongo === null && paramsSIO !== null && paramsSIO.length > 0;
        paramsMongo = paramsMongo || [];
        paramsSIO = paramsSIO || [];

		var opt = {
			database: paramsMongo[0] || CONFIG.mongodatabase || "webgme",
			host: paramsMongo[1] || paramsSIO[0] || CONFIG.mongoip || "localhost",
			port: paramsMongo[2] || paramsSIO[1] || CONFIG.mongoport || 27017
		};

        var database = null;
        if(isSIO){
            opt.type = "node";
            console.log("Opening database through socket.io connection on " + opt.host + (opt.port ? ":" + opt.port : ""));
            database = new Commit(new Cache(new Client(opt), {}));
        } else {
            console.log("Opening mongo database " + opt.database + " on " + opt.host + (opt.port ? ":" + opt.port : ""));
            database = new Commit(new Cache(new Mongo(opt), {}));
        }

		database.openDatabase = TASYNC.wrap(database.openDatabase);
		database.openProject = TASYNC.wrap(database.openProject);
		database.closeDatabase = TASYNC.wrap(database.closeDatabase);
		database.getProjectNames = TASYNC.wrap(database.getProjectNames);

		return TASYNC.call(openDatabase2, database, database.openDatabase());
	}

	function openDatabase2 (d) {
		database = d;
	}

	function closeDatabase () {
		if (database) {
			console.log("Closing database");

			var d = database;
			database = null;

			return d.closeDatabase();
		}
	}

	function getDatabase () {
		return database;
	}

	// --- project

	var project, core;

	function openProject (overRideName) {
		ASSERT(database);

		var params = getParameters("proj") || [];
		var name = params[0] || "test";
        if(typeof overRideName === 'string'){
            name = overRideName;
        }

		console.log("Opening project " + name);

		TASYNC.call(openProject2, database.openProject(name));
	}

	function openProject2 (p) {
		p.closeProject = TASYNC.wrap(p.closeProject);
		p.dumpObjects = TASYNC.wrap(p.dumpObjects);
		p.loadObject = TASYNC.wrap(p.loadObject);
		p.insertObject = TASYNC.wrap(p.insertObject);
		p.findHash = TASYNC.wrap(p.findHash);
		p.getBranchNames = TASYNC.wrap(p.getBranchNames);
		p.setBranchHash = TASYNC.wrap(p.setBranchHash);
		p.getBranchHash = TASYNC.wrap(p.getBranchHash);
		p.makeCommit = TASYNC.wrap(p.makeCommit);

		project = p;

        core = Core(project,{autopersist:true,usertype:'tasync'});
	}

	function closeProject () {
		if (project) {
			console.log("Closing project");

			var p = project;
			project = null;
			core = null;

			return p.closeProject();
		}
	}

	function getProject () {
		return project;
	}

	function getCore () {
		return core;
	}

	// --- progress

	var progress;

	function setProgress (func) {
		if (progress) {
			clearInterval(progress);
		}

		if (func) {
			progress = setInterval(func, 2000);
		}
	}

	// --- sax parsing

	var saxParse = TASYNC.wrap(function (xmlfile, handler, callback) {
		ASSERT(typeof handler.opentag === "function");
		ASSERT(typeof handler.closetag === "function");
		ASSERT(typeof handler.text === "function");
		ASSERT(typeof handler.getstat === "function");

		var parser = SAX.createStream(true, {
			trim: true
		});

		parser.on("opentag", handler.opentag);
		parser.on("closetag", handler.closetag);
		parser.on("text", handler.text);

		parser.on("error", function (error) {
			setProgress(null);
			callback(error);
		});

		parser.on("end", function () {
			console.log("Parsing done");
			setProgress(null);
			callback(null);
		});

		var stream = FS.createReadStream(xmlfile);

		stream.on("error", function (err) {
			setProgress(null);
			callback(new Error(err.code === "ENOENT" ? "File not found: " + xmlfile : "Unknown file error: " + JSON.stringify(err)));
		});

		stream.on("open", function () {
			console.log("Parsing " + xmlfile + " ...");
			stream.pipe(parser);
		});

		setProgress(function () {
			var stat = handler.getstat();
			console.log("  at line " + parser._parser.line + (typeof stat === "string" ? " (" + stat + ")" : ""));
		});
	});

	// --- export

	return {
		getParameters: getParameters,
		openDatabase: openDatabase,
		closeDatabase: closeDatabase,
		getDatabase: getDatabase,
		openProject: openProject,
		closeProject: closeProject,
		getProject: getProject,
		getCore: getCore,
		setProgress: setProgress,
		saxParse: saxParse
	};
});
<|endoftext|>


<commit_before>var http = require('https');
var request = require('request');
var fs = require('fs');

var parseDiff = require('parse-diff');
var _ = require('lodash');
var CLIEngine = require("eslint").CLIEngine;
const CHECKED_DIR = require('../constants').CHECKED_DIR;

const GITHUB_TOKEN = process.env.GITHUB_TOKEN || '';

var eslintCli = new CLIEngine({
    fix: false,
    envs: [
        "node",
        "browser",
        "worker",
        "jquery"
    ],
    baseConfig: {
        extends: ["airbnb"],
    },
    rules: {
        "new-cap": [
            2,
            {
                "capIsNewExceptions": [
                    "FluxMixin",
                    "StoreWatchMixin"
                ]
            }
        ],
        "import/extensions": 1,
        "no-useless-escape": 1,
        "no-bitwise": 1,
        "no-plusplus": 1,
        "react/forbid-prop-types": 1,
        "react/require-default-props": 1,
        "react/no-unused-prop-types": 1,
        "jsx-a11y/no-static-element-interactions": 1,
        "react/no-array-index-key": 1,
        "no-unused-vars": 1,
        "react/prefer-es6-class": 0,
        "react/no-deprecated": 0,
        "react/no-find-dom-node": 0,
        "global-require": 0,
        "import/no-webpack-loader-syntax": 0,
        "react/jsx-filename-extension": [1, {
            "extensions": [".js", ".jsx"]
        }],
        "import/no-extraneous-dependencies": 0,
        "import/no-unresolved": 0,
        "jsx-a11y/href-no-hash": 0
    },
    "parser": "babel-eslint",
    "parserOptions": {
        "ecmaVersion": 6,
        "ecmaFeatures": {
            "experimentalObjectRestSpread": true
        }
    },
    "globals": [
        "_",
        "tinymce",
        "jsonh",
        "compileSectionData",
        "dataprebuiltId",
        "autoresponderStatus",
        "MagicWand",
        "tinyMCE",
        "FB"
    ],
});

const checkEslint = pathList => {
    return eslintCli.executeOnFiles(pathList);
}

const getFilesFromDiff = diff => parseDiff(diff);

const regExpFilter = regExp => filename => {
    if (_.isArray(regExp)) {
        return _.every(regExp.map(re => re.test(filename)));
    }
    return regExp.test(filename);
}

const getFilePath = (repositoryOwner, repositoryName, sha, filename) =>
    `/${repositoryOwner}/${repositoryName}/${sha}/${filename}`;

const getGitHubHeaders = () => Object(
    {
        Authorization: `token ${GITHUB_TOKEN}`,
        Accept: 'application/vnd.github.v3.raw',
        'User-Agent': 'mrlinter',
        'content-type': 'application/json',
    }
)

const getRawGitHubOptions = opts => Object(
    {
        protocol: 'https:',
        host: 'raw.githubusercontent.com',
        path: getFilePath(opts.owner, opts.repository, opts.sha, opts.filename),
        headers: getGitHubHeaders(),
    }
);

const getGitHubFilePromise = (url, mediaType = 'application/vnd.github.v3.raw') => new Promise((resolve, reject) => {
    const githubRequestOptions = {
        url: url,
        headers: getGitHubHeaders(),
    };
    githubRequestOptions.headers['Accept'] = mediaType;
    request(githubRequestOptions, (error, response, body) => {
        const statusCode = response.statusCode;
        if (statusCode === 200) {
            resolve(body);
        } else {
            if (statusCode === 301 && response.headers.location) {
                resolve(getGitHubFilePromise(response.headers.location));
            } else {
                reject(statusCode);
            }
        }
    });
});

const prepareComment = (report, filePath) => {
    let commentBody = '';
    if (report.errorCount) {
        console.log(`Report have the ${report.errorCount} errors in ${report.results.length} files`);
        report.results.forEach((result, resultIndex) => {
            const resultFilename = filePath[result.filePath.split('/').slice(-1)];
            console.log(`Start processing ${resultIndex + 1} result of ${report.results.length} for ${resultFilename}`);
            let resultCommentPart = result.errorCount
                ? `- In the file [**${resultFilename}**], following are the ESLint issues :\n`
                : `- There are no ESLint issues in the file [**${resultFilename}**]\n`;
            if (result.errorCount) {
                const onlyErrorMessages = result.messages.filter(message => (message.severity === 2));
                result.messages.forEach((onlyErrorMessages, messageIndex) => {
                    console.log(`Start processing ${messageIndex + 1} of ${result.messages.length} message of ${resultFilename}`)
                    resultCommentPart += `> ${message.line}:${message.column}\t${message.message}\t${message.ruleId}\n`
                });
            }
            commentBody += `${resultCommentPart}\n\n`
        })
    }
    return commentBody;
}

const getCheckedDirName = requestId => `${CHECKED_DIR}-${requestId}`;

module.exports = {
    getGitHubFilePromise: getGitHubFilePromise,
    getFilesFromDiff: getFilesFromDiff,
    regExpFilter: regExpFilter,
    getFilePath: getFilePath,
    getGitHubHeaders: getGitHubHeaders,
    getRawGitHubOptions: getRawGitHubOptions,
    checkEslint: checkEslint,
    prepareComment: prepareComment,
    getCheckedDirName: getCheckedDirName,
}
<commit_msg>Fix regExp filter<commit_after>var http = require('https');
var request = require('request');
var fs = require('fs');

var parseDiff = require('parse-diff');
var _ = require('lodash');
var CLIEngine = require("eslint").CLIEngine;
const CHECKED_DIR = require('../constants').CHECKED_DIR;

const GITHUB_TOKEN = process.env.GITHUB_TOKEN || '';

var eslintCli = new CLIEngine({
    fix: false,
    envs: [
        "node",
        "browser",
        "worker",
        "jquery"
    ],
    baseConfig: {
        extends: ["airbnb"],
    },
    rules: {
        "new-cap": [
            2,
            {
                "capIsNewExceptions": [
                    "FluxMixin",
                    "StoreWatchMixin"
                ]
            }
        ],
        "import/extensions": 1,
        "no-useless-escape": 1,
        "no-bitwise": 1,
        "no-plusplus": 1,
        "react/forbid-prop-types": 1,
        "react/require-default-props": 1,
        "react/no-unused-prop-types": 1,
        "jsx-a11y/no-static-element-interactions": 1,
        "react/no-array-index-key": 1,
        "no-unused-vars": 1,
        "react/prefer-es6-class": 0,
        "react/no-deprecated": 0,
        "react/no-find-dom-node": 0,
        "global-require": 0,
        "import/no-webpack-loader-syntax": 0,
        "react/jsx-filename-extension": [1, {
            "extensions": [".js", ".jsx"]
        }],
        "import/no-extraneous-dependencies": 0,
        "import/no-unresolved": 0,
        "jsx-a11y/href-no-hash": 0
    },
    "parser": "babel-eslint",
    "parserOptions": {
        "ecmaVersion": 6,
        "ecmaFeatures": {
            "experimentalObjectRestSpread": true
        }
    },
    "globals": [
        "_",
        "tinymce",
        "jsonh",
        "compileSectionData",
        "dataprebuiltId",
        "autoresponderStatus",
        "MagicWand",
        "tinyMCE",
        "FB"
    ],
});

const checkEslint = pathList => {
    return eslintCli.executeOnFiles(pathList);
}

const getFilesFromDiff = diff => parseDiff(diff);

const regExpFilter = regExp => filename => {
    if (_.isArray(regExp)) {
        return _.any(regExp.map(re => re.test(filename)));
    }
    return regExp.test(filename);
}

const getFilePath = (repositoryOwner, repositoryName, sha, filename) =>
    `/${repositoryOwner}/${repositoryName}/${sha}/${filename}`;

const getGitHubHeaders = () => Object(
    {
        Authorization: `token ${GITHUB_TOKEN}`,
        Accept: 'application/vnd.github.v3.raw',
        'User-Agent': 'mrlinter',
        'content-type': 'application/json',
    }
)

const getRawGitHubOptions = opts => Object(
    {
        protocol: 'https:',
        host: 'raw.githubusercontent.com',
        path: getFilePath(opts.owner, opts.repository, opts.sha, opts.filename),
        headers: getGitHubHeaders(),
    }
);

const getGitHubFilePromise = (url, mediaType = 'application/vnd.github.v3.raw') => new Promise((resolve, reject) => {
    const githubRequestOptions = {
        url: url,
        headers: getGitHubHeaders(),
    };
    githubRequestOptions.headers['Accept'] = mediaType;
    request(githubRequestOptions, (error, response, body) => {
        const statusCode = response.statusCode;
        if (statusCode === 200) {
            resolve(body);
        } else {
            if (statusCode === 301 && response.headers.location) {
                resolve(getGitHubFilePromise(response.headers.location));
            } else {
                reject(statusCode);
            }
        }
    });
});

const prepareComment = (report, filePath) => {
    let commentBody = '';
    if (report.errorCount) {
        console.log(`Report have the ${report.errorCount} errors`);
        report.results.forEach((result, resultIndex) => {
            const resultFilename = filePath[result.filePath.split('/').slice(-1)];
            let resultCommentPart = result.errorCount
                ? `- In the file [**${resultFilename}**], following are the ESLint issues :\n`
                : `- There are no ESLint issues in the file [**${resultFilename}**]\n`;
            if (result.errorCount) {
                const onlyErrorMessages = result.messages.filter(message => (message.severity === 2));
                result.messages.forEach((onlyErrorMessages, messageIndex) => {
                    console.log(`Start processing ${messageIndex + 1} of ${result.messages.length} message of ${resultFilename}`)
                    resultCommentPart += `> ${message.line}:${message.column}\t${message.message}\t${message.ruleId}\n`
                });
            }
            commentBody += `${resultCommentPart}\n\n`
        })
    }
    return commentBody;
}

const getCheckedDirName = requestId => `${CHECKED_DIR}-${requestId}`;

module.exports = {
    getGitHubFilePromise: getGitHubFilePromise,
    getFilesFromDiff: getFilesFromDiff,
    regExpFilter: regExpFilter,
    getFilePath: getFilePath,
    getGitHubHeaders: getGitHubHeaders,
    getRawGitHubOptions: getRawGitHubOptions,
    checkEslint: checkEslint,
    prepareComment: prepareComment,
    getCheckedDirName: getCheckedDirName,
}
<|endoftext|>


<commit_before>/**
 * Mnemonist Merge Helpers
 * ========================
 *
 * Various merge algorithms used to handle sorted lists.
 */
var typed = require('./typed-arrays.js'),
    isArrayLike = require('./iterate.js').isArrayLike,
    FibonacciHeap = require('../fibonacci-heap.js');

/**
 * Merge two sorted array-like structures into one.
 *
 * @param  {array} a - First array.
 * @param  {array} b - Second array.
 * @return {array}
 */
function mergeArrays(a, b) {

  // One of the arrays is empty
  if (a.length === 0)
    return b.slice();
  if (b.length === 0)
    return a.slice();

  // Initializing target
  var array = new a.constructor(a.length + b.length);

  // Finding min array
  var tmp;

  if (a[0] > b[0]) {
    tmp = a;
    a = b;
    b = tmp;
  }

  // If array have non overlapping ranges, we can just concatenate them
  var aStart = a[0],
      aEnd = a[a.length - 1],
      bStart = b[0],
      bEnd = b[b.length - 1];

  if (aEnd <= bStart) {
    if (typed.isTypedArray(a))
      return typed.concat(a, b);
    return a.concat(b);
  }
  else if (bEnd <= aStart) {
    if (typed.isTypedArray(a))
      return typed.concat(b, a);
    return b.concat(a);
  }

  // Iterating until we overlap
  var i, l, v;

  for (i = 0, l = a.length; i < l; i++) {
    v = a[i];

    if (v <= bStart)
      array[i] = v;
    else
      break;
  }

  // Handling overlap
  var aPointer = i,
      aLength = a.length,
      bPointer = 0,
      bLength = b.length,
      aHead,
      bHead;

  while (aPointer < aLength && bPointer < bLength) {
    aHead = a[aPointer];
    bHead = b[bPointer];

    if (aHead <= bHead) {
      array[i++] = aHead;
      aPointer++;
    }
    else {
      array[i++] = bHead;
      bPointer++;
    }
  }

  // Filling
  while (aPointer < aLength)
    array[i++] = a[aPointer++];
  while (bPointer < bLength)
    array[i++] = b[bPointer++];

  return array;
}

/**
 * Merge k sorted array-like structures into one.
 *
 * @param  {array<array>} arrays - Arrays to merge.
 * @return {array}
 */
function kWayMergeArrays(arrays) {
  var length = 0,
      max = -Infinity,
      al,
      i,
      l;

  var filtered = [];

  for (i = 0, l = arrays.length; i < l; i++) {
    al = arrays[i].length;

    if (al === 0)
      continue;

    filtered.push(arrays[i]);

    length += al;

    if (al > max)
      max = al;
  }

  if (filtered.length === 0)
    return new arrays[0].constructor(0);

  if (filtered.length === 1)
    return filtered[0].slice();

  if (filtered.length === 2)
    return mergeArrays(filtered[0], filtered[1]);

  arrays = filtered;

  var array = new arrays[0].constructor(length);

  var PointerArray = typed.getPointerArray(max);

  var pointers = new PointerArray(arrays.length);

  // TODO: benchmark vs. a binomial heap
  var heap = new FibonacciHeap(function(a, b) {
    a = arrays[a][pointers[a]];
    b = arrays[b][pointers[b]];

    if (a < b)
      return -1;

    if (a > b)
      return 1;

    return 0;
  });

  for (i = 0; i < l; i++)
    heap.push(i);

  i = 0;

  var p,
      v;

  while (heap.size) {
    p = heap.pop();
    v = arrays[p][pointers[p]++];
    array[i++] = v;

    if (pointers[p] < arrays[p].length)
      heap.push(p);
  }

  return array;
}

/**
 * Variadic function using all of the above to return the desired result.
 *
 * @param  {...array}
 * @return {array}
 */
module.exports = function merge() {
  if (arguments.length === 2) {
    if (isArrayLike(arguments[0]))
      return mergeArrays(arguments[0], arguments[1]);
  }
  else {
    if (isArrayLike(arguments[0]))
      return kWayMergeArrays(arguments);
  }

  return null;
};
<commit_msg>Optims<commit_after>/**
 * Mnemonist Merge Helpers
 * ========================
 *
 * Various merge algorithms used to handle sorted lists.
 */
var typed = require('./typed-arrays.js'),
    isArrayLike = require('./iterate.js').isArrayLike,
    FibonacciHeap = require('../fibonacci-heap.js');

/**
 * Merge two sorted array-like structures into one.
 *
 * @param  {array} a - First array.
 * @param  {array} b - Second array.
 * @return {array}
 */
function mergeArrays(a, b) {

  // One of the arrays is empty
  if (a.length === 0)
    return b.slice();
  if (b.length === 0)
    return a.slice();

  // Finding min array
  var tmp;

  if (a[0] > b[0]) {
    tmp = a;
    a = b;
    b = tmp;
  }

  // If array have non overlapping ranges, we can just concatenate them
  var aStart = a[0],
      aEnd = a[a.length - 1],
      bStart = b[0],
      bEnd = b[b.length - 1];

  if (aEnd <= bStart) {
    if (typed.isTypedArray(a))
      return typed.concat(a, b);
    return a.concat(b);
  }
  else if (bEnd <= aStart) {
    if (typed.isTypedArray(a))
      return typed.concat(b, a);
    return b.concat(a);
  }

  // Initializing target
  var array = new a.constructor(a.length + b.length);

  // Iterating until we overlap
  var i, l, v;

  for (i = 0, l = a.length; i < l; i++) {
    v = a[i];

    if (v <= bStart)
      array[i] = v;
    else
      break;
  }

  // Handling overlap
  var aPointer = i,
      aLength = a.length,
      bPointer = 0,
      bLength = b.length,
      aHead,
      bHead;

  while (aPointer < aLength && bPointer < bLength) {
    aHead = a[aPointer];
    bHead = b[bPointer];

    if (aHead <= bHead) {
      array[i++] = aHead;
      aPointer++;
    }
    else {
      array[i++] = bHead;
      bPointer++;
    }
  }

  // Filling
  while (aPointer < aLength)
    array[i++] = a[aPointer++];
  while (bPointer < bLength)
    array[i++] = b[bPointer++];

  return array;
}

/**
 * Merge k sorted array-like structures into one.
 *
 * @param  {array<array>} arrays - Arrays to merge.
 * @return {array}
 */
function kWayMergeArrays(arrays) {
  var length = 0,
      max = -Infinity,
      al,
      i,
      l;

  var filtered = [];

  for (i = 0, l = arrays.length; i < l; i++) {
    al = arrays[i].length;

    if (al === 0)
      continue;

    filtered.push(arrays[i]);

    length += al;

    if (al > max)
      max = al;
  }

  if (filtered.length === 0)
    return new arrays[0].constructor(0);

  if (filtered.length === 1)
    return filtered[0].slice();

  if (filtered.length === 2)
    return mergeArrays(filtered[0], filtered[1]);

  arrays = filtered;

  var array = new arrays[0].constructor(length);

  var PointerArray = typed.getPointerArray(max);

  var pointers = new PointerArray(arrays.length);

  // TODO: benchmark vs. a binomial heap
  var heap = new FibonacciHeap(function(a, b) {
    a = arrays[a][pointers[a]];
    b = arrays[b][pointers[b]];

    if (a < b)
      return -1;

    if (a > b)
      return 1;

    return 0;
  });

  for (i = 0; i < l; i++)
    heap.push(i);

  i = 0;

  var p,
      v;

  while (heap.size) {
    p = heap.pop();
    v = arrays[p][pointers[p]++];
    array[i++] = v;

    if (pointers[p] < arrays[p].length)
      heap.push(p);
  }

  return array;
}

/**
 * Variadic function using all of the above to return the desired result.
 *
 * @param  {...array}
 * @return {array}
 */
module.exports = function merge() {
  if (arguments.length === 2) {
    if (isArrayLike(arguments[0]))
      return mergeArrays(arguments[0], arguments[1]);
  }
  else {
    if (isArrayLike(arguments[0]))
      return kWayMergeArrays(arguments);
  }

  return null;
};
<|endoftext|>


<commit_before>var InteractActions = function (stompClient, gameUID) {
    "use strict";
    this.stompClient = stompClient;
    this.gameUID = gameUID;
    this.ACTION_CLASSES = {
        DROP_ACTIVE: 'drop-active',
        DROP_TARGET: 'drop-target',
        CAN_DROP: 'can-drop'
    };
    this.startOfMove = true;
    this.sourceId = "";
    this.destId = "";
};

InteractActions.prototype = {
    onMove : function (event) {
        "use strict";
        var target = event.target,
            // keep the dragged position in the data-x/data-y attributes
            x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
            y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy,
            correctY = target.transform.baseVal[0].matrix.f,
            correctX = target.transform.baseVal[0].matrix.e;
        // translate the element
        target.style.webkitTransform =
            target.style.transform =
            'translate(' + (x + correctX) + 'px, ' + (y + correctY) + 'px)';

        // update the posiion attributes
        target.setAttribute('data-x', x);
        target.setAttribute('data-y', y);
    },

    onDragEnter : function (event) {
        "use strict";
        var draggableElement = event.relatedTarget,
            dropzoneElement = event.target;

            // feedback the possibility of a drop
        dropzoneElement.classList.add(this.ACTION_CLASSES.DROP_TARGET);
        draggableElement.classList.add(this.ACTION_CLASSES.CAN_DROP);
    },

    onDropActivate : function (event) {
        "use strict";
        // add active dropzone feedback
        event.target.classList.add(this.ACTION_CLASSES.DROP_ACTIVE);
    },

    onDragLeave : function (event) {
        "use strict";
        event.target.classList.remove(this.ACTION_CLASSES.DROP_TARGET);
        event.relatedTarget.classList.remove(this.ACTION_CLASSES.CAN_DROP);
        if (this.startOfMove) {
            this.sourceId = event.target.id;
            this.startOfMove = false;
        }
    },

    onDrop : function (event) {
        "use strict";
        this.destId = event.target.id;
        this.startOfMove = true;
        var move = this.sourceId + "-" + this.destId;
        this.stompClient.send("/app/move/" + this.gameUID, {priority: 9}, move);
    },

    onDropDeactivate : function (event) {
        "use strict";
        // remove active dropzone feedback
        event.target.classList.remove(this.ACTION_CLASSES.DROP_ACTIVE);
        event.target.classList.remove(this.ACTION_CLASSES.DROP_TARGET);
    }
};

/*global interact*/
function chessGameInteract(stompClient, gameUID) {
    "use strict";

    var DRAGGABLE_CLASS = '.draggable',
        DROPZONE_CLASS = '.dropzone',
        DROPZONE_ACCEPT_CLASS = '.chesspiece',
        RESTRICTION_ELEMENT = '#layer',
        actions = new InteractActions(stompClient, gameUID);

    interact(DRAGGABLE_CLASS).draggable({
        // enable inertial throwing
        inertia: true,
        // keep the element within the area of it's parent
        restrict: {
            restriction: RESTRICTION_ELEMENT,
            endOnly: true,
            elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
        },

        // call this function on every dragmove event
        onmove: function (event) {
            actions.onMove.call(actions, event);
        }
    });

    interact(DROPZONE_CLASS).dropzone({
        accept: DROPZONE_ACCEPT_CLASS,
        overlap: 0.1,
        ondropactivate: function (event) {
            actions.onDropActivate.call(actions, event);
        },
        ondragenter: function (event) {
            actions.onDragEnter.call(actions, event);
        },
        ondragleave: function (event) {
            actions.onDragLeave.call(actions, event);
        },
        ondrop: function (event) {
            actions.onDrop.call(actions, event);
        },
        ondropdeactivate: function (event) {
            actions.onDropDeactivate.call(actions, event);
        }
    });
}

<commit_msg>Add debug console statements to InteractActions functions<commit_after>/*
 * @file To set up the interact.js library to allow the user to move the chess pieces on the board
 * @author Adrian McLaughlin
 */

/*global interact*/
/*global console*/

/*
 * Creates an InteractActions object
 * To be used by Interact.js
 * @class
 * @access private
 * @param {stompConnection} stompClient - STOMP Connection to server
 * @param {string} gameUID - String represention of the Game unique number
 */
var InteractActions = function (stompClient, gameUID) {
    "use strict";
    this.stompClient = stompClient;
    this.gameUID = gameUID;
    this.ACTION_CLASSES = {
        DROP_ACTIVE: 'drop-active',
        DROP_TARGET: 'drop-target',
        CAN_DROP: 'can-drop'
    };
    this.startOfMove = true;
    this.sourceId = "";
    this.destId = "";
};

InteractActions.prototype = {
    onMove : function (event) {
        "use strict";
        var target = event.target,
            // keep the dragged position in the data-x/data-y attributes
            x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
            y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy,
            correctY = target.transform.baseVal[0].matrix.f,
            correctX = target.transform.baseVal[0].matrix.e;
        // translate the element
        target.style.webkitTransform =
            target.style.transform =
            'translate(' + (x + correctX) + 'px, ' + (y + correctY) + 'px)';

        // update the posiion attributes
        target.setAttribute('data-x', x);
        target.setAttribute('data-y', y);
    },

    onDragEnter : function (event) {
        "use strict";
        console.log("Drop dragEnter");
        var draggableElement = event.relatedTarget,
            dropzoneElement = event.target;

            // feedback the possibility of a drop
        dropzoneElement.classList.add(this.ACTION_CLASSES.DROP_TARGET);
        draggableElement.classList.add(this.ACTION_CLASSES.CAN_DROP);
    },

    onDropActivate : function (event) {
        "use strict";
        console.log("Drop onDropActivate");
        // add active dropzone feedback
        event.target.classList.add(this.ACTION_CLASSES.DROP_ACTIVE);
    },

    onDragLeave : function (event) {
        "use strict";
        console.log("Drop onDragLeave");
        event.target.classList.remove(this.ACTION_CLASSES.DROP_TARGET);
        event.relatedTarget.classList.remove(this.ACTION_CLASSES.CAN_DROP);
        if (this.startOfMove) {
            this.sourceId = event.target.id;
            this.startOfMove = false;
        }
    },

    onDrop : function (event) {
        "use strict";
        console.log("Drop onDrop");
        this.destId = event.target.id;
        this.startOfMove = true;
        var move = this.sourceId + "-" + this.destId;
        this.stompClient.send("/app/move/" + this.gameUID, {priority: 9}, move);
    },

    onDropDeactivate : function (event) {
        "use strict";
        console.log("Drop deactivate");
        // remove active dropzone feedback
        event.target.classList.remove(this.ACTION_CLASSES.DROP_ACTIVE);
        event.target.classList.remove(this.ACTION_CLASSES.DROP_TARGET);
    }
};

/*
 *
 */
function chessGameInteract(stompClient, gameUID) {
    "use strict";

    var DRAGGABLE_CLASS = '.draggable',
        DROPZONE_CLASS = '.dropzone',
        DROPZONE_ACCEPT_CLASS = '.chesspiece',
        RESTRICTION_ELEMENT = '#layer',
        actions = new InteractActions(stompClient, gameUID);

    interact(DRAGGABLE_CLASS).draggable({
        // enable inertial throwing
        inertia: true,
        // keep the element within the area of it's parent
        restrict: {
            restriction: RESTRICTION_ELEMENT,
            endOnly: true,
            elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
        },

        // call this function on every dragmove event
        onmove: function (event) {
            actions.onMove.call(actions, event);
        }
    });

    interact(DROPZONE_CLASS).dropzone({
        accept: DROPZONE_ACCEPT_CLASS,
        overlap: 0.1,
        ondropactivate: function (event) {
            actions.onDropActivate.call(actions, event);
        },
        ondragenter: function (event) {
            actions.onDragEnter.call(actions, event);
        },
        ondragleave: function (event) {
            actions.onDragLeave.call(actions, event);
        },
        ondrop: function (event) {
            actions.onDrop.call(actions, event);
        },
        ondropdeactivate: function (event) {
            actions.onDropDeactivate.call(actions, event);
        }
    });
}

<|endoftext|>


<commit_before>var _ = require('underscore');

/**
 * SubscriptionManager Middleware
 *
 * - handles 'subscribe' packet
 * - handles 'unsubscribe' packets
 * - executes 'subscribeTopic' and 'unsubscribeTopic'
 *
 * TODO: Support QoS2
 * TODO: Forward retained messages for new subscriptions.
 * TODO: Forward messages according to the subscriptions and messages max QoS.
 * TODO: On Unsubscribe ensure that all QoS1 and QoS2 get completed
 *
 * @param {Object} config
 *
 * @example
 * stack.use(new SubscriptionManager({
 *   subscribeTopic: function(ctx, callback) {
 *     // make subscription
 *     callback(ctx.qos);
 *   },
 *   unsubscribeTopic: function(ctx, callback) {
 *     // make unsubscription
 *     callback();
 *   }
 * }));
 */

var SubscriptionManager = function(config){
  this.config = _.defaults(config || {}, {
    subscribeTopic: function(ctx, callback) {
      callback(ctx.qos);
    },
    unsubscribeTopic: function(ctx, callback) {
      callback();
    }
  });
};

SubscriptionManager.prototype.subscribeTopic = function(ctx, callback) {
  this.config.subscribeTopic(ctx, callback);
};

SubscriptionManager.prototype.unsubscribeTopic = function(ctx, callback) {
  this.config.unsubscribeTopic(ctx, callback);
};

SubscriptionManager.prototype.handle = function(client, packet, next){
  var self = this;
  if(packet.cmd == 'subscribe') {
    var granted = [];
    _.each(packet.subscriptions, function(s) {
      self.stack.execute('subscribeTopic', {
        client: client,
        packet: packet,
        topic: s.topic,
        qos: s.qos
      }, function(err, results){
        if(err) return next(err);

        var grant = Math.min.apply(null, _.flatten(results));
        granted.push(grant === false ? 128 : Math.min(grant, 1));
        if(granted.length == packet.subscriptions.length) {
          return client.suback({
            messageId: packet.messageId,
            granted: granted
          });
        }
      });
    });
  } else if(packet.cmd == 'unsubscribe') {
    var i = 0;
    _.each(packet.unsubscriptions, function(us){
      self.stack.execute('unsubscribeTopic', {
        client: client,
        packet: packet,
        topic: us
      }, function(err){
        i++;
        if(err) return next(err);
        if(packet.unsubscriptions.length == i) {
          return client.unsuback({
            messageId: packet.messageId
          });
        }
      });
    });
  } else {
    return next();
  }
};

module.exports = SubscriptionManager;
<commit_msg>by default grant only QoS 0<commit_after>var _ = require('underscore');

/**
 * SubscriptionManager Middleware
 *
 * - handles 'subscribe' packet
 * - handles 'unsubscribe' packets
 * - executes 'subscribeTopic' and 'unsubscribeTopic'
 *
 * TODO: Support QoS2
 * TODO: Forward retained messages for new subscriptions.
 * TODO: Forward messages according to the subscriptions and messages max QoS.
 * TODO: On Unsubscribe ensure that all QoS1 and QoS2 get completed
 *
 * @param {Object} config
 *
 * @example
 * stack.use(new SubscriptionManager({
 *   subscribeTopic: function(ctx, callback) {
 *     // make subscription
 *     callback(ctx.qos);
 *   },
 *   unsubscribeTopic: function(ctx, callback) {
 *     // make unsubscription
 *     callback();
 *   }
 * }));
 */

var SubscriptionManager = function(config){
  this.config = _.defaults(config || {}, {
    subscribeTopic: function(ctx, callback) {
      callback(0);
    },
    unsubscribeTopic: function(ctx, callback) {
      callback();
    }
  });
};

SubscriptionManager.prototype.subscribeTopic = function(ctx, callback) {
  this.config.subscribeTopic(ctx, callback);
};

SubscriptionManager.prototype.unsubscribeTopic = function(ctx, callback) {
  this.config.unsubscribeTopic(ctx, callback);
};

SubscriptionManager.prototype.handle = function(client, packet, next){
  var self = this;
  if(packet.cmd == 'subscribe') {
    var granted = [];
    _.each(packet.subscriptions, function(s) {
      self.stack.execute('subscribeTopic', {
        client: client,
        packet: packet,
        topic: s.topic,
        qos: s.qos
      }, function(err, results){
        if(err) return next(err);

        var grant = Math.min.apply(null, _.flatten(results));
        granted.push(grant === false ? 128 : Math.min(grant, 1));
        if(granted.length == packet.subscriptions.length) {
          return client.suback({
            messageId: packet.messageId,
            granted: granted
          });
        }
      });
    });
  } else if(packet.cmd == 'unsubscribe') {
    var i = 0;
    _.each(packet.unsubscriptions, function(us){
      self.stack.execute('unsubscribeTopic', {
        client: client,
        packet: packet,
        topic: us
      }, function(err){
        i++;
        if(err) return next(err);
        if(packet.unsubscriptions.length == i) {
          return client.unsuback({
            messageId: packet.messageId
          });
        }
      });
    });
  } else {
    return next();
  }
};

module.exports = SubscriptionManager;
<|endoftext|>


<commit_before>import React from "react";
import { graphql } from "react-apollo";
import gql from "graphql-tag";
import injectSheet from "react-jss";
import { Grid, Row, Col } from "react-bootstrap/lib";

import {
  FeaturedArticle,
  RecommendedArticles,
  LatestArticlesRibbon,
  LeftColumn,
  RightColumn,
} from "../../articles/components/summaries";
import { SectionFeature, SectionColumn } from "../../sections/components";

const HomePageQuery = gql`
  query HomePageQuery {
    featuredArticle {
      title
      slug
      preview
      created_at
      contributors {
        first_name
        last_name
        slug
      }
      media {
        title
        media_type
        attachment_url
        medium_attachment_url
        thumb_attachment_url
      }
      section {
        name
        permalink
      }
    }
    columnArticles {
      title
      slug
      preview
      created_at
      contributors {
        first_name
        last_name
        slug
      }
      media {
        attachment_url
      }
      section {
        name
        permalink
      }
    }
  }
`;

const styles = {
  HomePage: {
    margin: "23px 0px 13px",
  },
  recommendedArticles: {
    padding: 0,
  },
  primaryComponents: {
    borderRight: "solid 1px #ddd",
    marginBottom: "19px",
    paddingRight: "14px",
  },
  nineeleven:{
    maxWidth: "100%",
    Height: "auto",
    marginBottom: "10px"
  },
  "@media (max-width: 991px)": {
    primaryComponents: {
      borderRight: "none",
      paddingRight: 0,
    }
  },
  "@media (max-width: 767px)": {
    skinnyCol: {
      padding: "0 !important",
    },
  },
  adbanner: {
    fontFamily: "Circular Std",
    marginTop: "0%",
    margin: "auto",
  },
  "@media screen and (min-width: 769px)": {
    adbanner: {
      display: "none",
    },
  },
};

const HomePage = ({ classes, data }) => {
  if (data.loading) {
    return null;
  }
  const { featuredArticle, columnArticles } = data;

  const firstColumnSectionSlugs = ["opinions", "features", "humor"];
  const secondColumnSectionSlugs = [
    "staff-editorials",
    "ae",
    "sports-at-stuyvesant",
  ];
  return (

      <Grid fluid>
        <Row>

                Check out the promotions on the bottom of the page!

          <Col
            xs={12}
            sm={12}
            md={9}
            lg={9}
            className={classes.primaryComponents}
          >
            <FeaturedArticle article={featuredArticle} />
            <SectionFeature slug={"news"} />
          </Col>
          <Col
            xsHidden
            smHidden
            md={3}
            lg={3}
            className={classes.recommendedArticles}
          >
            <RecommendedArticles />
          </Col>
        </Row>
        <Row>
          <Col xsHidden sm={12} md={12} lg={12}>
            <LatestArticlesRibbon className={classes.latestArticlesRibbon} />
          </Col>
        </Row>
        <Row>
          <LeftColumn articles={columnArticles.slice(0, 3)} />
          <Col xs={12} sm={3} md={3} lg={3} className={classes.skinnyCol}>
            <SectionColumn slugs={firstColumnSectionSlugs} />
          </Col>
          <Col xs={12} sm={3} md={3} lg={3} className={classes.skinnyCol}>
            <SectionColumn slugs={secondColumnSectionSlugs} />
          </Col>
          <RightColumn articles={columnArticles.slice(3)} />
        </Row>
      </Grid>

  );
};

export default graphql(HomePageQuery)(injectSheet(styles)(HomePage));
<commit_msg>remove 9/11 banner<commit_after>import React from "react";
import { graphql } from "react-apollo";
import gql from "graphql-tag";
import injectSheet from "react-jss";
import { Grid, Row, Col } from "react-bootstrap/lib";

import {
  FeaturedArticle,
  RecommendedArticles,
  LatestArticlesRibbon,
  LeftColumn,
  RightColumn,
} from "../../articles/components/summaries";
import { SectionFeature, SectionColumn } from "../../sections/components";

const HomePageQuery = gql`
  query HomePageQuery {
    featuredArticle {
      title
      slug
      preview
      created_at
      contributors {
        first_name
        last_name
        slug
      }
      media {
        title
        media_type
        attachment_url
        medium_attachment_url
        thumb_attachment_url
      }
      section {
        name
        permalink
      }
    }
    columnArticles {
      title
      slug
      preview
      created_at
      contributors {
        first_name
        last_name
        slug
      }
      media {
        attachment_url
      }
      section {
        name
        permalink
      }
    }
  }
`;

const styles = {
  HomePage: {
    margin: "23px 0px 13px",
  },
  recommendedArticles: {
    padding: 0,
  },
  primaryComponents: {
    borderRight: "solid 1px #ddd",
    marginBottom: "19px",
    paddingRight: "14px",
  },
  "@media (max-width: 991px)": {
    primaryComponents: {
      borderRight: "none",
      paddingRight: 0,
    }
  },
  "@media (max-width: 767px)": {
    skinnyCol: {
      padding: "0 !important",
    },
  },
  adbanner: {
    fontFamily: "Circular Std",
    marginTop: "0%",
    margin: "auto",
  },
  "@media screen and (min-width: 769px)": {
    adbanner: {
      display: "none",
    },
  },
};

const HomePage = ({ classes, data }) => {
  if (data.loading) {
    return null;
  }
  const { featuredArticle, columnArticles } = data;

  const firstColumnSectionSlugs = ["opinions", "features", "humor"];
  const secondColumnSectionSlugs = [
    "staff-editorials",
    "ae",
    "sports-at-stuyvesant",
  ];
  return (

      <Grid fluid>
        <Row>

                Check out the promotions on the bottom of the page!

          <Col
            xs={12}
            sm={12}
            md={9}
            lg={9}
            className={classes.primaryComponents}
          >
            <FeaturedArticle article={featuredArticle} />
            <SectionFeature slug={"news"} />
          </Col>
          <Col
            xsHidden
            smHidden
            md={3}
            lg={3}
            className={classes.recommendedArticles}
          >
            <RecommendedArticles />
          </Col>
        </Row>
        <Row>
          <Col xsHidden sm={12} md={12} lg={12}>
            <LatestArticlesRibbon className={classes.latestArticlesRibbon} />
          </Col>
        </Row>
        <Row>
          <LeftColumn articles={columnArticles.slice(0, 3)} />
          <Col xs={12} sm={3} md={3} lg={3} className={classes.skinnyCol}>
            <SectionColumn slugs={firstColumnSectionSlugs} />
          </Col>
          <Col xs={12} sm={3} md={3} lg={3} className={classes.skinnyCol}>
            <SectionColumn slugs={secondColumnSectionSlugs} />
          </Col>
          <RightColumn articles={columnArticles.slice(3)} />
        </Row>
      </Grid>

  );
};

export default graphql(HomePageQuery)(injectSheet(styles)(HomePage));
<|endoftext|>