<commit_before>/* jshint -W084, -W099 */
// Credit: http://dabblet.com/

(function(diff_match_patch) {

	function cledit(contentElt, scrollElt, windowParam) {
		var editor = {
			$contentElt: contentElt,
			$scrollElt: scrollElt || contentElt,
			$window: windowParam || window,
			$keystrokes: {},
			$markers: []
		};
		editor.$document = editor.$window.document;
		cledit.Utils.createEventHooks(editor);
		var scrollTop;
		var debounce = cledit.Utils.debounce;

		editor.toggleEditable = function(isEditable) {
			if (isEditable === undefined) {
				isEditable = !contentElt.contentEditable;
			}
			contentElt.contentEditable = isEditable;
		};
		editor.toggleEditable(true);

		function getTextContent() {
			var textContent = contentElt.textContent.replace(/\r\n?/g, '\n'); // Mac/DOS to Unix
			if (textContent.slice(-1) !== '\n') {
				textContent += '\n';
			}
			return textContent;
		}

		function getLastContent() {
			return lastTextContent;
		}

		var lastTextContent = getTextContent();
		var highlighter = new cledit.Highlighter(editor);

		var sectionList;

		function parseSections(content, isInit) {
			sectionList = highlighter.parseSections(content, isInit);
			editor.$allElements = Array.prototype.slice.call(contentElt.querySelectorAll('.cledit-section *'));
			editor.$trigger('contentChanged', content, sectionList);
		}

		// Used to detect editor changes
		var watcher = new cledit.Watcher(editor, checkContentChange);
		watcher.startWatching();

		var diffMatchPatch = new diff_match_patch();
		/*
		 var jsonDiffPatch = jsondiffpatch.create({
		 objectHash: function(obj) {
		 return JSON.stringify(obj);
		 },
		 arrays: {
		 detectMove: false
		 },
		 textDiff: {
		 minLength: 9999999
		 }
		 });
		 */

		var selectionMgr = new cledit.SelectionMgr(editor);
		// TODO
		// $(document).on('selectionchange', '.editor-content', selectionMgr.saveSelectionState.bind(selectionMgr, true, false));

		function adjustCursorPosition(force) {
			selectionMgr.saveSelectionState(true, true, force);
		}

		function replaceContent(selectionStart, selectionEnd, replacement) {
			var min = Math.min(selectionStart, selectionEnd);
			var max = Math.max(selectionStart, selectionEnd);
			var range = selectionMgr.createRange(min, max);
			var rangeText = '' + range;
			// Range can contain a br element, which is not taken into account in rangeText
			if (rangeText.length === max - min && rangeText == replacement) {
				return;
			}
			range.deleteContents();
			range.insertNode(editor.$document.createTextNode(replacement));
			return range;
		}

		var ignorePatches = false;

		function setContent(value, noUndo) {
			var result = setContentInternal(value);
			ignorePatches = result.range ? noUndo : false;
			return result;
		}

		function setContentInternal(value, noWatch, maxStartOffset) {
			var textContent = getTextContent();
			maxStartOffset = maxStartOffset !== undefined && maxStartOffset < textContent.length ? maxStartOffset : textContent.length - 1;
			var startOffset = Math.min(
				diffMatchPatch.diff_commonPrefix(textContent, value),
				maxStartOffset
			);
			var endOffset = Math.min(
				diffMatchPatch.diff_commonSuffix(textContent, value),
				textContent.length - startOffset,
				value.length - startOffset
			);
			var replacement = value.substring(startOffset, value.length - endOffset);
			var range;
			if (noWatch) {
				watcher.noWatch(function() {
					range = replaceContent(startOffset, textContent.length - endOffset, replacement);
					if(range) {
						lastTextContent = value;
						parseSections(value);
					}
				});
			} else {
				range = replaceContent(startOffset, textContent.length - endOffset, replacement);
			}
			return {
				start: startOffset,
				end: value.length - endOffset,
				range: range
			};
		}

		function replace(selectionStart, selectionEnd, replacement) {
			undoMgr.setDefaultMode('single');
			replaceContent(selectionStart, selectionEnd, replacement);
			var endOffset = selectionStart + replacement.length;
			selectionMgr.setSelectionStartEnd(endOffset, endOffset);
			selectionMgr.updateCursorCoordinates(true);
		}

		function replaceAll(search, replacement) {
			undoMgr.setDefaultMode('single');
			var textContent = getTextContent();
			var value = textContent.replace(search, replacement);
			if (value != textContent) {
				var offset = editor.setContentInternal(value);
				selectionMgr.setSelectionStartEnd(offset.end, offset.end);
				selectionMgr.updateCursorCoordinates(true);
			}
		}

		function replacePreviousText(text, replacement) {
			var offset = selectionMgr.selectionStart;
			if (offset !== selectionMgr.selectionEnd) {
				return false;
			}
			var range = selectionMgr.createRange(offset - text.length, offset);
			if ('' + range != text) {
				return false;
			}
			range.deleteContents();
			range.insertNode(editor.$document.createTextNode(replacement));
			offset = offset - text.length + replacement.length;
			selectionMgr.setSelectionStartEnd(offset, offset);
			selectionMgr.updateCursorCoordinates(true);
			return true;
		}

		function focus() {
			selectionMgr.restoreSelection();
			scrollElt.scrollTop = scrollTop;
		}

		var undoMgr = new cledit.UndoMgr(editor);

		// TODO
		/*
		 function onComment() {
		 if(watcher.isWatching === true) {
		 undoMgr.currentMode = undoMgr.currentMode || 'comment';
		 undoMgr.saveState();
		 }
		 }

		 eventMgr.addListener('onDiscussionCreated', onComment);
		 eventMgr.addListener('onDiscussionRemoved', onComment);
		 eventMgr.addListener('onCommentsChanged', onComment);
		 */

		function addMarker(marker) {
			editor.$markers.indexOf(marker) === -1 && editor.$markers.push(marker);
		}

		function removeMarker(marker) {
			var index = editor.$markers.indexOf(marker);
			index !== -1 && editor.$markers.splice(index, 1);
		}

		var triggerSpellCheck = debounce(function() {
			var selection = editor.$window.getSelection();
			if (!selectionMgr.hasFocus || highlighter.isComposing || selectionMgr.selectionStart !== selectionMgr.selectionEnd || !selection.modify) {
				return;
			}
			// Hack for Chrome to trigger the spell checker
			if (selectionMgr.selectionStart) {
				selection.modify("move", "backward", "character");
				selection.modify("move", "forward", "character");
			} else {
				selection.modify("move", "forward", "character");
				selection.modify("move", "backward", "character");
			}
		}, 10);

		function checkContentChange(mutations) {
			var removedSections = {};
			var modifiedSections = {};

			function markModifiedSection(node) {
				while (node && node !== contentElt) {
					if (node.section) {
						(node.parentNode ? modifiedSections : removedSections)[node.section.id] = node.section;
						return;
					}
					node = node.parentNode;
				}
			}

			mutations.forEach(function(mutation) {
				markModifiedSection(mutation.target);
				Array.prototype.forEach.call(mutation.addedNodes, markModifiedSection);
				Array.prototype.forEach.call(mutation.removedNodes, markModifiedSection);
			});
			removedSections = Object.keys(removedSections).map(function(key) {
				return removedSections[key];
			});
			modifiedSections = Object.keys(modifiedSections).map(function(key) {
				return modifiedSections[key];
			});
			var isSelectionSaved;
			watcher.noWatch(function() {
				isSelectionSaved = highlighter.fixContent(modifiedSections, removedSections, mutations);
			});
			var newTextContent = getTextContent();
			if (newTextContent && newTextContent == lastTextContent) {
				return;
			}
			var diffs = diffMatchPatch.diff_main(lastTextContent, newTextContent);
			var patch = diffMatchPatch.patch_make(lastTextContent, diffs);
			if(!ignorePatches) {
				undoMgr.addPatch(patch);
				undoMgr.setDefaultMode('typing');
			}

			editor.$markers.forEach(function(marker) {
				marker.adjustOffset(diffs);
			});

			// TODO
			/*
			 var discussionList = _.values(fileDesc.discussionList);
			 fileDesc.newDiscussion && discussionList.push(fileDesc.newDiscussion);
			 var updateDiscussionList = adjustCommentOffsets(textContent, newTextContent, discussionList);
			 if(updateDiscussionList === true) {
			 fileDesc.discussionList = fileDesc.discussionList; // Write discussionList in localStorage
			 }
			 */
			lastTextContent = newTextContent;
			isSelectionSaved || selectionMgr.saveSelectionState();
			parseSections(lastTextContent);
			// TODO
			//updateDiscussionList && eventMgr.onCommentsChanged(fileDesc);
			ignorePatches || undoMgr.saveState();
			ignorePatches = false;
			triggerSpellCheck();
		}

		// See https://gist.github.com/shimondoodkin/1081133
		// TODO
		/*
		 if(/AppleWebKit\/([\d.]+)/.exec(navigator.userAgent)) {
		 var $editableFix = $('<input style="width:1px;height:1px;border:none;margin:0;padding:0;" tabIndex="-1">').appendTo('html');
		 $contentElt.blur(function() {
		 $editableFix[0].setSelectionRange(0, 0);
		 $editableFix.blur();
		 });
		 }
		 */

		function setSelection(start, end) {
			end = end === undefined ? start : end;
			selectionMgr.setSelectionStartEnd(start, end);
			selectionMgr.updateCursorCoordinates();
		}

		function keydownHandler(handler) {
			return function(evt) {
				if (
					evt.which !== 17 && // Ctrl
					evt.which !== 91 && // Cmd
					evt.which !== 18 && // Alt
					evt.which !== 16 // Shift
				) {
					handler(evt);
				}
			};
		}

		contentElt.addEventListener('keydown', keydownHandler(function(evt) {
			selectionMgr.saveSelectionState();
			adjustCursorPosition();
			Object.keys(editor.$keystrokes).some(function(key) {
				return editor.$keystrokes[key].perform(evt, editor);
			});
		}), false);

		// In case of Ctrl/Cmd+A outside the editor element
		editor.$window.addEventListener('keydown', keydownHandler(function() {
			adjustCursorPosition();
		}), false);

		// Mouseup can happen outside the editor element
		editor.$window.addEventListener('mouseup', selectionMgr.saveSelectionState.bind(selectionMgr, true, false));
		// This can also provoke selection changes and does not fire mouseup event on Chrome/OSX
		contentElt.addEventListener('contextmenu', selectionMgr.saveSelectionState.bind(selectionMgr, true, false));

		contentElt.addEventListener('compositionstart', function() {
			highlighter.isComposing++;
		}, false);

		contentElt.addEventListener('compositionend', function() {
			setTimeout(function() {
				highlighter.isComposing--;
			}, 0);
		}, false);

		contentElt.addEventListener('paste', function(evt) {
			undoMgr.setCurrentMode('single');
			evt.preventDefault();
			var data, clipboardData = evt.clipboardData;
			if (clipboardData) {
				data = clipboardData.getData('text/plain');
			} else {
				clipboardData = editor.$window.clipboardData;
				data = clipboardData && clipboardData.getData('Text');
			}
			if (!data) {
				return;
			}
			replace(selectionMgr.selectionStart, selectionMgr.selectionEnd, data);
			adjustCursorPosition();
		}, false);

		contentElt.addEventListener('cut', function() {
			undoMgr.setCurrentMode('single');
			adjustCursorPosition();
		}, false);

		contentElt.addEventListener('focus', function() {
			selectionMgr.hasFocus = true;
		}, false);

		contentElt.addEventListener('blur', function() {
			selectionMgr.hasFocus = false;
		}, false);

		scrollElt.addEventListener('scroll', function() {
			scrollTop = scrollElt.scrollTop;
		}, false);

		function addKeystroke(key, keystroke) {
			editor.$keystrokes[key] = keystroke;
		}
		Object.keys(cledit.defaultKeystrokes).forEach(function(key) {
			addKeystroke(key, cledit.defaultKeystrokes[key]);
		});

		editor.selectionMgr = selectionMgr;
		editor.undoMgr = undoMgr;
		editor.highlighter = highlighter;
		editor.watcher = watcher;
		editor.adjustCursorPosition = adjustCursorPosition;
		editor.setContent = setContent;
		editor.setContentInternal = setContentInternal;
		editor.replace = replace;
		editor.replaceAll = replaceAll;
		editor.replacePreviousText = replacePreviousText;
		editor.getContent = getTextContent;
		editor.getLastContent = getLastContent;
		editor.focus = focus;
		editor.setSelection = setSelection;
		editor.addKeystroke = addKeystroke;
		editor.addMarker = addMarker;
		editor.removeMarker = removeMarker;

		editor.init = function(options) {
			options = cledit.Utils.extend({
				cursorFocusRatio: 0.5,
				highlighter: function(text) {
					return text;
				},
				sectionDelimiter: ''
			}, options || {});
			editor.options = options;

			if (options.content !== undefined) {
				lastTextContent = options.content;
			}

			if (options.sectionDelimiter && !(options.sectionDelimiter instanceof RegExp)) {
				options.sectionDelimiter = new RegExp(options.sectionDelimiter, 'gm');
			}

			parseSections(lastTextContent, true);
			if (options.selectionStart !== undefined && options.selectionEnd !== undefined) {
				editor.setSelection(options.selectionStart, options.selectionEnd);
			} else {
				selectionMgr.saveSelectionState();
			}
			undoMgr.init();

			if (options.scrollTop !== undefined) {
				scrollElt.scrollTop = options.scrollTop;
			}

			scrollTop = scrollElt.scrollTop;
		};

		return editor;
	}

	window.cledit = cledit;
})(window.diff_match_patch);
<commit_msg>Fixed default highlighter<commit_after>/* jshint -W084, -W099 */
// Credit: http://dabblet.com/

