<commit_before>"use strict";

const videoClass = "chrome-better-HTML5-video",
      directVideoClass = "DIRECT-chrome-better-HTML5-video",
      ignoreVideoClass = "IGNORE-chrome-better-HTML5-video";

var toggleChecked, toggleEnabled, observer, dirVideo, regVideos = [];

const shortcutFuncs = {
	togglePlay: function(v){
		if(v.paused)
			v.play();
		else
			v.pause();
	},

	toStart: function(v){
		v.currentTime = 0;
	},

	toEnd: function(v){
		v.currentTime = v.duration;
	},

	skipLeft: function(v,key,shift,ctrl){
		if(shift)
			v.currentTime -= 10;
		else if(ctrl)
			v.currentTime -= 1;
		else
			v.currentTime -= 5;
	},

	skipRight: function(v,key,shift,ctrl){
		if(shift)
			v.currentTime += 10;
		else if(ctrl)
			v.currentTime += 1;
		else
			v.currentTime += 5;
	},

	increaseVol: function(v){
		if(v.volume <= 0.9) v.volume += 0.1;
		else v.volume = 1;
	},

	decreaseVol: function(v){
		if(v.volume >= 0.1) v.volume -= 0.1;
		else v.volume = 0;
	},

	toggleMute: function(v){
		v.muted = !v.muted;
	},

	toggleFS: function(v){
		if(document.webkitFullscreenElement)
			document.webkitExitFullscreen();
		else
			v.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
	},

	reloadVideo: function(v){
		const currTime = v.currentTime;
		v.load();
		v.currentTime = currTime;
	},

	slowOrPrevFrame: function(v,key,shift){
		if(shift) // Less-Than
			v.playbackRate -= 0.25;
		else // Comma
			v.currentTime -= 1/60;
	},

	fastOrNextFrame: function(v,key,shift){
		if(shift) // Greater-Than
			v.playbackRate += 0.25;
		else // Period
			v.currentTime += 1/60;
	},

	normalSpeed: function(v,key,shift){
		if(shift) // ?
			v.playbackRate = v.defaultPlaybackRate;
	},

	toPercentage: function(v,key){
		v.currentTime = v.duration * (key - 48) / 10.0;
	}
};

const keyFuncs = {
	32 : shortcutFuncs.togglePlay,      // Space
	75 : shortcutFuncs.togglePlay,      // K
	35 : shortcutFuncs.toEnd,           // End
	48 : shortcutFuncs.toStart,         // 0
	36 : shortcutFuncs.toStart,         // Home
	37 : shortcutFuncs.skipLeft,        // Left arrow
	74 : shortcutFuncs.skipLeft,        // J
	39 : shortcutFuncs.skipRight,       // Right arrow
	76 : shortcutFuncs.skipRight,       // L
	38 : shortcutFuncs.increaseVol,     // Up arrow
	40 : shortcutFuncs.decreaseVol,     // Down arrow
	77 : shortcutFuncs.toggleMute,      // M
	70 : shortcutFuncs.toggleFS,        // F
	82 : shortcutFuncs.reloadVideo,     // R
	188: shortcutFuncs.slowOrPrevFrame, // Comma or Less-Than
	190: shortcutFuncs.fastOrNextFrame, // Period or Greater-Than
	191: shortcutFuncs.normalSpeed,     // Forward slash or ?
	49 : shortcutFuncs.toPercentage,    // 1
	50 : shortcutFuncs.toPercentage,    // 2
	51 : shortcutFuncs.toPercentage,    // 3
	52 : shortcutFuncs.toPercentage,    // 4
	53 : shortcutFuncs.toPercentage,    // 5
	54 : shortcutFuncs.toPercentage,    // 6
	55 : shortcutFuncs.toPercentage,    // 7
	56 : shortcutFuncs.toPercentage,    // 8
	57 : shortcutFuncs.toPercentage,    // 9
};

function registerDirectVideo(v){
	unregisterAllVideos();
	if(dirVideo){
		unregisterDirectVideo(v !== dirVideo);
	}
	dirVideo = v;
	v.classList.add(directVideoClass);
	document.addEventListener("click", directHandleClick);
	document.addEventListener("keydown", directHandleKeyDown);
	document.addEventListener("keypress", handleKeyOther);
	document.addEventListener("keyup", handleKeyOther);
}

function unregisterDirectVideo(reregister){
	document.removeEventListener("click", directHandleClick);
	document.removeEventListener("keydown", directHandleKeyDown);
	document.removeEventListener("keypress", handleKeyOther);
	document.removeEventListener("keyup", handleKeyOther);
	dirVideo.classList.remove(directVideoClass);
	if(reregister && document.body.contains(dirVideo)){
		registerVideo(dirVideo);
		dirVideo.focus();
	}
	dirVideo = undefined;
}

function registerVideo(v){
	regVideos.push(v);
	v.classList.add(videoClass);
	v.addEventListener("click", handleClick);
	v.addEventListener("keydown", handleKeyDown);
	v.addEventListener("keypress", handleKeyOther);
	v.addEventListener("keyup", handleKeyOther);
}

function unregisterVideo(v){
	regVideos.remove(v);
	v.classList.remove(videoClass);
	v.removeEventListener("click", handleClick);
	v.removeEventListener("keydown", handleKeyDown);
	v.removeEventListener("keypress", handleKeyOther);
	v.removeEventListener("keyup", handleKeyOther);
}

function registerAllValidVideos(vs){
	for(let i = 0; i < vs.length; ++i){
		if(vs[i].hasAttribute("controls")
		&&!vs[i].classList.contains(videoClass)
		&&!vs[i].classList.contains(ignoreVideoClass))
			registerVideo(vs[i]);
	}
}

function unregisterAllVideos(){
	for(let i = 0; i < regVideos.length; ++i){
		const v = regVideos[i];
		v.classList.remove(videoClass);
		v.removeEventListener("click", handleClick);
		v.removeEventListener("keydown", handleKeyDown);
		v.removeEventListener("keypress", handleKeyOther);
		v.removeEventListener("keyup", handleKeyOther);
	}
	regVideos = [];
}

function directHandleClick(e){
	shortcutFuncs.togglePlay(dirVideo);
}

function directHandleKeyDown(e){
	return handleKeyDown(e, dirVideo);
}

function handleClick(e){
	if(document.activeElement === this){
		shortcutFuncs.togglePlay(this);
		return true;
	}else{
		this.focus();
		e.preventDefault();
		e.stopPropagation();
		return false
	}
}

function handleKeyDown(e, v){
	if(e.altKey || e.metaKey){
		return true; // Do not activate
	}
	const func = keyFuncs[e.keyCode];
	if(func){
		if((func.length < 3 && e.shiftKey) ||
		   (func.length < 4 && e.ctrlKey)){
			return true; // Do not activate
		}
		func(v || this, e.keyCode, e.shiftKey, e.ctrlKey);
		e.preventDefault();
		e.stopPropagation();
		return false;
	}
	return true; // Do not prevent default if no UI activated
}

function handleKeyOther(e){
	if(e.altKey || e.metaKey){
		return true; // Do not prevent default
	}
	const func = keyFuncs[e.keyCode];
	if(func){
		if((func.length < 3 && e.shiftKey) ||
		   (func.length < 4 && e.ctrlKey)){
			return true; // Do not prevent default
		}
		e.preventDefault();
		e.stopPropagation();
		return false;
	}
	return true; // Do not prevent default if no UI activated
}

function handleFullscreen(){
	if(document.webkitFullscreenElement
	&& document.webkitFullscreenElement.classList.contains(videoClass))
		document.webkitFullscreenElement.focus()
}

function updateContextTarget(e){
	if(e.target && e.target.tagName && e.target.tagName.toLowerCase() === 'video'){
		let target  = e.target,
		    checked = target.classList.contains(ignoreVideoClass),
		    enabled = target.hasAttribute('controls');
		if(toggleChecked !== checked || toggleEnabled !== enabled){
			chrome.runtime.sendMessage({
				toggleChecked: checked,
				toggleEnabled: enabled
			}, function(response) {
				if(!response){
					console.log("Error while connecting:",
						chrome.runtime.lastError.message);
					return;
				}
				if(response.clicked){
					if(response.ignoreVideo){
						if(target.classList.contains(directVideoClass)){
							unregisterDirectVideo(false);
						}
						if(target.classList.contains(videoClass)){
							unregisterVideo(target);
						}
						target.classList.add(ignoreVideoClass);
					}else{
						target.classList.remove(ignoreVideoClass);
						if(target.hasAttribute("controls")){
							if(document.body.children.length === 1
							&& document.body.firstElementChild === target){
								registerDirectVideo(target);
							}else{
								registerVideo(target);
							}
						}
					}
				}
			});
			toggleChecked = checked;
			toggleEnabled = enabled;
		}
	}
}

function handleMutationRecords(mrs){
	for(let i = 0; i < mrs.length; ++i){
		if(mrs[i].type === "attributes" && mrs[i].attributeName === "controls"){
			const t = mrs[i].target;
			if(!t.hasAttribute("controls")){
				if(t.classList.contains(directVideoClass)){
					unregisterDirectVideo(false);
				}else if(t.classList.contains(videoClass)){
					unregisterVideo(t);
				}
			}else if(t.tagName.toLowerCase() === "video"
			&&      !t.classList.contains(ignoreVideoClass)){
				if(document.body.children.length === 1
				&& document.body.firstElementChild === t){
					registerDirectVideo(t);
				}else{
					registerVideo(t);
					t.focus();
				}
			}
		}else if(mrs[i].type === "childList"){
			// Handle direct video access
			if(dirVideo && (document.body.children.length !== 1
			|| document.body.firstElementChild !== dirVideo)){
				unregisterDirectVideo(true);
			}
			if(document.body.children.length === 1
			&& document.body.firstElementChild.tagName.toLowerCase() === "video"
			&& document.body.firstElementChild.hasAttribute("controls")
			&&!document.body.firstElementChild.classList.contains(ignoreVideoClass)
			&&!document.body.firstElementChild.classList.contains(directVideoClass)){
				registerDirectVideo(document.body.firstElementChild);
			}else if(mrs[i].addedNodes){
				for(let j = 0; j < mrs[i].addedNodes.length; ++j){
					const an = mrs[i].addedNodes[j];
					if(an.tagName && an.tagName.toLowerCase() === "video"){
						if(an.hasAttribute("controls")
						&&!an.classList.contains(videoClass)
						&&!an.classList.contains(ignoreVideoClass))
							registerVideo(an);
					}else if(an.getElementsByTagName){
						registerAllValidVideos(an.getElementsByTagName("video"));
					}
				}
			}
			if(mrs[i].removedNodes){
				for(let j = 0; j < mrs[i].removedNodes.length; ++j){
					const rn = mrs[i].removedNodes[j];
					if(rn.classList){
						if(rn.classList.contains(videoClass)){
							unregisterVideo(rn);
						}else if(rn.classList.contains(directVideoClass)){
							unregisterDirectVideo(false);
						}
					}
				}
			}
		}
	}
}

