<commit_before>// This looks for file defaults.js in resource folder, expects:
//	defaultsVersion - (string) version of defaults.js file, not mandatory but always helpful
//	objName - (string) main object name for the add-on, to be added to window element
//	objPathString - (string) add-on path name to use in URIs
//	prefList: (object) { prefName: defaultValue } - add-on preferences
//	startConditions(aData, aReason) -	(optional) (method) should return false if any requirements the add-on needs aren't met,
//						otherwise return true or call continueStartup(aData, aReason)
//	onStartup/onShutdown/onInstall/onUninstall(aData, aReason) - (optional) (methods) to be called on startup() and shutdown() to initialize and terminate the add-on
//	resource folder in installpath, with modules folder containing Modules, sandboxUtils and utils modules
//	chrome.manifest file with content, locale and skin declarations properly set
// handleDeadObject(ex) - 	expects [nsIScriptError object] ex. Shows dead object notices as warnings only in the console.
//				If the code can handle them accordingly and firefox does its thing, they shouldn't cause any problems.
// prepareObject(window, aName) - initializes a window-dependent add-on object with utils loaded into it, returns the newly created object
//	window - (xul object) the window object to be initialized
//	(optional) aName - (string) the object name, defaults to objName
// removeObject(window, aName) - closes and removes the object initialized by prepareObject()
//	see prepareObject()
// preparePreferences(window, aName) - loads the preferencesUtils module into that window's object initialized by prepareObject() (if it hasn't yet, it will be initialized)
//	see prepareObject()
// listenOnce(aSubject, type, handler, capture) - adds handler to window listening to event type that will be removed after one execution.
//	aSubject - (xul object) to add the handler to
//	type - (string) event type to listen to
//	handler - (function(event, aSubject)) - method to be called when event is triggered
//	(optional) capture - (bool) capture mode
// callOnLoad(aSubject, aCallback, beforeComplete) - calls aCallback immediately if aWindow is already loaded, otherwise waits for the load event to be fired on that window.
//	aSubject - (xul object) to execute aCallback on
//	aCallback - (function(aSubject)) to be called on aSubject
//	(optional) beforeComplete - (bool) if true, aCallback will be called on aSubject immediately, regardless of its readyState value; defaults to false.
// disable() - disables the add-on, in general the add-on disabling itself is a bad idea so I shouldn't use it
// Note: Firefox 34 is the minimum version supported as the modules assume we're in a version with Australis already,
// along with xulStore already implemented, in detriment of localstore.rdf.

let bootstrapVersion = '1.7.6';
let UNLOADED = false;
let STARTED = false;
let Addon = {};
let AddonData = null;
let onceListeners = [];
let alwaysRunOnShutdown = [];
let isChrome = true;

// Globals - lets me use objects that I can share through all the windows
let Globals = {};

const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm");

// easy and useful helpers for when I'm debugging
XPCOMUtils.defineLazyModuleGetter(this, "console", "resource://gre/modules/devtools/Console.jsm");
function LOG(str) {
	if(!str) { str = typeof(str)+': '+str; }
	console.log(objName+' :: CHROME :: '+str);
}

XPCOMUtils.defineLazyServiceGetter(Services, "xulStore", "@mozilla.org/xul/xulstore;1", "nsIXULStore");
XPCOMUtils.defineLazyServiceGetter(Services, "navigator", "@mozilla.org/network/protocol;1?name=http", "nsIHttpProtocolHandler");
XPCOMUtils.defineLazyServiceGetter(Services, "stylesheet", "@mozilla.org/content/style-sheet-service;1", "nsIStyleSheetService");

// I check these pretty much everywhere, so might as well keep a single reference to them
let WINNT = Services.appinfo.OS == 'WINNT';
let DARWIN = Services.appinfo.OS == 'Darwin';
let LINUX = Services.appinfo.OS != 'WINNT' && Services.appinfo.OS != 'Darwin';

function handleDeadObject(ex) {
	if(ex.message == "can't access dead object") {
		var scriptError = Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError);
		scriptError.init("Can't access dead object. This shouldn't cause any problems.", ex.sourceName || ex.fileName || null, ex.sourceLine || null, ex.lineNumber || null, ex.columnNumber || null, scriptError.warningFlag, 'XPConnect JavaScript');
		Services.console.logMessage(scriptError);
		return true;
	} else {
		Cu.reportError(ex);
		return false;
	}
}

function prepareObject(window, aName) {
	// I can override the object name if I want
	let objectName = aName || objName;
	if(window[objectName]) { return; }

	var rtl = getComputedStyle(window.document.documentElement).direction == 'rtl';

	window[objectName] = {
		objName: objectName,
		objPathString: objPathString,
		_UUID: new Date().getTime(),
		RTL: rtl,
		LTR: !rtl,

		// every supposedly global variable is inaccessible because bootstraped means sandboxed, so I have to reference all these;
		// it's easier to reference more specific objects from within the modules for better control, only setting these two here because they're more generalized
		window: window,
		get document () { return window.document; },
		$: function(id) { return window.document.getElementById(id); },
		$$: function(sel) { return window.document.querySelectorAll(sel); }
	};

	Services.scriptloader.loadSubScript("resource://"+objPathString+"/modules/utils/Modules.jsm", window[objectName]);
	Services.scriptloader.loadSubScript("resource://"+objPathString+"/modules/utils/windowUtilsPreload.jsm", window[objectName]);
	window[objectName].Modules.load("utils/windowUtils");

	setAttribute(window.document.documentElement, objectName+'_UUID', window[objectName]._UUID);
	setAttribute(window.document.documentElement, objectName+'_Version', AddonData.version);
}

function removeObject(window, aName) {
	let objectName = aName || objName;

	if(window[objectName]) {
		removeAttribute(window.document.documentElement, objectName+'_UUID');
		removeAttribute(window.document.documentElement, objectName+'_Version');
		window[objectName].Modules.unload("utils/windowUtils");
		delete window[objectName];
	}
}

function preparePreferences(window, aName) {
	let objectName = aName || objName;

	if(!window[objectName]) {
		prepareObject(window, objectName);
	}
	window[objectName].Modules.load("utils/preferencesUtils");
}

function removeOnceListener(oncer) {
	for(var i=0; i<onceListeners.length; i++) {
		if(!oncer) {
			onceListeners[i]();
			continue;
		}

		if(onceListeners[i] == oncer) {
			onceListeners.splice(i, 1);
			return;
		}
	}

	if(!oncer) {
		onceListeners = [];
	}
}

function listenOnce(aSubject, type, handler, capture) {
	if(UNLOADED || !aSubject || !aSubject.addEventListener) { return; }

	var runOnce = function(event) {
		try { aSubject.removeEventListener(type, runOnce, capture); }
		catch(ex) { handleDeadObject(ex); } // Prevents some can't access dead object errors
		if(!UNLOADED && event !== undefined) {
			removeOnceListener(runOnce);
			try { handler(event, aSubject); }
			catch(ex) { Cu.reportError(ex); }
		}
	};

	aSubject.addEventListener(type, runOnce, capture);
	onceListeners.push(runOnce);
}

function callOnLoad(aSubject, aCallback, beforeComplete) {
	if(aSubject.document.readyState == 'complete' || beforeComplete) {
		try { aCallback(aSubject); }
		catch(ex) { Cu.reportError(ex); }
		return;
	}

	// don't wait for the load event if we're terminating
	if(UNLOADED) { return; }

	listenOnce(aSubject, "load", function() {
		if(UNLOADED) { return; }

		try { aCallback(aSubject); }
		catch(ex) { Cu.reportError(ex); }
	}, false);
}

function setResourceHandler() {
	let alias = Services.io.newFileURI(AddonData.installPath);
	let resourceURI = (AddonData.installPath.isDirectory()) ? alias.spec : 'jar:' + alias.spec + '!/';
	resourceURI += 'resource/';

	// Set the default strings for the add-on
	Services.scriptloader.loadSubScript(resourceURI + 'defaults.js', this);

	alias = Services.io.newURI(resourceURI, null, null);
	let resource = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
	resource.setSubstitution(objPathString, alias);

	// Get the utils.jsm module into our sandbox
	Services.scriptloader.loadSubScript("resource://"+objPathString+"/modules/utils/Modules.jsm", this);
	Services.scriptloader.loadSubScript("resource://"+objPathString+"/modules/utils/sandboxUtilsPreload.jsm", this);
	Modules.load("utils/sandboxUtils");
}

function removeResourceHandler() {
	Modules.unload("utils/sandboxUtils");

	let resource = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
	resource.setSubstitution(objPathString, null);
}

function disable() {
	AddonManager.getAddonByID(AddonData.id, function(addon) {
		addon.userDisabled = true;
	});
}

function continueStartup(aReason) {
	STARTED = aReason;
	if(typeof(onStartup) == 'function') {
		onStartup(AddonData, aReason);
	}
}

function startup(aData, aReason) {
	UNLOADED = false;
	AddonData = aData;

	// to make sure we get always the most recent files when updating the add-on, see:
	// https://bugzilla.mozilla.org/show_bug.cgi?id=918033
	// https://bugzilla.mozilla.org/show_bug.cgi?id=1051238
	AddonData.initTime = new Date().getTime();

	// This includes the optionsURL property
	AddonManager.getAddonByID(AddonData.id, function(addon) {
		if(typeof(UNLOADED) == 'undefined' || UNLOADED) { return; }
		Addon = addon;
	});

	// add resource:// protocol handler so I can access my modules
	setResourceHandler();

	// set add-on preferences defaults
	// This should come before startConditions() so we can use it in there
	Prefs.setDefaults(prefList);

	if(typeof(startConditions) != 'function' || startConditions(aReason)) {
		continueStartup(aReason);
	}
}

function shutdown(aData, aReason) {
	UNLOADED = aReason;

	if(aReason == APP_SHUTDOWN) {
		// List of methods that must always be run on shutdown, such as restoring some native prefs
		while(alwaysRunOnShutdown.length > 0) {
			alwaysRunOnShutdown.pop()();
		}

		removeOnceListener();
		return;
	}

	if(STARTED) {
		closeOptions();
		if(typeof(onShutdown) == 'function') {
			onShutdown(aData, aReason);
		}
	}

	// remove resource://
	removeResourceHandler();
	removeOnceListener();
}

function install(aData, aReason) {
	if(typeof(onInstall) == 'function') {
		onInstall(aData, aReason);
	}
}