(function(diff_match_patch) {

	function cledit(contentElt, scrollElt, windowParam) {
		var editor = {
			$contentElt: contentElt,
			$scrollElt: scrollElt || contentElt,
			$window: windowParam || window,
			$keystrokes: {},
			$markers: []
		};
		editor.$document = editor.$window.document;
		cledit.Utils.createEventHooks(editor);
		var scrollTop;
		var debounce = cledit.Utils.debounce;

		editor.toggleEditable = function(isEditable) {
			if (isEditable === undefined) {
				isEditable = !contentElt.contentEditable;
			}
			contentElt.contentEditable = isEditable;
		};
		editor.toggleEditable(true);

		function getTextContent() {
			var textContent = contentElt.textContent.replace(/\r\n?/g, '\n'); // Mac/DOS to Unix
			if (textContent.slice(-1) !== '\n') {
				textContent += '\n';
			}
			return textContent;
		}

		function getLastContent() {
			return lastTextContent;
		}

		var lastTextContent = getTextContent();
		var highlighter = new cledit.Highlighter(editor);

		var sectionList;

		function parseSections(content, isInit) {
			sectionList = highlighter.parseSections(content, isInit);
			editor.$allElements = Array.prototype.slice.call(contentElt.querySelectorAll('.cledit-section *'));
			editor.$trigger('contentChanged', content, sectionList);
		}

		// Used to detect editor changes
		var watcher = new cledit.Watcher(editor, checkContentChange);
		watcher.startWatching();

		var diffMatchPatch = new diff_match_patch();
		/*
		 var jsonDiffPatch = jsondiffpatch.create({
		 objectHash: function(obj) {
		 return JSON.stringify(obj);
		 },
		 arrays: {
		 detectMove: false
		 },
		 textDiff: {
		 minLength: 9999999
		 }
		 });
		 */

		var selectionMgr = new cledit.SelectionMgr(editor);
		// TODO
		// $(document).on('selectionchange', '.editor-content', selectionMgr.saveSelectionState.bind(selectionMgr, true, false));

		function adjustCursorPosition(force) {
			selectionMgr.saveSelectionState(true, true, force);
		}

		function replaceContent(selectionStart, selectionEnd, replacement) {
			var min = Math.min(selectionStart, selectionEnd);
			var max = Math.max(selectionStart, selectionEnd);
			var range = selectionMgr.createRange(min, max);
			var rangeText = '' + range;
			// Range can contain a br element, which is not taken into account in rangeText
			if (rangeText.length === max - min && rangeText == replacement) {
				return;
			}
			range.deleteContents();
			range.insertNode(editor.$document.createTextNode(replacement));
			return range;
		}

		var ignorePatches = false;

		function setContent(value, noUndo) {
			var result = setContentInternal(value);
			ignorePatches = result.range ? noUndo : false;
			return result;
		}

		function setContentInternal(value, noWatch, maxStartOffset) {
			var textContent = getTextContent();
			maxStartOffset = maxStartOffset !== undefined && maxStartOffset < textContent.length ? maxStartOffset : textContent.length - 1;
			var startOffset = Math.min(
				diffMatchPatch.diff_commonPrefix(textContent, value),
				maxStartOffset
			);
			var endOffset = Math.min(
				diffMatchPatch.diff_commonSuffix(textContent, value),
				textContent.length - startOffset,
				value.length - startOffset
			);
			var replacement = value.substring(startOffset, value.length - endOffset);
			var range;
			if (noWatch) {
				watcher.noWatch(function() {
					range = replaceContent(startOffset, textContent.length - endOffset, replacement);
					if(range) {
						lastTextContent = value;
						parseSections(value);
					}
				});
			} else {
				range = replaceContent(startOffset, textContent.length - endOffset, replacement);
			}
			return {
				start: startOffset,
				end: value.length - endOffset,
				range: range
			};
		}

		function replace(selectionStart, selectionEnd, replacement) {
			undoMgr.setDefaultMode('single');
			replaceContent(selectionStart, selectionEnd, replacement);
			var endOffset = selectionStart + replacement.length;
			selectionMgr.setSelectionStartEnd(endOffset, endOffset);
			selectionMgr.updateCursorCoordinates(true);
		}

		function replaceAll(search, replacement) {
			undoMgr.setDefaultMode('single');
			var textContent = getTextContent();
			var value = textContent.replace(search, replacement);
			if (value != textContent) {
				var offset = editor.setContentInternal(value);
				selectionMgr.setSelectionStartEnd(offset.end, offset.end);
				selectionMgr.updateCursorCoordinates(true);
			}
		}

		function replacePreviousText(text, replacement) {
			var offset = selectionMgr.selectionStart;
			if (offset !== selectionMgr.selectionEnd) {
				return false;
			}
			var range = selectionMgr.createRange(offset - text.length, offset);
			if ('' + range != text) {
				return false;
			}
			range.deleteContents();
			range.insertNode(editor.$document.createTextNode(replacement));
			offset = offset - text.length + replacement.length;
			selectionMgr.setSelectionStartEnd(offset, offset);
			selectionMgr.updateCursorCoordinates(true);
			return true;
		}

		function focus() {
			selectionMgr.restoreSelection();
			scrollElt.scrollTop = scrollTop;
		}

		var undoMgr = new cledit.UndoMgr(editor);

		// TODO
		/*
		 function onComment() {
		 if(watcher.isWatching === true) {
		 undoMgr.currentMode = undoMgr.currentMode || 'comment';
		 undoMgr.saveState();
		 }
		 }

		 eventMgr.addListener('onDiscussionCreated', onComment);
		 eventMgr.addListener('onDiscussionRemoved', onComment);
		 eventMgr.addListener('onCommentsChanged', onComment);
		 */

		function addMarker(marker) {
			editor.$markers.indexOf(marker) === -1 && editor.$markers.push(marker);
		}

		function removeMarker(marker) {
			var index = editor.$markers.indexOf(marker);
			index !== -1 && editor.$markers.splice(index, 1);
		}

		var triggerSpellCheck = debounce(function() {
			var selection = editor.$window.getSelection();
			if (!selectionMgr.hasFocus || highlighter.isComposing || selectionMgr.selectionStart !== selectionMgr.selectionEnd || !selection.modify) {
				return;
			}
			// Hack for Chrome to trigger the spell checker
			if (selectionMgr.selectionStart) {
				selection.modify("move", "backward", "character");
				selection.modify("move", "forward", "character");
			} else {
				selection.modify("move", "forward", "character");
				selection.modify("move", "backward", "character");
			}
		}, 10);

		function checkContentChange(mutations) {
			var removedSections = {};
			var modifiedSections = {};

			function markModifiedSection(node) {
				while (node && node !== contentElt) {
					if (node.section) {
						(node.parentNode ? modifiedSections : removedSections)[node.section.id] = node.section;
						return;
					}
					node = node.parentNode;
				}
			}

			mutations.forEach(function(mutation) {
				markModifiedSection(mutation.target);
				Array.prototype.forEach.call(mutation.addedNodes, markModifiedSection);
				Array.prototype.forEach.call(mutation.removedNodes, markModifiedSection);
			});
			removedSections = Object.keys(removedSections).map(function(key) {
				return removedSections[key];
			});
			modifiedSections = Object.keys(modifiedSections).map(function(key) {
				return modifiedSections[key];
			});
			var isSelectionSaved;
			watcher.noWatch(function() {
				isSelectionSaved = highlighter.fixContent(modifiedSections, removedSections, mutations);
			});
			var newTextContent = getTextContent();
			if (newTextContent && newTextContent == lastTextContent) {
				return;
			}
			var diffs = diffMatchPatch.diff_main(lastTextContent, newTextContent);
			var patch = diffMatchPatch.patch_make(lastTextContent, diffs);
			if(!ignorePatches) {
				undoMgr.addPatch(patch);
				undoMgr.setDefaultMode('typing');
			}

			editor.$markers.forEach(function(marker) {
				marker.adjustOffset(diffs);
			});

			// TODO
			/*
			 var discussionList = _.values(fileDesc.discussionList);
			 fileDesc.newDiscussion && discussionList.push(fileDesc.newDiscussion);
			 var updateDiscussionList = adjustCommentOffsets(textContent, newTextContent, discussionList);
			 if(updateDiscussionList === true) {
			 fileDesc.discussionList = fileDesc.discussionList; // Write discussionList in localStorage
			 }
			 */
			lastTextContent = newTextContent;
			isSelectionSaved || selectionMgr.saveSelectionState();
			parseSections(lastTextContent);
			// TODO
			//updateDiscussionList && eventMgr.onCommentsChanged(fileDesc);
			ignorePatches || undoMgr.saveState();
			ignorePatches = false;
			triggerSpellCheck();
		}

		// See https://gist.github.com/shimondoodkin/1081133
		// TODO
		/*
		 if(/AppleWebKit\/([\d.]+)/.exec(navigator.userAgent)) {
		 var $editableFix = $('<input style="width:1px;height:1px;border:none;margin:0;padding:0;" tabIndex="-1">').appendTo('html');
		 $contentElt.blur(function() {
		 $editableFix[0].setSelectionRange(0, 0);
		 $editableFix.blur();
		 });
		 }
		 */

		function setSelection(start, end) {
			end = end === undefined ? start : end;
			selectionMgr.setSelectionStartEnd(start, end);
			selectionMgr.updateCursorCoordinates();
		}

		function keydownHandler(handler) {
			return function(evt) {
				if (
					evt.which !== 17 && // Ctrl
					evt.which !== 91 && // Cmd
					evt.which !== 18 && // Alt
					evt.which !== 16 // Shift
				) {
					handler(evt);
				}
			};
		}

		contentElt.addEventListener('keydown', keydownHandler(function(evt) {
			selectionMgr.saveSelectionState();
			adjustCursorPosition();
			Object.keys(editor.$keystrokes).some(function(key) {
				return editor.$keystrokes[key].perform(evt, editor);
			});
		}), false);

		// In case of Ctrl/Cmd+A outside the editor element
		editor.$window.addEventListener('keydown', keydownHandler(function() {
			adjustCursorPosition();
		}), false);

		// Mouseup can happen outside the editor element
		editor.$window.addEventListener('mouseup', selectionMgr.saveSelectionState.bind(selectionMgr, true, false));
		// This can also provoke selection changes and does not fire mouseup event on Chrome/OSX
		contentElt.addEventListener('contextmenu', selectionMgr.saveSelectionState.bind(selectionMgr, true, false));

		contentElt.addEventListener('compositionstart', function() {
			highlighter.isComposing++;
		}, false);

		contentElt.addEventListener('compositionend', function() {
			setTimeout(function() {
				highlighter.isComposing--;
			}, 0);
		}, false);

		contentElt.addEventListener('paste', function(evt) {
			undoMgr.setCurrentMode('single');
			evt.preventDefault();
			var data, clipboardData = evt.clipboardData;
			if (clipboardData) {
				data = clipboardData.getData('text/plain');
			} else {
				clipboardData = editor.$window.clipboardData;
				data = clipboardData && clipboardData.getData('Text');
			}
			if (!data) {
				return;
			}
			replace(selectionMgr.selectionStart, selectionMgr.selectionEnd, data);
			adjustCursorPosition();
		}, false);

		contentElt.addEventListener('cut', function() {
			undoMgr.setCurrentMode('single');
			adjustCursorPosition();
		}, false);

		contentElt.addEventListener('focus', function() {
			selectionMgr.hasFocus = true;
		}, false);

		contentElt.addEventListener('blur', function() {
			selectionMgr.hasFocus = false;
		}, false);

		scrollElt.addEventListener('scroll', function() {
			scrollTop = scrollElt.scrollTop;
		}, false);

		function addKeystroke(key, keystroke) {
			editor.$keystrokes[key] = keystroke;
		}
		Object.keys(cledit.defaultKeystrokes).forEach(function(key) {
			addKeystroke(key, cledit.defaultKeystrokes[key]);
		});

		editor.selectionMgr = selectionMgr;
		editor.undoMgr = undoMgr;
		editor.highlighter = highlighter;
		editor.watcher = watcher;
		editor.adjustCursorPosition = adjustCursorPosition;
		editor.setContent = setContent;
		editor.setContentInternal = setContentInternal;
		editor.replace = replace;
		editor.replaceAll = replaceAll;
		editor.replacePreviousText = replacePreviousText;
		editor.getContent = getTextContent;
		editor.getLastContent = getLastContent;
		editor.focus = focus;
		editor.setSelection = setSelection;
		editor.addKeystroke = addKeystroke;
		editor.addMarker = addMarker;
		editor.removeMarker = removeMarker;

		editor.init = function(options) {
			options = cledit.Utils.extend({
				cursorFocusRatio: 0.5,
				highlighter: function(text) {
					return text.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' ');
				},
				sectionDelimiter: ''
			}, options || {});
			editor.options = options;

			if (options.content !== undefined) {
				lastTextContent = options.content;
			}

			if (options.sectionDelimiter && !(options.sectionDelimiter instanceof RegExp)) {
				options.sectionDelimiter = new RegExp(options.sectionDelimiter, 'gm');
			}

			parseSections(lastTextContent, true);
			if (options.selectionStart !== undefined && options.selectionEnd !== undefined) {
				editor.setSelection(options.selectionStart, options.selectionEnd);
			} else {
				selectionMgr.saveSelectionState();
			}
			undoMgr.init();

			if (options.scrollTop !== undefined) {
				scrollElt.scrollTop = options.scrollTop;
			}

			scrollTop = scrollElt.scrollTop;
		};

		return editor;
	}

	window.cledit = cledit;
})(window.diff_match_patch);
<|endoftext|>