function enableExtension(){
	document.addEventListener("webkitfullscreenchange", handleFullscreen);
	document.addEventListener("mouseover", updateContextTarget);
	document.addEventListener("mousedown", updateContextTarget);
	document.addEventListener("contextmenu", updateContextTarget);

	if(document.body.children.length === 1 // Handle direct video access
	&& document.body.firstElementChild.tagName.toLowerCase() === "video"
	&& document.body.firstElementChild.hasAttribute("controls")
	&&!document.body.firstElementChild.classList.contains(ignoreVideoClass)){
		registerDirectVideo(document.body.firstElementChild);
	}else{
		registerAllValidVideos(document.getElementsByTagName("video"));
	}

	observer = observer || new MutationObserver(handleMutationRecords);
	observer.observe(document.documentElement, {
		childList: true,
		attributes: true,
		attributeFilter: ["controls"],
		subtree: true
	});
}

function  disableExtension(){
	document.removeEventListener("webkitfullscreenchange", handleFullscreen);
	document.removeEventListener("mouseover", updateContextTarget);
	document.removeEventListener("mousedown", updateContextTarget);
	document.removeEventListener("contextmenu", updateContextTarget);

	if(dirVideo) unregisterDirectVideo(false);
	unregisterAllVideos();

	if(observer) observer.disconnect();
}

if(document.readyState !== "loading")
	enableExtension();
else
	window.addEventListener("load", enableExtension);
<commit_msg>Fix error when disabling videos<commit_after>"use strict";

const videoClass = "chrome-better-HTML5-video",
      directVideoClass = "DIRECT-chrome-better-HTML5-video",
      ignoreVideoClass = "IGNORE-chrome-better-HTML5-video";

var toggleChecked, toggleEnabled, observer, dirVideo, regVideos = [];

const shortcutFuncs = {
	togglePlay: function(v){
		if(v.paused)
			v.play();
		else
			v.pause();
	},

	toStart: function(v){
		v.currentTime = 0;
	},

	toEnd: function(v){
		v.currentTime = v.duration;
	},

	skipLeft: function(v,key,shift,ctrl){
		if(shift)
			v.currentTime -= 10;
		else if(ctrl)
			v.currentTime -= 1;
		else
			v.currentTime -= 5;
	},

	skipRight: function(v,key,shift,ctrl){
		if(shift)
			v.currentTime += 10;
		else if(ctrl)
			v.currentTime += 1;
		else
			v.currentTime += 5;
	},

	increaseVol: function(v){
		if(v.volume <= 0.9) v.volume += 0.1;
		else v.volume = 1;
	},

	decreaseVol: function(v){
		if(v.volume >= 0.1) v.volume -= 0.1;
		else v.volume = 0;
	},

	toggleMute: function(v){
		v.muted = !v.muted;
	},

	toggleFS: function(v){
		if(document.webkitFullscreenElement)
			document.webkitExitFullscreen();
		else
			v.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
	},

	reloadVideo: function(v){
		const currTime = v.currentTime;
		v.load();
		v.currentTime = currTime;
	},

	slowOrPrevFrame: function(v,key,shift){
		if(shift) // Less-Than
			v.playbackRate -= 0.25;
		else // Comma
			v.currentTime -= 1/60;
	},

	fastOrNextFrame: function(v,key,shift){
		if(shift) // Greater-Than
			v.playbackRate += 0.25;
		else // Period
			v.currentTime += 1/60;
	},

	normalSpeed: function(v,key,shift){
		if(shift) // ?
			v.playbackRate = v.defaultPlaybackRate;
	},

	toPercentage: function(v,key){
		v.currentTime = v.duration * (key - 48) / 10.0;
	}
};

const keyFuncs = {
	32 : shortcutFuncs.togglePlay,      // Space
	75 : shortcutFuncs.togglePlay,      // K
	35 : shortcutFuncs.toEnd,           // End
	48 : shortcutFuncs.toStart,         // 0
	36 : shortcutFuncs.toStart,         // Home
	37 : shortcutFuncs.skipLeft,        // Left arrow
	74 : shortcutFuncs.skipLeft,        // J
	39 : shortcutFuncs.skipRight,       // Right arrow
	76 : shortcutFuncs.skipRight,       // L
	38 : shortcutFuncs.increaseVol,     // Up arrow
	40 : shortcutFuncs.decreaseVol,     // Down arrow
	77 : shortcutFuncs.toggleMute,      // M
	70 : shortcutFuncs.toggleFS,        // F
	82 : shortcutFuncs.reloadVideo,     // R
	188: shortcutFuncs.slowOrPrevFrame, // Comma or Less-Than
	190: shortcutFuncs.fastOrNextFrame, // Period or Greater-Than
	191: shortcutFuncs.normalSpeed,     // Forward slash or ?
	49 : shortcutFuncs.toPercentage,    // 1
	50 : shortcutFuncs.toPercentage,    // 2
	51 : shortcutFuncs.toPercentage,    // 3
	52 : shortcutFuncs.toPercentage,    // 4
	53 : shortcutFuncs.toPercentage,    // 5
	54 : shortcutFuncs.toPercentage,    // 6
	55 : shortcutFuncs.toPercentage,    // 7
	56 : shortcutFuncs.toPercentage,    // 8
	57 : shortcutFuncs.toPercentage,    // 9
};

function registerDirectVideo(v){
	unregisterAllVideos();
	if(dirVideo){
		unregisterDirectVideo(v !== dirVideo);
	}
	dirVideo = v;
	v.classList.add(directVideoClass);
	document.addEventListener("click", directHandleClick);
	document.addEventListener("keydown", directHandleKeyDown);
	document.addEventListener("keypress", handleKeyOther);
	document.addEventListener("keyup", handleKeyOther);
}

function unregisterDirectVideo(reregister){
	document.removeEventListener("click", directHandleClick);
	document.removeEventListener("keydown", directHandleKeyDown);
	document.removeEventListener("keypress", handleKeyOther);
	document.removeEventListener("keyup", handleKeyOther);
	dirVideo.classList.remove(directVideoClass);
	if(reregister && document.body.contains(dirVideo)){
		registerVideo(dirVideo);
		dirVideo.focus();
	}
	dirVideo = undefined;
}

function registerVideo(v){
	regVideos.push(v);
	v.classList.add(videoClass);
	v.addEventListener("click", handleClick);
	v.addEventListener("keydown", handleKeyDown);
	v.addEventListener("keypress", handleKeyOther);
	v.addEventListener("keyup", handleKeyOther);
}

function unregisterVideo(v){
	regVideos.splice(regVideos.indexOf(v), 1);
	v.classList.remove(videoClass);
	v.removeEventListener("click", handleClick);
	v.removeEventListener("keydown", handleKeyDown);
	v.removeEventListener("keypress", handleKeyOther);
	v.removeEventListener("keyup", handleKeyOther);
}

function registerAllValidVideos(vs){
	for(let i = 0; i < vs.length; ++i){
		if(vs[i].hasAttribute("controls")
		&&!vs[i].classList.contains(videoClass)
		&&!vs[i].classList.contains(ignoreVideoClass))
			registerVideo(vs[i]);
	}
}

function unregisterAllVideos(){
	for(let i = 0; i < regVideos.length; ++i){
		const v = regVideos[i];
		v.classList.remove(videoClass);
		v.removeEventListener("click", handleClick);
		v.removeEventListener("keydown", handleKeyDown);
		v.removeEventListener("keypress", handleKeyOther);
		v.removeEventListener("keyup", handleKeyOther);
	}
	regVideos = [];
}

function directHandleClick(e){
	shortcutFuncs.togglePlay(dirVideo);
}

function directHandleKeyDown(e){
	return handleKeyDown(e, dirVideo);
}

function handleClick(e){
	if(document.activeElement === this){
		shortcutFuncs.togglePlay(this);
		return true;
	}else{
		this.focus();
		e.preventDefault();
		e.stopPropagation();
		return false
	}
}

function handleKeyDown(e, v){
	if(e.altKey || e.metaKey){
		return true; // Do not activate
	}
	const func = keyFuncs[e.keyCode];
	if(func){
		if((func.length < 3 && e.shiftKey) ||
		   (func.length < 4 && e.ctrlKey)){
			return true; // Do not activate
		}
		func(v || this, e.keyCode, e.shiftKey, e.ctrlKey);
		e.preventDefault();
		e.stopPropagation();
		return false;
	}
	return true; // Do not prevent default if no UI activated
}

function handleKeyOther(e){
	if(e.altKey || e.metaKey){
		return true; // Do not prevent default
	}
	const func = keyFuncs[e.keyCode];
	if(func){
		if((func.length < 3 && e.shiftKey) ||
		   (func.length < 4 && e.ctrlKey)){
			return true; // Do not prevent default
		}
		e.preventDefault();
		e.stopPropagation();
		return false;
	}
	return true; // Do not prevent default if no UI activated
}

function handleFullscreen(){
	if(document.webkitFullscreenElement
	&& document.webkitFullscreenElement.classList.contains(videoClass))
		document.webkitFullscreenElement.focus()
}