function uninstall(aData, aReason) {
	if(typeof(onUninstall) == 'function') {
		onUninstall(aData, aReason);
	}
}
<commit_msg>expect resource in chrome.manifest<commit_after>// This looks for file defaults.js in resource folder, expects:
//	defaultsVersion - (string) version of defaults.js file, not mandatory but always helpful
//	objName - (string) main object name for the add-on, to be added to window element
//	objPathString - (string) add-on path name to use in URIs
//	prefList: (object) { prefName: defaultValue } - add-on preferences
//	startConditions(aData, aReason) -	(optional) (method) should return false if any requirements the add-on needs aren't met,
//						otherwise return true or call continueStartup(aData, aReason)
//	onStartup/onShutdown/onInstall/onUninstall(aData, aReason) - (optional) (methods) to be called on startup() and shutdown() to initialize and terminate the add-on
//	resource folder in installpath, with modules folder containing Modules, sandboxUtils and utils modules
//	chrome.manifest file with content, locale, skin and resource declarations properly set
// handleDeadObject(ex) - 	expects [nsIScriptError object] ex. Shows dead object notices as warnings only in the console.
//				If the code can handle them accordingly and firefox does its thing, they shouldn't cause any problems.
// prepareObject(window, aName) - initializes a window-dependent add-on object with utils loaded into it, returns the newly created object
//	window - (xul object) the window object to be initialized
//	(optional) aName - (string) the object name, defaults to objName
// removeObject(window, aName) - closes and removes the object initialized by prepareObject()
//	see prepareObject()
// preparePreferences(window, aName) - loads the preferencesUtils module into that window's object initialized by prepareObject() (if it hasn't yet, it will be initialized)
//	see prepareObject()
// listenOnce(aSubject, type, handler, capture) - adds handler to window listening to event type that will be removed after one execution.
//	aSubject - (xul object) to add the handler to
//	type - (string) event type to listen to
//	handler - (function(event, aSubject)) - method to be called when event is triggered
//	(optional) capture - (bool) capture mode
// callOnLoad(aSubject, aCallback, beforeComplete) - calls aCallback immediately if aWindow is already loaded, otherwise waits for the load event to be fired on that window.
//	aSubject - (xul object) to execute aCallback on
//	aCallback - (function(aSubject)) to be called on aSubject
//	(optional) beforeComplete - (bool) if true, aCallback will be called on aSubject immediately, regardless of its readyState value; defaults to false.
// disable() - disables the add-on, in general the add-on disabling itself is a bad idea so I shouldn't use it
// Note: Firefox 38 is the minimum version supported as the script assumes the resource path will be automatically loaded from chrome.manifest.

let bootstrapVersion = '1.7.7';
let UNLOADED = false;
let STARTED = false;
let Addon = {};
let AddonData = null;
let onceListeners = [];
let alwaysRunOnShutdown = [];
let isChrome = true;

// Globals - lets me use objects that I can share through all the windows
let Globals = {};

const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm");

// easy and useful helpers for when I'm debugging
XPCOMUtils.defineLazyModuleGetter(this, "console", "resource://gre/modules/devtools/Console.jsm");
function LOG(str) {
	if(!str) { str = typeof(str)+': '+str; }
	console.log(objName+' :: CHROME :: '+str);
}

XPCOMUtils.defineLazyServiceGetter(Services, "xulStore", "@mozilla.org/xul/xulstore;1", "nsIXULStore");
XPCOMUtils.defineLazyServiceGetter(Services, "navigator", "@mozilla.org/network/protocol;1?name=http", "nsIHttpProtocolHandler");
XPCOMUtils.defineLazyServiceGetter(Services, "stylesheet", "@mozilla.org/content/style-sheet-service;1", "nsIStyleSheetService");

// I check these pretty much everywhere, so might as well keep a single reference to them
let WINNT = Services.appinfo.OS == 'WINNT';
let DARWIN = Services.appinfo.OS == 'Darwin';
let LINUX = Services.appinfo.OS != 'WINNT' && Services.appinfo.OS != 'Darwin';

function handleDeadObject(ex) {
	if(ex.message == "can't access dead object") {
		var scriptError = Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError);
		scriptError.init("Can't access dead object. This shouldn't cause any problems.", ex.sourceName || ex.fileName || null, ex.sourceLine || null, ex.lineNumber || null, ex.columnNumber || null, scriptError.warningFlag, 'XPConnect JavaScript');
		Services.console.logMessage(scriptError);
		return true;
	} else {
		Cu.reportError(ex);
		return false;
	}
}

function prepareObject(window, aName) {
	// I can override the object name if I want
	let objectName = aName || objName;
	if(window[objectName]) { return; }

	var rtl = getComputedStyle(window.document.documentElement).direction == 'rtl';

	window[objectName] = {
		objName: objectName,
		objPathString: objPathString,
		_UUID: new Date().getTime(),
		RTL: rtl,
		LTR: !rtl,

		// every supposedly global variable is inaccessible because bootstraped means sandboxed, so I have to reference all these;
		// it's easier to reference more specific objects from within the modules for better control, only setting these two here because they're more generalized
		window: window,
		get document () { return window.document; },
		$: function(id) { return window.document.getElementById(id); },
		$$: function(sel) { return window.document.querySelectorAll(sel); }
	};

	Services.scriptloader.loadSubScript("resource://"+objPathString+"/modules/utils/Modules.jsm", window[objectName]);
	Services.scriptloader.loadSubScript("resource://"+objPathString+"/modules/utils/windowUtilsPreload.jsm", window[objectName]);
	window[objectName].Modules.load("utils/windowUtils");

	setAttribute(window.document.documentElement, objectName+'_UUID', window[objectName]._UUID);
	setAttribute(window.document.documentElement, objectName+'_Version', AddonData.version);
}

function removeObject(window, aName) {
	let objectName = aName || objName;

	if(window[objectName]) {
		removeAttribute(window.document.documentElement, objectName+'_UUID');
		removeAttribute(window.document.documentElement, objectName+'_Version');
		window[objectName].Modules.unload("utils/windowUtils");
		delete window[objectName];
	}
}

function preparePreferences(window, aName) {
	let objectName = aName || objName;

	if(!window[objectName]) {
		prepareObject(window, objectName);
	}
	window[objectName].Modules.load("utils/preferencesUtils");
}

function removeOnceListener(oncer) {
	for(var i=0; i<onceListeners.length; i++) {
		if(!oncer) {
			onceListeners[i]();
			continue;
		}

		if(onceListeners[i] == oncer) {
			onceListeners.splice(i, 1);
			return;
		}
	}

	if(!oncer) {
		onceListeners = [];
	}
}

function listenOnce(aSubject, type, handler, capture) {
	if(UNLOADED || !aSubject || !aSubject.addEventListener) { return; }

	var runOnce = function(event) {
		try { aSubject.removeEventListener(type, runOnce, capture); }
		catch(ex) { handleDeadObject(ex); } // Prevents some can't access dead object errors
		if(!UNLOADED && event !== undefined) {
			removeOnceListener(runOnce);
			try { handler(event, aSubject); }
			catch(ex) { Cu.reportError(ex); }
		}
	};

	aSubject.addEventListener(type, runOnce, capture);
	onceListeners.push(runOnce);
}

function callOnLoad(aSubject, aCallback, beforeComplete) {
	if(aSubject.document.readyState == 'complete' || beforeComplete) {
		try { aCallback(aSubject); }
		catch(ex) { Cu.reportError(ex); }
		return;
	}

	// don't wait for the load event if we're terminating
	if(UNLOADED) { return; }

	listenOnce(aSubject, "load", function() {
		if(UNLOADED) { return; }

		try { aCallback(aSubject); }
		catch(ex) { Cu.reportError(ex); }
	}, false);
}

function disable() {
	AddonManager.getAddonByID(AddonData.id, function(addon) {
		addon.userDisabled = true;
	});
}

function continueStartup(aReason) {
	STARTED = aReason;
	if(typeof(onStartup) == 'function') {
		onStartup(AddonData, aReason);
	}
}

function startup(aData, aReason) {
	UNLOADED = false;
	AddonData = aData;

	// to make sure we get always the most recent files when updating the add-on, see:
	// https://bugzilla.mozilla.org/show_bug.cgi?id=918033
	// https://bugzilla.mozilla.org/show_bug.cgi?id=1051238
	AddonData.initTime = new Date().getTime();

	// This includes the optionsURL property
	AddonManager.getAddonByID(AddonData.id, function(addon) {
		if(typeof(UNLOADED) == 'undefined' || UNLOADED) { return; }
		Addon = addon;
	});

	// Set the default strings for the add-on
	let alias = Services.io.newFileURI(AddonData.installPath);
	let defaultsURI = ((AddonData.installPath.isDirectory()) ? alias.spec : 'jar:' + alias.spec + '!/')+'resource/defaults.js';
	Services.scriptloader.loadSubScript(defaultsURI, this);

	// Get the utils.jsm module into our sandbox
	Services.scriptloader.loadSubScript("resource://"+objPathString+"/modules/utils/Modules.jsm", this);
	Services.scriptloader.loadSubScript("resource://"+objPathString+"/modules/utils/sandboxUtilsPreload.jsm", this);
	Modules.load("utils/sandboxUtils");

	// set add-on preferences defaults
	// This should come before startConditions() so we can use it in there
	Prefs.setDefaults(prefList);

	if(typeof(startConditions) != 'function' || startConditions(aReason)) {
		continueStartup(aReason);
	}
}

function shutdown(aData, aReason) {
	UNLOADED = aReason;

	if(aReason == APP_SHUTDOWN) {
		// List of methods that must always be run on shutdown, such as restoring some native prefs
		while(alwaysRunOnShutdown.length > 0) {
			alwaysRunOnShutdown.pop()();
		}

		removeOnceListener();
		return;
	}

	if(STARTED) {
		closeOptions();
		if(typeof(onShutdown) == 'function') {
			onShutdown(aData, aReason);
		}
	}

	Modules.unload("utils/sandboxUtils");
	removeOnceListener();
}

function install(aData, aReason) {
	if(typeof(onInstall) == 'function') {
		onInstall(aData, aReason);
	}
}

function uninstall(aData, aReason) {
	if(typeof(onUninstall) == 'function') {
		onUninstall(aData, aReason);
	}
}
<|endoftext|>


<commit_before>
const ohm = require('ohm-js');
const fs = require('fs');
const grammar = ohm.grammar();

class Program {
  constructor(e) {
    this.body = e;
  }
}

class Block {
  constuctor(body) {
    this.body = body;
  }
}

class Statement {
}

class IfStatement extends Statement {
  constructor(condition, body, elseIfStmt, elseStmt) {
    this.condition = condition;
    this.body = body;
    this.elseIf = elseIfStmt;
    this.else = elseStmt;
  }
  toString() {
    "if " + " { " + this.condition + " } " + " else " + " { " + this.body + " } ";
  }
}