<commit_before>/**
 * Database implementation for GPGMail_Mobile.
 *
 * @author  Alexander Willner <alex@willner.ws>
 * @version 2011-02-22
 * @see     http://gpgtools.org
 * @license BSD
 */

/* database binding -------------------------------------------------------- */
$(function() {
                $('a[name="importKey"]').bind('click',function() {
                        if($('textarea[name="key"]').val() == "") {
                            alert("Currently only import via copy&paste is supported");
                            return;
                        }
                        if($('input[name="keyname"]').val() == "") {
                            alert("Please set a key name");
                            return;
                        }
                        dbSetPrivateKey($('input[name="keyname"]').val(),
                                        $('textarea[name="key"]').val());
                });
});
$(function() {
                $('a[name="deleteKey"]').bind('click',function() {
                        if($('select[name="secretkeys"]').val() == undefined) {
                            alert("Please select a key");
                            return;
                        }
                        dbRemovePrivateKey($('select[name="secretkeys"]').val());
                });
});
$(function() {
                $('input[name="defaultSign"]').bind('click',function() {
                        if($(this).is(':checked')) {
                            dbSetDefaultSign(1);
                        } else  {
                            dbSetDefaultSign(0);
                        }
                });
});
/* ------------------------------------------------------------------------- */

/* database initialization ------------------------------------------------- */
var db = null;

function sqlFail(tx, err) { alert("SQL failed: " + err.message); }
function sqlWin(response) { console.log("SQL succeeded."); }
function txFail(err) { alert("TX failed: " + err.message); }
function txWin(tx) { console.log("TX succeeded."); }

try {
    if (window.openDatabase) {
        db = openDatabase("GPGMail", "1.0", "GPGMail mobile", 200000);
        if (!db)
            alert("Failed to open the database on disk.  This is probably " +
                  "because the version was bad or there is not enough space" +
                  "left in this domain's quota");
    } else {
        alert("Couldn't open the database.");
    }
} catch(err) {
    db = null;
    alert("Couldn't open the database (exception): " + err);
}

if (db != null) {addEventListener('load', dbInitialize(), false);}

function dbInitialize() {
    db.transaction(function(tx) {
        tx.executeSql("SELECT COUNT(*) FROM Options", [],
            function(result) {/**/;},
            function(tx, error) {
                tx.executeSql("CREATE TABLE Options (" +
                              " id REAL UNIQUE, " +
                              " defaultSign TEXT, " +
                              " defaultVerify TEXT)",
                              [],
                              sqlWin,
                              sqlFail
                             );
        });
    }, txFail, txWin);
    db.transaction(function(tx) {
        tx.executeSql("SELECT COUNT(*) FROM PrivateKeys", [],
            function(result) {/**/;},
            function(tx, error) {
                tx.executeSql("CREATE TABLE PrivateKeys " +
                              " (id REAL UNIQUE, key TEXT)",
                              [],
                              sqlWin,
                              sqlFail
                             );
            });
    }, txFail, txWin);
    dbShowPrivateKeys();
}
/* ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
function dbSetPrivateKey(id, key) {
    db.transaction(function (tx) {
        tx.executeSql("REPLACE INTO PrivateKeys (id, key) " +
                      " VALUES (?, ?)",
                      [id, key],
                      function(tx, result) {dbShowPrivateKeys(); sqlWin();},
                      sqlFail
                     );
    }, txFail, txWin);
}
function dbRemovePrivateKey(id) {
    db.transaction(function (tx) {
        tx.executeSql("DELETE FROM PrivateKeys WHERE id = ?",
                      [id],
                      function(tx, result) {dbShowPrivateKeys(); sqlWin();},
                      sqlFail
                     );
    }, txFail, txWin);
}
function dbGetFirstPrivateKey(callback) {
    var key = "";
    db.transaction(function (tx) {
        tx.executeSql("SELECT * FROM PrivateKeys LIMIT 1",
                      [],
                      function(tx, result) {
                          if (result.rows.length > 0) {
                              key = result.rows.item(0)['key'];
                          }
                          callback(key);
                      },
                      sqlFail);
    }, txFail, txWin);
}
function dbShowPrivateKeys() {
    db.transaction(function (tx) {
        tx.executeSql("SELECT * FROM PrivateKeys",
                      [],
                      function(tx, result) {
                          $('#secretkeys').children().remove();
                          for(var i = 0; i < result.rows.length; i++) {
                              id = result.rows.item(i)['id'];
                              key = result.rows.item(i)['key'];
                              $('#secretkeys').append('<option value="'+id+'">'+id+'</option>');
                          }
                      },
                      sqlFail);
    }, txFail, txWin);
}
/* ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
function dbIsDefaultSign() {
    db.transaction(function (tx) {
        tx.executeSql("SELECT defaultSign FROM Options WHERE id = 1", [],
                      sqlWin, sqlFail);
    }, txFail, txWin);
}

function dbSetDefaultSign(isSet) {
    db.transaction(function (tx) {
        tx.executeSql("UPDATE Options SET defaultSign = ? WHERE id = 1",
                      [isSet], sqlWin, sqlFail);
    }, txFail, txWin);
}
/* ------------------------------------------------------------------------- */
<commit_msg>fixed mobile phone touch events<commit_after>/**
 * Database implementation for GPGMail_Mobile.
 *
 * @author  Alexander Willner <alex@willner.ws>
 * @version 2011-02-22
 * @see     http://gpgtools.org
 * @license BSD
 */

/* database binding -------------------------------------------------------- */
$(function() {
                $('#importKey').bind('click tap',function() {
                        if($('#key').val() == "") {
                            alert("Please paste the key. This is the only supported way currently.");
                            return;
                        }
                        if($('#keyname').val() == "") {
                            alert("Please set a key name.");
                            return;
                        }
                        dbSetPrivateKey($('#keyname').val(),
                                        $('#key').val());
                });
});
$(function() {
                $('#deleteKey').bind('click tap',function() {
                        if($('#secretkeys').val() == undefined) {
                            alert("Please select a key");
                            return;
                        }
                        dbRemovePrivateKey($('#secretkeys').val());
                });
});
$(function() {
                $('#defaultSign').bind('click tap',function() {
                        if($(this).is(':checked')) {
                            dbSetDefaultSign(1);
                        } else  {
                            dbSetDefaultSign(0);
                        }
                });
});
/* ------------------------------------------------------------------------- */

/* database initialization ------------------------------------------------- */
var db = null;

function sqlFail(tx, err) { alert("SQL failed: " + err.message); }
function sqlWin(response) { console.log("SQL succeeded."); }
function txFail(err) { alert("TX failed: " + err.message); }
function txWin(tx) { console.log("TX succeeded."); }

try {
    if (window.openDatabase) {
        db = openDatabase("GPGMail", "1.0", "GPGMail mobile", 200000);
        if (!db)
            alert("Failed to open the database on disk.  This is probably " +
                  "because the version was bad or there is not enough space" +
                  "left in this domain's quota");
    } else {
        alert("Couldn't open the database.");
    }
} catch(err) {
    db = null;
    alert("Couldn't open the database (exception): " + err);
}

if (db != null) {addEventListener('load', dbInitialize(), false);}