function updateContextTarget(e){
	if(e.target && e.target.tagName && e.target.tagName.toLowerCase() === 'video'){
		let target  = e.target,
		    checked = target.classList.contains(ignoreVideoClass),
		    enabled = target.hasAttribute('controls');
		if(toggleChecked !== checked || toggleEnabled !== enabled){
			chrome.runtime.sendMessage({
				toggleChecked: checked,
				toggleEnabled: enabled
			}, function(response) {
				if(!response){
					console.log("Error while connecting:",
						chrome.runtime.lastError.message);
					return;
				}
				if(response.clicked){
					if(response.ignoreVideo){
						if(target.classList.contains(directVideoClass)){
							unregisterDirectVideo(false);
						}
						if(target.classList.contains(videoClass)){
							unregisterVideo(target);
						}
						target.classList.add(ignoreVideoClass);
					}else{
						target.classList.remove(ignoreVideoClass);
						if(target.hasAttribute("controls")){
							if(document.body.children.length === 1
							&& document.body.firstElementChild === target){
								registerDirectVideo(target);
							}else{
								registerVideo(target);
							}
						}
					}
				}
			});
			toggleChecked = checked;
			toggleEnabled = enabled;
		}
	}
}

function handleMutationRecords(mrs){
	for(let i = 0; i < mrs.length; ++i){
		if(mrs[i].type === "attributes" && mrs[i].attributeName === "controls"){
			const t = mrs[i].target;
			if(!t.hasAttribute("controls")){
				if(t.classList.contains(directVideoClass)){
					unregisterDirectVideo(false);
				}else if(t.classList.contains(videoClass)){
					unregisterVideo(t);
				}
			}else if(t.tagName.toLowerCase() === "video"
			&&      !t.classList.contains(ignoreVideoClass)){
				if(document.body.children.length === 1
				&& document.body.firstElementChild === t){
					registerDirectVideo(t);
				}else{
					registerVideo(t);
					t.focus();
				}
			}
		}else if(mrs[i].type === "childList"){
			// Handle direct video access
			if(dirVideo && (document.body.children.length !== 1
			|| document.body.firstElementChild !== dirVideo)){
				unregisterDirectVideo(true);
			}
			if(document.body.children.length === 1
			&& document.body.firstElementChild.tagName.toLowerCase() === "video"
			&& document.body.firstElementChild.hasAttribute("controls")
			&&!document.body.firstElementChild.classList.contains(ignoreVideoClass)
			&&!document.body.firstElementChild.classList.contains(directVideoClass)){
				registerDirectVideo(document.body.firstElementChild);
			}else if(mrs[i].addedNodes){
				for(let j = 0; j < mrs[i].addedNodes.length; ++j){
					const an = mrs[i].addedNodes[j];
					if(an.tagName && an.tagName.toLowerCase() === "video"){
						if(an.hasAttribute("controls")
						&&!an.classList.contains(videoClass)
						&&!an.classList.contains(ignoreVideoClass))
							registerVideo(an);
					}else if(an.getElementsByTagName){
						registerAllValidVideos(an.getElementsByTagName("video"));
					}
				}
			}
			if(mrs[i].removedNodes){
				for(let j = 0; j < mrs[i].removedNodes.length; ++j){
					const rn = mrs[i].removedNodes[j];
					if(rn.classList){
						if(rn.classList.contains(videoClass)){
							unregisterVideo(rn);
						}else if(rn.classList.contains(directVideoClass)){
							unregisterDirectVideo(false);
						}
					}
				}
			}
		}
	}
}

function enableExtension(){
	document.addEventListener("webkitfullscreenchange", handleFullscreen);
	document.addEventListener("mouseover", updateContextTarget);
	document.addEventListener("mousedown", updateContextTarget);
	document.addEventListener("contextmenu", updateContextTarget);

	if(document.body.children.length === 1 // Handle direct video access
	&& document.body.firstElementChild.tagName.toLowerCase() === "video"
	&& document.body.firstElementChild.hasAttribute("controls")
	&&!document.body.firstElementChild.classList.contains(ignoreVideoClass)){
		registerDirectVideo(document.body.firstElementChild);
	}else{
		registerAllValidVideos(document.getElementsByTagName("video"));
	}

	observer = observer || new MutationObserver(handleMutationRecords);
	observer.observe(document.documentElement, {
		childList: true,
		attributes: true,
		attributeFilter: ["controls"],
		subtree: true
	});
}

function  disableExtension(){
	document.removeEventListener("webkitfullscreenchange", handleFullscreen);
	document.removeEventListener("mouseover", updateContextTarget);
	document.removeEventListener("mousedown", updateContextTarget);
	document.removeEventListener("contextmenu", updateContextTarget);

	if(dirVideo) unregisterDirectVideo(false);
	unregisterAllVideos();

	if(observer) observer.disconnect();
}

if(document.readyState !== "loading")
	enableExtension();
else
	window.addEventListener("load", enableExtension);
<|endoftext|>


<commit_before>import {v4 as uuid} from 'uuid';

import commandSchemaValidator from '../../src/commandSchemaValidator';

/**
 * We don't want to test each schema for every command.
 * Just test that the validator throws on missing command name (schema can not be loaded)
 * Just test that on schema validation error, the validator throws
 */
test('validates successfully ', () => {
  commandSchemaValidator({
    id: uuid(),
    name: 'setUsername',
    roomId: 'some-room',
    payload: {username: 'Thom'}
  });
});

test('throws on invalid command (id missing)', () => {
  expect(() =>
    commandSchemaValidator({
      roomId: 'some-room',
      name: 'setUsername',
      payload: {}
    })
  ).toThrow(/Missing required property: id/);
});

test('throws on invalid command (payload misses property)', () => {
  expect(() =>
    commandSchemaValidator({
      id: uuid(),
      roomId: 'some-room',
      name: 'setUsername',
      payload: {}
    })
  ).toThrow(/Missing required property: username/);
});

test('throws on invalid email', () => {
  expect(() =>
    commandSchemaValidator({
      id: uuid(),
      roomId: 'some-room',
      name: 'setEmail',
      payload: {
        email: 'tisodgjfkjhlk'
      }
    })
  ).toThrow(/Format validation failed \(must be a valid email-address\) in \/payload\/email/);
});

test('throws on invalid roomId', () => {
  expect(() =>
    commandSchemaValidator({
      id: uuid(),
      roomId: 'SomeRoom.?with&invalid¼chars#',
      name: 'joinRoom',
      payload: {}
    })
  ).toThrow(
    /Format validation failed \(must be a valid roomId: only the following characters are allowed: a-z 0-9 _ -\) in \/roomId/
  );
});

test('throws on invalid userId', () => {
  expect(() =>
    commandSchemaValidator({
      id: uuid(),
      roomId: 'custom-room-id',
      name: 'joinRoom',
      userId: 'sdgdgkjslgjslkjglskgjdlksjgl'
    })
  ).toThrow(/Format validation failed \(must be a valid uuid v4\) in \/userId/);
});

test('works with valid userId', () => {
  commandSchemaValidator({
    id: uuid(),
    roomId: 'custom-room-id',
    name: 'joinRoom',
    userId: uuid()
  });
});
<commit_msg>#118 fix test<commit_after>import {v4 as uuid} from 'uuid';

import commandSchemaValidator from '../../src/commandSchemaValidator';

/**
 * We don't want to test each schema for every command.
 * Just test that the validator throws on missing command name (schema can not be loaded)
 * Just test that on schema validation error, the validator throws
 */
test('validates successfully ', () => {
  commandSchemaValidator({
    id: uuid(),
    name: 'setUsername',
    roomId: 'some-room',
    payload: {username: 'Thom'}
  });
});

test('throws on invalid command (id missing)', () => {
  expect(() =>
    commandSchemaValidator({
      roomId: 'some-room',
      name: 'setUsername',
      payload: {}
    })
  ).toThrow(/Missing required property: id/);
});

test('throws on invalid command (payload misses property)', () => {
  expect(() =>
    commandSchemaValidator({
      id: uuid(),
      roomId: 'some-room',
      name: 'setUsername',
      payload: {}
    })
  ).toThrow(/Missing required property: username/);
});

test('throws on invalid email', () => {
  expect(() =>
    commandSchemaValidator({
      id: uuid(),
      roomId: 'some-room',
      name: 'setEmail',
      payload: {
        email: 'tisodgjfkjhlk'
      }
    })
  ).toThrow(/Format validation failed \(must be a valid email-address\) in \/payload\/email/);
});

test('throws on invalid roomId', () => {
  expect(() =>
    commandSchemaValidator({
      id: uuid(),
      roomId: 'SomeRoom.?with&invalid¼chars#',
      name: 'joinRoom',
      payload: {}
    })
  ).toThrow(
    /Format validation failed \(must be a valid roomId: only the following characters are allowed: a-z 0-9 _ -\) in \/roomId/
  );
});

test('throws on invalid userId', () => {
  expect(() =>
    commandSchemaValidator({
      id: uuid(),
      roomId: 'custom-room-id',
      name: 'joinRoom',
      userId: 'sdgdgkjslgjslkjglskgjdlksjgl'
    })
  ).toThrow(/Format validation failed \(must be a valid uuid v4\) in \/userId/);
});

test('works with valid userId', () => {
  commandSchemaValidator({
    id: uuid(),
    roomId: 'custom-room-id',
    name: 'joinRoom',
    userId: uuid(),
    payload: {}
  });
});
<|endoftext|>


<commit_before>var http = require('http'),
	url = require('url'),
	util = require('util'),
	events = require('events'),
    fs = require('fs'),
    path = require('path'),
    port = 1234;

function main(argv) {
    var server = new HttpServer({
        'GET':createServlet(StaticServlet),
        'POST':createServlet(StaticServlet),
        'HEAD':createServlet(StaticServlet)
    }).start(port);

    return server;
}

function escapeHtml(value) {
    return value.toString().replace('<', '<').replace('>', '>').replace('"', '"');
}