class ElseIfStatement extends Statement {
  constructor(condition, body, elseIfStmt) {
    this.condition = condition;
    this.body = body;
    // this.elseIf = elseIfStmt;
  }
    toString() {
      "else if " + " { " + this.condition + " } " + " then " + " { " + this.body + " } ";
    }
}

class ForStatement extends Statement {
  constructor(identifier, structure, body) {
    this.for = identifier;
    this.in = structure;
    this.body = body;
  }
    toString() {
      "for " + this.for + " in " + this.in + " { " + this.body + " } ";
    }
}

class WhileStatement extends Statement {
  constructor(condition, body) {
    this.condition = condition;
    this.body = body;
  }
  toString() {
    "while " + this.condition + " { " + this.body + " } ";
  }
}

class MatchStatement extends Statement {
  constructor(e1, e2) {
    this.e1 = e1;
    this.e2 = e2;
  }
  toString() {
    "match " + this.e1 + " with " + this.e2;
  }
}

class ReturnStatement extends Statement {
  constructor(body) {
    this.body = body;
  }
  toString() {
    "return " + this.body;
  }
}

class VariableDecl extends Statement {
  constructor(id, type, value){
    this.id = id;
    this.type = type;
    this.value = value;
  }
  toString() {
    "let " + this.id.join(" , ") + " = " + this.value.join(" , ");
  }
}

class ArrayVariableDecl extends Statement {
  constructor(id, type, value){
    this.id = id;
    this.type = type;
    this.value = value;
  }
  toString() {
    "let " + this.id.join(" , ") + " = " + " [ " + this.value.join(" , ") + " ] ";
  }
}

class ConstDecl extends Statement {
  constructor(id, type, value){
    this.id = id;
    this.type = type;
    this.value = value;
  }
  toString() {
    "set " + this.id.join(" , ") + " = " + this.value.join(" , ");
  }
}

class ArrayConstDecl extends Statement {
  constructor(id, type, value){
    this.id = id;
    this.type = type;
    this.value = value;
  }
  toString() {
    "set " + this.id.join(" , ") + " = " + " [ " + this.value.join(" , ") + " ] ";
  }
}

class Expression {
}

class BinaryExpression extends Expression {
  constructor(e1, op, e2) {
    super();
    this.left = e1;
    this.op = op;
    this.right = e2;
  }
}

class UnaryExpression extends Expression {
  constructor(op, e) {
    super();
    this.op = op;
    this.operand = e;
  }
}

class IdExpression extends Expression {
  constructor(idValue) {
    super();
    this.value = idValue;
  }
}

class Literal {
}

class FloatLiteral extends Literal {
  constructor(float) {
    super();
    this.value = float;
  }
}

class BooleanLiteral extends Literal {
  constructor(bool) {
    super();
    this.value = bool;
  }
}

class StringLiteral extends Literal {
  constructor(string) {
    super();
    this.value = string;
  }
}

const semantics = grammar.createSemantics().addOperation('ast', {

  Program(body) {
    return new Program(body.ast);
  },
  Block(stmt, _) {
    return new Block(stmt.ast());
  },

//   Stmt_if() {
//     return new IfStatement();
//   },
  Stmt_for(fr, e, i, struct, l, b, r) {
    return new ForStatement(e.ast(), struct.ast(), b.ast();
  },
  Stmt_while(w, e, l, b, r) {
    return new WhileStatement(e.ast(), b.ast());
  },
  Stmt_match(m, e1, w, e2) {
    return new MatchStatement(e1.ast(), e2.ast());
  },
  Stmt_return(r, b) {
    return new ReturnStatement(b.ast());
  },
  Var_Decl(l, id, _, eq, v, _) {
    return new VariableDecl(v.sourceString);
  },
  Array_Decl(l, arr,  _, eq, l, v, _, r) {
    return new ArrayVariableDecl(v.sourceString);
  },

  Const_Decl(s, id, _, eq, v, _) {
    return new ConstDecl(v.sourceString);
  },
  Array_ConstDecl(s, id, _, eq, l, v, _, r) {
    return new ArrayConstDecl(v.sourceString);
  },

  Exp_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(), "or", e2.ast());
  },
  Exp_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(), "and", e2.ast());
  },
  Exp1_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(), op.sourceString, e2.ast());
  },
  Exp2_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(), op.sourceString, e2.ast());
  },
  Exp3_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(),op.sourceString, e2.ast());
  },
  Exp4_unary(op, e) {
    return new UnaryExpression("-", e.ast());
  },
  Exp5_parens(left, e, right) {
    return e.ast();
  },
  id(idValue) {
    return new IdExpression(this.sourceString);
  },
  floatlit(float) {
    return new FloatLiteral(this.sourceString);
  },
  boollit(bool) {
    return new BooleanLiteral(this.sourceString);
  },
  stringlit(string) {
    return new StringLiteral(this.sourceString);
  }
});

module.exports = parse = function(text) {
  var match;
  match = grammar.match(text);
  if (!match.succeeded()) {
    throw match.message;
  }
  return semantics(match).ast();
};
<commit_msg>still need iF<commit_after>
const ohm = require('ohm-js');
const fs = require('fs');
const grammar = ohm.grammar();

class Program {
  constructor(e) {
    this.body = e;
  }
}

class Block {
  constuctor(body) {
    this.body = body;
  }
}

class Statement {
}

// class IfStatement extends Statement {
//   constructor(condition, body, elseIfStmt, elseStmt) {
//     this.condition = condition;
//     this.body = body;
//     this.elseIf = elseIfStmt;
//     this.else = elseStmt;
//   }
//   toString() {
//     "if " + " { " + this.condition + " } " + " else " + " { " + this.body + " } ";
//   }
// }
//
// class ElseIfStatement extends Statement {
//   constructor(condition, body, elseIfStmt) {
//     this.condition = condition;
//     this.body = body;
//     // this.elseIf = elseIfStmt;
//   }
//     toString() {
//       "else if " + " { " + this.condition + " } " + " then " + " { " + this.body + " } ";
//     }
// }

class ForStatement extends Statement {
  constructor(identifier, structure, body) {
    this.for = identifier;
    this.in = structure;
    this.body = body;
  }
    toString() {
      "for " + this.for + " in " + this.in + " { " + this.body + " } ";
    }
}

class WhileStatement extends Statement {
  constructor(condition, body) {
    this.condition = condition;
    this.body = body;
  }
  toString() {
    "while " + this.condition + " { " + this.body + " } ";
  }
}

class MatchStatement extends Statement {
  constructor(e1, e2) {
    this.e1 = e1;
    this.e2 = e2;
  }
  toString() {
    "match " + this.e1 + " with " + this.e2;
  }
}

class ReturnStatement extends Statement {
  constructor(body) {
    this.body = body;
  }
  toString() {
    "return " + this.body;
  }
}

class VariableDecl extends Statement {
  constructor(id, type, value){
    this.id = id;
    this.type = type;
    this.value = value;
  }
  toString() {
    "let " + this.id.join(" , ") + " = " + this.value.join(" , ");
  }
}

class ArrayVariableDecl extends Statement {
  constructor(id, type, value){
    this.id = id;
    this.type = type;
    this.value = value;
  }
  toString() {
    "let " + this.id.join(" , ") + " = " + " [ " + this.value.join(" , ") + " ] ";
  }
}

class ConstDecl extends Statement {
  constructor(id, type, value){
    this.id = id;
    this.type = type;
    this.value = value;
  }
  toString() {
    "set " + this.id.join(" , ") + " = " + this.value.join(" , ");
  }
}

class ArrayConstDecl extends Statement {
  constructor(id, type, value){
    this.id = id;
    this.type = type;
    this.value = value;
  }
  toString() {
    "set " + this.id.join(" , ") + " = " + " [ " + this.value.join(" , ") + " ] ";
  }
}

class Expression {
}

class BinaryExpression extends Expression {
  constructor(e1, op, e2) {
    super();
    this.left = e1;
    this.op = op;
    this.right = e2;
  }
}

class UnaryExpression extends Expression {
  constructor(op, e) {
    super();
    this.op = op;
    this.operand = e;
  }
}

class IdExpression extends Expression {
  constructor(idValue) {
    super();
    this.value = idValue;
  }
}

class Literal {
}

class FloatLiteral extends Literal {
  constructor(float) {
    super();
    this.value = float;
  }
}

class BooleanLiteral extends Literal {
  constructor(bool) {
    super();
    this.value = bool;
  }
}

class StringLiteral extends Literal {
  constructor(string) {
    super();
    this.value = string;
  }
}

const semantics = grammar.createSemantics().addOperation('ast', {

  Program(body) {
    return new Program(body.ast);
  },
  Block(stmt, _) {
    return new Block(stmt.ast());
  },

//   Stmt_if() {
//     return new IfStatement();
//   },
  Stmt_for(fr, e, i, struct, l, b, r) {
    return new ForStatement(e.ast(), struct.ast(), b.ast();
  },
  Stmt_while(w, e, l, b, r) {
    return new WhileStatement(e.ast(), b.ast());
  },
  Stmt_match(m, e1, w, e2) {
    return new MatchStatement(e1.ast(), e2.ast());
  },
  Stmt_return(r, b) {
    return new ReturnStatement(b.ast());
  },
  Var_Decl(l, id, _, eq, v, _) {
    return new VariableDecl(v.sourceString);
  },
  Array_Decl(l, arr,  _, eq, l, v, _, r) {
    return new ArrayVariableDecl(v.sourceString);
  },
  Const_Decl(s, id, _, eq, v, _) {
    return new ConstDecl(v.sourceString);
  },
  Array_ConstDecl(s, id, _, eq, l, v, _, r) {
    return new ArrayConstDecl(v.sourceString);
  },
  Exp_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(), "or", e2.ast());
  },
  Exp_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(), "and", e2.ast());
  },
  Exp1_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(), op.sourceString, e2.ast());
  },
  Exp2_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(), op.sourceString, e2.ast());
  },
  Exp3_binary(e1, op, e2) {
    return new BinaryExpression(e1.ast(),op.sourceString, e2.ast());
  },
  Exp4_unary(op, e) {
    return new UnaryExpression("-", e.ast());
  },
  Exp5_parens(left, e, right) {
    return e.ast();
  },
  id(idValue) {
    return new IdExpression(this.sourceString);
  },
  floatlit(float) {
    return new FloatLiteral(this.sourceString);
  },
  boollit(bool) {
    return new BooleanLiteral(this.sourceString);
  },
  stringlit(string) {
    return new StringLiteral(this.sourceString);
  }
});

module.exports = parse = function(text) {
  var match;
  match = grammar.match(text);
  if (!match.succeeded()) {
    throw match.message;
  }
  return semantics(match).ast();
};
<|endoftext|>