function dbInitialize() {
    db.transaction(function(tx) {
        tx.executeSql("SELECT COUNT(*) FROM Options", [],
            function(result) {/**/;},
            function(tx, error) {
                tx.executeSql("CREATE TABLE Options (" +
                              " id REAL UNIQUE, " +
                              " defaultSign TEXT, " +
                              " defaultVerify TEXT)",
                              [],
                              sqlWin,
                              sqlFail
                             );
        });
    }, txFail, txWin);
    db.transaction(function(tx) {
        tx.executeSql("SELECT COUNT(*) FROM PrivateKeys", [],
            function(result) {/**/;},
            function(tx, error) {
                tx.executeSql("CREATE TABLE PrivateKeys " +
                              " (id REAL UNIQUE, key TEXT)",
                              [],
                              sqlWin,
                              sqlFail
                             );
            });
    }, txFail, txWin);
    dbShowPrivateKeys();
}
/* ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
function dbSetPrivateKey(id, key) {
    db.transaction(function (tx) {
        tx.executeSql("REPLACE INTO PrivateKeys (id, key) " +
                      " VALUES (?, ?)",
                      [id, key],
                      function(tx, result) {dbShowPrivateKeys(); sqlWin();},
                      sqlFail
                     );
    }, txFail, txWin);
}
function dbRemovePrivateKey(id) {
    db.transaction(function (tx) {
        tx.executeSql("DELETE FROM PrivateKeys WHERE id = ?",
                      [id],
                      function(tx, result) {dbShowPrivateKeys(); sqlWin();},
                      sqlFail
                     );
    }, txFail, txWin);
}
function dbGetFirstPrivateKey(callback) {
    var key = "";
    db.transaction(function (tx) {
        tx.executeSql("SELECT * FROM PrivateKeys LIMIT 1",
                      [],
                      function(tx, result) {
                          if (result.rows.length > 0) {
                              key = result.rows.item(0)['key'];
                          }
                          callback(key);
                      },
                      sqlFail);
    }, txFail, txWin);
}
function dbShowPrivateKeys() {
    db.transaction(function (tx) {
        tx.executeSql("SELECT * FROM PrivateKeys",
                      [],
                      function(tx, result) {
                          $('#secretkeys').children().remove();
                          for(var i = 0; i < result.rows.length; i++) {
                              id = result.rows.item(i)['id'];
                              key = result.rows.item(i)['key'];
                              $('#secretkeys').append('<option value="'+id+'">'+id+'</option>');
                          }
                      },
                      sqlFail);
    }, txFail, txWin);
}
/* ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
function dbIsDefaultSign() {
    db.transaction(function (tx) {
        tx.executeSql("SELECT defaultSign FROM Options WHERE id = 1", [],
                      sqlWin, sqlFail);
    }, txFail, txWin);
}

function dbSetDefaultSign(isSet) {
    db.transaction(function (tx) {
        tx.executeSql("UPDATE Options SET defaultSign = ? WHERE id = 1",
                      [isSet], sqlWin, sqlFail);
    }, txFail, txWin);
}
/* ------------------------------------------------------------------------- */
<|endoftext|>


<commit_before>var webpack = require("webpack");
var WebpackDevServer = require("webpack-dev-server");

var port = 8080;
var config = require("../webpack.config.js");

// enable inline mode. see https://webpack.github.io/docs/webpack-dev-server.html#inline-mode-with-node-js-api
var frontEndEntry = config[0];
var entry = frontEndEntry.entry;

entry['webpack_client'] =  "webpack-dev-server/client?http://localhost:" + port + "/";
entry['webpack_hot'] = "webpack/hot/dev-server";
frontEndEntry.plugins.push(new webpack.HotModuleReplacementPlugin());

var compiler = webpack(config);

console.log("Loading WebpackDevServer");

var server = new WebpackDevServer(compiler, {
  contentBase: "/dist",
  // Can also be an array, or: contentBase: "http://localhost/",
  //contentBase: "http://localhost:8080",

  // Enable special support for Hot Module Replacement(see 'inline' commend above)
  hot: true,

  // access dev server from arbitrary url for html5 router
  historyApiFallback: true,

  // Set this if you want to enable gzip compression for assets
  compress: false,

  // route /api calls to the API server (see https://github.com/webpack/webpack-dev-server/pull/127 )
  proxy: {
     "/api/**": "http://localhost:3000"
  },

  setup: function(app) {
    // express app custom handlers
  },

  // pass [static options](http://expressjs.com/en/4x/api.html#express.static) to inner express server
  staticOptions: {
  },

  clientLogLevel: "info",
  // Control the console log messages shown in the browser when using inline mode. Can be `error`, `warning`, `info` or `none`.

  // webpack-dev-middleware options
  quiet: false,
  noInfo: false,
  lazy: false,
  filename: "bundle.js",
  watchOptions: {
    aggregateTimeout: 300,
    poll: 1000
  },
  //publicPath: "/",
  headers: { "X-Custom-Header": "yes" },
  stats: { colors: true }
});

var base_url = "http://localhost:" + port;

server.listen(port, function() {
    console.log("Available entry routes:");
    console.log(base_url + "/");
    console.log(base_url + "/webpack-dev-server/");
});

<commit_msg>test heroku<commit_after>var webpack = require("webpack");
var WebpackDevServer = require("webpack-dev-server");

var port = process.env.PORT || 8080;
var config = require("../webpack.config.js");

// enable inline mode. see https://webpack.github.io/docs/webpack-dev-server.html#inline-mode-with-node-js-api
var frontEndEntry = config[0];
var entry = frontEndEntry.entry;

entry['webpack_client'] =  "webpack-dev-server/client?http://localhost:" + port + "/";
entry['webpack_hot'] = "webpack/hot/dev-server";
frontEndEntry.plugins.push(new webpack.HotModuleReplacementPlugin());

var compiler = webpack(config);

console.log("Loading WebpackDevServer");

var server = new WebpackDevServer(compiler, {
  contentBase: "/dist",
  // Can also be an array, or: contentBase: "http://localhost/",
  //contentBase: "http://localhost:8080",

  // Enable special support for Hot Module Replacement(see 'inline' commend above)
  hot: true,

  // access dev server from arbitrary url for html5 router
  historyApiFallback: true,

  // Set this if you want to enable gzip compression for assets
  compress: false,

  // route /api calls to the API server (see https://github.com/webpack/webpack-dev-server/pull/127 )
  proxy: {
     "/api/**": "http://localhost:3000"
  },

  setup: function(app) {
    // express app custom handlers
  },

  // pass [static options](http://expressjs.com/en/4x/api.html#express.static) to inner express server
  staticOptions: {
  },

  clientLogLevel: "info",
  // Control the console log messages shown in the browser when using inline mode. Can be `error`, `warning`, `info` or `none`.

  // webpack-dev-middleware options
  quiet: false,
  noInfo: false,
  lazy: false,
  filename: "bundle.js",
  watchOptions: {
    aggregateTimeout: 300,
    poll: 1000
  },
  //publicPath: "/",
  headers: { "X-Custom-Header": "yes" },
  stats: { colors: true }
});

var base_url = "http://localhost:" + port;

server.listen(port, function() {
    console.log("Available entry routes:");
    console.log(base_url + "/");
    console.log(base_url + "/webpack-dev-server/");
});

<|endoftext|>


<commit_before>/*
Small logger for plugin hooks.
*/

(function() {

  var colors = require('colors/safe'),
    MESSAGES_PREFIX = '    ';

  module.exports = {
    header: header,
    info: info,
    warn: warn,
    error: error,
    success: success
  };

  // region Public API

  /**
   * Print header.
   *
   * @param {String} msg - header message
   */
  function header(msg) {
    var message = colors.underline(msg);
    console.log(message);
  }

  /**
   * Print informational message.
   * Message will have prefix with empty spaces.
   *
   * @param {String} msg - message to print
   */
  function info(msg) {
    var message = formatMessage(msg);
    console.log(message);
  }

  /**
   * Print error message.
   *
   * @param {String} msg - message to print
   */
  function error(msg) {
    var message = formatMessage(msg),
      coloredMsg = colors.red(message);

    console.log(coloredMsg);
  }

  /**
   * Print warning message.
   *
   * @param {String} msg - message to print
   */
  function warn(msg) {
    var message = formatMessage(msg),
      coloredMsg = colors.yellow(message);

    console.log(coloredMsg);
  }

  /**
   * Print success message.
   *
   * @param {String} msg - message to print
   */
  function success(msg) {
    var message = formatMessage(msg),
      coloredMsg = colors.green(message);

    console.log(coloredMsg);
  }

  // endregion

  // region Private API

  /**
   * Format message before printing it to console.
   *
   * @param {String} msg - unformatted message
   * @return {String} formatted message
   */
  function formatMessage(msg) {
    return MESSAGES_PREFIX + msg;
  }

  // endregion

})();
<commit_msg>Changed logger's module inclusion<commit_after>/*
Small logger for plugin hooks.
*/

(function() {

  var colors = require('colors'),
    MESSAGES_PREFIX = '    ';

  module.exports = {
    header: header,
    info: info,
    warn: warn,
    error: error,
    success: success
  };

  // region Public API

  /**
   * Print header.
   *
   * @param {String} msg - header message
   */
  function header(msg) {
    var message = colors.underline(msg);
    console.log(message);
  }

  /**
   * Print informational message.
   * Message will have prefix with empty spaces.
   *
   * @param {String} msg - message to print
   */
  function info(msg) {
    var message = formatMessage(msg);
    console.log(message);
  }

  /**
   * Print error message.
   *
   * @param {String} msg - message to print
   */
  function error(msg) {
    var message = formatMessage(msg),
      coloredMsg = colors.red(message);

    console.log(coloredMsg);
  }

  /**
   * Print warning message.
   *
   * @param {String} msg - message to print
   */
  function warn(msg) {
    var message = formatMessage(msg),
      coloredMsg = colors.yellow(message);

    console.log(coloredMsg);
  }

  /**
   * Print success message.
   *
   * @param {String} msg - message to print
   */
  function success(msg) {
    var message = formatMessage(msg),
      coloredMsg = colors.green(message);

    console.log(coloredMsg);
  }

  // endregion

  // region Private API

  /**
   * Format message before printing it to console.
   *
   * @param {String} msg - unformatted message
   * @return {String} formatted message
   */
  function formatMessage(msg) {
    return MESSAGES_PREFIX + msg;
  }

  // endregion

})();
<|endoftext|>


<commit_before>const fs = require('fs');
const http = require('http');
const shell = require('shelljs');
const decompress = require('decompress');
const decompressTargz = require('decompress-targz');
const env = require('./env.js');
const { exec } = require('./helper.js');

function writeFile(url, destination, resolve, reject) {
    const file = fs.createWriteStream(destination);

    const req = http.get(url, (res) => {
        res.pipe(file);
    });

    req.on('error', (e) => {
        file.unlink(destination);
        reject(e);
    });

    file.on('error', () => {
        file.unlink(destination);
        reject(new Error('File error'));
    });

    file.on('finish', resolve);
}

function download(url, destination) {
    if (fs.existsSync(destination)) {
        shell.echo(`${destination} already exists. Skipping download.`);

        return Promise.resolve();
    }

    const executor = writeFile.bind(null, url, destination);
    return new Promise(executor);
}

function validateFile(fileName) {
    let res;

    if (env.isWindows) {
        const output = exec(`certutil -hashfile ${fileName} SHA512`).split('\r\n');

        // `certutil` returns 2byte separated string
        // (e.g. "a9 89 b5 27 f3 f9 90 d4 71 e6 d4 7e e4 10 e5 7d 8b e7 62 0b")
        const sha512 = output[1].replace(/ /g, '');

        res = `${sha512}  ${fileName}`;
    } else {
        res = exec(`shasum -a 512 ${fileName}`).trim();
    }

    if (res !== env.sha512sum) {
        throw new Error(`Wrong sha512 for ${fileName}! Expected "${env.sha512sum}", got "${res}".`);
    }
}

function clearPath() {
    if (!shell.test('-d', env.sourceFolder)) {
        return;
    }

    shell.rm('-rf', env.sourceFolder);
}

function moveFolder() {
    if (env.isWindows) {
        shell.cp('-r', env.downloadedFolderName, env.sourceFolder);
        shell.rm('-rf', env.downloadedFolderName);
        return;
    }

    shell.mv(`${env.downloadedFolderName}/zookeeper-client/zookeeper-client-c`, env.sourceFolder);
}

function applyPatches() {
    if (env.isWindows) {
        const destination = `${env.sourceFolder}/src`;

        shell.sed('-i', '#include "zookeeper_log.h"', '#include "zookeeper_log.h"\n#include "winport.h"\n', `${destination}/zk_log.c`);
        shell.sed('-i', '#include "zookeeper.h"', '#include "winport.h"\n#include "zookeeper.h"\n', `${destination}/zk_adaptor.h`);
        shell.sed('-i', '#include "zk_adaptor.h"', '#include "zk_adaptor.h"\n#include "winport.h"\n', `${destination}/zookeeper.c`);

        if (!process.env.ZK_INSTALL_VERBOSE) {
            const cmakeFile = 'CMakeLists.txt';
            shell.cp(`${env.rootFolder}/patches/${cmakeFile}`, `${env.sourceFolder}/src/${cmakeFile}`);
        }
    } else {
        exec(`patch -p0 < ${env.rootFolder}/patches/ZOOKEEPER-3078.patch`);
        shell.cp('-R', `${env.rootFolder}/patches/autoreconf/*`, `${env.sourceFolder}`);
    }
}