function createServlet(Class) {
    var servlet = new Class();
    return servlet.handleRequest.bind(servlet);
}

function HttpServer(handlers) {
    this.handlers = handlers;
    this.server = http.createServer(this.handleRequest_.bind(this));
}

HttpServer.prototype.start = function (port) {
    this.port = port;
    this.server.listen(port);
    util.puts('Server running at http://localhost:' + this.port + '/');
};

HttpServer.prototype.parseUrl_ = function (urlString) {
    var parsed = url.parse(urlString);
    parsed.pathname = url.resolve('/', parsed.pathname);
    return url.parse(url.format(parsed), true);
};

HttpServer.prototype.handleRequest_ = function (req, res) {
    var logEntry = req.method + ' ' + req.url;
    if (req.headers['user-agent']) {
        logEntry += ' ' + req.headers['user-agent'];
    }
    util.puts(logEntry);
    req.url = this.parseUrl_(req.url);
    var handler = this.handlers[req.method];
    if (!handler) {
        res.writeHead(501);
        res.end();
    } else {
        handler.call(this, req, res);
    }
};

function StaticServlet() {}

StaticServlet.MimeMap = {
    'txt':'text/plain',
    'html':'text/html',
    'css':'text/css',
    'xml':'application/xml',
    'json':'application/json',
    'js':'application/javascript',
    'jpg':'image/jpeg',
    'jpeg':'image/jpeg',
    'gif':'image/gif',
    'png':'image/png',
    'svg':'image/svg+xml'
};

StaticServlet.prototype.handleRequest = function (req, res) {
    var self = this;
    var path = ('./' + req.url.pathname).replace('//', '/').replace(/%(..)/g, function (match, hex) {
        return String.fromCharCode(parseInt(hex, 16));
    });
    var parts = path.split('/');
    if (parts[parts.length - 1].charAt(0) === '.')
        return self.sendForbidden_(req, res, path);

    if (req.method === 'POST') {
        if (self.attemptingToAccessOutsideLocalAppPath(parts)) {
            return self.sendForbidden_(req, res, path);
        }

        return self.writeFile_(req, res, path);
    }

    self.findAndSendTarget(req, path, res, self);
}

StaticServlet.prototype.findAndSendTarget = function(req, path, res, self) {
util.puts(path);
	fs.stat(path, function (err, stat) {
        if (err && path.indexOf('app/') >= 0)
            return self.sendMissing_(req, res, path);
        else if (err) {
            if (path.indexOf('.json') == -1) {
                return self.findAndSendTarget(req, path + ".json", res, self);
            } else if (!fs.fileExistsSync(path + ".json") && path.indexOf('/data/') != -1) {
					self.sendMissing_(req, res, path);
            }

            return self.sendDefault_(req, res);
        }

        if (fs.fileExistsSync(path + ".json")) {
            return self.findAndSendTarget(req, path + ".json", res, self);
        }

        var indexOfLastSlash = path.lastIndexOf('/');
        var indexOfSecondToLastSlash = path.lastIndexOf('/', indexOfLastSlash-1);
        var secondToLastNode = path.substr(indexOfSecondToLastSlash + 1, indexOfLastSlash-indexOfSecondToLastSlash-1);
        if (stat.isDirectory() && secondToLastNode != "event" && secondToLastNode != "user") {
            if (path.indexOf('/data/') == -1) {
                return self.sendDefault_(req, res);
            }
            return self.sendAllJsonFilesAppended_(req, res, path);
        }
		if (!fs.fileExistsSync(path)) {
            return self.sendMissing_(req, path, res);
        }
        return self.sendFile_(req, res, path);
    });
}

StaticServlet.prototype.attemptingToAccessOutsideLocalAppPath = function (pathParts) {
    if (pathParts[0] !== '.')
        return true;

    for (var idx = 0; idx < pathParts.length; idx++) {
        if (pathParts[idx].indexOf("..") != -1 || pathParts[idx].indexOf("c:\\") != -1 || pathParts[idx].indexOf("/c/") != -1) {
            return true;
        }
    }

    return false;
};