<commit_before>module.exports = {
  "server": {
    baseDir: "./"
  },
  "files": [
    "assets/css/**/*.css"
  ],
  "browser": "default",
  "injectChanges": true,
  "online": false,
  "open": false,
  "port": 3000,
  "proxy": false,
  "notify": false,
  "watchTask": true
};
<commit_msg>Update Browsersync to watch correct directory for CSS.<commit_after>module.exports = {
  "server": {
    baseDir: "./"
  },
  "files": [
    "css/**/*.css"
  ],
  "browser": "default",
  "injectChanges": true,
  "online": false,
  "open": false,
  "port": 3000,
  "proxy": false,
  "notify": false,
  "watchTask": true
};
<|endoftext|>


<commit_before>const request = require('superagent')
const decompress = require('decompress')
const parse = require('csv-parser')
const pumpify = require('pumpify').obj
const through = require('through2').obj
const {decodeStream} = require('iconv-lite')
const toArray = require('get-stream').array
const {trimStart, trimEnd, keyBy} = require('lodash')
const {bufferToStream} = require('./buffer-stream')

const COMMUNES_2017_URL = 'https://www.insee.fr/fr/statistiques/fichier/2666684/france2017-txt.zip'

async function getCommunesBuffer() {
  const response = await request.get(COMMUNES_2017_URL)
    .buffer(true)
    .parse(request.parse['application/octet-stream'])
  const archiveBuffer = response.body
  const decompressedFiles = await decompress(archiveBuffer)
  return decompressedFiles[0].data
}

function buildNom(NCCENR, ARTMIN) {
  if (!ARTMIN) return NCCENR
  const trimmedArticle = trimStart(trimEnd(ARTMIN, ')'), '(')
  return trimmedArticle.endsWith('\'') ? trimmedArticle + NCCENR : trimmedArticle + ' ' + NCCENR
}

function eachCommune(commune, enc, cb) {
  const {ACTUAL, DEP, COM, NCCENR, ARTMIN} = commune
  if (ACTUAL === '9') return cb() // On ignore les fractions cantonales
  const code = DEP + COM
  const nom = buildNom(NCCENR, ARTMIN)
  cb(null, {code, nom, status: ACTUAL})
}

async function getCommunes() {
  const communesBuffer = await getCommunesBuffer()
  return toArray(
    pumpify(
      bufferToStream(communesBuffer),
      decodeStream('win1252'),
      parse({separator: '\t', strict: true}),
      through(eachCommune)
    )
  )
}

async function getIndexedCommunes() {
  const communes = await getCommunes()
  return keyBy(communes, 'code')
}

module.exports = {getCommunes, getIndexedCommunes}
<commit_msg>COG 2018<commit_after>const request = require('superagent')
const decompress = require('decompress')
const parse = require('csv-parser')
const pumpify = require('pumpify').obj
const through = require('through2').obj
const {decodeStream} = require('iconv-lite')
const toArray = require('get-stream').array
const {trimStart, trimEnd, keyBy} = require('lodash')
const {bufferToStream} = require('./buffer-stream')

const COMMUNES_2018_URL = 'https://www.insee.fr/fr/statistiques/fichier/3363419/France2018-txt.zip'

async function getCommunesBuffer() {
  const response = await request.get(COMMUNES_2018_URL)
    .buffer(true)
    .parse(request.parse['application/octet-stream'])
  const archiveBuffer = response.body
  const decompressedFiles = await decompress(archiveBuffer)
  return decompressedFiles[0].data
}

function buildNom(NCCENR, ARTMIN) {
  if (!ARTMIN) return NCCENR
  const trimmedArticle = trimStart(trimEnd(ARTMIN, ')'), '(')
  return trimmedArticle.endsWith('\'') ? trimmedArticle + NCCENR : trimmedArticle + ' ' + NCCENR
}

function eachCommune(commune, enc, cb) {
  const {ACTUAL, DEP, COM, NCCENR, ARTMIN} = commune
  if (ACTUAL === '9') return cb() // On ignore les fractions cantonales
  const code = DEP + COM
  const nom = buildNom(NCCENR, ARTMIN)
  cb(null, {code, nom, status: ACTUAL})
}

async function getCommunes() {
  const communesBuffer = await getCommunesBuffer()
  return toArray(
    pumpify(
      bufferToStream(communesBuffer),
      decodeStream('win1252'),
      parse({separator: '\t', strict: true}),
      through(eachCommune)
    )
  )
}

async function getIndexedCommunes() {
  const communes = await getCommunes()
  return keyBy(communes, 'code')
}

module.exports = {getCommunes, getIndexedCommunes}
<|endoftext|>


<commit_before>/* camp.js: server-side Ajax handler that wraps around Node.js.
 * Copyright © 2011 Thaddee Tyl, Jan Keromnes. All rights reserved.
 * Code covered by the LGPL license. */

var EventEmitter = require ('events').EventEmitter;
var Plate = exports.Plate = require ('./plate');

// Template system.
//

var catches = [];
var fallthrough = [];
exports.handle = function (paths, literalcall, evtcb) {
  catches.push ([RegExp(paths).source, literalcall, evtcb]);
};
exports.notfound = function (paths, literalcall, evtcb) {
  fallthrough.push ([RegExp(paths).source, literalcall, evtcb]);
};

// Register ajax action.
//

exports.Server = new EventEmitter ();

exports.add = (function () {

  // The exports.add function is the following.
  var adder = function (action, callback, evtname) {
  	exports.Server.Actions[action] = [callback, evtname];
  };

  exports.Server.Actions = {};    // This will be extended by the add function.

  return adder;
})();

exports.Server.mime = {
  'txt': 'text/plain',
  'html': 'text/html',
  'xhtml': 'text/html',
  'htm': 'text/html',
  'xml': 'text/xml',
  'css': 'text/css',
  'csv': 'text/csv',
  'dtd': 'application/xml-dtd',

  'js': 'text/javascript',
  'json': 'application/json',
  'css': 'text/css',
  'html': 'text/html',
  'c': 'text/x-csrc',
  'cpp': 'text/x-c++src',
  'java': 'text/x-java',
  'groovy': 'text/x-groovy',
  'clj': 'text/x-clojure',
  'coffee': 'text/x-coffeescript',
  'diff': 'text/x-diff',
  'hs': 'text/x-haskell',
  'lua': 'text/x-lua',
  'md': 'text/x-markdown',
  'nt': 'text/n-triples',
  'pas': 'text/x-pascal',
  'pl': 'text/x-perl',
  'php': 'text/x-php',
  'pls': 'text/x-plsql',
  'sql': 'text/x-plsql',
  'py': 'text/x-python',
  'r': 'text/x-rsrc',
  'rst': 'text/x-rst',
  'rb': 'text/x-ruby',
  'rs': 'text/x-rustsrc',
  'scm': 'text/x-scheme',
  'ss': 'text/x-scheme',
  'rkt': 'text/x-scheme',
  'st': 'text/x-stsrc',
  'sparql': 'text/x-sparql-query',
  'tex': 'text/x-stex',
  'latex': 'text/x-stex',
  'vtl': 'text/velocity',
  'yaml': 'text/x-yaml',

  'pdf': 'application/pdf',
  'ps': 'application/postscript',
  'odt': 'application/vnd.oasis.opendocument.text',
  'ods': 'application/vnd.oasis.opendocument.spreadsheet',
  'odp': 'application/vnd.oasis.opendocument.presentation',
  'xls': 'application/vnd.ms-excel',
  'doc': 'application/vnd.msword',
  'ppt': 'application/vnd.ms-powerpoint',
  'xul': 'application/vnd.mozilla.xul+xml',
  'kml': 'application/vnd.google-earth.kml+xml',
  'dvi': 'application/x-dvi',
  'tex': 'application/x-latex',
  'ttf': 'application/x-font-ttf',
  'swf': 'application/x-shockwave-flash',
  'rar': 'application/x-rar-compressed',
  'zip': 'application/zip',
  'tar': 'application/x-tar',
  'gz': 'application/x-gzip',

  'ogg': 'audio/ogg',
  'mp3': 'audio/mpeg',
  'mpeg': 'audio/mpeg',
  'wav': 'audio/vnd.wave',
  'wma': 'audio/x-ms-wma',
  'gif': 'image/gif',
  'jpg': 'image/jpeg',
  'jpeg': 'image/jpeg',
  'png': 'image/png',
  'svg': 'image/svg+xml',
  'tiff': 'image/tiff',
  'ico': 'image/vnd.microsoft.icon',
  'mp4': 'video/mp4',
  'ogv': 'video/ogg',
  'mov': 'video/quicktime',
  'webm': 'video/webm',
  'wmv': 'video/x-ms-wmv'
};
exports.Server.binaries = [
  'pdf', 'ps', 'odt', 'ods', 'odp', 'xls', 'doc', 'ppt', 'dvi', 'ttf', 'swf',
  'rar', 'zip', 'tar', 'gz', 'ogg', 'mp3', 'mpeg', 'wav', 'wma', 'gif', 'jpg',
  'jpeg', 'png', 'svg', 'tiff', 'ico', 'mp4', 'ogv', 'mov', 'webm', 'wmv'
];

// We'll need to parse the query (either POST or GET) as a literal.
function parsequery (query, strquery) {
  var items = strquery.split('&');
  for (var item in items) {
    // Each element of key=value is then again split along `=`.
    var elems = items[item].split('=');
    try {
      query[unescape(elems[0])] = JSON.parse(unescape(elems[1]));
    } catch (e) {
      console.log ('query:', JSON.stringify(query), e.toString());
    }
  }
  return query;
}

// Internal start function.
//