if (env.isAlreadyBuilt) {
    shell.echo('Zookeeper has already been built');
    shell.exit(0);
}

shell.config.fatal = true;
shell.config.verbose = true;

shell.cd(env.workFolder);

download(env.downloadUrl, env.downloadedFileName)
    .then(() => {
        validateFile(env.downloadedFileName);

        clearPath();

        decompress(env.downloadedFileName, './', {
            plugins: [
                decompressTargz(),
            ],
        }).then(() => {
            moveFolder();
            applyPatches();
        }).catch((e) => {
            shell.echo(`Error: ${e.message}`);
            shell.exit(1);
        });
    })
    .catch((e) => {
        shell.echo(`Unable to download zookeeper library. Error: ${e.message}`);
        shell.exit(1);
    });
<commit_msg>fix: typo<commit_after>const fs = require('fs');
const http = require('http');
const shell = require('shelljs');
const decompress = require('decompress');
const decompressTargz = require('decompress-targz');
const env = require('./env.js');
const { exec } = require('./helper.js');

function writeFile(url, destination, resolve, reject) {
    const file = fs.createWriteStream(destination);

    const req = http.get(url, (res) => {
        res.pipe(file);
    });

    req.on('error', (e) => {
        file.unlink(destination);
        reject(e);
    });

    file.on('error', () => {
        file.unlink(destination);
        reject(new Error('File error'));
    });

    file.on('finish', resolve);
}

function download(url, destination) {
    if (fs.existsSync(destination)) {
        shell.echo(`${destination} already exists. Skipping download.`);

        return Promise.resolve();
    }

    const executor = writeFile.bind(null, url, destination);
    return new Promise(executor);
}

function validateFile(fileName) {
    let res;

    if (env.isWindows) {
        const output = exec(`certutil -hashfile ${fileName} SHA512`).split('\r\n');

        // `certutil` returns 2byte separated string
        // (e.g. "a9 89 b5 27 f3 f9 90 d4 71 e6 d4 7e e4 10 e5 7d 8b e7 62 0b")
        const sha512 = output[1].replace(/ /g, '');

        res = `${sha512}  ${fileName}`;
    } else {
        res = exec(`shasum -a 512 ${fileName}`).trim();
    }

    if (res !== env.sha512sum) {
        throw new Error(`Wrong sha512 for ${fileName}! Expected "${env.sha512sum}", got "${res}".`);
    }
}

function clearPath() {
    if (!shell.test('-d', env.sourceFolder)) {
        return;
    }

    shell.rm('-rf', env.sourceFolder);
}

function moveFolder() {
    const sourceCodeFolder = `${env.downloadedFolderName}/zookeeper-client/zookeeper-client-c`;
    if (env.isWindows) {
        shell.cp('-r', sourceCodeFolder, env.sourceFolder);
        shell.rm('-rf', env.downloadedFolderName);
        return;
    }

    shell.mv(sourceCodeFolder, env.sourceFolder);
}

function applyPatches() {
    if (env.isWindows) {
        const destination = `${env.sourceFolder}/src`;

        shell.sed('-i', '#include "zookeeper_log.h"', '#include "zookeeper_log.h"\n#include "winport.h"\n', `${destination}/zk_log.c`);
        shell.sed('-i', '#include "zookeeper.h"', '#include "winport.h"\n#include "zookeeper.h"\n', `${destination}/zk_adaptor.h`);
        shell.sed('-i', '#include "zk_adaptor.h"', '#include "zk_adaptor.h"\n#include "winport.h"\n', `${destination}/zookeeper.c`);

        if (!process.env.ZK_INSTALL_VERBOSE) {
            const cmakeFile = 'CMakeLists.txt';
            shell.cp(`${env.rootFolder}/patches/${cmakeFile}`, `${env.sourceFolder}/src/${cmakeFile}`);
        }
    } else {
        exec(`patch -p0 < ${env.rootFolder}/patches/ZOOKEEPER-3078.patch`);
        shell.cp('-R', `${env.rootFolder}/patches/autoreconf/*`, `${env.sourceFolder}`);
    }
}

if (env.isAlreadyBuilt) {
    shell.echo('Zookeeper has already been built');
    shell.exit(0);
}

shell.config.fatal = true;
shell.config.verbose = true;

shell.cd(env.workFolder);

download(env.downloadUrl, env.downloadedFileName)
    .then(() => {
        validateFile(env.downloadedFileName);

        clearPath();

        decompress(env.downloadedFileName, './', {
            plugins: [
                decompressTargz(),
            ],
        }).then(() => {
            moveFolder();
            applyPatches();
        }).catch((e) => {
            shell.echo(`Error: ${e.message}`);
            shell.exit(1);
        });
    })
    .catch((e) => {
        shell.echo(`Unable to download zookeeper library. Error: ${e.message}`);
        shell.exit(1);
    });
<|endoftext|>


<commit_before>(function(Backbone) {
    var init = function(trigger, triggerEvents) {

    // backbone-events-promises
    // ========================
    //
    // This plugin to [backbone.js](http://backbonejs.org/) can add
    // promise functionality to Backbone.Events (and any Backbone
    // object which extends Backbone.Events - which is pretty much
    // all of them).
    //
    // Why?
    // ----
    //
    // If you have an event listener that needs to make an async call
    // to complete its function, and you might do something
    //
    // Dependencies
    // ------------
    // It implements promises by using `$.Deferred` and `$.when` either. This can be
    // provided via [jQuery](http://jquery.org) or [Zepto](http://zeptojs.com/) (requires
    // including Zepto's deferred plugin). Potentially, other
    // sources such as when.js could be used if a shim was provided to
    // apply it's functions to `$.Deferred` and `$.when`.
    //
    // It also depends on `_.extend()`. Underscore is already a hard dependency of Backbone,
    // so no harm done there.
    //
    // Backwards Breaking Changes
    // --------------------------
    // The only thing that happens by default here is setting
    // `Backbone.Events.promises()`.
    //
    // Backbone.Events.promises(enable, [context], [options]);
    // --------------------------------------------
    // Enables the backbone-promises functionality for events.

        Backbone.Events.promises = function(enable, context, options) {

            // The biggest change that happens after enabling backbone-promises
            // is that `Backbone.Events.trigger()` will return a promise. This means if
            // you are chaining a method after calling `trigger()` in your code
            // (ex. `.trigger(event).somethingElse()`), it will cause a fatal error and break.
            // However, backbone-promises can be configured to use a different method name
            // than `.trigger()` if you can think of a better name that won't cause
            // conflicts in your application.

            var method;
            if (enable === undefined) {
                enable = true;
            }
            options = options || {};
            options = _.extend({
                method: "trigger"
            }, options);
            method = options.method;

            // You can pass a context in the second parameter which will
            // apply the backbone-promises functionality to that object.
            // By default, the context is `Backbone.Events`.

            if (!context) {
                context = Backbone.Events;
            }

            // Additionally, the original functionality can
            // be restored by using `Backbone.Events.promises(false, [context])`.
            // backbone-promises also reserves use of `context._promises` to store configuration data.
            // Currently, it is used to store the original version of the trigger function.

            if (!enable) {
                if (!context._promises) {
                    return;
                }
                if (!context._promises.original) {
                    return;
                }
                method = context._promises.method;
                context[method] = context._promises.original;
                delete context._promises;
                return context;
            }

            if (enable) {
                if (context._promises) {
                    return;
                }
                context._promises = _.extend(options, {
                    original: context[method]
                });
                context[method] = trigger;
            }
        };
    },

    // Usage
    // -----

    // To enable on all Backbone objects, use the following code before creating
    // any Backbone objects in your application.
    //     var objs = ['Model', 'Collection', 'Router', 'View', 'History'];
    //     Backbone.Events.promises(true);
    //     for (var i = 0, l = objs.length; i < l; i++) {
    //         Backbone.Events.promises(true, Backbone[objs[i]].prototype);
    //     }

    // // Backbone.Events.trigger now returns a promise
    // var promise = Backbone.Events.trigger( "event name", arg1, arg2 );

    // // Each callback assigned to the event *can* return a promise.
    // // If a promise is returned, it will be added to the list of promises to resolve.
    // http://api.jquery.com/jQuery.when/

    // Under The Hood
    // --------------

    // Here we are modifying the `Backbone.Event.trigger()` method and we also
    // have to copy several private functions and aliases from the Backbone source
    // code. See annotated source over here: http://backbonejs.org/docs/backbone.html.
    // It should be exactly the same as the original version except it returns
    // a promise.
    // The promise object is the result of a `$.when()` call. The arguments to
    // `$.when are callbacks returning the results of each event listener.
    // See [api.jquery.com/jQuery.when/](http://api.jquery.com/jQuery.when/).

    array = [],
    push = array.push,
    slice = array.slice,
    splice = array.splice,
    eventSplitter = /\s+/,
    eventsApi = function(obj, action, name, rest) {
        if (!name) {
            return true;
        }
        if (typeof name === 'object') {
            for (var key in name) {
                obj[action].apply(obj, [key, name[key]].concat(rest));
            }
            return false;
        }
        if (eventSplitter.test(name)) {
            var names = name.split(eventSplitter);
            for (var i = 0, l = names.length; i < l; i++) {
                obj[action].apply(obj, [names[i]].concat(rest));
            }
            return false;
        }
        return true;
    },
    trigger = function(name) {
        if (!this._events) {
            return $.when();
        }
        var args = slice.call(arguments, 1);
        if (!eventsApi(this, 'trigger', name, args)) {
            return $.when();
        }
        var events = this._events[name];
        var allEvents = this._events.all;
        if (events) {
            return triggerEvents(events, args);
        }
        if (allEvents) {
            return triggerEvents(allEvents, arguments);
        }
        return $.when();
    },

    // We attempted to follow Backbone's lead here with
    // optimizing the manner to call event listeners. The idea is that
    // javascript's `call()` method is faster
    // than `apply` and most events are called with only a few arguments.
    //
    // This is where we differ from Backbone and create an
    // array of callback which is sent to `$.when()`.

    triggerEvents = function(events, args) {
        var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2], cbs = [];
        switch (args.length) {
        case 0:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx));
            }
            break;
        case 1:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1));
            }
            break;
        case 2:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1, a2));
            }
            break;
        case 3:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1, a2, a3));
            }
            break;
        default:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.apply(ev.ctx, args));
            }
            break;
        }
        return $.when.apply($, cbs);
    };

    init(trigger, triggerEvents);

})(Backbone);
<commit_msg>Fixed comment for why you need this functionality<commit_after>(function(Backbone) {
    var init = function(trigger, triggerEvents) {

    // backbone-events-promises
    // ========================
    //
    // This plugin to [backbone.js](http://backbonejs.org/) can add
    // promise functionality to Backbone.Events (and any Backbone
    // object which extends Backbone.Events - which is pretty much
    // all of them).
    //
    // Why?
    // ----
    //
    // You fire an event and need to make sure all event listeners
    // have finished their async calls before you do something destructive
    // like change the browser location.
    //
    // Dependencies
    // ------------
    // It implements promises by using `$.Deferred` and `$.when` either. This can be
    // provided via [jQuery](http://jquery.org) or [Zepto](http://zeptojs.com/) (requires
    // including Zepto's deferred plugin). Potentially, other
    // sources such as when.js could be used if a shim was provided to
    // apply it's functions to `$.Deferred` and `$.when`.
    //
    // It also depends on `_.extend()`. Underscore is already a hard dependency of Backbone,
    // so no harm done there.
    //
    // Backwards Breaking Changes
    // --------------------------
    // The only thing that happens by default here is setting
    // `Backbone.Events.promises()`.
    //
    // Backbone.Events.promises(enable, [context], [options]);
    // --------------------------------------------
    // Enables the backbone-promises functionality for events.

        Backbone.Events.promises = function(enable, context, options) {

            // The biggest change that happens after enabling backbone-promises
            // is that `Backbone.Events.trigger()` will return a promise. This means if
            // you are chaining a method after calling `trigger()` in your code
            // (ex. `.trigger(event).somethingElse()`), it will cause a fatal error and break.
            // However, backbone-promises can be configured to use a different method name
            // than `.trigger()` if you can think of a better name that won't cause
            // conflicts in your application.

            var method;
            if (enable === undefined) {
                enable = true;
            }
            options = options || {};
            options = _.extend({
                method: "trigger"
            }, options);
            method = options.method;

            // You can pass a context in the second parameter which will
            // apply the backbone-promises functionality to that object.
            // By default, the context is `Backbone.Events`.

            if (!context) {
                context = Backbone.Events;
            }

            // Additionally, the original functionality can
            // be restored by using `Backbone.Events.promises(false, [context])`.
            // backbone-promises also reserves use of `context._promises` to store configuration data.
            // Currently, it is used to store the original version of the trigger function.

            if (!enable) {
                if (!context._promises) {
                    return;
                }
                if (!context._promises.original) {
                    return;
                }
                method = context._promises.method;
                context[method] = context._promises.original;
                delete context._promises;
                return context;
            }

            if (enable) {
                if (context._promises) {
                    return;
                }
                context._promises = _.extend(options, {
                    original: context[method]
                });
                context[method] = trigger;
            }
        };
    },

    // Usage
    // -----

    // To enable on all Backbone objects, use the following code before creating
    // any Backbone objects in your application.
    //     var objs = ['Model', 'Collection', 'Router', 'View', 'History'];
    //     Backbone.Events.promises(true);
    //     for (var i = 0, l = objs.length; i < l; i++) {
    //         Backbone.Events.promises(true, Backbone[objs[i]].prototype);
    //     }

    // // Backbone.Events.trigger now returns a promise
    // var promise = Backbone.Events.trigger( "event name", arg1, arg2 );

    // // Each callback assigned to the event *can* return a promise.
    // // If a promise is returned, it will be added to the list of promises to resolve.
    // http://api.jquery.com/jQuery.when/

    // Under The Hood
    // --------------

    // Here we are modifying the `Backbone.Event.trigger()` method and we also
    // have to copy several private functions and aliases from the Backbone source
    // code. See annotated source over here: http://backbonejs.org/docs/backbone.html.
    // It should be exactly the same as the original version except it returns
    // a promise.
    // The promise object is the result of a `$.when()` call. The arguments to
    // `$.when are callbacks returning the results of each event listener.
    // See [api.jquery.com/jQuery.when/](http://api.jquery.com/jQuery.when/).

    array = [],
    push = array.push,
    slice = array.slice,
    splice = array.splice,
    eventSplitter = /\s+/,
    eventsApi = function(obj, action, name, rest) {
        if (!name) {
            return true;
        }
        if (typeof name === 'object') {
            for (var key in name) {
                obj[action].apply(obj, [key, name[key]].concat(rest));
            }
            return false;
        }
        if (eventSplitter.test(name)) {
            var names = name.split(eventSplitter);
            for (var i = 0, l = names.length; i < l; i++) {
                obj[action].apply(obj, [names[i]].concat(rest));
            }
            return false;
        }
        return true;
    },
    trigger = function(name) {
        if (!this._events) {
            return $.when();
        }
        var args = slice.call(arguments, 1);
        if (!eventsApi(this, 'trigger', name, args)) {
            return $.when();
        }
        var events = this._events[name];
        var allEvents = this._events.all;
        if (events) {
            return triggerEvents(events, args);
        }
        if (allEvents) {
            return triggerEvents(allEvents, arguments);
        }
        return $.when();
    },

    // We attempted to follow Backbone's lead here with
    // optimizing the manner to call event listeners. The idea is that
    // javascript's `call()` method is faster
    // than `apply` and most events are called with only a few arguments.
    //
    // This is where we differ from Backbone and create an
    // array of callback which is sent to `$.when()`.

    triggerEvents = function(events, args) {
        var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2], cbs = [];
        switch (args.length) {
        case 0:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx));
            }
            break;
        case 1:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1));
            }
            break;
        case 2:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1, a2));
            }
            break;
        case 3:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1, a2, a3));
            }
            break;
        default:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.apply(ev.ctx, args));
            }
            break;
        }
        return $.when.apply($, cbs);
    };

    init(trigger, triggerEvents);

})(Backbone);
<|endoftext|>