StaticServlet.prototype.sendError_ = function (req, res, error) {
    res.writeHead(500, {'Content-Type':'text/html'});
    res.write('<!doctype html>\n');
    res.write('<title>Internal Server Error</title>\n');
    res.write('
Internal Server Error
');
    res.write('
' + escapeHtml(util.inspect(error)) + '
');
    util.puts('500 Internal Server Error');
    util.puts(util.inspect(error));
};

StaticServlet.prototype.sendMissing_ = function (req, res, path) {
    path = path.substring(1);
    res.writeHead(404, {'Content-Type':'text/html'});
    res.write('<!doctype html>\n');
    res.write('<title>404 Not Found</title>\n');
    res.write('
Not Found
');
    res.write('
The requested URL ' + escapeHtml(path) + ' was not found on this server.
');
    res.end();
    util.puts('404 Not Found: ' + path);
};

StaticServlet.prototype.sendForbidden_ = function (req, res, path) {
    path = path.substring(1);
    res.writeHead(403, {
        'Content-Type':'text/html'
    });
    res.write('<!doctype html>\n');
    res.write('<title>403 Forbidden</title>\n');
    res.write('
Forbidden
');
    res.write(
        '
You do not have permission to access ' +
            escapeHtml(path) + ' on this server.
'
    );
    res.end();
    util.puts('403 Forbidden: ' + path);
};

StaticServlet.prototype.sendRedirect_ = function (req, res, redirectUrl) {
    res.writeHead(301, {
        'Content-Type':'text/html',
        'Location':redirectUrl
    });
    res.write('<!doctype html>\n');
    res.write('<title>301 Moved Permanently</title>\n');
    res.write('
Moved Permanently
');
    res.write(
        '
The document has moved here.
'
    );
    res.end();
    util.puts('301 Moved Permanently: ' + redirectUrl);
};

StaticServlet.prototype.sendDefault_ = function (req, res) {
    var self = this;
    var path = 'app/index.html'

    var file = fs.createReadStream(path);
    res.writeHead(200, {
        'Content-Type':StaticServlet.
            MimeMap[path.split('.').pop()] || 'text/plain'
    });
    if (req.method === 'HEAD') {
        res.end();
    } else {
        file.on('data', res.write.bind(res));
        file.on('close', function () {
            res.end();
        });
        file.on('error', function (error) {
            self.sendError_(req, res, error);
        });
    }
};

StaticServlet.prototype.sendFile_ = function (req, res, path) {
    var self = this;
    var file = fs.createReadStream(path);
    res.writeHead(200, {
        'Content-Type':StaticServlet.
            MimeMap[path.split('.').pop()] || 'text/plain'
    });
    if (req.method === 'HEAD') {
        res.end();
    } else {
        file.on('data', res.write.bind(res));
        file.on('close', function () {
            res.end();
        });
        file.on('error', function (error) {
            self.sendError_(req, res, error);
        });
    }
};

StaticServlet.prototype.sendAllJsonFilesAppended_ = function (req, res, path) {
    var self = this;
    var files = []
    try {
        files = fs.readdirSync(path);
    }
    catch (e) {
        self.writeSuccessHeader(res, path);
        res.write("[]");
        res.end();
    }
    var results = "[";
    for (var idx = 0; idx < files.length; idx++) {
        if (files[idx].indexOf(".json") == files[idx].length - 5) {
            results += fs.readFileSync(path + "/" + files[idx]) + ",";
        }
    }
    results = results.substr(0, results.length - 1);
    results += "]";
    self.writeSuccessHeader(res, path);
    res.write(results);
    res.end();

};

StaticServlet.prototype.writeFile_ = function (req, res, path) {
    var self = this;

    res.writeHead(200, {
        'Content-Type':'text/plain'
    });
    if (req.method === 'HEAD') {
        res.end();
    } else {
        var targetDir = path.substr(0, path.lastIndexOf('/'));
        var dirExists;
        try {
            var stats = fs.lstatSync(targetDir);
            dirExists = stats.isDirectory();
        } catch(e) {dirExists = false;}

        if (!dirExists) {
            fs.mkdirSyncRecursive(targetDir);
        }
        var writeStream = fs.createWriteStream(path + ".json");
        req.pipe(writeStream);

        req.on('end', function () {
            res.writeHead(200, {"content-type":"text/html"});
            res.end('Save Successful');
        });

        writeStream.on('error', function (err) {
            console.log(err);
            self.sendError_(req, res, err);
        });
    }
};

StaticServlet.prototype.writeSuccessHeader = function (res, path) {
    res.writeHead(200, {
        'Content-Type':StaticServlet.
            MimeMap[path.split('.').pop()] || 'text/plain'
    });
}
StaticServlet.prototype.sendDirectory_ = function (req, res, path) {
    var self = this;
    if (path.match(/[^\/]$/)) {
        req.url.pathname += '/';
        var redirectUrl = url.format(url.parse(url.format(req.url)));
        return self.sendRedirect_(req, res, redirectUrl);
    }
    fs.readdir(path, function (err, files) {
        if (err)
            return self.sendError_(req, res, error);

        if (!files.length)
            return self.writeDirectoryIndex_(req, res, path, []);

        var remaining = files.length;
        files.forEach(function (fileName, index) {
            fs.stat(path + '/' + fileName, function (err, stat) {
                if (err)
                    return self.sendError_(req, res, err);
                if (stat.isDirectory()) {
                    files[index] = fileName + '/';
                }
                if (!(--remaining))
                    return self.writeDirectoryIndex_(req, res, path, files);
            });
        });
    });
};

StaticServlet.prototype.writeDirectoryIndex_ = function (req, res, path, files) {
    path = path.substring(1);
    res.writeHead(200, {
        'Content-Type':'text/html'
    });
    if (req.method === 'HEAD') {
        res.end();
        return;
    }
    res.write('<!doctype html>\n');
    res.write('<title>' + escapeHtml(path) + '</title>\n');
    res.write('\n');
    res.write('
Directory: ' + escapeHtml(path) + '
');
    res.write('
');
    files.forEach(function (fileName) {
        if (fileName.charAt(0) !== '.') {
            res.write('
' +
                escapeHtml(fileName) + '
');
        }
    });
    res.write('
');
    res.end();
};

fs.fileExistsSync = function (filePath) {
    try {
        var stats = fs.lstatSync(filePath);

        return stats.isFile();
    }
    catch (e) {
        return false;
    }
}

fs.mkdirSyncRecursive = function(dirPath) {
    try{
        fs.mkdirSync(dirPath);
    } catch(e) {
        fs.mkdirSyncRecursive(path.dirname(dirPath));
        fs.mkdirSyncRecursive(dirPath);

    }
};

main(process.argv);<commit_msg>stable version 2<commit_after>var http = require('http'),
	url = require('url'),
	util = require('util'),
	events = require('events'),
    fs = require('fs'),
    path = require('path'),
    port = 1234;

function main(argv) {
    new HttpServer({
        'GET':createServlet(StaticServlet),
        'POST':createServlet(StaticServlet),
        'HEAD':createServlet(StaticServlet)
    }).start(process.env.PORT || port);
}

function escapeHtml(value) {
    return value.toString().replace('<', '<').replace('>', '>').replace('"', '"');
}

function createServlet(Class) {
    var servlet = new Class();
    return servlet.handleRequest.bind(servlet);
}

function HttpServer(handlers) {
    this.handlers = handlers;
    this.server = http.createServer(this.handleRequest_.bind(this));
}

HttpServer.prototype.start = function (port) {
    this.port = port;
    this.server.listen(port);
    util.puts('Server running at http://localhost:' + this.port + '/');
};

HttpServer.prototype.parseUrl_ = function (urlString) {
    var parsed = url.parse(urlString);
    parsed.pathname = url.resolve('/', parsed.pathname);
    return url.parse(url.format(parsed), true);
};

HttpServer.prototype.handleRequest_ = function (req, res) {
    var logEntry = req.method + ' ' + req.url;
    if (req.headers['user-agent']) {
        logEntry += ' ' + req.headers['user-agent'];
    }
    util.puts(logEntry);
    req.url = this.parseUrl_(req.url);
    var handler = this.handlers[req.method];
    if (!handler) {
        res.writeHead(501);
        res.end();
    } else {
        handler.call(this, req, res);
    }
};

function StaticServlet() {}

StaticServlet.MimeMap = {
    'txt':'text/plain',
    'html':'text/html',
    'css':'text/css',
    'xml':'application/xml',
    'json':'application/json',
    'js':'application/javascript',
    'jpg':'image/jpeg',
    'jpeg':'image/jpeg',
    'gif':'image/gif',
    'png':'image/png',
    'svg':'image/svg+xml'
};

StaticServlet.prototype.handleRequest = function (req, res) {
    var self = this;
    var path = ('./' + req.url.pathname).replace('//', '/').replace(/%(..)/g, function (match, hex) {
        return String.fromCharCode(parseInt(hex, 16));
    });
    var parts = path.split('/');
    if (parts[parts.length - 1].charAt(0) === '.')
        return self.sendForbidden_(req, res, path);

    if (req.method === 'POST') {
        if (self.attemptingToAccessOutsideLocalAppPath(parts)) {
            return self.sendForbidden_(req, res, path);
        }

        return self.writeFile_(req, res, path);
    }

    self.findAndSendTarget(req, path, res, self);
}

StaticServlet.prototype.findAndSendTarget = function(req, path, res, self) {
util.puts(path);
	fs.stat(path, function (err, stat) {
        if (err && path.indexOf('app/') >= 0)
            return self.sendMissing_(req, res, path);
        else if (err) {
            if (path.indexOf('.json') == -1) {
                return self.findAndSendTarget(req, path + ".json", res, self);
            } else if (!fs.fileExistsSync(path + ".json") && path.indexOf('/data/') != -1) {
					self.sendMissing_(req, res, path);
            }

            return self.sendDefault_(req, res);
        }

        if (fs.fileExistsSync(path + ".json")) {
            return self.findAndSendTarget(req, path + ".json", res, self);
        }

        var indexOfLastSlash = path.lastIndexOf('/');
        var indexOfSecondToLastSlash = path.lastIndexOf('/', indexOfLastSlash-1);
        var secondToLastNode = path.substr(indexOfSecondToLastSlash + 1, indexOfLastSlash-indexOfSecondToLastSlash-1);
        if (stat.isDirectory() && secondToLastNode != "event" && secondToLastNode != "user") {
            if (path.indexOf('/data/') == -1) {
                return self.sendDefault_(req, res);
            }
            return self.sendAllJsonFilesAppended_(req, res, path);
        }
		if (!fs.fileExistsSync(path)) {
            return self.sendMissing_(req, path, res);
        }
        return self.sendFile_(req, res, path);
    });
}

StaticServlet.prototype.attemptingToAccessOutsideLocalAppPath = function (pathParts) {
    if (pathParts[0] !== '.')
        return true;

    for (var idx = 0; idx < pathParts.length; idx++) {
        if (pathParts[idx].indexOf("..") != -1 || pathParts[idx].indexOf("c:\\") != -1 || pathParts[idx].indexOf("/c/") != -1) {
            return true;
        }
    }

    return false;
};

StaticServlet.prototype.sendError_ = function (req, res, error) {
    res.writeHead(500, {'Content-Type':'text/html'});
    res.write('<!doctype html>\n');
    res.write('<title>Internal Server Error</title>\n');
    res.write('
Internal Server Error
');
    res.write('
' + escapeHtml(util.inspect(error)) + '
');
    util.puts('500 Internal Server Error');
    util.puts(util.inspect(error));
};

StaticServlet.prototype.sendMissing_ = function (req, res, path) {
    path = path.substring(1);
    res.writeHead(404, {'Content-Type':'text/html'});
    res.write('<!doctype html>\n');
    res.write('<title>404 Not Found</title>\n');
    res.write('
Not Found
');
    res.write('
The requested URL ' + escapeHtml(path) + ' was not found on this server.
');
    res.end();
    util.puts('404 Not Found: ' + path);
};

StaticServlet.prototype.sendForbidden_ = function (req, res, path) {
    path = path.substring(1);
    res.writeHead(403, {
        'Content-Type':'text/html'
    });
    res.write('<!doctype html>\n');
    res.write('<title>403 Forbidden</title>\n');
    res.write('
Forbidden
');
    res.write('
You do not have permission to access ' + escapeHtml(path) + ' on this server.
');
    res.end();
    util.puts('403 Forbidden: ' + path);
};

StaticServlet.prototype.sendRedirect_ = function (req, res, redirectUrl) {
    res.writeHead(301, {'Content-Type':'text/html', 'Location':redirectUrl});
    res.write('<!doctype html>\n');
    res.write('<title>301 Moved Permanently</title>\n');
    res.write('
Moved Permanently
');
    res.write('
The document has moved here.
' );
    res.end();
    util.puts('301 Moved Permanently: ' + redirectUrl);
};

StaticServlet.prototype.sendDefault_ = function (req, res) {
    var self = this;
    var path = 'index.html'

    var file = fs.createReadStream(path);
    res.writeHead(200, {
        'Content-Type':StaticServlet.
            MimeMap[path.split('.').pop()] || 'text/plain'
    });
    if (req.method === 'HEAD') {
        res.end();
    } else {
        file.on('data', res.write.bind(res));
        file.on('close', function () {
            res.end();
        });
        file.on('error', function (error) {
            self.sendError_(req, res, error);
        });
    }
};

StaticServlet.prototype.sendFile_ = function (req, res, path) {
    var self = this;
    var file = fs.createReadStream(path);
    res.writeHead(200, {'Content-Type':StaticServlet.MimeMap[path.split('.').pop()] || 'text/plain'});
    if (req.method === 'HEAD') {
        res.end();
    } else {
        file.on('data', res.write.bind(res));
        file.on('close', function () {
            res.end();
        });
        file.on('error', function (error) {
            self.sendError_(req, res, error);
        });
    }
};

StaticServlet.prototype.sendAllJsonFilesAppended_ = function (req, res, path) {
    var self = this;
    var files = []
    try {
        files = fs.readdirSync(path);
    }
    catch (e) {
        self.writeSuccessHeader(res, path);
        res.write("[]");
        res.end();
    }
    var results = "[";
    for (var idx = 0; idx < files.length; idx++) {
        if (files[idx].indexOf(".json") == files[idx].length - 5) {
            results += fs.readFileSync(path + "/" + files[idx]) + ",";
        }
    }
    results = results.substr(0, results.length - 1);
    results += "]";
    self.writeSuccessHeader(res, path);
    res.write(results);
    res.end();

};

StaticServlet.prototype.writeFile_ = function (req, res, path) {
    var self = this;

    res.writeHead(200, {'Content-Type':'text/plain'});
    if (req.method === 'HEAD') {
        res.end();
    } else {
        var targetDir = path.substr(0, path.lastIndexOf('/'));
        var dirExists;
        try {
            var stats = fs.lstatSync(targetDir);
            dirExists = stats.isDirectory();
        } catch(e) {dirExists = false;}

        if (!dirExists) {
            fs.mkdirSyncRecursive(targetDir);
        }
        var writeStream = fs.createWriteStream(path + ".json");
        req.pipe(writeStream);

        req.on('end', function () {
            res.writeHead(200, {"content-type":"text/html"});
            res.end('Save Successful');
        });

        writeStream.on('error', function (err) {
            console.log(err);
            self.sendError_(req, res, err);
        });
    }
};

StaticServlet.prototype.writeSuccessHeader = function (res, path) {
    res.writeHead(200, {
        'Content-Type':StaticServlet.
            MimeMap[path.split('.').pop()] || 'text/plain'
    });
}
StaticServlet.prototype.sendDirectory_ = function (req, res, path) {
    var self = this;
    if (path.match(/[^\/]$/)) {
        req.url.pathname += '/';
        var redirectUrl = url.format(url.parse(url.format(req.url)));
        return self.sendRedirect_(req, res, redirectUrl);
    }
    fs.readdir(path, function (err, files) {
        if (err)
            return self.sendError_(req, res, error);

        if (!files.length)
            return self.writeDirectoryIndex_(req, res, path, []);

        var remaining = files.length;
        files.forEach(function (fileName, index) {
            fs.stat(path + '/' + fileName, function (err, stat) {
                if (err)
                    return self.sendError_(req, res, err);
                if (stat.isDirectory()) {
                    files[index] = fileName + '/';
                }
                if (!(--remaining))
                    return self.writeDirectoryIndex_(req, res, path, files);
            });
        });
    });
};

StaticServlet.prototype.writeDirectoryIndex_ = function (req, res, path, files) {
    path = path.substring(1);
    res.writeHead(200, {
        'Content-Type':'text/html'
    });
    if (req.method === 'HEAD') {
        res.end();
        return;
    }
    res.write('<!doctype html>\n');
    res.write('<title>' + escapeHtml(path) + '</title>\n');
    res.write('\n');
    res.write('
Directory: ' + escapeHtml(path) + '
');
    res.write('
');
    files.forEach(function (fileName) {
        if (fileName.charAt(0) !== '.') {
            res.write('
' +
                escapeHtml(fileName) + '
');
        }
    });
    res.write('
');
    res.end();
};

fs.fileExistsSync = function (filePath) {
    try {
        var stats = fs.lstatSync(filePath);
        return stats.isFile();
    }
    catch (e) {
        return false;
    }
}

fs.mkdirSyncRecursive = function(dirPath) {
    try{
        fs.mkdirSync(dirPath);
    } catch(e) {
        fs.mkdirSyncRecursive(path.dirname(dirPath));
        fs.mkdirSyncRecursive(dirPath);
    }
};

main(process.argv);<|endoftext|>


<commit_before>var Phase = require('html5/parser/phase').Phase;

var start_tag_handlers = {
	html: 'startTagHtml',
	frameset: 'startTagFrameset',
	frame: 'startTagFrame',
	noframes: 'startTagNoFrames',
	"-default": 'startTagOther'
}

var end_tag_handlers = {
	frameset: 'endTagFrameset',
	noframes: 'endTagNoframes',
	'-default': 'endTagOther',
}

exports.Phase = p = function InFramesetPhase(parser, tree) {
	Phase.call(this, parser, tree);
	this.start_tag_handlers = start_tag_handlers;
	this.end_tag_handlers = end_tag_handlers;
}

p.prototype = new Phase;

p.prototype.processCharacters = function(data) {
	this.parse_error("unexpected-char-in-frameset");
}

p.prototype.startTagFrameset = function(name, attributes) {
	this.tree.insert_element(name, attributes);
}

p.prototype.startTagFrame = function(name, attributes) {
	this.tree.insert_element(name, attributes);
	this.tree.open_elements.pop();
}

p.prototype.startTagNoframes = function(name, attributes) {
	new inBody(this.parser, this.tree).processStartTag(name, attributes);
}

p.prototype.startTagOther = function(name, attributes) {
	this.parse_error("unexpected-start-tag-in-frameset", {name: name});
}

p.prototype.endTagFrameset = function(name, attributes) {
	if(this.tree.open_elements[this.tree.open_elements.length - 1].tagName == 'html') {
		// inner_html case
		this.parse_error("unexpected-frameset-in-frameset-innerhtml");
	} else {
		this.tree.open_elements.pop();
	}

	if(!this.parser.inner_html && this.tree.open_elements[this.tree.open_elements.length - 1].tagName != 'frameset') {
		// If we're not in inner_html mode an the current node is not a "frameset" element (anymore) then switch
		this.parser.newPhase('afterFrameset');
	}
}

p.prototype.endTagNoframes = function(name) {
	new inBody(this.parser, this.tree).processEndTag(name);
}

p.prototype.endTagOther = function(name) {
	this.parser_error("unexpected-end-tag-in-frameset", {name: name});
}
<commit_msg>- fix missing require in in_frameset_phase<commit_after>var Phase = require('html5/parser/phase').Phase;
var inBody = require('html5/parser/in_body_phase').Phase;

var start_tag_handlers = {
	html: 'startTagHtml',
	frameset: 'startTagFrameset',
	frame: 'startTagFrame',
	noframes: 'startTagNoFrames',
	"-default": 'startTagOther'
}

var end_tag_handlers = {
	frameset: 'endTagFrameset',
	noframes: 'endTagNoframes',
	'-default': 'endTagOther',
}

exports.Phase = p = function InFramesetPhase(parser, tree) {
	Phase.call(this, parser, tree);
	this.start_tag_handlers = start_tag_handlers;
	this.end_tag_handlers = end_tag_handlers;
}

p.prototype = new Phase;

p.prototype.processCharacters = function(data) {
	this.parse_error("unexpected-char-in-frameset");
}

p.prototype.startTagFrameset = function(name, attributes) {
	this.tree.insert_element(name, attributes);
}

p.prototype.startTagFrame = function(name, attributes) {
	this.tree.insert_element(name, attributes);
	this.tree.open_elements.pop();
}

p.prototype.startTagNoframes = function(name, attributes) {
	new inBody(this.parser, this.tree).processStartTag(name, attributes);
}

p.prototype.startTagOther = function(name, attributes) {
	this.parse_error("unexpected-start-tag-in-frameset", {name: name});
}

p.prototype.endTagFrameset = function(name, attributes) {
	if(this.tree.open_elements[this.tree.open_elements.length - 1].tagName == 'html') {
		// inner_html case
		this.parse_error("unexpected-frameset-in-frameset-innerhtml");
	} else {
		this.tree.open_elements.pop();
	}

	if(!this.parser.inner_html && this.tree.open_elements[this.tree.open_elements.length - 1].tagName != 'frameset') {
		// If we're not in inner_html mode an the current node is not a "frameset" element (anymore) then switch
		this.parser.newPhase('afterFrameset');
	}
}

p.prototype.endTagNoframes = function(name) {
	new inBody(this.parser, this.tree).processEndTag(name);
}

p.prototype.endTagOther = function(name) {
	this.parser_error("unexpected-end-tag-in-frameset", {name: name});
}
<|endoftext|>


<commit_before>'use strict';

// Messenger API integration example
// We assume you have:
// * a Wit.ai bot setup (https://wit.ai/docs/quickstart)
// * a Messenger Platform setup (https://developers.facebook.com/docs/messenger-platform/quickstart)
// You need to `npm install` the following dependencies: body-parser, express, request.
//
// 1. npm install body-parser express request
// 2. Download and install ngrok from https://ngrok.com/download
// 3. ./ngrok -http 8445
// 4. WIT_TOKEN=your_access_token FB_PAGE_ID=your_page_id FB_PAGE_TOKEN=your_page_token FB_VERIFY_TOKEN=verify_token node examples/messenger.js
// 5. Subscribe your page to the Webhooks using verify_token and `https://<your_ngrok_io>/fb` as callback URL.
// 6. Talk to your bot on Messenger!

const bodyParser = require('body-parser');
const express = require('express');
const request = require('request');

// When not cloning the `node-wit` repo, replace the `require` like so:
// const Wit = require('node-wit').Wit;
const Wit = require('node-wit').Wit;

// Webserver parameter
const PORT = process.env.PORT || 1337;

// Wit.ai parameters
const WIT_TOKEN = process.env.WIT_TOKEN;

// Messenger API parameters
const FB_PAGE_ID = process.env.FB_PAGE_ID && Number(process.env.FB_PAGE_ID);
if (!FB_PAGE_ID) {
  throw new Error('missing FB_PAGE_ID');
}
const FB_PAGE_TOKEN = process.env.FB_PAGE_TOKEN;
if (!FB_PAGE_TOKEN) {
  throw new Error('missing FB_PAGE_TOKEN');
}
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;

// Messenger API specific code

// See the Send API reference
// https://developers.facebook.com/docs/messenger-platform/send-api-reference
const fbReq = request.defaults({
  uri: 'https://graph.facebook.com/me/messages',
  method: 'POST',
  json: true,
  qs: { access_token: FB_PAGE_TOKEN },
  headers: {'Content-Type': 'application/json'},
});

const fbMessage = (recipientId, msg, cb) => {
  const opts = {
    form: {
      recipient: {
        id: recipientId,
      },
      message: {
        text: msg,
      },
    },
  };
  fbReq(opts, (err, resp, data) => {
    if (cb) {
      cb(err || data.error && data.error.message, data);
    }
  });
};

// See the Webhook reference
// https://developers.facebook.com/docs/messenger-platform/webhook-reference
const getFirstMessagingEntry = (body) => {
  const val = body.object == 'page' &&
    body.entry &&
    Array.isArray(body.entry) &&
    body.entry.length > 0 &&
    body.entry[0] &&
    body.entry[0].id == FB_PAGE_ID &&
    body.entry[0].messaging &&
    Array.isArray(body.entry[0].messaging) &&
    body.entry[0].messaging.length > 0 &&
    body.entry[0].messaging[0]
  ;
  return val || null;
};

// Wit.ai bot specific code

// This will contain all user sessions.
// Each session has an entry:
// sessionId -> {fbid: facebookUserId, context: sessionState}
const sessions = {};

const findOrCreateSession = (fbid) => {
  let sessionId;
  // Let's see if we already have a session for the user fbid
  Object.keys(sessions).forEach(k => {
    if (sessions[k].fbid === fbid) {
      // Yep, got it!
      sessionId = k;
    }
  });
  if (!sessionId) {
    // No session found for user fbid, let's create a new one
    sessionId = new Date().toISOString();
    sessions[sessionId] = {fbid: fbid, context: {}};
  }
  return sessionId;
};

// Our bot actions
const actions = {
  say: (sessionId, context, message, cb) => {
    // Our bot has something to say!
    // Let's retrieve the Facebook user whose session belongs to
    const recipientId = sessions[sessionId].fbid;
    if (recipientId) {
      // Yay, we found our recipient!
      // Let's forward our bot response to her.
      fbMessage(recipientId, message, (err, data) => {
        if (err) {
          console.log(
            'Oops! An error occurred while forwarding the response to',
            recipientId,
            ':',
            err
          );
        }

        // Let's give the wheel back to our bot
        cb();
      });
    } else {
      console.log('Oops! Couldn\'t find user for session:', sessionId);
      // Giving the wheel back to our bot
      cb();
    }
  },
  merge: (sessionId, context, entities, message, cb) => {
    let query = maybeGetFirstValue(entities, 'guide_building');
    let room = maybeGetFirstValue(entities, 'number');
    cb(context);
  },
  error: (sessionId, context, err) => {
    console.log(err.message);
  },
  search: (sessionId, context, cb) => {
    context.floor = 'first';
    // TODO: get coordinates from DB
    context.url = `http://www.google.com/maps?saddr=My+Location&daddr=32.7745127,35.0231037`;
    cb(context);
  }
  // You should implement your custom actions here
  // See https://wit.ai/docs/quickstart
};

// Setting up our bot
const wit = new Wit(WIT_TOKEN, actions);

// Starting our webserver and putting it all together
const app = express();
app.set('port', PORT);
app.listen(app.get('port'));
app.use(bodyParser.json());

app.get('/', function (req, res) {
  res.send('Hello World!');
})

// Webhook setup
app.get('/fb', (req, res) => {
  if (!FB_VERIFY_TOKEN) {
    throw new Error('missing FB_VERIFY_TOKEN');
  }
  if (req.query['hub.mode'] === 'subscribe' &&
    req.query['hub.verify_token'] === FB_VERIFY_TOKEN) {
    res.send(req.query['hub.challenge']);
  } else {
    res.sendStatus(400);
  }
});

// Message handler
app.post('/fb', (req, res) => {
  // Parsing the Messenger API response
  const messaging = getFirstMessagingEntry(req.body);
  if (messaging && messaging.message && messaging.recipient.id === FB_PAGE_ID) {
    // Yay! We got a new message!

    // We retrieve the Facebook user ID of the sender
    const sender = messaging.sender.id;

    // We retrieve the user's current session, or create one if it doesn't exist
    // This is needed for our bot to figure out the conversation history
    const sessionId = findOrCreateSession(sender);

    // We retrieve the message content
    const msg = messaging.message.text;
    const atts = messaging.message.attachments;

    if (atts) {
      // We received an attachment

      // Let's reply with an automatic message
      fbMessage(
        sender,
        'Sorry I can only process text messages for now.'
      );
    } else if (msg) {
      // We received a text message

      // Let's forward the message to the Wit.ai Bot Engine
      // This will run all actions until our bot has nothing left to do
      wit.runActions(
        sessionId, // the user's current session
        msg, // the user's message
        sessions[sessionId].context, // the user's current session state
        (error, context) => {
          if (error) {
            console.log('Oops! Got an error from Wit:', error);
          } else {
            // Our bot did everything it has to do.
            // Now it's waiting for further messages to proceed.
            console.log('Waiting for futher messages.');

            // Based on the session state, you might want to reset the session.
            // This depends heavily on the business logic of your bot.
            // Example:
            // if (context['done']) {
            //   delete sessions[sessionId];
            // }

            // Updating the user's current session state
            sessions[sessionId].context = context;
          }
        }
      );
    }
  }
  res.sendStatus(200);
});

<commit_msg>fix(server): retrieve entities<commit_after>'use strict';

// Messenger API integration example
// We assume you have:
// * a Wit.ai bot setup (https://wit.ai/docs/quickstart)
// * a Messenger Platform setup (https://developers.facebook.com/docs/messenger-platform/quickstart)
// You need to `npm install` the following dependencies: body-parser, express, request.
//
// 1. npm install body-parser express request
// 2. Download and install ngrok from https://ngrok.com/download
// 3. ./ngrok -http 8445
// 4. WIT_TOKEN=your_access_token FB_PAGE_ID=your_page_id FB_PAGE_TOKEN=your_page_token FB_VERIFY_TOKEN=verify_token node examples/messenger.js
// 5. Subscribe your page to the Webhooks using verify_token and `https://<your_ngrok_io>/fb` as callback URL.
// 6. Talk to your bot on Messenger!

const bodyParser = require('body-parser');
const express = require('express');
const request = require('request');

// When not cloning the `node-wit` repo, replace the `require` like so:
// const Wit = require('node-wit').Wit;
const Wit = require('node-wit').Wit;

// Webserver parameter
const PORT = process.env.PORT || 1337;

// Wit.ai parameters
const WIT_TOKEN = process.env.WIT_TOKEN;

// Messenger API parameters
const FB_PAGE_ID = process.env.FB_PAGE_ID && Number(process.env.FB_PAGE_ID);
if (!FB_PAGE_ID) {
  throw new Error('missing FB_PAGE_ID');
}
const FB_PAGE_TOKEN = process.env.FB_PAGE_TOKEN;
if (!FB_PAGE_TOKEN) {
  throw new Error('missing FB_PAGE_TOKEN');
}
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;

// Messenger API specific code

// See the Send API reference
// https://developers.facebook.com/docs/messenger-platform/send-api-reference
const fbReq = request.defaults({
  uri: 'https://graph.facebook.com/me/messages',
  method: 'POST',
  json: true,
  qs: { access_token: FB_PAGE_TOKEN },
  headers: {'Content-Type': 'application/json'},
});

const fbMessage = (recipientId, msg, cb) => {
  const opts = {
    form: {
      recipient: {
        id: recipientId,
      },
      message: {
        text: msg,
      },
    },
  };
  fbReq(opts, (err, resp, data) => {
    if (cb) {
      cb(err || data.error && data.error.message, data);
    }
  });
};

// See the Webhook reference
// https://developers.facebook.com/docs/messenger-platform/webhook-reference
const getFirstMessagingEntry = (body) => {
  const val = body.object == 'page' &&
    body.entry &&
    Array.isArray(body.entry) &&
    body.entry.length > 0 &&
    body.entry[0] &&
    body.entry[0].id == FB_PAGE_ID &&
    body.entry[0].messaging &&
    Array.isArray(body.entry[0].messaging) &&
    body.entry[0].messaging.length > 0 &&
    body.entry[0].messaging[0]
  ;
  return val || null;
};

// Wit.ai bot specific code

// This will contain all user sessions.
// Each session has an entry:
// sessionId -> {fbid: facebookUserId, context: sessionState}
const sessions = {};

const findOrCreateSession = (fbid) => {
  let sessionId;
  // Let's see if we already have a session for the user fbid
  Object.keys(sessions).forEach(k => {
    if (sessions[k].fbid === fbid) {
      // Yep, got it!
      sessionId = k;
    }
  });
  if (!sessionId) {
    // No session found for user fbid, let's create a new one
    sessionId = new Date().toISOString();
    sessions[sessionId] = {fbid: fbid, context: {}};
  }
  return sessionId;
};

const maybeGetFirstValue = (entities, entity) => {
  const val = entities && entities[entity] &&
    Array.isArray(entities[entity]) &&
    entities[entity].length > 0 &&
    entities[entity][0].value
  ;
  if (!val) {
    return null;
  }
  return typeof val === 'object' ? val.value : val;
};

// Our bot actions
const actions = {
  say: (sessionId, context, message, cb) => {
    // Our bot has something to say!
    // Let's retrieve the Facebook user whose session belongs to
    const recipientId = sessions[sessionId].fbid;
    if (recipientId) {
      // Yay, we found our recipient!
      // Let's forward our bot response to her.
      fbMessage(recipientId, message, (err, data) => {
        if (err) {
          console.log(
            'Oops! An error occurred while forwarding the response to',
            recipientId,
            ':',
            err
          );
        }

        // Let's give the wheel back to our bot
        cb();
      });
    } else {
      console.log('Oops! Couldn\'t find user for session:', sessionId);
      // Giving the wheel back to our bot
      cb();
    }
  },
  merge: (sessionId, context, entities, message, cb) => {
    let query = maybeGetFirstValue(entities, 'guide_building');
    let room = maybeGetFirstValue(entities, 'number');
    cb(context);
  },
  error: (sessionId, context, err) => {
    console.log(err.message);
  },
  search: (sessionId, context, cb) => {
    context.floor = 'first';
    // TODO: get coordinates from DB
    context.url = `http://www.google.com/maps?saddr=My+Location&daddr=32.7745127,35.0231037`;
    cb(context);
  }
  // You should implement your custom actions here
  // See https://wit.ai/docs/quickstart
};

// Setting up our bot
const wit = new Wit(WIT_TOKEN, actions);

// Starting our webserver and putting it all together
const app = express();
app.set('port', PORT);
app.listen(app.get('port'));
app.use(bodyParser.json());

app.get('/', function (req, res) {
  res.send('Hello World!');
})

// Webhook setup
app.get('/fb', (req, res) => {
  if (!FB_VERIFY_TOKEN) {
    throw new Error('missing FB_VERIFY_TOKEN');
  }
  if (req.query['hub.mode'] === 'subscribe' &&
    req.query['hub.verify_token'] === FB_VERIFY_TOKEN) {
    res.send(req.query['hub.challenge']);
  } else {
    res.sendStatus(400);
  }
});

// Message handler
app.post('/fb', (req, res) => {
  // Parsing the Messenger API response
  const messaging = getFirstMessagingEntry(req.body);
  if (messaging && messaging.message && messaging.recipient.id === FB_PAGE_ID) {
    // Yay! We got a new message!

    // We retrieve the Facebook user ID of the sender
    const sender = messaging.sender.id;

    // We retrieve the user's current session, or create one if it doesn't exist
    // This is needed for our bot to figure out the conversation history
    const sessionId = findOrCreateSession(sender);

    // We retrieve the message content
    const msg = messaging.message.text;
    const atts = messaging.message.attachments;

    if (atts) {
      // We received an attachment

      // Let's reply with an automatic message
      fbMessage(
        sender,
        'Sorry I can only process text messages for now.'
      );
    } else if (msg) {
      // We received a text message

      // Let's forward the message to the Wit.ai Bot Engine
      // This will run all actions until our bot has nothing left to do
      wit.runActions(
        sessionId, // the user's current session
        msg, // the user's message
        sessions[sessionId].context, // the user's current session state
        (error, context) => {
          if (error) {
            console.log('Oops! Got an error from Wit:', error);
          } else {
            // Our bot did everything it has to do.
            // Now it's waiting for further messages to proceed.
            console.log('Waiting for futher messages.');

            // Based on the session state, you might want to reset the session.
            // This depends heavily on the business logic of your bot.
            // Example:
            // if (context['done']) {
            //   delete sessions[sessionId];
            // }

            // Updating the user's current session state
            sessions[sessionId].context = context;
          }
        }
      );
    }
  }
  res.sendStatus(200);
});

<|endoftext|>


<commit_before>/*jslint node: true, white: true */

'use strict';

var gutil = require('gulp-util');
var fs = require('fs');
var path = require('path');
var which = require('which');
var through = require('through2');
var spawn = require('win-spawn');
var cheerio = require('cheerio');

module.exports = function () {
	try {
		which.sync('premailer');
	} catch (err) {
		throw new gutil.PluginError('gulp-premailer', 'You need to have Ruby and Premailer installed and in your PATH for this task to work.');
	}

	var stream = through.obj(function (file, enc, done) {
		if (file.isNull()) {
			self.push(file);
			return done();
		}

		if (file.isStream()) {
			self.emit('error', new gutil.PluginError('gulp-premailer', 'Streaming not supported'));
			return done();
		}

		file.contents = new Buffer(file.contents.toString());

		var self = this;
		var errors = '';
		var bufferObjs = [];
		var cp = spawn('premailer', [file.path]);

		cp.on('error', function (err) {
			self.emit('error', new gutil.PluginError('gulp-premailer', err));
			self.push(file);
			return done();
		});

		cp.stderr.on('data', function (data) {
			errors += data;
		});

		cp.stdout.on('data', function (data) {
			bufferObjs.push(data);
		});

		cp.on('close', function (code) {
			if (code === 127) {
				self.emit('error', new gutil.PluginError('gulp-premailer', 'You need to have Ruby and Premailer installed and in your PATH for this task to work.'));
				self.push(file);
				return done();
			}

			if (errors) {
				self.emit('error', new gutil.PluginError('gulp-premailer', '\n' + errors.replace('Use --trace for backtrace.\n', '')));
				self.push(file);
				return done();
			}

			if (code > 0) {
				self.emit('error', new gutil.PluginError('gulp-premailer', 'Exited with error code ' + code));
				self.push(file);
				return done();
			}

			file.contents = new Buffer.concat(bufferObjs);
			self.push(file);
			done();
		});
	});

	return stream;
};
<commit_msg>support cli args<commit_after>/*jslint node: true, white: true */

'use strict';

var gutil = require('gulp-util');
var fs = require('fs');
var path = require('path');
var which = require('which');
var through = require('through2');
var spawn = require('win-spawn');
var cheerio = require('cheerio');

module.exports = function (opts) {
	try {
		which.sync('premailer');
	} catch (err) {
		throw new gutil.PluginError('gulp-premailer', 'You need to have Ruby and Premailer installed and in your PATH for this task to work.');
	}

	var stream = through.obj(function (file, enc, done) {
		if (file.isNull()) {
			self.push(file);
			return done();
		}

		if (file.isStream()) {
			self.emit('error', new gutil.PluginError('gulp-premailer', 'Streaming not supported'));
			return done();
		}

		file.contents = new Buffer(file.contents.toString());

		var self = this;
		var errors = '';
		var bufferObjs = [];
		var args = [file.path];

		// Convert JS object to CLI args.. i.e. query-string: foo to
		// --query-string=foo
		if(typeof(opts) == 'object') {
			Object.keys(opts).forEach(function(key) {
				if(opts[key]) {
					args.push('--' + key.replace(/^--/,'') + '=' + opts[key] + '');
				}
			});
		}

		var cp = spawn('premailer', args);

		cp.on('error', function (err) {
			self.emit('error', new gutil.PluginError('gulp-premailer', err));
			self.push(file);
			return done();
		});

		cp.stderr.on('data', function (data) {
			errors += data;
		});

		cp.stdout.on('data', function (data) {
			bufferObjs.push(data);
		});

		cp.on('close', function (code) {
			if (code === 127) {
				self.emit('error', new gutil.PluginError('gulp-premailer', 'You need to have Ruby and Premailer installed and in your PATH for this task to work.'));
				self.push(file);
				return done();
			}

			if (errors) {
				self.emit('error', new gutil.PluginError('gulp-premailer', '\n' + errors.replace('Use --trace for backtrace.\n', '')));
				self.push(file);
				return done();
			}

			if (code > 0) {
				self.emit('error', new gutil.PluginError('gulp-premailer', 'Exited with error code ' + code));
				self.push(file);
				return done();
			}

			file.contents = new Buffer.concat(bufferObjs);
			self.push(file);
			done();
		});
	});

	return stream;
};
<|endoftext|>


<commit_before>var nbind = require('nbind');
var binding = nbind.init(__dirname);
var Ui = binding.lib.Ui;

var loopRunning = false;

module.exports = binding.lib;

function stopLoop() {
	if (!loopRunning) {
		return;
	}
	loopRunning = false;
	Ui.quit();
}

function startLoop(cb) {
	function step() {
		Ui.mainStep(false);
		if (loopRunning) {
			setImmediate(step);
		} else if (cb) {
			cb();
		}
	}

	if (loopRunning) {
		return;
	}

	loopRunning = true;
	Ui.mainSteps();
	step();
}

function Color(r, g, b, a) {
	this.r = r;
	this.g = g;
	this.b = b;
	this.a = a;
}

Color.prototype.fromJS = function fromJS(output) {
	output(this.r, this.g, this.b, this.a);
};

binding.bind('Color', Color);

function Point(x, y) {
	this.x = x;
	this.y = y;
}

Point.prototype.fromJS = function fromJS(output) {
	output(this.x, this.y);
};

binding.bind('Point', Point);

function Size(w, h) {
	this.w = w;
	this.h = h;
}

Size.prototype.fromJS = function fromJS(output) {
	output(this.w, this.h);
};

binding.bind('Size', Size);

module.exports.Size = Size;
module.exports.Point = Point;
module.exports.Color = Color;
module.exports.startLoop = startLoop;
module.exports.stopLoop = stopLoop;
<commit_msg>switched mainStep recursion to use setTimeout<commit_after>var nbind = require('nbind');
var binding = nbind.init(__dirname);
var Ui = binding.lib.Ui;

var loopRunning = false;

module.exports = binding.lib;

function stopLoop() {
	if (!loopRunning) {
		return;
	}
	loopRunning = false;
	Ui.quit();
}

function startLoop(cb) {
	function step() {
		Ui.mainStep(false);
		if (loopRunning) {
			setTimeout(step);
		} else if (cb) {
			cb();
		}
	}

	if (loopRunning) {
		return;
	}

	loopRunning = true;
	Ui.mainSteps();
	step();
}

function Color(r, g, b, a) {
	this.r = r;
	this.g = g;
	this.b = b;
	this.a = a;
}

Color.prototype.fromJS = function fromJS(output) {
	output(this.r, this.g, this.b, this.a);
};

binding.bind('Color', Color);

function Point(x, y) {
	this.x = x;
	this.y = y;
}

Point.prototype.fromJS = function fromJS(output) {
	output(this.x, this.y);
};

binding.bind('Point', Point);

function Size(w, h) {
	this.w = w;
	this.h = h;
}

Size.prototype.fromJS = function fromJS(output) {
	output(this.w, this.h);
};

binding.bind('Size', Size);

module.exports.Size = Size;
module.exports.Point = Point;
module.exports.Color = Color;
module.exports.startLoop = startLoop;
module.exports.stopLoop = stopLoop;
<|endoftext|>


<commit_before>/**
 * ScreenshotsController
 * ====================
 * Handles display of a user screenshots.
 */

function ScreenshotsController(screenshots, Screenshot, $location) {
  this.screenshots = screenshots;
  this.url = '';
  this.addScreenshot = function(url){
    Screenshot.addScreenshot(url)
      .success(function(data){
        console.log(data);
      });
  };
  this.getScreenshots = function(id){
    Screenshot.getScreenshots(id)
      .success(function(data){
        console.log(data);
        this.screenshots = data;
      });
  };
  this.changeView = function(screenshotId) {
    $location.path('/screenshot/' + screenshotId);
  };
}

ScreenshotsController.$inject = [
  'screenshots',
  'Screenshot',
  '$location'
];

angular.module('Archivr.screenshots', [
  'Archivr.services.User',
  'Archivr.services.Screenshot'
]).controller('ScreenshotsController', ScreenshotsController);
<commit_msg>change $location order<commit_after>/**
 * ScreenshotsController
 * ====================
 * Handles display of a user screenshots.
 */

function ScreenshotsController($location, screenshots, Screenshot) {
  this.screenshots = screenshots;
  this.url = '';
  this.addScreenshot = function(url){
    Screenshot.addScreenshot(url)
      .success(function(data){
        console.log(data);
      });
  };
  this.getScreenshots = function(id){
    Screenshot.getScreenshots(id)
      .success(function(data){
        console.log(data);
        //this.screenshots = data; -> don't need this since we resolve the screenshots on app.js and inject them here
      });
  };
  this.changeView = function(screenshotId) {
    $location.path('/screenshot/' + screenshotId);
  };
}

ScreenshotsController.$inject = [
  '$location',
  'screenshots',
  'Screenshot'
];

angular.module('Archivr.screenshots', [
  'Archivr.services.User',
  'Archivr.services.Screenshot'
]).controller('ScreenshotsController', ScreenshotsController);
<|endoftext|>


<commit_before><commit_msg>bugfix - inherited targets now handled correctly (set handling now checks if given item exists in the base)<commit_after><|endoftext|>