exports.Server.start = function (port, security, debug) {
  "use strict";

  var http = require('http')
    , https = require('https')
    , p = require('path')
    , fs = require('fs')
    , url = require('url')
    , qs = require('querystring');

  // The request listener
  function listener(req,res){
    var uri = url.parse (req.url, true);
    var path = uri.pathname;
    var query = uri.query;

    try {
      if (debug > 5) { console.log(path); } ///
      var realpath = '.' + path;

      /* Differed sendback function (choice between func and object).
       * `getsentback` is the function that returns either an object or ∅..
       * `treat(res)` is a func that the result goes through and is sent.
       * `sentback` is a function, fired by the event whose name is that
       * that function's name. */
      var differedresult = function (getsentback, treat, sentback) {
        if (sentback !== undefined) {
          // Event-based ajax call.
          var evtname = sentback.name;

          if (typeof sentback !== 'function' && debug > 2) {
            console.log ('warning: has a third parameter that isn\'t an ' +
              'event callback (ie, a function).');
          }

          req.pause ();   // We must wait for an event to happen.
          exports.Server.on (evtname, function evtnamecb () {
            var args = [];    // The argument list to send to action.
            for (var i in arguments) { args.push (arguments[i]); }

            var resp = sentback.apply (query, args);
            if (debug > 3) { console.log ('event',evtname,
                                      'yields',JSON.stringify(resp)); }
            if (resp !== undefined) {
              if (debug > 3) { console.log ('subsequently writing it'); }
              try {
                req.resume ();
                res.end (treat (resp));
              } catch (e) {
                if (debug > 2) { console.log (e.message); }
              }
              // Remove callback.
              exports.Server.removeListener (evtname, evtnamecb);
            }
          });
          getsentback ();

        } else {
          // Handle the action the usual way.
          res.end (treat (getsentback() || {}));
        }
      };

      if (/^\/\$/.test (path)) {
        // This is an ajax action.
        if (debug > 3) { console.log ('validated action', path); } ///
        var action = path.slice (2);

        res.writeHead (200, {'Content-Type': exports.Server.mime['json']});

        /* Handler for when we get a data request. */
        var gotrequest = function (chunk) {

          if (chunk !== undefined) {
            /* Parse the chunk (it is an object literal). */
            parsequery (query, chunk.toString ());
          }

          /* Launch the defined action. */
          if (exports.Server.Actions[action]) {
            var getsentback = function() {
              return exports.Server.Actions[action][0] (query);
            },  evtcb =  exports.Server.Actions[action][1];
            differedresult (getsentback, JSON.stringify, evtcb);
          } else {
            res.end ('404');
          }

        };
        if (req.method === 'POST') req.on ('data', gotrequest);
        else gotrequest();

      } else {
        if (debug > 3) { console.log ('validated', path); }  ///
        //TODO: make it a stream.

        /* What extension is it? */
        var ext = p.extname (realpath).slice (1);

        // Path catching mechanism.
        var catchpath = function (platepaths) {
          if (debug > 1 && platepaths.length > 1) {
            console.log ('More than one plate paths match', path + ':');
            platepaths.forEach (function (path) {console.log ('-',path);});
          }
          var pathmatch = path.match (RegExp (platepaths[0][0]));

          // What does the plate handling yield? Direcly data, or...
          var completion = function() {
            var result = platepaths[0][1] (query, pathmatch);
            // Extension of the template.
            ext = p.extname (pathmatch[0]).slice (1);
            res.writeHead (200, {
              'Content-Type': exports.Server.mime[ext] || 'text/plain'
            });
            return result;
          },  treat = function (templatedata) {
            var data = fs.readFileSync ('.' + pathmatch[0]);
            if (data === undefined) {
              if (debug > 0) { console.log ('Template not found:', err.path); }
              res.writeHead (404, 'Where the hell do you think you\'re going?');
              res.end ('404: thou hast finished me!\n');
            }
            return Plate.format (data.toString (), templatedata);
          };

          // `platepaths[0][2]` is the callback associated to the event,
          // if it exists.
          differedresult (completion, treat, platepaths[0][2]);

        };

        // Do we need template preprocessing?
        var platepaths;
        if ((platepaths = catches.filter (function(key) {
            return RegExp(key[0]).test (path);
          })).length > 0) {
          catchpath (platepaths);

        } else {
          // realpath is a real path!
          if (realpath.match (/\/$/)) {
            realpath = realpath + 'index.html';
            ext = 'html';
          }
          fs.readFile(realpath
              , exports.Server.binaries.indexOf (ext) !== -1? 'binary': 'utf8'
              , function (err, data) {
            if (err) {
              if ((platepaths = fallthrough.filter (function(key) {
                  return RegExp(key[0]).test (path);
              })).length > 0) {
                catchpath (platepaths);

              } else {
                if (debug > 0) { console.log ('File not found:', err.path); }
                res.writeHead (404, 'Where the hell do you think you\'re going?');
                res.end ('404: thou hast finished me!\n');
              }

            } else {
              res.writeHead (200, {
                'Content-Type': exports.Server.mime[ext] || 'text/plain'
              });
              res.end (data, 'binary');
            }
          });
        }
      }

    } catch(e) {
      res.writeHead (404, 'You killed me!');
      if (debug > 1) { res.write(e.toString() + '\n'); }
      res.end ('404: thou hast finished me!\n');
    }

  };

  // Are we running https?
  if (security.key && security.cert) { // yep
    https.createServer({
      key: fs.readFileSync(security.key),
      cert: fs.readFileSync(security.cert)
    },listener).listen(port);
  } else { // nope
    http.createServer(listener).listen(port);
  }
};

// Exported start function.
//
exports.start = function(options) {
  var security = {};
  if (options.secure === 'yes' || options.key || options.cert) {
    security.key = options.key || '../https.key',
    security.cert = options.cert || '../https.crt'
  }
  var debug = options.debug || 0,
      port = options.port || ( security.key && security.cert ? 443 : 80 );
  exports.Server.start(port,security,debug);
};
<commit_msg>Allows to call Camp.start() without params<commit_after>/* camp.js: server-side Ajax handler that wraps around Node.js.
 * Copyright © 2011 Thaddee Tyl, Jan Keromnes. All rights reserved.
 * Code covered by the LGPL license. */

var EventEmitter = require ('events').EventEmitter;
var Plate = exports.Plate = require ('./plate');

// Template system.
//

var catches = [];
var fallthrough = [];
exports.handle = function (paths, literalcall, evtcb) {
  catches.push ([RegExp(paths).source, literalcall, evtcb]);
};
exports.notfound = function (paths, literalcall, evtcb) {
  fallthrough.push ([RegExp(paths).source, literalcall, evtcb]);
};

// Register ajax action.
//

exports.Server = new EventEmitter ();

exports.add = (function () {

  // The exports.add function is the following.
  var adder = function (action, callback, evtname) {
  	exports.Server.Actions[action] = [callback, evtname];
  };

  exports.Server.Actions = {};    // This will be extended by the add function.

  return adder;
})();

exports.Server.mime = {
  'txt': 'text/plain',
  'html': 'text/html',
  'xhtml': 'text/html',
  'htm': 'text/html',
  'xml': 'text/xml',
  'css': 'text/css',
  'csv': 'text/csv',
  'dtd': 'application/xml-dtd',

  'js': 'text/javascript',
  'json': 'application/json',
  'css': 'text/css',
  'html': 'text/html',
  'c': 'text/x-csrc',
  'cpp': 'text/x-c++src',
  'java': 'text/x-java',
  'groovy': 'text/x-groovy',
  'clj': 'text/x-clojure',
  'coffee': 'text/x-coffeescript',
  'diff': 'text/x-diff',
  'hs': 'text/x-haskell',
  'lua': 'text/x-lua',
  'md': 'text/x-markdown',
  'nt': 'text/n-triples',
  'pas': 'text/x-pascal',
  'pl': 'text/x-perl',
  'php': 'text/x-php',
  'pls': 'text/x-plsql',
  'sql': 'text/x-plsql',
  'py': 'text/x-python',
  'r': 'text/x-rsrc',
  'rst': 'text/x-rst',
  'rb': 'text/x-ruby',
  'rs': 'text/x-rustsrc',
  'scm': 'text/x-scheme',
  'ss': 'text/x-scheme',
  'rkt': 'text/x-scheme',
  'st': 'text/x-stsrc',
  'sparql': 'text/x-sparql-query',
  'tex': 'text/x-stex',
  'latex': 'text/x-stex',
  'vtl': 'text/velocity',
  'yaml': 'text/x-yaml',

  'pdf': 'application/pdf',
  'ps': 'application/postscript',
  'odt': 'application/vnd.oasis.opendocument.text',
  'ods': 'application/vnd.oasis.opendocument.spreadsheet',
  'odp': 'application/vnd.oasis.opendocument.presentation',
  'xls': 'application/vnd.ms-excel',
  'doc': 'application/vnd.msword',
  'ppt': 'application/vnd.ms-powerpoint',
  'xul': 'application/vnd.mozilla.xul+xml',
  'kml': 'application/vnd.google-earth.kml+xml',
  'dvi': 'application/x-dvi',
  'tex': 'application/x-latex',
  'ttf': 'application/x-font-ttf',
  'swf': 'application/x-shockwave-flash',
  'rar': 'application/x-rar-compressed',
  'zip': 'application/zip',
  'tar': 'application/x-tar',
  'gz': 'application/x-gzip',

  'ogg': 'audio/ogg',
  'mp3': 'audio/mpeg',
  'mpeg': 'audio/mpeg',
  'wav': 'audio/vnd.wave',
  'wma': 'audio/x-ms-wma',
  'gif': 'image/gif',
  'jpg': 'image/jpeg',
  'jpeg': 'image/jpeg',
  'png': 'image/png',
  'svg': 'image/svg+xml',
  'tiff': 'image/tiff',
  'ico': 'image/vnd.microsoft.icon',
  'mp4': 'video/mp4',
  'ogv': 'video/ogg',
  'mov': 'video/quicktime',
  'webm': 'video/webm',
  'wmv': 'video/x-ms-wmv'
};
exports.Server.binaries = [
  'pdf', 'ps', 'odt', 'ods', 'odp', 'xls', 'doc', 'ppt', 'dvi', 'ttf', 'swf',
  'rar', 'zip', 'tar', 'gz', 'ogg', 'mp3', 'mpeg', 'wav', 'wma', 'gif', 'jpg',
  'jpeg', 'png', 'svg', 'tiff', 'ico', 'mp4', 'ogv', 'mov', 'webm', 'wmv'
];

// We'll need to parse the query (either POST or GET) as a literal.
function parsequery (query, strquery) {
  var items = strquery.split('&');
  for (var item in items) {
    // Each element of key=value is then again split along `=`.
    var elems = items[item].split('=');
    try {
      query[unescape(elems[0])] = JSON.parse(unescape(elems[1]));
    } catch (e) {
      console.log ('query:', JSON.stringify(query), e.toString());
    }
  }
  return query;
}

// Internal start function.
//