<commit_before>'use strict';

//
// Email service. Send emails to recipients in raw or HTML format.
//

var nodemailer = require('nodemailer');
var emailTemplates = require('email-templates');
var path = require('path');
var templatesDir = path.resolve(__dirname + '/templates');
var esnConf = require('../esn-config');
var transport;

var opts = {
  from: 'no-reply@hiveety.org'
};

/**
 * Set the nodemailer transport
 *
 * @param {transport} t
 */
exports.setTransport = function(t) {
  transport = t;
};

/**
 * Set the templates directory
 *
 * @param {string} t
 */
exports.setTemplatesDir = function(t) {
  templatesDir = t;
};

/**
 * Get the mail configuration
 *
 * @param {fn} done
 */
var mailconfig = function(done) {
  esnConf('mail').get(function(err, data) {
    return done(err, data ||  opts);
  });
};
exports.mailconfig = mailconfig;

/**
 * Initialize the mail transport on first call else get it from cache
 *
 * @param {fn} done
 */
var getMailTransport = function(done) {
  if (transport) {
    return done(null, transport);
  }

  mailconfig(function(err, data) {
    if (err) {
      return done(err);
    }
    if (!data.transport) {
      return done(new Error('Mail transport is not configured'));
    }
    transport = nodemailer.createTransport(data.transport.type, data.transport.config);
    return done(null, transport);
  });
};

/**
 * Check if template has attachments
 *
 * @param {string} template
 */
var hasAttachments = function(template) {
  return false;
};

/**
 * Get the template attachments as array of {filename, filepath, cid}
 *
 * @param {string} template
 */
var attachments = function(template) {
  return [];
};

/**
 * Send an HTML email rendered from a template
 *
 * @param {string} to - recipient (as CSV if N recipients)
 * @param {string} type
 * @param {hash} locals
 * @param {fn} done
 */
exports.sendHTML = function(from, to, subject, type, locals, done) {
  if (!to) {
    return done(new Error('Recipient can not be null'));
  }

  getMailTransport(function(err, transport) {
    if (err) {
      return done(err);
    }

    emailTemplates(templatesDir, function(err, template) {
      if (err) {
        return done(err);
      }

      template(type, locals, function(err, html, text) {
        if (err) {
          return done(err);
        }

        mailconfig(function(err, data) {
          if (err) {
            return done(err);
          }
          var message = {
            from: from ||  data.from,
            to: to,
            subject: subject,
            html: html,
            text: text
          };

          if (hasAttachments(type)) {
            message.attachments = attachments(type);
            message.forceEmbeddedImages = true;
          }
          transport.sendMail(message, function(err, response) {
            if (err) {
              return done(err);
            }
            done(null, response);
          });
        });
      });
    });
  });
};

/**
 * Send raw email to recipient
 *
 * @param {string} to - recipient (as CSV if multiple recipients)
 * @param {string} text
 * @param {fn} done
 */
exports.send = function(from, to, subject, text, done) {
  if (!to) {
    return done(new Error('Recipient can not be null'));
  }
  if (!text) {
    return done(new Error('Email content can not be null'));
  }

  getMailTransport(function(err, transport) {
    if (err) {
      return done(err);
    }

    mailconfig(function(err, data) {
      if (err) {
        return done(err);
      }

      var message = {
        from: from ||  data.from,
        to: to,
        subject: subject,
        text: text
      };
      transport.sendMail(message, function(err, response) {
        if (err) {
          return done(err);
        }
        done(null, response);
      });
    });
  });
};
<commit_msg>OR-90 Fix doc<commit_after>'use strict';

//
// Email service. Send emails to recipients in raw or HTML format.
//

var nodemailer = require('nodemailer');
var emailTemplates = require('email-templates');
var path = require('path');
var templatesDir = path.resolve(__dirname + '/templates');
var esnConf = require('../esn-config');
var transport;

var opts = {
  from: 'no-reply@hiveety.org'
};

/**
 * Set the nodemailer transport
 *
 * @param {transport} t
 */
exports.setTransport = function(t) {
  transport = t;
};

/**
 * Set the templates directory
 *
 * @param {string} t
 */
exports.setTemplatesDir = function(t) {
  templatesDir = t;
};

/**
 * Get the mail configuration
 *
 * @param {fn} done
 */
var mailconfig = function(done) {
  esnConf('mail').get(function(err, data) {
    return done(err, data ||  opts);
  });
};
exports.mailconfig = mailconfig;

/**
 * Initialize the mail transport on first call else get it from cache
 *
 * @param {fn} done
 */
var getMailTransport = function(done) {
  if (transport) {
    return done(null, transport);
  }

  mailconfig(function(err, data) {
    if (err) {
      return done(err);
    }
    if (!data.transport) {
      return done(new Error('Mail transport is not configured'));
    }
    transport = nodemailer.createTransport(data.transport.type, data.transport.config);
    return done(null, transport);
  });
};

/**
 * Check if template has attachments
 *
 * @param {string} template
 */
var hasAttachments = function(template) {
  return false;
};

/**
 * Get the template attachments as array of {filename, filepath, cid}
 *
 * @param {string} template
 */
var attachments = function(template) {
  return [];
};

/**
 * Send an HTML email rendered from a template
 *
 * @param {string} from - source
 * @param {string} to - recipient (as CSV if N recipients)
 * @param {string} type
 * @param {hash} locals
 * @param {fn} done
 */
exports.sendHTML = function(from, to, subject, type, locals, done) {
  if (!to) {
    return done(new Error('Recipient can not be null'));
  }

  getMailTransport(function(err, transport) {
    if (err) {
      return done(err);
    }

    emailTemplates(templatesDir, function(err, template) {
      if (err) {
        return done(err);
      }

      template(type, locals, function(err, html, text) {
        if (err) {
          return done(err);
        }

        mailconfig(function(err, data) {
          if (err) {
            return done(err);
          }
          var message = {
            from: from ||  data.from,
            to: to,
            subject: subject,
            html: html,
            text: text
          };

          if (hasAttachments(type)) {
            message.attachments = attachments(type);
            message.forceEmbeddedImages = true;
          }
          transport.sendMail(message, function(err, response) {
            if (err) {
              return done(err);
            }
            done(null, response);
          });
        });
      });
    });
  });
};

/**
 * Send raw email to recipient
 *
 * @param {string} from - source
 * @param {string} to - recipient (as CSV if multiple recipients)
 * @param {string} text
 * @param {fn} done
 */
exports.send = function(from, to, subject, text, done) {
  if (!to) {
    return done(new Error('Recipient can not be null'));
  }
  if (!text) {
    return done(new Error('Email content can not be null'));
  }

  getMailTransport(function(err, transport) {
    if (err) {
      return done(err);
    }

    mailconfig(function(err, data) {
      if (err) {
        return done(err);
      }

      var message = {
        from: from ||  data.from,
        to: to,
        subject: subject,
        text: text
      };
      transport.sendMail(message, function(err, response) {
        if (err) {
          return done(err);
        }
        done(null, response);
      });
    });
  });
};
<|endoftext|>


<commit_before>'use strict';

//var config = require('../config');

var mongoose = require('mongoose');
var _ = require('underscore');
var Schema = mongoose.Schema;

var ChallengeSchema = new Schema({
  name: {
    type: String,
    required: true
  },
  description: {
    type: String,
    required: true
  },
  // refer actions schema
  actions: [
    {
      type: Schema.Types.ObjectId,
      ref: 'Action',
      required: true
    }
  ],
  //ratings for challenges
  ratings: {
    type: [
      {
        userId: {
          type: Schema.Types.ObjectId, // _id of rater
          required: true
        },
        rating: {
          type: Number,
          min: 1,
          max: 5,
          required: true
        },
        comment: String
      }
    ],
    default: []
  }
});

var Challenge = mongoose.model('Challenge', ChallengeSchema);

var includeRatingStats = function(challenge) {
  var cnt = 0;
  var sum = 0;

  _.each(challenge.ratings, function(rating) {
    sum += rating.rating;
    cnt++;
  });

  //Same logic as action's ratings
  challenge.avgRating = cnt ? sum / cnt : 0;
  challenge.numRatings = cnt;
};

//Create challenge
exports.create = function(challenge, cb) {
  Challenge.create({
    name: challenge.name,
    description: challenge.description,
    actions: challenge.actions,
    ratings: challenge.ratings || [],
  }, cb);
};

//Get challenge information with ratings
exports.get = function(id, cb) {
  Challenge.findOne({
    _id: id
  }, function(err, challenge) {
    if (err) {
      cb(err);
    } else if (!challenge) {
      cb('Challenge not found');
    } else {
      challenge = challenge.toObject();
      includeRatingStats(challenge);
      cb(null, challenge);
    }
  });
};

//Search challenge by name
exports.search = function(cname, cb) {
  Challenge.find({
    name : new RegExp('^' + cname + '$', 'i')
  }, function(err, challenge) {
    if (err) {
      cb(err);
    } else if (!challenge) {
      cb('Challenge not found');
    } else {
      challenge = challenge.toObject();
      cb(null, challenge);
    }
  });
};

//Delete a challenge with id
exports.delete = function(id, cb) {
  Challenge.remove({
    _id: id
  }, cb);
};

//Get a list of all challenges
exports.all = function(limit, skip, includeRatings, cb) {
  Challenge
  .find({})
  .sort({'date': -1})
  .skip(skip)
  .limit(limit)
  .exec(function(err, challenges) {
    if (err) {
      cb(err);
    } else {
      // convert every returned challenges into a raw object (remove mongoose magic)
      for (var i = 0; i < challenges.length; i++) {
        challenges[i] = challenges[i].toObject();
      }

      // calculate rating stats for each challenges
      _.each(challenges, includeRatingStats);

      // get rid of ratings
      if (!includeRatings) {
        _.each(challenges, function(challenge) {
          challenge.ratings = undefined;
        });
      }
      cb(null, challenges);
    }
  });
};

exports.rate = function(id, userId, rating, comment, cb) {
  Challenge.findOne({
    _id: id
  }, function(err, challenge) {
    if (err) {
      cb(err);
    } else if (!challenge) {
      cb('Challenge not found');
    } else {
      challenge.ratings.addToSet({
        userId: userId,
        rating: rating,
        comment: comment
      });

      challenge.save(function(err) {
        cb(err);
      });
    }
  });
};

var Challenge = mongoose.model('Challenge', ChallengeSchema);

module.exports = {
  Challenge: Challenge
};
<commit_msg>export challenge model as Challenge.model<commit_after>'use strict';

//var config = require('../config');

var mongoose = require('mongoose');
var _ = require('underscore');
var Schema = mongoose.Schema;

var ChallengeSchema = new Schema({
  name: {
    type: String,
    required: true
  },
  description: {
    type: String,
    required: true
  },
  // refer actions schema
  actions: [
    {
      type: Schema.Types.ObjectId,
      ref: 'Action',
      required: true
    }
  ],
  //ratings for challenges
  ratings: {
    type: [
      {
        userId: {
          type: Schema.Types.ObjectId, // _id of rater
          required: true
        },
        rating: {
          type: Number,
          min: 1,
          max: 5,
          required: true
        },
        comment: String
      }
    ],
    default: []
  }
});

var Challenge = mongoose.model('Challenge', ChallengeSchema);

var includeRatingStats = function(challenge) {
  var cnt = 0;
  var sum = 0;

  _.each(challenge.ratings, function(rating) {
    sum += rating.rating;
    cnt++;
  });

  //Same logic as action's ratings
  challenge.avgRating = cnt ? sum / cnt : 0;
  challenge.numRatings = cnt;
};

//Create challenge
exports.create = function(challenge, cb) {
  Challenge.create({
    name: challenge.name,
    description: challenge.description,
    actions: challenge.actions,
    ratings: challenge.ratings || [],
  }, cb);
};

//Get challenge information with ratings
exports.get = function(id, cb) {
  Challenge.findOne({
    _id: id
  }, function(err, challenge) {
    if (err) {
      cb(err);
    } else if (!challenge) {
      cb('Challenge not found');
    } else {
      challenge = challenge.toObject();
      includeRatingStats(challenge);
      cb(null, challenge);
    }
  });
};

//Search challenge by name
exports.search = function(cname, cb) {
  Challenge.find({
    name : new RegExp('^' + cname + '$', 'i')
  }, function(err, challenge) {
    if (err) {
      cb(err);
    } else if (!challenge) {
      cb('Challenge not found');
    } else {
      challenge = challenge.toObject();
      cb(null, challenge);
    }
  });
};

//Delete a challenge with id
exports.delete = function(id, cb) {
  Challenge.remove({
    _id: id
  }, cb);
};

//Get a list of all challenges
exports.all = function(limit, skip, includeRatings, cb) {
  Challenge
  .find({})
  .sort({'date': -1})
  .skip(skip)
  .limit(limit)
  .exec(function(err, challenges) {
    if (err) {
      cb(err);
    } else {
      // convert every returned challenges into a raw object (remove mongoose magic)
      for (var i = 0; i < challenges.length; i++) {
        challenges[i] = challenges[i].toObject();
      }

      // calculate rating stats for each challenges
      _.each(challenges, includeRatingStats);

      // get rid of ratings
      if (!includeRatings) {
        _.each(challenges, function(challenge) {
          challenge.ratings = undefined;
        });
      }
      cb(null, challenges);
    }
  });
};

exports.rate = function(id, userId, rating, comment, cb) {
  Challenge.findOne({
    _id: id
  }, function(err, challenge) {
    if (err) {
      cb(err);
    } else if (!challenge) {
      cb('Challenge not found');
    } else {
      challenge.ratings.addToSet({
        userId: userId,
        rating: rating,
        comment: comment
      });

      challenge.save(function(err) {
        cb(err);
      });
    }
  });
};

exports.model = Challenge;
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

export const COLUMN_TYPES = {
  CHECKABLE: 'checkable',
  DATE_EDITABLE: 'editableDate',
  DATE: 'date',
  DROP_DOWN: 'dropdown',
  ICON: 'icon',
  NUMERIC_EDITABLE: 'editableNumeric',
  NUMERIC: 'numeric',
  STRING_EDITABLE: 'editableString',
  STRING: 'string',
};

export const COLUMN_KEYS = {
  AVAILABLE_QUANTITY: 'availableQuantity',
  BATCH: 'batch',
  CODE: 'code',
  COMMENT: 'comment',
  COUNTED_TOTAL_QUANTITY: 'countedTotalQuantity',
  CREATED_DATE: 'createdDate',
  DIFFERENCE: 'difference',
  ENTRY_DATE: 'entryDate',
  EXPIRY_DATE: 'expiryDate',
  ITEM_CODE: 'itemCode',
  ITEM_NAME: 'itemName',
  MONTHLY_USAGE: 'monthlyUsage',
  NAME: 'name',
  NUMBER_OF_ITEMS: 'numberOfItems',
  OTHER_PARTY_NAME: 'otherPartyName',
  OUR_STOCK_ON_HAND: 'ourStockOnHand',
  PRICE: 'price',
  REASON_TITLE: 'reasonTitle',
  REMOVE: 'remove',
  REQUIRED_QUANTITY: 'requiredQuantity',
  SELECTED: 'selected',
  SERIAL_NUMBER: 'serialNumber',
  SNAPSHOT_TOTAL_QUANTITY: 'snapshotTotalQuantity',
  STATUS: 'status',
  STOCK_ON_HAND: 'stockOnHand',
  SUGGESTED_QUANTITY: 'suggestedQuantity',
  SUPPLIED_QUANTITY: 'suppliedQuantity',
  TOTAL_QUANTITY: 'totalQuantity',
  UNIT: 'unit',
  VALUE: 'value',
};

export const COLUMN_NAMES = {
  AVAILABLE_QUANTITY: 'availableQuantity',
  BATCH_NAME: 'batch',
  BATCHES: 'batches',
  CODE: 'code',
  COMMENT: 'comment',
  COUNTED_TOTAL_QUANTITY: 'countedTotalQuantity',
  CREATED_DATE: 'createdDate',
  CUSTOMER: 'customer',
  DIFFERENCE: 'difference',
  EDITABLE_COMMENT: 'editableComment',
  EDITABLE_REQUIRED_QUANTITY: 'editableRequiredQuantity',
  EDITABLE_VALUE: 'editableValue',
  EDITABLE_TOTAL_QUANTITY: 'editableTotalQuantity',
  ENTRY_DATE: 'entryDate',
  EXPIRY_DATE: 'expiryDate',
  INVOICE_NUMBER: 'invoiceNumber',
  ITEM_CODE: 'itemCode',
  ITEM_NAME: 'itemName',
  MONTHLY_USAGE: 'monthlyUsage',
  NAME: 'name',
  NUMBER_OF_ITEMS: 'numberOfItems',
  OUR_STOCK_ON_HAND: 'ourStockOnHand',
  PRICE: 'price',
  QUESTION: 'question',
  REASON: 'reason',
  REMOVE: 'remove',
  REQUIRED_QUANTITY: 'requiredQuantity',
  REQUISITION_NUMBER: 'requisitionNumber',
  SELECTED: 'selected',
  SNAPSHOT_TOTAL_QUANTITY: 'snapshotTotalQuantity',
  STATUS: 'status',
  SUGGESTED_QUANTITY: 'suggestedQuantity',
  SUPPLIED_QUANTITY: 'suppliedQuantity',
  SUPPLIER: 'supplier',
  THEIR_STOCK_ON_HAND: 'theirStockOnHand',
  TOTAL_QUANTITY: 'totalQuantity',
  UNIT: 'unit',
};

export default { COLUMN_TYPES, COLUMN_NAMES, COLUMN_KEYS };
<commit_msg>Add fix column value after merge<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

export const COLUMN_TYPES = {
  CHECKABLE: 'checkable',
  DATE_EDITABLE: 'editableDate',
  DATE: 'date',
  DROP_DOWN: 'dropdown',
  ICON: 'icon',
  NUMERIC_EDITABLE: 'editableNumeric',
  NUMERIC: 'numeric',
  STRING_EDITABLE: 'editableString',
  STRING: 'string',
};

export const COLUMN_KEYS = {
  AVAILABLE_QUANTITY: 'availableQuantity',
  BATCH: 'batch',
  CODE: 'code',
  COMMENT: 'comment',
  COUNTED_TOTAL_QUANTITY: 'countedTotalQuantity',
  CREATED_DATE: 'createdDate',
  DIFFERENCE: 'difference',
  ENTRY_DATE: 'entryDate',
  EXPIRY_DATE: 'expiryDate',
  ITEM_CODE: 'itemCode',
  ITEM_NAME: 'itemName',
  MONTHLY_USAGE: 'monthlyUsage',
  NAME: 'name',
  NUMBER_OF_ITEMS: 'numberOfItems',
  OTHER_PARTY_NAME: 'otherPartyName',
  OUR_STOCK_ON_HAND: 'ourStockOnHand',
  PRICE: 'price',
  REASON_TITLE: 'reasonTitle',
  REMOVE: 'remove',
  REQUIRED_QUANTITY: 'requiredQuantity',
  SELECTED: 'selected',
  SERIAL_NUMBER: 'serialNumber',
  SNAPSHOT_TOTAL_QUANTITY: 'snapshotTotalQuantity',
  STATUS: 'status',
  STOCK_ON_HAND: 'stockOnHand',
  SUGGESTED_QUANTITY: 'suggestedQuantity',
  SUPPLIED_QUANTITY: 'suppliedQuantity',
  TOTAL_QUANTITY: 'totalQuantity',
  UNIT: 'unitString',
  VALUE: 'value',
};