exports.Server.start = function (port, security, debug) {
  "use strict";

  var http = require('http')
    , https = require('https')
    , p = require('path')
    , fs = require('fs')
    , url = require('url')
    , qs = require('querystring');

  // The request listener
  function listener(req,res){
    var uri = url.parse (req.url, true);
    var path = uri.pathname;
    var query = uri.query;

    try {
      if (debug > 5) { console.log(path); } ///
      var realpath = '.' + path;

      /* Differed sendback function (choice between func and object).
       * `getsentback` is the function that returns either an object or ∅..
       * `treat(res)` is a func that the result goes through and is sent.
       * `sentback` is a function, fired by the event whose name is that
       * that function's name. */
      var differedresult = function (getsentback, treat, sentback) {
        if (sentback !== undefined) {
          // Event-based ajax call.
          var evtname = sentback.name;

          if (typeof sentback !== 'function' && debug > 2) {
            console.log ('warning: has a third parameter that isn\'t an ' +
              'event callback (ie, a function).');
          }

          req.pause ();   // We must wait for an event to happen.
          exports.Server.on (evtname, function evtnamecb () {
            var args = [];    // The argument list to send to action.
            for (var i in arguments) { args.push (arguments[i]); }

            var resp = sentback.apply (query, args);
            if (debug > 3) { console.log ('event',evtname,
                                      'yields',JSON.stringify(resp)); }
            if (resp !== undefined) {
              if (debug > 3) { console.log ('subsequently writing it'); }
              try {
                req.resume ();
                res.end (treat (resp));
              } catch (e) {
                if (debug > 2) { console.log (e.message); }
              }
              // Remove callback.
              exports.Server.removeListener (evtname, evtnamecb);
            }
          });
          getsentback ();

        } else {
          // Handle the action the usual way.
          res.end (treat (getsentback() || {}));
        }
      };

      if (/^\/\$/.test (path)) {
        // This is an ajax action.
        if (debug > 3) { console.log ('validated action', path); } ///
        var action = path.slice (2);

        res.writeHead (200, {'Content-Type': exports.Server.mime['json']});

        /* Handler for when we get a data request. */
        var gotrequest = function (chunk) {

          if (chunk !== undefined) {
            /* Parse the chunk (it is an object literal). */
            parsequery (query, chunk.toString ());
          }

          /* Launch the defined action. */
          if (exports.Server.Actions[action]) {
            var getsentback = function() {
              return exports.Server.Actions[action][0] (query);
            },  evtcb =  exports.Server.Actions[action][1];
            differedresult (getsentback, JSON.stringify, evtcb);
          } else {
            res.end ('404');
          }

        };
        if (req.method === 'POST') req.on ('data', gotrequest);
        else gotrequest();

      } else {
        if (debug > 3) { console.log ('validated', path); }  ///
        //TODO: make it a stream.

        /* What extension is it? */
        var ext = p.extname (realpath).slice (1);

        // Path catching mechanism.
        var catchpath = function (platepaths) {
          if (debug > 1 && platepaths.length > 1) {
            console.log ('More than one plate paths match', path + ':');
            platepaths.forEach (function (path) {console.log ('-',path);});
          }
          var pathmatch = path.match (RegExp (platepaths[0][0]));

          // What does the plate handling yield? Direcly data, or...
          var completion = function() {
            var result = platepaths[0][1] (query, pathmatch);
            // Extension of the template.
            ext = p.extname (pathmatch[0]).slice (1);
            res.writeHead (200, {
              'Content-Type': exports.Server.mime[ext] || 'text/plain'
            });
            return result;
          },  treat = function (templatedata) {
            var data = fs.readFileSync ('.' + pathmatch[0]);
            if (data === undefined) {
              if (debug > 0) { console.log ('Template not found:', err.path); }
              res.writeHead (404, 'Where the hell do you think you\'re going?');
              res.end ('404: thou hast finished me!\n');
            }
            return Plate.format (data.toString (), templatedata);
          };

          // `platepaths[0][2]` is the callback associated to the event,
          // if it exists.
          differedresult (completion, treat, platepaths[0][2]);

        };

        // Do we need template preprocessing?
        var platepaths;
        if ((platepaths = catches.filter (function(key) {
            return RegExp(key[0]).test (path);
          })).length > 0) {
          catchpath (platepaths);

        } else {
          // realpath is a real path!
          if (realpath.match (/\/$/)) {
            realpath = realpath + 'index.html';
            ext = 'html';
          }
          fs.readFile(realpath
              , exports.Server.binaries.indexOf (ext) !== -1? 'binary': 'utf8'
              , function (err, data) {
            if (err) {
              if ((platepaths = fallthrough.filter (function(key) {
                  return RegExp(key[0]).test (path);
              })).length > 0) {
                catchpath (platepaths);

              } else {
                if (debug > 0) { console.log ('File not found:', err.path); }
                res.writeHead (404, 'Where the hell do you think you\'re going?');
                res.end ('404: thou hast finished me!\n');
              }

            } else {
              res.writeHead (200, {
                'Content-Type': exports.Server.mime[ext] || 'text/plain'
              });
              res.end (data, 'binary');
            }
          });
        }
      }

    } catch(e) {
      res.writeHead (404, 'You killed me!');
      if (debug > 1) { res.write(e.toString() + '\n'); }
      res.end ('404: thou hast finished me!\n');
    }

  };

  // Are we running https?
  if (security.key && security.cert) { // yep
    https.createServer({
      key: fs.readFileSync(security.key),
      cert: fs.readFileSync(security.cert)
    },listener).listen(port);
  } else { // nope
    http.createServer(listener).listen(port);
  }
};

// Exported start function.
//
exports.start = function(options) {
  var security = {},
      options = options || {};
  if (options.secure === 'yes' || options.key || options.cert) {
    security.key = options.key || '../https.key',
    security.cert = options.cert || '../https.crt'
  }
  var debug = options.debug || 0,
      port = options.port || ( security.key && security.cert ? 443 : 80 );
  exports.Server.start(port,security,debug);
};
<|endoftext|>


<commit_before>(function(){
/**
 * CARDBOARD
 * Minimalistic, portable, style-able forms for JSON schemas and javascript
 * objects.
 *
 * Demo: http://htmlpreview.github.io/?https://github.com/avinoamr/cardboard/blob/master/example.html
 *
 * The MIT License (MIT)
 * Copyright (c) 2013 Roi Avinoam

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
const STYLE = `
.cardboard {
    border-bottom: 1px solid #ddd;
    display: block;
}

.cardboard .cardboard-hidden {
    display: none;
}

.cardboard .cardboard-flex {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}

.cardboard .cardboard-grow {
    flex-grow: 1
}

.cardboard .cardboard-full {
    width: 100%;
}

.cardboard section {
    border-top: 1px solid #ddd;
    width: 100%;
}

.cardboard section > header {
    text-transform: uppercase;
    font-weight: bold;
    font-size: 12px;
    color: #7f8c8d;
    padding: 12px;
}

.cardboard .cardboard-nest {
    box-sizing: border-box;
    border-left: 30px solid #f5f5f5;
}

.cardboard input {
    display: block;
    border: none;
    outline: none;
    background: none;
    font-weight: normal;
}

.cardboard .cardboard-toggle {
    cursor: pointer;
}

.cardboard .cardboard-toggle:before {
    content: '';
    position: relative;
    vertical-align: top;
    top: 0.35em;
    left: 0.15em;

    display: inline-block;
    margin-right: 1em;
    width: 0.45em;
    height: 0.45em;

    border-style: solid;
    border-width: 0.15em 0.15em 0 0;
    border-color: #7f8c8d;
    transform: rotate(45deg);
    transition: transform .3s, top .3s;
}

.cardboard .cardboard-toggle.cardboard-open:before {
    top: 0.15em;
    transform: rotate(135deg);
}
`
class Cardboard extends HTMLElement {
    attachedCallback() { // custom-elements v0
        this.connectedCallback()
    }

    connectedCallback() {
        var s = this.parentNode.querySelector('style#cardboard-style')
        if (s) {
            return
        }

        var s = $('')
        this.parentNode.insertBefore(s, this)
    }

    data(data) {
        this._data = data
        return this
    }

    schema(schema) {
        this._schema = schema
        return this
    }

    render() {
        var el = this
        el.classList.add('cardboard')
        var inputs = draw(this._schema, this._data, {})
        el.innerHTML = ''
        $(el).appendMany(inputs)
        return el
    }

    static register(name, drawFn) {
        this.inputs[name] = drawFn
        return this
    }
}

Cardboard.inputs = {}

function draw(schema, data, options) {
    if (!schema || !schema.type) {
        schema = extend(Cardboard._autoSchema(data), schema)
    }

    if (schema.hidden) {
        return
    }

    var inputFn = Cardboard.inputs[schema.type] || Cardboard.inputs.string
    return inputFn(schema, data, options)
}

function drawItems(schema, data, options) {
    options._nest = options._nest || 0
    if (!options._nest) {
        return drawItems.inner(schema, data, options)
    }

    var expand = $('

')
    var container = $('

')

    var items
    expand.on('click', function() {
        expand.classList.toggle('cardboard-open')
        if (!items) {
            items = drawItems.inner(schema, data, options)
            container.appendMany(items)
        }

        container.style.display = expand.classList.contains('cardboard-open')
            ? '' : 'none'
    })

    return [expand, container]
}

drawItems.inner = function(schema, items, options) {
    var nest = options._nest
    var headers = []
    var sections = items
        .filter(function(item) {
            return item.k[0] !== '_' && !item.schema.hidden
        })
        .map(function (item) {
            var section = $(`

            `)
            .on('input', onChange)
            .on('change', onChange)

            function onChange(ev) {
                if (ev.detail === undefined) {
                    ev.detail = ev.target.value
                }
                item.data[item.k] = ev.detail
                ev.detail = item.data
            }

            var header = section.$$('header')
            header.innerHTML = schema.title || item.k
            headers.push(header)

            if (nest > 0) {
                header.classList.add('cardboard-nest')
                header.style['border-left-width'] =
                    (nest * 30) + 'px'
            }

            options = { _nest: nest + 1 }
            // item.schema._nest = nest + 1
            return section.appendMany(draw(item.schema, item.v, options))
        })

    // // uniform width
    // setTimeout(function () {
    //     var max = headers.reduce(function (max, h) {
    //         return Math.max(max, h.getBoundingClientRect().width)
    //     }, 0)
    //
    //     headers.forEach(function (h) {
    //         h.style.width = max + 'px'
    //     })
    // })

    return sections
}

function drawObject(schema, data, options) {
    data = data || {}
    var props = schema.properties || {}
    var items = Object.keys(props).map(function(k) {
        return { schema: props[k], k: k, v: (data || {})[k], data: data }
    })

    return drawItems(schema, items, options)
}

function drawArray(schema, data, options) {
    data = data || []
    var items = (data || []).map(function(d, idx) {
        return { schema: schema.item || {}, k: idx, v: d, data: data }
    })

    return drawItems(schema, items, options)
}

function drawEnum(schema, data) {
    return schema.enum.reduce(function (select, item) {
        var option = $('<option>' + item + '</option>')
            .attr('selected', item == data)

        return select.appendMany(option)
    }, $('<select></select>'))
}

function drawInput(format, schema, data) {
    return schema.enum
        ? drawEnum(schema, data)
            .attr('disabled', schema.readOnly)

        : $('<input class="cardboard-grow" />')
            .attr('type', format || 'text')
            .attr('value', data || schema.default || '')
            .attr('placeholder', schema.placeholder || '')
            .attr('disabled', schema.readOnly)
}

function drawString (schema, data) {
    return drawInput(schema.format || 'text', schema, data)
}

function drawNumber (schema, data) {
    return drawInput('number', schema, data)
        .on('input', onChange)
        .on('change', onChange)

    function onChange(ev) {
        ev.detail = parseFloat(ev.target.value)
    }
}

function drawBoolean(schema, data) {
    return drawInput('checkbox', schema, data)
        .attr('checked', data)
        .on('input', onChange)
        .on('change', onChange)

    function onChange(ev) {
        ev.detail = ev.target.checked
    }
}

Cardboard._autoSchema = function(data) {
    var schema = {
        type: Array.isArray(data) ? 'array' : typeof data
    }

    if (schema.type === 'object') {
        schema.properties = {}
        Object.keys(data).forEach(function (k) {
            schema.properties[k] = Cardboard._autoSchema(data[k])
        })
    }

    return schema
}

// create DOM element from an HTML string
function $(el, args) {
    if (typeof el === 'string') {
        var tmp = document.createElement('div')
        tmp.innerHTML = el
        el = tmp.children[0]
    }

    el.$$ = function(selector) {
        return $(el.querySelector(selector))
    }
    el.attr = function(k, v) {
        !v
            ? el.removeAttribute(k)
            : el.setAttribute(k, v)
        return el
    }
    el.appendMany = function(items) {
        items || (items = [])
        items = Array.isArray(items) ? items : [items]
        items.forEach(el.appendChild.bind(el))
        return el
    }
    el.on = function() {
        el.addEventListener.apply(el, arguments)
        return el
    }
    return el
}

function extend(target, source) {
    for (var k in source) {
        if (source[k] !== undefined) {
            target[k] = source[k]
        }
    }
    return target
}

function cardboard(el) {
    if (el instanceof cardboard.Cardboard) {
        return el // idempotent
    }

    Object.setPrototypeOf(el, cardboard.Cardboard.prototype)
    el.connectedCallback() // harmless even when not connected.
    return el
}

cardboard.register = Cardboard.register.bind(Cardboard)
cardboard.Cardboard = Cardboard
    .register('object', drawObject)
    .register('array', drawArray)
    .register('text', drawString)
    .register('string', drawString)
    .register('number', drawNumber)
    .register('int', drawNumber)
    .register('integer', drawNumber)
    .register('float', drawNumber)
    .register('boolean', drawBoolean)
    .register('boo', drawBoolean)
    .register(Object, drawObject)
    .register(Array, drawArray)
    .register(String, drawString)
    .register(Number, drawNumber)
    .register(Boolean, drawBoolean)

// register the element
document.addEventListener('DOMContentLoaded', function () {
    if ('customElements' in window) {
        window.customElements.define('card-board', Cardboard)
    } else if ('registerElement' in document) {
        cardboard.Cardboard = document.registerElement('card-board', Cardboard)
    } else {
        console.warn('<card-board>: custom elements aren\'t supported')
        console.warn('<card-board>: Initialize <draw-box> with cardboard(el)')
    }
})

window.cardboard = cardboard
})()
<commit_msg>Bugfix: title didn't work<commit_after>(function(){
/**
 * CARDBOARD
 * Minimalistic, portable, style-able forms for JSON schemas and javascript
 * objects.
 *
 * Demo: http://htmlpreview.github.io/?https://github.com/avinoamr/cardboard/blob/master/example.html
 *
 * The MIT License (MIT)
 * Copyright (c) 2013 Roi Avinoam

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
const STYLE = `
.cardboard {
    border-bottom: 1px solid #ddd;
    display: block;
}

.cardboard .cardboard-hidden {
    display: none;
}

.cardboard .cardboard-flex {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}

.cardboard .cardboard-grow {
    flex-grow: 1
}

.cardboard .cardboard-full {
    width: 100%;
}

.cardboard section {
    border-top: 1px solid #ddd;
    width: 100%;
}

.cardboard section > header {
    text-transform: uppercase;
    font-weight: bold;
    font-size: 12px;
    color: #7f8c8d;
    padding: 12px;
}

.cardboard .cardboard-nest {
    box-sizing: border-box;
    border-left: 30px solid #f5f5f5;
}

.cardboard input {
    display: block;
    border: none;
    outline: none;
    background: none;
    font-weight: normal;
}

.cardboard .cardboard-toggle {
    cursor: pointer;
}

.cardboard .cardboard-toggle:before {
    content: '';
    position: relative;
    vertical-align: top;
    top: 0.35em;
    left: 0.15em;

    display: inline-block;
    margin-right: 1em;
    width: 0.45em;
    height: 0.45em;

    border-style: solid;
    border-width: 0.15em 0.15em 0 0;
    border-color: #7f8c8d;
    transform: rotate(45deg);
    transition: transform .3s, top .3s;
}

.cardboard .cardboard-toggle.cardboard-open:before {
    top: 0.15em;
    transform: rotate(135deg);
}
`
class Cardboard extends HTMLElement {
    attachedCallback() { // custom-elements v0
        this.connectedCallback()
    }

    connectedCallback() {
        var s = this.parentNode.querySelector('style#cardboard-style')
        if (s) {
            return
        }

        var s = $('')
        this.parentNode.insertBefore(s, this)
    }

    data(data) {
        this._data = data
        return this
    }

    schema(schema) {
        this._schema = schema
        return this
    }

    render() {
        var el = this
        el.classList.add('cardboard')
        var inputs = draw(this._schema, this._data, {})
        el.innerHTML = ''
        $(el).appendMany(inputs)
        return el
    }

    static register(name, drawFn) {
        this.inputs[name] = drawFn
        return this
    }
}

Cardboard.inputs = {}

function draw(schema, data, options) {
    if (!schema || !schema.type) {
        schema = extend(Cardboard._autoSchema(data), schema)
    }

    if (schema.hidden) {
        return
    }

    var inputFn = Cardboard.inputs[schema.type] || Cardboard.inputs.string
    return inputFn(schema, data, options)
}

function drawItems(schema, data, options) {
    options._nest = options._nest || 0
    if (!options._nest) {
        return drawItems.inner(schema, data, options)
    }

    var expand = $('

')
    var container = $('

')

    var items
    expand.on('click', function() {
        expand.classList.toggle('cardboard-open')
        if (!items) {
            items = drawItems.inner(schema, data, options)
            container.appendMany(items)
        }

        container.style.display = expand.classList.contains('cardboard-open')
            ? '' : 'none'
    })

    return [expand, container]
}

drawItems.inner = function(schema, items, options) {
    var nest = options._nest
    var headers = []
    var sections = items
        .filter(function(item) {
            return item.k[0] !== '_' && !item.schema.hidden
        })
        .map(function (item) {
            var section = $(`

            `)
            .on('input', onChange)
            .on('change', onChange)

            function onChange(ev) {
                if (ev.detail === undefined) {
                    ev.detail = ev.target.value
                }
                item.data[item.k] = ev.detail
                ev.detail = item.data
            }

            var header = section.$$('header')
            header.innerHTML = item.schema.title || item.k
            headers.push(header)

            if (nest > 0) {
                header.classList.add('cardboard-nest')
                header.style['border-left-width'] =
                    (nest * 30) + 'px'
            }

            options = { _nest: nest + 1 }
            // item.schema._nest = nest + 1
            return section.appendMany(draw(item.schema, item.v, options))
        })

    // // uniform width
    // setTimeout(function () {
    //     var max = headers.reduce(function (max, h) {
    //         return Math.max(max, h.getBoundingClientRect().width)
    //     }, 0)
    //
    //     headers.forEach(function (h) {
    //         h.style.width = max + 'px'
    //     })
    // })

    return sections
}

function drawObject(schema, data, options) {
    data = data || {}
    var props = schema.properties || {}
    var items = Object.keys(props).map(function(k) {
        return { schema: props[k], k: k, v: (data || {})[k], data: data }
    })

    return drawItems(schema, items, options)
}

function drawArray(schema, data, options) {
    data = data || []
    var items = (data || []).map(function(d, idx) {
        return { schema: schema.item || {}, k: idx, v: d, data: data }
    })

    return drawItems(schema, items, options)
}

function drawEnum(schema, data) {
    return schema.enum.reduce(function (select, item) {
        var option = $('<option>' + item + '</option>')
            .attr('selected', item == data)

        return select.appendMany(option)
    }, $('<select></select>'))
}

function drawInput(format, schema, data) {
    return schema.enum
        ? drawEnum(schema, data)
            .attr('disabled', schema.readOnly)

        : $('<input class="cardboard-grow" />')
            .attr('type', format || 'text')
            .attr('value', data || schema.default || '')
            .attr('placeholder', schema.placeholder || '')
            .attr('disabled', schema.readOnly)
}

function drawString (schema, data) {
    return drawInput(schema.format || 'text', schema, data)
}

function drawNumber (schema, data) {
    return drawInput('number', schema, data)
        .on('input', onChange)
        .on('change', onChange)

    function onChange(ev) {
        ev.detail = parseFloat(ev.target.value)
    }
}

function drawBoolean(schema, data) {
    return drawInput('checkbox', schema, data)
        .attr('checked', data)
        .on('input', onChange)
        .on('change', onChange)

    function onChange(ev) {
        ev.detail = ev.target.checked
    }
}

Cardboard._autoSchema = function(data) {
    var schema = {
        type: Array.isArray(data) ? 'array' : typeof data
    }

    if (schema.type === 'object') {
        schema.properties = {}
        Object.keys(data).forEach(function (k) {
            schema.properties[k] = Cardboard._autoSchema(data[k])
        })
    }

    return schema
}

// create DOM element from an HTML string
function $(el, args) {
    if (typeof el === 'string') {
        var tmp = document.createElement('div')
        tmp.innerHTML = el
        el = tmp.children[0]
    }

    el.$$ = function(selector) {
        return $(el.querySelector(selector))
    }
    el.attr = function(k, v) {
        !v
            ? el.removeAttribute(k)
            : el.setAttribute(k, v)
        return el
    }
    el.appendMany = function(items) {
        items || (items = [])
        items = Array.isArray(items) ? items : [items]
        items.forEach(el.appendChild.bind(el))
        return el
    }
    el.on = function() {
        el.addEventListener.apply(el, arguments)
        return el
    }
    return el
}

function extend(target, source) {
    for (var k in source) {
        if (source[k] !== undefined) {
            target[k] = source[k]
        }
    }
    return target
}

function cardboard(el) {
    if (el instanceof cardboard.Cardboard) {
        return el // idempotent
    }

    Object.setPrototypeOf(el, cardboard.Cardboard.prototype)
    el.connectedCallback() // harmless even when not connected.
    return el
}

cardboard.register = Cardboard.register.bind(Cardboard)
cardboard.Cardboard = Cardboard
    .register('object', drawObject)
    .register('array', drawArray)
    .register('text', drawString)
    .register('string', drawString)
    .register('number', drawNumber)
    .register('int', drawNumber)
    .register('integer', drawNumber)
    .register('float', drawNumber)
    .register('boolean', drawBoolean)
    .register('boo', drawBoolean)
    .register(Object, drawObject)
    .register(Array, drawArray)
    .register(String, drawString)
    .register(Number, drawNumber)
    .register(Boolean, drawBoolean)

// register the element
document.addEventListener('DOMContentLoaded', function () {
    if ('customElements' in window) {
        window.customElements.define('card-board', Cardboard)
    } else if ('registerElement' in document) {
        cardboard.Cardboard = document.registerElement('card-board', Cardboard)
    } else {
        console.warn('<card-board>: custom elements aren\'t supported')
        console.warn('<card-board>: Initialize <draw-box> with cardboard(el)')
    }
})

window.cardboard = cardboard
})()
<|endoftext|>


<commit_before>/* global CanvasRenderingContext2D */

function chachacat(imagedata, opts) {

  // image data helpers ////////////////////////////////////////////////////

  opts = opts || {};
  var threshold = opts.threshold === 0 ? 0 : opts.threshold || 128;

  var hull;

  var w, h, row;

  // complain on no argument
  if (!imagedata) {
    throw new TypeError("No input");

  // arrays are our hull data format
  } else if (Array.isArray(imagedata)) {
    hull = imagedata;

  // if we've gotten something that doesn't resemble image data
  } else if (!imagedata.data) {
    // if we can't get image data from it
    if (!(imagedata.getImageData && imagedata.canvas)) {
      // if we can get a context from it
      if (imagedata.getContext) {
        // try getting a 2d rendering context
        imagedata = imagedata.getContext('2d');
      // otherwise, don't even bother trying
      } else {
        throw new TypeError("Can't get image data or hull from input");
      }
    }
    // Try getting image data from a render context
    imagedata = imagedata.getImageData(0, 0,
      imagedata.canvas.width, imagedata.canvas.height);
  }
  // If we're going to calculate the hull
  if (!hull) {
    w = imagedata.width;
    h = imagedata.height;

    // Save a row value if we're going to evaluate thresholds
    if (threshold > 0) {
      row = 4 * w;
    // Shortcut area if not actually hulling
    } else {
      return opts.returnHull ? [[0,0], [w,0], [w,h], [0,h]] : w*h;
    }
  }

  // convex hull calculation ///////////////////////////////////////////////

  function loopSide(increment) {
    var chain = [];
    var link = [0,0];

    function moveWouldBeCounterClockwise() {
      if (chain.length > 1) {
        var o = chain[chain.length - 2];
        var ox = o[0], oy = o[1];
        var a = chain[chain.length - 1];
        return ((a[0] - ox) * (link[1] - oy) -
                (a[1] - oy) * (link[0] - ox)) <= 0;
      } else return false;
    }

    var xstart, xlimit, ystart, ylimit, nedge, fedge;

    if (increment > 0) {
      xstart = 0;   ystart = 0;   nedge = 0;
      xlimit = w;   ylimit = h;   fedge = 1;
    } else {
      xstart = w-1; ystart = h-1; nedge = 1;
      xlimit = 1;   ylimit = 1;   fedge = 0;
    }

    var lastWasCloser = false;

    for (var ix = xstart; ix * increment < xlimit; ix += increment) {
      for (var iy = ystart; iy * increment < ylimit; iy += increment) {

        // If we've hit this column's first opaque value
        if (imagedata.data[iy * row + ix*4 + 3] >= threshold) {
          // if there are at least two points to compare with
          if (chain.length > 1) {
            // if we're closer to our probe edge than the last pixel
            if ((iy + nedge) * increment < link[1] * increment) {
              // use the nearer-to-start corner of this pixel
              link[0] = ix + nedge;
              // note that we got closer
              lastWasCloser = true;
            // if we're further from our probe edge than the last pixel
            } else {
              // if the last pixel used only the near-to-start edge
              if (lastWasCloser) {
                // push the far-from-start corner of the apex pixel
                chain.push([link[0]+increment, link[1]]);
                // note that we got farther
                lastWasCloser = false;
              }
              // use the far-from-start corner of this pixel
              link[0] = ix + fedge;
            }
            // note the edge that we're colliding with
            link[1] = iy + nedge;
            // reduce prior concavities
            while (moveWouldBeCounterClockwise()) {
               chain.pop();
            }
            // add the new furthest-along point
            chain.push(link.slice());
          // if there aren't nodes on the chain yet
          } else {
            // Record current height
            link[1] = iy + nedge;
            // Push both corners of this pixel on this edge
            chain.push([ix + nedge, link[1]], [ix + fedge, link[1]]);
          }

          // start the next column
          break;
        }
      }
    }

    // if the last pixel used only the near-to-start corner
    if (lastWasCloser) {
      // push the far-from-start corner of the last pixel
      chain.push([link[0]+increment, link[1]]);
    }

    return chain;
  }

  // if we didn't get the hull as our input, calculate the hull
  if (!hull) hull = loopSide(1).concat(loopSide(-1));

  // allow for early hull return (mostly for demo / debugging)
  if (opts.returnHull) return hull;

  // area calculation //////////////////////////////////////////////////////

  // if no opaque pixels were found, the area is zero
  if (hull.length == 0) return 0;

  // push wraparound vertex
  hull.push(hull[0], hull[1]);

  var area = 0;
  for (var i = 1; i < hull.length-2; i++) {
    area += hull[i][0] * (hull[i+1][1] - hull[i-1][1]);
  }
  return area /= 2;
}
<commit_msg>Fix area calculation not taking the last vertex into account<commit_after>/* global CanvasRenderingContext2D */

function chachacat(imagedata, opts) {

  // image data helpers ////////////////////////////////////////////////////

  opts = opts || {};
  var threshold = opts.threshold === 0 ? 0 : opts.threshold || 128;

  var hull;

  var w, h, row;

  // complain on no argument
  if (!imagedata) {
    throw new TypeError("No input");

  // arrays are our hull data format
  } else if (Array.isArray(imagedata)) {
    hull = imagedata;

  // if we've gotten something that doesn't resemble image data
  } else if (!imagedata.data) {
    // if we can't get image data from it
    if (!(imagedata.getImageData && imagedata.canvas)) {
      // if we can get a context from it
      if (imagedata.getContext) {
        // try getting a 2d rendering context
        imagedata = imagedata.getContext('2d');
      // otherwise, don't even bother trying
      } else {
        throw new TypeError("Can't get image data or hull from input");
      }
    }
    // Try getting image data from a render context
    imagedata = imagedata.getImageData(0, 0,
      imagedata.canvas.width, imagedata.canvas.height);
  }
  // If we're going to calculate the hull
  if (!hull) {
    w = imagedata.width;
    h = imagedata.height;

    // Save a row value if we're going to evaluate thresholds
    if (threshold > 0) {
      row = 4 * w;
    // Shortcut area if not actually hulling
    } else {
      return opts.returnHull ? [[0,0], [w,0], [w,h], [0,h]] : w*h;
    }
  }

  // convex hull calculation ///////////////////////////////////////////////

  function loopSide(increment) {
    var chain = [];
    var link = [0,0];

    function moveWouldBeCounterClockwise() {
      if (chain.length > 1) {
        var o = chain[chain.length - 2];
        var ox = o[0], oy = o[1];
        var a = chain[chain.length - 1];
        return ((a[0] - ox) * (link[1] - oy) -
                (a[1] - oy) * (link[0] - ox)) <= 0;
      } else return false;
    }

    var xstart, xlimit, ystart, ylimit, nedge, fedge;

    if (increment > 0) {
      xstart = 0;   ystart = 0;   nedge = 0;
      xlimit = w;   ylimit = h;   fedge = 1;
    } else {
      xstart = w-1; ystart = h-1; nedge = 1;
      xlimit = 1;   ylimit = 1;   fedge = 0;
    }

    var lastWasCloser = false;

    for (var ix = xstart; ix * increment < xlimit; ix += increment) {
      for (var iy = ystart; iy * increment < ylimit; iy += increment) {

        // If we've hit this column's first opaque value
        if (imagedata.data[iy * row + ix*4 + 3] >= threshold) {
          // if there are at least two points to compare with
          if (chain.length > 1) {
            // if we're closer to our probe edge than the last pixel
            if ((iy + nedge) * increment < link[1] * increment) {
              // use the nearer-to-start corner of this pixel
              link[0] = ix + nedge;
              // note that we got closer
              lastWasCloser = true;
            // if we're further from our probe edge than the last pixel
            } else {
              // if the last pixel used only the near-to-start edge
              if (lastWasCloser) {
                // push the far-from-start corner of the apex pixel
                chain.push([link[0]+increment, link[1]]);
                // note that we got farther
                lastWasCloser = false;
              }
              // use the far-from-start corner of this pixel
              link[0] = ix + fedge;
            }
            // note the edge that we're colliding with
            link[1] = iy + nedge;
            // reduce prior concavities
            while (moveWouldBeCounterClockwise()) {
               chain.pop();
            }
            // add the new furthest-along point
            chain.push(link.slice());
          // if there aren't nodes on the chain yet
          } else {
            // Record current height
            link[1] = iy + nedge;
            // Push both corners of this pixel on this edge
            chain.push([ix + nedge, link[1]], [ix + fedge, link[1]]);
          }

          // start the next column
          break;
        }
      }
    }

    // if the last pixel used only the near-to-start corner
    if (lastWasCloser) {
      // push the far-from-start corner of the last pixel
      chain.push([link[0]+increment, link[1]]);
    }

    return chain;
  }

  // if we didn't get the hull as our input, calculate the hull
  if (!hull) hull = loopSide(1).concat(loopSide(-1));

  // allow for early hull return (mostly for demo / debugging)
  if (opts.returnHull) return hull;

  // area calculation //////////////////////////////////////////////////////

  // if no opaque pixels were found, the area is zero
  if (hull.length == 0) return 0;

  // push wraparound vertex
  hull.push(hull[0], hull[1]);

  var area = 0;
  for (var i = 1; i < hull.length - 1; i++) {
    area += hull[i][0] * (hull[i+1][1] - hull[i-1][1]);
  }
  return area /= 2;
}
<|endoftext|>