export const COLUMN_NAMES = {
  AVAILABLE_QUANTITY: 'availableQuantity',
  BATCH_NAME: 'batch',
  BATCHES: 'batches',
  CODE: 'code',
  COMMENT: 'comment',
  COUNTED_TOTAL_QUANTITY: 'countedTotalQuantity',
  CREATED_DATE: 'createdDate',
  CUSTOMER: 'customer',
  DIFFERENCE: 'difference',
  EDITABLE_COMMENT: 'editableComment',
  EDITABLE_REQUIRED_QUANTITY: 'editableRequiredQuantity',
  EDITABLE_VALUE: 'editableValue',
  EDITABLE_TOTAL_QUANTITY: 'editableTotalQuantity',
  ENTRY_DATE: 'entryDate',
  EXPIRY_DATE: 'expiryDate',
  INVOICE_NUMBER: 'invoiceNumber',
  ITEM_CODE: 'itemCode',
  ITEM_NAME: 'itemName',
  MONTHLY_USAGE: 'monthlyUsage',
  NAME: 'name',
  NUMBER_OF_ITEMS: 'numberOfItems',
  OUR_STOCK_ON_HAND: 'ourStockOnHand',
  PRICE: 'price',
  QUESTION: 'question',
  REASON: 'reason',
  REMOVE: 'remove',
  REQUIRED_QUANTITY: 'requiredQuantity',
  REQUISITION_NUMBER: 'requisitionNumber',
  SELECTED: 'selected',
  SNAPSHOT_TOTAL_QUANTITY: 'snapshotTotalQuantity',
  STATUS: 'status',
  SUGGESTED_QUANTITY: 'suggestedQuantity',
  SUPPLIED_QUANTITY: 'suppliedQuantity',
  SUPPLIER: 'supplier',
  THEIR_STOCK_ON_HAND: 'theirStockOnHand',
  TOTAL_QUANTITY: 'totalQuantity',
  UNIT: 'unit',
};

export default { COLUMN_TYPES, COLUMN_NAMES, COLUMN_KEYS };
<|endoftext|>


<commit_before>import Service from '@ember/service';

export default class StateService extends Service {
  helpers = new Map();
  prevId = null;
  updateSelection(id) {
    const oldInstance = this.helpers.get(this.prevId)
    if (oldInstance) {
      oldInstance.isSelected = false;
      oldInstance.recompute();
    }
    this.prevId = id;
    const newInstance = this.helpers.get(this.prevId)
    if (newInstance) {
      newInstance.isSelected = true;
      newInstance.recompute();
    }
  }
}
<commit_msg>simplify update logic<commit_after>import Service from '@ember/service';

export default class StateService extends Service {
  helpers = new Map();
  prevId = null;
  updateHelper(id, isSelected) {
    const instance = this.helpers.get(id)
    if (instance) {
      instance.isSelected = isSelected;
      instance.recompute();
    }
  }
  updateSelection(id) {
    this.updateHelper(this.prevId, false);
    this.prevId = id;
    this.updateHelper(this.prevId, true);
  }
}
<|endoftext|>


<commit_before>frappe.provide("frappe.ui");
frappe.provide("frappe.web_form");
import EventEmitterMixin from '../../frappe/event_emitter';

export default class WebForm extends frappe.ui.FieldGroup {
	constructor(opts) {
		super();
		Object.assign(this, opts);
		frappe.web_form = this;
		frappe.web_form.events = {};
		Object.assign(frappe.web_form.events, EventEmitterMixin);
	}

	prepare(web_form_doc, doc) {
		Object.assign(this, web_form_doc);
		this.fields = web_form_doc.web_form_fields;
		this.doc = doc;
	}

	make() {
		super.make();
		this.set_field_values();
		if (this.introduction_text) this.set_form_description(this.introduction_text);
		if (this.allow_print && !this.is_new) this.setup_print_button();
		if (this.allow_delete && !this.is_new) this.setup_delete_button();
		if (this.is_new) this.setup_cancel_button();
		this.setup_primary_action();
		$(".link-btn").remove();

		// webform client script
		frappe.init_client_script && frappe.init_client_script();
		frappe.web_form.events.trigger('after_load');
	}

	on(fieldname, handler) {
		let field = this.fields_dict[fieldname];
		field.df.change = () => {
			handler(field, field.value);
		};
	}

	set_field_values() {
		if (this.doc.name) this.set_values(this.doc);
		else return;
	}

	set_default_values() {
		let values = frappe.utils.get_query_params();
		delete values.new;
		this.set_values(values);
	}

	set_form_description(intro) {
		let intro_wrapper = document.getElementById('introduction');
		intro_wrapper.innerHTML = intro;
	}

	add_button(name, type, action, wrapper_class=".web-form-actions") {
		const button = document.createElement("button");
		button.classList.add("btn", "btn-" + type, "btn-sm", "ml-2");
		button.innerHTML = name;
		button.onclick = action;
		document.querySelector(wrapper_class).appendChild(button);
	}

	add_button_to_footer(name, type, action) {
		this.add_button(name, type, action, '.web-form-footer');
	}

	add_button_to_header(name, type, action) {
		this.add_button(name, type, action, '.web-form-actions');
	}

	setup_primary_action() {
		this.add_button_to_header(this.button_label || "Save", "primary", () =>
			this.save()
		);

		this.add_button_to_footer(this.button_label || "Save", "primary", () =>
			this.save()
		);
	}

	setup_cancel_button() {
		this.add_button_to_header("Cancel", "light", () => this.cancel());
	}

	setup_delete_button() {
		this.add_button_to_header("Delete", "danger", () => this.delete());
	}

	setup_print_button() {
		this.add_button_to_header(
			'',
			"light",
			() => this.print()
		);
	}

	save() {
		this.validate && this.validate();

		// validation hack: get_values will check for missing data
		let isvalid = super.get_values(this.allow_incomplete);

		if (!isvalid) return;

		if (window.saving) return;
		let for_payment = Boolean(this.accept_payment && !this.doc.paid);

		this.doc.doctype = this.doc_type;
		this.doc.web_form_name = this.name;

		// Save
		window.saving = true;
		frappe.form_dirty = false;

		frappe.call({
			type: "POST",
			method: "frappe.website.doctype.web_form.web_form.accept",
			args: {
				data: this.doc,
				web_form: this.name,
				docname: this.doc.name,
				for_payment
			},
			callback: response => {
				// Check for any exception in response
				if (!response.exc) {
					// Success
					this.handle_success(response.message);
					frappe.web_form.events.trigger('after_save');
				}
			},
			always: function() {
				window.saving = false;
			}
		});
		return true;
	}

	delete() {
		frappe.call({
			type: "POST",
			method: "frappe.website.doctype.web_form.web_form.delete",
			args: {
				web_form_name: this.name,
				docname: this.doc.name
			}
		});
	}

	print() {
		window.location.href = `/printview?
			doctype=${this.doc_type}
			&name=${this.doc.name}
			&format=${this.print_format || "Standard"}`;
	}

	cancel() {
		window.location.href = window.location.pathname;
	}

	handle_success(data) {
		if (this.accept_payment && !this.doc.paid) {
			window.location.href = data;
		}

		const success_dialog = new frappe.ui.Dialog({
			title: __("Saved Successfully"),
			secondary_action: () => {
				if (this.success_url) {
					window.location.pathname = this.success_url;
				} else if(this.login_required) {
					window.location.href =
						window.location.pathname + "?name=" + data.name;
				}
			}
		});

		success_dialog.show();
		const success_message =
			this.success_message || __("Your information has been submitted");
		success_dialog.set_message(success_message);
	}
}<commit_msg>style(web-form): change delete button to an icon<commit_after>frappe.provide("frappe.ui");
frappe.provide("frappe.web_form");
import EventEmitterMixin from '../../frappe/event_emitter';

export default class WebForm extends frappe.ui.FieldGroup {
	constructor(opts) {
		super();
		Object.assign(this, opts);
		frappe.web_form = this;
		frappe.web_form.events = {};
		Object.assign(frappe.web_form.events, EventEmitterMixin);
	}

	prepare(web_form_doc, doc) {
		Object.assign(this, web_form_doc);
		this.fields = web_form_doc.web_form_fields;
		this.doc = doc;
	}

	make() {
		super.make();
		this.set_field_values();
		if (this.introduction_text) this.set_form_description(this.introduction_text);
		if (this.allow_print && !this.is_new) this.setup_print_button();
		if (this.allow_delete && !this.is_new) this.setup_delete_button();
		if (this.is_new) this.setup_cancel_button();
		this.setup_primary_action();
		$(".link-btn").remove();

		// webform client script
		frappe.init_client_script && frappe.init_client_script();
		frappe.web_form.events.trigger('after_load');
	}

	on(fieldname, handler) {
		let field = this.fields_dict[fieldname];
		field.df.change = () => {
			handler(field, field.value);
		};
	}

	set_field_values() {
		if (this.doc.name) this.set_values(this.doc);
		else return;
	}

	set_default_values() {
		let values = frappe.utils.get_query_params();
		delete values.new;
		this.set_values(values);
	}

	set_form_description(intro) {
		let intro_wrapper = document.getElementById('introduction');
		intro_wrapper.innerHTML = intro;
	}

	add_button(name, type, action, wrapper_class=".web-form-actions") {
		const button = document.createElement("button");
		button.classList.add("btn", "btn-" + type, "btn-sm", "ml-2");
		button.innerHTML = name;
		button.onclick = action;
		document.querySelector(wrapper_class).appendChild(button);
	}

	add_button_to_footer(name, type, action) {
		this.add_button(name, type, action, '.web-form-footer');
	}

	add_button_to_header(name, type, action) {
		this.add_button(name, type, action, '.web-form-actions');
	}

	setup_primary_action() {
		this.add_button_to_header(this.button_label || "Save", "primary", () =>
			this.save()
		);

		this.add_button_to_footer(this.button_label || "Save", "primary", () =>
			this.save()
		);
	}

	setup_cancel_button() {
		this.add_button_to_header("Cancel", "light", () => this.cancel());
	}

	setup_delete_button() {
		this.add_button_to_header(
			'',
			"light",
			() => this.delete()
		);
	}

	setup_print_button() {
		this.add_button_to_header(
			'',
			"light",
			() => this.print()
		);
	}

	save() {
		this.validate && this.validate();

		// validation hack: get_values will check for missing data
		let isvalid = super.get_values(this.allow_incomplete);

		if (!isvalid) return;

		if (window.saving) return;
		let for_payment = Boolean(this.accept_payment && !this.doc.paid);

		this.doc.doctype = this.doc_type;
		this.doc.web_form_name = this.name;

		// Save
		window.saving = true;
		frappe.form_dirty = false;

		frappe.call({
			type: "POST",
			method: "frappe.website.doctype.web_form.web_form.accept",
			args: {
				data: this.doc,
				web_form: this.name,
				docname: this.doc.name,
				for_payment
			},
			callback: response => {
				// Check for any exception in response
				if (!response.exc) {
					// Success
					this.handle_success(response.message);
					frappe.web_form.events.trigger('after_save');
				}
			},
			always: function() {
				window.saving = false;
			}
		});
		return true;
	}

	delete() {
		frappe.call({
			type: "POST",
			method: "frappe.website.doctype.web_form.web_form.delete",
			args: {
				web_form_name: this.name,
				docname: this.doc.name
			}
		});
	}

	print() {
		window.location.href = `/printview?
			doctype=${this.doc_type}
			&name=${this.doc.name}
			&format=${this.print_format || "Standard"}`;
	}

	cancel() {
		window.location.href = window.location.pathname;
	}

	handle_success(data) {
		if (this.accept_payment && !this.doc.paid) {
			window.location.href = data;
		}

		const success_dialog = new frappe.ui.Dialog({
			title: __("Saved Successfully"),
			secondary_action: () => {
				if (this.success_url) {
					window.location.pathname = this.success_url;
				} else if(this.login_required) {
					window.location.href =
						window.location.pathname + "?name=" + data.name;
				}
			}
		});

		success_dialog.show();
		const success_message =
			this.success_message || __("Your information has been submitted");
		success_dialog.set_message(success_message);
	}
}<|endoftext|>