<commit_before>////////////////////////////////////////////////////////////////////////////////
/// A JS implementation of Raft
/// by Max Neunhöffer
/// Copyright 2014, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

// The following function is executed regularly, it does not have
// access to anything in the Foxx app except the collections via the
// names stateCollName and logCollName which are assigned as variables
// in the context where this function is parsed.

function heartBeat() {
  var db = require("internal").db;
  var stateColl = db._collection(stateCollName);
  var logColl = db._collection(logCollName);
  var state = stateColl.document("root");
}

(function () {
  "use strict";
  var Foxx = require("org/arangodb/foxx"),
      ArangoError = require("org/arangodb").ArangoError,
      log = require("console").log,
      controller = new Foxx.Controller(applicationContext),
      internal = require("internal");

  var logCollName = applicationContext.collectionName("log");
  var logColl = applicationContext.collection("log");
  var stateCollName = applicationContext.collectionName("state");
  var stateColl = applicationContext.collection("state");

  // Get an entry:
  controller.get('/getState', function (req, res) {
    log("getState called");
    var d;
    try {
      d = stateColl.document("root");
      res.json(d);
    }
    catch (e) {
      res.json(e);
    }
  });

  // Answer to request vote RPC:
  controller.put('/requestVote', function (req, res) {
    var body = req.body();
    log("requestVote called: " + JSON.stringify(body));
  } );

  // Answer to append to log RPC:
  controller.put('/appendLog', function (req, res) {
    var body = req.body();
    log("appendLog called: " + JSON.stringify(body));
  } );

  // Register a new follower in BOOT phase, as soon as the cluster is
  // complete we start:
  controller.post('/newFollower', function (req, res) {
    var body = req.body();
    log("newFollower called: " + JSON.stringify(body));
  } );

  try {
    internal.unregisterTask("raft-heartbeat");
  }
  catch (e) {
  }
  require("internal").registerTask( {
    id: "raft-heartbeat",
    name: "raft-heartbeat",
    offset: 0,
    period: 1.0,  // every second
    command: "var stateCollName = '" + stateCollName + "';" +
             "var logCollName = '" + logCollName + "';" +
             "(" + heartBeat.toString() + ")();"
  } );
  log("Have registered task raft-heartbeat");
}());

<commit_msg>Use Foxx queues for heartbeat.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// A JS implementation of Raft
/// by Max Neunhöffer
/// Copyright 2014, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

// The following function is executed regularly, it does not have
// access to anything in the Foxx app except the collections via the
// names stateCollName and logCollName which are assigned as variables
// in the context where this function is parsed.

(function () {
  "use strict";
  var Foxx = require("org/arangodb/foxx"),
      ArangoError = require("org/arangodb").ArangoError,
      log = require("console").log,
      controller = new Foxx.Controller(applicationContext),
      internal = require("internal");

  var logCollName = applicationContext.collectionName("log");
  var logColl = applicationContext.collection("log");
  var stateCollName = applicationContext.collectionName("state");
  var stateColl = applicationContext.collection("state");

  var raftQueue = Foxx.queues.create("raft");

  // Get an entry:
  controller.get('/getState', function (req, res) {
    log("getState called");
    var d;
    try {
      d = stateColl.document("root");
      res.json(d);
    }
    catch (e) {
      res.json(e);
    }
  });

  // Answer to request vote RPC:
  controller.put('/requestVote', function (req, res) {
    var body = req.body();
    log("requestVote called: " + JSON.stringify(body));
  } );

  // Answer to append to log RPC:
  controller.put('/appendLog', function (req, res) {
    var body = req.body();
    log("appendLog called: " + JSON.stringify(body));
  } );

  // Register a new follower in BOOT phase, as soon as the cluster is
  // complete we start:
  controller.post('/newServer', function (req, res) {
    var body = req.body();
    log("newFollower called: " + JSON.stringify(body));
    var state = stateColl.document("root");
    state.servers.push(body.endpoint);
    stateColl.replace(state, state);
    res.json({error:false});
  } );

  // Start service:
  controller.post('/start', function (req, res) {
    var body = req.body();
    log("start called: " + JSON.stringify(body));
    var state = stateColl.document("root");
    state.state = "FOLLOWER";
    stateColl.replace(state, state);
    res.json({error:false});
  } );

  var heartBeat = function (number) {
    var state = stateColl.document("root");
    log("Heartbeat "+number+":" + JSON.stringify(state));
    raftQueue.push("raft-heartbeat", number+1,
                   { delayUntil: Date.now() + 3000 });
  };

  Foxx.queues.registerJobType("raft-heartbeat", heartBeat);
  log("Cleaning out queue...");
  var l = raftQueue.all();
  for (var i = 0; i < l.length; i++) {
    raftQueue.delete(l[i]);
  }
  log("Scheduling job 1");
  raftQueue.push("raft-heartbeat", 1, { delayUntil: Date.now() + 3000 });
}());

<|endoftext|>


<commit_before>// main.js
var loc = '../';
require.config({
    baseUrl: loc + 'js',
    paths: {
        jquery: loc + 'bower_components/jquery/dist/jquery',
        q: loc + 'bower_components/q/q',
        underscore: loc + 'bower_components/underscore/underscore',
        bootstrap: loc + 'bower_components/bootstrap/dist/js/bootstrap.min',
        react: loc + 'bower_components/react/react-with-addons',
        jschannel: loc + 'bower_components/jschannel/src/jschannel',
        imjs:  loc + 'bower_components/imjs/js/im'
    },
    shim: {
        backbone: {
            deps: [
                'underscore',
                'jquery'
            ],
            exports: 'Backbone'
        },
        bootstrap: {
          deps: ['jquery'],
          exports: '$'
        },
        jschannel: {
          exports: 'Channel'
        },
        underscore: {
            deps: [
            ],
            exports: '_'
        },
        react: {
            exports: 'React',
        }
    }
});

require(['react', 'imjs', './analysis-tools', 'jschannel', 'bootstrap'], function (React, imjs, View, Channel) {
    'use strict';

    var chan = Channel.build({
      window: window.parent,
      origin: '*',
      scope: 'CurrentStep'
    });

    chan.bind('init', function (trans, params) {

      var listName = params.listName;
      var serviceArgs = params.service;
      var rootNode = document.body;
      var service = imjs.Service.connect(serviceArgs);

      service.fetchList(listName).then(function showList (list) {
        var listView = new View({
          service: service,
          list: list
        });
        React.renderComponent(listView, rootNode);
      });
    });

    // Inherit parent styles by importing stylesheets.
    var oHead = document.getElementsByTagName("head")[0];
    var arrStyleSheets = window.parent.document.getElementsByTagName("link");
    for (var i = 0; i < arrStyleSheets.length; i++)
        oHead.appendChild(arrStyleSheets[i].cloneNode(true));
});
<commit_msg>This worked for main.js<commit_after>// main.js
var loc = '../';
require.config({
    baseUrl: 'js',
    paths: {
        jquery: loc + 'bower_components/jquery/dist/jquery',
        q: loc + 'bower_components/q/q',
        underscore: loc + 'bower_components/underscore/underscore',
        bootstrap: loc + 'bower_components/bootstrap/dist/js/bootstrap.min',
        react: loc + 'bower_components/react/react-with-addons',
        jschannel: loc + 'bower_components/jschannel/src/jschannel',
        imjs:  loc + 'bower_components/imjs/js/im'
    },
    shim: {
        backbone: {
            deps: [
                'underscore',
                'jquery'
            ],
            exports: 'Backbone'
        },
        bootstrap: {
          deps: ['jquery'],
          exports: '$'
        },
        jschannel: {
          exports: 'Channel'
        },
        underscore: {
            deps: [
            ],
            exports: '_'
        },
        react: {
            exports: 'React',
        }
    }
});

require(['react', 'imjs', './analysis-tools', 'jschannel', 'bootstrap'], function (React, imjs, View, Channel) {
    'use strict';

    var chan = Channel.build({
      window: window.parent,
      origin: '*',
      scope: 'CurrentStep'
    });

    chan.bind('init', function (trans, params) {

      var listName = params.listName;
      var serviceArgs = params.service;
      var rootNode = document.body;
      var service = imjs.Service.connect(serviceArgs);

      service.fetchList(listName).then(function showList (list) {
        var listView = new View({
          service: service,
          list: list
        });
        React.renderComponent(listView, rootNode);
      });
    });

    // Inherit parent styles by importing stylesheets.
    var oHead = document.getElementsByTagName("head")[0];
    var arrStyleSheets = window.parent.document.getElementsByTagName("link");
    for (var i = 0; i < arrStyleSheets.length; i++)
        oHead.appendChild(arrStyleSheets[i].cloneNode(true));
});
<|endoftext|>


<commit_before>/*
 * raja browser client
 */
(function() {

window.raja = new Raja();

loadScript('/socket.io/socket.io.js', function(err) {
	if (err) throw err;
	var proto = io.Manager.prototype;
	raja._on = proto.on;
	raja._emit = proto.emit;
	raja.off = proto.off;
	raja.listeners = proto.listeners;
	raja.ready();
});

function Raja() {
	this.delays = [];
	this.base = document.getElementById('raja-io').content;
}

Raja.prototype.delay = function(url, query, listener) {
	this.delays.push([url, query, listener]);
	return this;
};

Raja.prototype.ready = function() {
	this.url = absolute(document.location, '.');
	// work around webkit bug https://bugs.webkit.org/show_bug.cgi?id=4363
	var lastMod = Date.parse(document.lastModified);
	var now = new Date();
	var diff = (new Date(now.toLocaleString())).getTimezoneOffset() - now.getTimezoneOffset();
	if (!diff) diff = now.getTimezoneOffset() * 60000;
	else diff = 0;
	this.mtime = lastMod - diff;

	if (isNaN(this.mtime)) this.mtime = Date.now();
	this.resources = {};
	var links = document.head.querySelectorAll('link[rel="resource"]');
	for (var i=0; i < links.length; i++) {
		var link = links.item(i);
		this.resources[link.href] = {url: link.href, mtime: this.mtime};
	}
	var list = this.delays;
	delete this.delays;
	for (var i=0; i < list.length; i++) {
		this.on.apply(this, list[i]);
	}
};

Raja.prototype.link = function(url) {
	var link = $('head > link[rel="resource"][href="'+url+'"]');
	if (link) return;
	link = document.createElement('link');
	link.rel = "resource";
	link.href = url;
	var tn = document.createTextNode("\n");
	document.head.insertBefore(link, document.head.firstChild);
	document.head.insertBefore(tn, link);
};

Raja.prototype.emit = function(what) {
	var args = Array.prototype.slice.call(arguments, 0);
	try {
		this._emit.apply(this, args);
	} catch(e) {
		console.error(e);
	}
	if (what == "error" && this.listeners("error").length == 0) {
		args.shift();
		console.error.apply(console, args);
	}
};

Raja.prototype.on = function(url, query, listener) {
	if (!listener && typeof query == "function") {
		listener = query;
		query = null;
	}
	if (!this.resources) {
		return this.delay(url, query, listener);
	}
	if (!this.io) this.setio();
	var self = this;
	if (url == "error") return this._on(url, listener);
	var plistener = function() {
		try {
			listener.apply(null, Array.prototype.slice.call(arguments));
		} catch(e) {
			self.emit('error', e);
		}
	};
	url = absolute(document.location, url);
	this._on(url, plistener);
	var resources = this.resources;
	var resource = resources[url];
	if (!resource) resource = resources[url] = {url: url, requests: {}};
	if (resource.error) return;

	var xurl = urlQuery(url, query);

	(function(next) {
		var reqs = resource.requests;
		var queues = resource.queues || {};
		if (reqs[xurl] !== undefined) {
			listener(reqs[xurl].data, {
				method:"get",
				url: url,
				query: reqs[xurl].query,
				mtime: resource.mtime
			});
			return next();
		} else if (resource.mtime !== undefined) {
			// resource merged, just join it
			return next();
		} else if (queues[xurl]) {
			// resource is currently loading
			queues.push(listener);
			return;
		}
		// resource has not been loaded, is not loading. Proceed
		queues[xurl] = [listener];
		var xhr = Raja.prototype.GET(xurl, function(err, obj) {
			if (err) {
				resource.error = err;
				return next(err);
			}
			var mtime = tryDate(xhr.getResponseHeader("Last-Modified"));
			self.link(resource.url);
			resource.mtime = mtime;
			reqs[xurl] = {
				data: obj,
				query: query
			};
			var queue = queues[xurl];
			for (var i=0; i < queue.length; i++) {
				try {
					queue[i](obj, {
						method:"get",
						url: url,
						query: query,
						mtime: mtime
					});
				} catch(e) {
					console.error(e);
				}
			}
			delete queues[xurl];
			next();
		});
	})(function(err) {
		if (err) self.emit('error', err);
	});
	return this;
};

Raja.prototype.setio = function() {
	this.io = io(this.base);
	var self = this;
	this.io.on('reconnect_failed', function(err) {
		if (err) self.emit('error', err);
	});
	this.io.emit('join', {
		room: this.url,
		mtime: this.mtime
	});

	this.io.on('message', function(msg) {
		if (!msg.url) return;
		var data = msg.data;
		if (data) delete msg.data;
		var fresh = msg.mtime > self.mtime;
		if (fresh) {
			self.mtime = msg.mtime;
		}
		var parents = msg.parents;
		parents.unshift(msg.url);
		for (var i=0; i < parents.length; i++) {
			var url = parents[i];
			var resource = self.resources[url];
			if (resource) {
				if (!resource.mtime || msg.mtime > resource.mtime) resource.mtime = msg.mtime;
				self.emit(msg.url, data, msg);
			} else if (fresh && url != self.url) {
				// some dependency that isn't a resource - a static file ? - has changed
			}
		}
	});
};

function absolute(loc, url) {
	if (/^https?/i.test(url)) return url;
	var path = loc.pathname;
	if (url.indexOf('..') == 0) {
		path = path.split('/');
		path.pop();
		url = path.join('/') + url.substring(2);
	} else if (url == '.') {
		 return loc.href;
	} else if (url.indexOf('.') == 0) {
		url = path + url.substring(1);
	} else if (url.indexOf('/') != 0) {
		var base = path.split('/');
		base.pop();
		base = base.join('/');
		url = base + '/' + url;
	}
	url = loc.protocol + '//' + loc.host + url;
	return url;
}
Raja.prototype.absolute = absolute;

function urlParams(url, params) {
	if (!params) return url;
	return url.replace(/\/:(\w+)/g, function(str, name) {
		var val = params[name];
		if (val != null) {
			delete params[name];
			return '/' + val;
		} else {
			return '/:' + name;
		}
	});
}
Raja.prototype.urlParams = urlParams;

function urlQuery(url, query) {
	if (!query) return url;
	var comps = [];
	for (var k in query) comps.push[{key: k, val: query[k]}];
	comps.sort(function(a, b) {
		if (a.key < b.key) return 1;
		else if (a.key > b.key) return -1;
		else return 0;
	});
	var str, list = [];
	for (var i=0; i < comps.length; i++) {
		str = encodeURIComponent(comps[i].key);
		if (comps[i].val != null) str += '=' + encodeURIComponent(comps[i].val);
		list.push(str);
	}
	if (list.length) {
		if (url.indexOf('?') > 0) url += '&';
		else url += '?';
		url += list.join('&');
	}
	return url;
}
Raja.prototype.urlQuery = urlQuery;

for (var method in {GET:1, PUT:1, POST:1, DELETE:1}) {
	Raja.prototype[method] = (function(method) { return function(url, query, body, cb) {
		if (!cb) {
			if (typeof body == "function") {
				cb = body;
				body = null;
			} else if (typeof query == "function") {
				cb = query;
				query = null;
			} else {
				cb = function(err) {
					if (err) console.error(err);
				};
			}
		}
		// consume parameters from query object
		url = urlParams(url, query);
		url = absolute(document.location, url);
		if (/^(HEAD|GET|COPY)$/i.test(method)) {
			query = query || body || {};
		} else {
			// give priority to body
			if (!body && query) {
				body = query;
				query = null;
			}
			if (body) body = JSON.stringify(body);
		}
		url = urlQuery(url, query);
		var xhr = new XMLHttpRequest();
		xhr.open(method, url, true);
		xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
		xhr.onreadystatechange = function (e) {
			if (xhr.readyState == 4) {
				var code = xhr.status;
				var response = tryJSON(xhr.responseText);
				if (code >= 200 && code < 400) {
					cb(null, response);
				} else {
					var err = new Error(response);
					err.code = code;
					cb(err);
				}
			}
		};
		xhr.send(body);
		return xhr;
	};})(method);
}

function loadScript(url, cb) {
	var script = document.createElement("script");
	script.async = true;
	script.type = 'text/javascript';
	script.charset = 'utf-8';
	script.src = url;
	function done() {
		script.onload = null;
		script.onerror = null;
		if (script.parentNode) {
			script.parentNode.removeChild(script);
		}
		script = null;
	}
	script.onload = function() {
		done();
		cb();
	};
	script.onerror = function(e) {
		done();
		cb(e);
	};
	// Circumvent IE6 bugs with base elements
	document.head.insertBefore(script, document.head.firstChild);
}
Raja.prototype.loadScript = loadScript;

function tryJSON(txt) {
	var obj;
	try {
		obj = JSON.parse(txt);
	} catch(e) {
		return txt;
	}
	return obj;
}

function tryDate(txt) {
	if (!txt) return;
	var date = new Date(txt);
	var time = date.getTime();
	if (isNaN(time)) return;
	else return time;
}

function $(str) {
	return document.querySelector(str);
}

})();
<commit_msg>Typo in urlQuery<commit_after>/*
 * raja browser client
 */
(function() {

window.raja = new Raja();

loadScript('/socket.io/socket.io.js', function(err) {
	if (err) throw err;
	var proto = io.Manager.prototype;
	raja._on = proto.on;
	raja._emit = proto.emit;
	raja.off = proto.off;
	raja.listeners = proto.listeners;
	raja.ready();
});

function Raja() {
	this.delays = [];
	this.base = document.getElementById('raja-io').content;
}

Raja.prototype.delay = function(url, query, listener) {
	this.delays.push([url, query, listener]);
	return this;
};

Raja.prototype.ready = function() {
	this.url = absolute(document.location, '.');
	// work around webkit bug https://bugs.webkit.org/show_bug.cgi?id=4363
	var lastMod = Date.parse(document.lastModified);
	var now = new Date();
	var diff = (new Date(now.toLocaleString())).getTimezoneOffset() - now.getTimezoneOffset();
	if (!diff) diff = now.getTimezoneOffset() * 60000;
	else diff = 0;
	this.mtime = lastMod - diff;

	if (isNaN(this.mtime)) this.mtime = Date.now();
	this.resources = {};
	var links = document.head.querySelectorAll('link[rel="resource"]');
	for (var i=0; i < links.length; i++) {
		var link = links.item(i);
		this.resources[link.href] = {url: link.href, mtime: this.mtime};
	}
	var list = this.delays;
	delete this.delays;
	for (var i=0; i < list.length; i++) {
		this.on.apply(this, list[i]);
	}
};

Raja.prototype.link = function(url) {
	var link = $('head > link[rel="resource"][href="'+url+'"]');
	if (link) return;
	link = document.createElement('link');
	link.rel = "resource";
	link.href = url;
	var tn = document.createTextNode("\n");
	document.head.insertBefore(link, document.head.firstChild);
	document.head.insertBefore(tn, link);
};

Raja.prototype.emit = function(what) {
	var args = Array.prototype.slice.call(arguments, 0);
	try {
		this._emit.apply(this, args);
	} catch(e) {
		console.error(e);
	}
	if (what == "error" && this.listeners("error").length == 0) {
		args.shift();
		console.error.apply(console, args);
	}
};

Raja.prototype.on = function(url, query, listener) {
	if (!listener && typeof query == "function") {
		listener = query;
		query = null;
	}
	if (!this.resources) {
		return this.delay(url, query, listener);
	}
	if (!this.io) this.setio();
	var self = this;
	if (url == "error") return this._on(url, listener);
	var plistener = function() {
		try {
			listener.apply(null, Array.prototype.slice.call(arguments));
		} catch(e) {
			self.emit('error', e);
		}
	};
	url = absolute(document.location, url);
	this._on(url, plistener);
	var resources = this.resources;
	var resource = resources[url];
	if (!resource) resource = resources[url] = {url: url, requests: {}};
	if (resource.error) return;

	var xurl = urlQuery(url, query);

	(function(next) {
		var reqs = resource.requests;
		var queues = resource.queues || {};
		if (reqs[xurl] !== undefined) {
			listener(reqs[xurl].data, {
				method:"get",
				url: url,
				query: reqs[xurl].query,
				mtime: resource.mtime
			});
			return next();
		} else if (resource.mtime !== undefined) {
			// resource merged, just join it
			return next();
		} else if (queues[xurl]) {
			// resource is currently loading
			queues.push(listener);
			return;
		}
		// resource has not been loaded, is not loading. Proceed
		queues[xurl] = [listener];
		var xhr = Raja.prototype.GET(xurl, function(err, obj) {
			if (err) {
				resource.error = err;
				return next(err);
			}
			var mtime = tryDate(xhr.getResponseHeader("Last-Modified"));
			self.link(resource.url);
			resource.mtime = mtime;
			reqs[xurl] = {
				data: obj,
				query: query
			};
			var queue = queues[xurl];
			for (var i=0; i < queue.length; i++) {
				try {
					queue[i](obj, {
						method:"get",
						url: url,
						query: query,
						mtime: mtime
					});
				} catch(e) {
					console.error(e);
				}
			}
			delete queues[xurl];
			next();
		});
	})(function(err) {
		if (err) self.emit('error', err);
	});
	return this;
};

Raja.prototype.setio = function() {
	this.io = io(this.base);
	var self = this;
	this.io.on('reconnect_failed', function(err) {
		if (err) self.emit('error', err);
	});
	this.io.emit('join', {
		room: this.url,
		mtime: this.mtime
	});

	this.io.on('message', function(msg) {
		if (!msg.url) return;
		var data = msg.data;
		if (data) delete msg.data;
		var fresh = msg.mtime > self.mtime;
		if (fresh) {
			self.mtime = msg.mtime;
		}
		var parents = msg.parents;
		parents.unshift(msg.url);
		for (var i=0; i < parents.length; i++) {
			var url = parents[i];
			var resource = self.resources[url];
			if (resource) {
				if (!resource.mtime || msg.mtime > resource.mtime) resource.mtime = msg.mtime;
				self.emit(msg.url, data, msg);
			} else if (fresh && url != self.url) {
				// some dependency that isn't a resource - a static file ? - has changed
			}
		}
	});
};

function absolute(loc, url) {
	if (/^https?/i.test(url)) return url;
	var path = loc.pathname;
	if (url.indexOf('..') == 0) {
		path = path.split('/');
		path.pop();
		url = path.join('/') + url.substring(2);
	} else if (url == '.') {
		 return loc.href;
	} else if (url.indexOf('.') == 0) {
		url = path + url.substring(1);
	} else if (url.indexOf('/') != 0) {
		var base = path.split('/');
		base.pop();
		base = base.join('/');
		url = base + '/' + url;
	}
	url = loc.protocol + '//' + loc.host + url;
	return url;
}
Raja.prototype.absolute = absolute;

function urlParams(url, params) {
	if (!params) return url;
	return url.replace(/\/:(\w+)/g, function(str, name) {
		var val = params[name];
		if (val != null) {
			delete params[name];
			return '/' + val;
		} else {
			return '/:' + name;
		}
	});
}
Raja.prototype.urlParams = urlParams;

function urlQuery(url, query) {
	if (!query) return url;
	var comps = [];
	for (var k in query) comps.push({key: k, val: query[k]});
	comps.sort(function(a, b) {
		if (a.key < b.key) return 1;
		else if (a.key > b.key) return -1;
		else return 0;
	});
	var str, list = [];
	for (var i=0; i < comps.length; i++) {
		str = encodeURIComponent(comps[i].key);
		if (comps[i].val != null) str += '=' + encodeURIComponent(comps[i].val);
		list.push(str);
	}
	if (list.length) {
		if (url.indexOf('?') > 0) url += '&';
		else url += '?';
		url += list.join('&');
	}
	return url;
}
Raja.prototype.urlQuery = urlQuery;

for (var method in {GET:1, PUT:1, POST:1, DELETE:1}) {
	Raja.prototype[method] = (function(method) { return function(url, query, body, cb) {
		if (!cb) {
			if (typeof body == "function") {
				cb = body;
				body = null;
			} else if (typeof query == "function") {
				cb = query;
				query = null;
			} else {
				cb = function(err) {
					if (err) console.error(err);
				};
			}
		}
		// consume parameters from query object
		url = urlParams(url, query);
		url = absolute(document.location, url);
		if (/^(HEAD|GET|COPY)$/i.test(method)) {
			query = query || body || {};
		} else {
			// give priority to body
			if (!body && query) {
				body = query;
				query = null;
			}
			if (body) body = JSON.stringify(body);
		}
		url = urlQuery(url, query);
		var xhr = new XMLHttpRequest();
		xhr.open(method, url, true);
		xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
		xhr.onreadystatechange = function (e) {
			if (xhr.readyState == 4) {
				var code = xhr.status;
				var response = tryJSON(xhr.responseText);
				if (code >= 200 && code < 400) {
					cb(null, response);
				} else {
					var err = new Error(response);
					err.code = code;
					cb(err);
				}
			}
		};
		xhr.send(body);
		return xhr;
	};})(method);
}

function loadScript(url, cb) {
	var script = document.createElement("script");
	script.async = true;
	script.type = 'text/javascript';
	script.charset = 'utf-8';
	script.src = url;
	function done() {
		script.onload = null;
		script.onerror = null;
		if (script.parentNode) {
			script.parentNode.removeChild(script);
		}
		script = null;
	}
	script.onload = function() {
		done();
		cb();
	};
	script.onerror = function(e) {
		done();
		cb(e);
	};
	// Circumvent IE6 bugs with base elements
	document.head.insertBefore(script, document.head.firstChild);
}
Raja.prototype.loadScript = loadScript;

function tryJSON(txt) {
	var obj;
	try {
		obj = JSON.parse(txt);
	} catch(e) {
		return txt;
	}
	return obj;
}

function tryDate(txt) {
	if (!txt) return;
	var date = new Date(txt);
	var time = date.getTime();
	if (isNaN(time)) return;
	else return time;
}

function $(str) {
	return document.querySelector(str);
}

})();
<|endoftext|>


<commit_before>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @emails react-core
 */

'use strict';

var React;
var ReactNoop;

describe('ReactIncremental', function() {
  beforeEach(function() {
    React = require('React');
    ReactNoop = require('ReactNoop');
    spyOn(console, 'log');
  });

  it('should render a simple component', function() {

    function Bar() {
      return
Hello World
;
    }

    function Foo() {
      return <Bar isBar={true} />;
    }

    ReactNoop.render(<Foo />);
    ReactNoop.flush();

  });

  it('should render a simple component, in steps if needed', function() {

    var barCalled = false;
    function Bar() {
      barCalled = true;
      return
Hello World
;
    }

    var fooCalled = false;
    function Foo() {
      fooCalled = true;
      return [
        <Bar isBar={true} />,
        <Bar isBar={true} />,
      ];
    }

    ReactNoop.render(<Foo />);
    expect(fooCalled).toBe(false);
    expect(barCalled).toBe(false);
    // Do one step of work.
    ReactNoop.flushLowPri(7);
    expect(fooCalled).toBe(true);
    expect(barCalled).toBe(false);
    // Do the rest of the work.
    ReactNoop.flushLowPri(50);
    expect(fooCalled).toBe(true);
    expect(barCalled).toBe(true);
  });

  it('updates a previous render', function() {

    var ops = [];

    function Header() {
      ops.push('Header');
      return
Hi
;
    }

    function Content(props) {
      ops.push('Content');
      return
{props.children}
;
    }

    function Footer() {
      ops.push('Footer');
      return Bye;
    }

    var header = ;
    var footer = ;

    function Foo(props) {
      ops.push('Foo');
      return (

          {header}
          <Content>{props.text}</Content>
          {footer}

      );
    }

    ReactNoop.render(<Foo text="foo" />);
    ReactNoop.flush();

    expect(ops).toEqual(['Foo', 'Header', 'Content', 'Footer']);

    ops = [];

    ReactNoop.render(<Foo text="bar" />);
    ReactNoop.flush();

    // Since this is an update, it should bail out and reuse the work from
    // Header and Content.
    expect(ops).toEqual(['Foo', 'Content']);

  });

});
<commit_msg>Test ability to abort work<commit_after>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @emails react-core
 */

'use strict';

var React;
var ReactNoop;

describe('ReactIncremental', function() {
  beforeEach(function() {
    React = require('React');
    ReactNoop = require('ReactNoop');
    spyOn(console, 'log');
  });

  it('should render a simple component', function() {

    function Bar() {
      return
Hello World
;
    }

    function Foo() {
      return <Bar isBar={true} />;
    }

    ReactNoop.render(<Foo />);
    ReactNoop.flush();

  });

  it('should render a simple component, in steps if needed', function() {

    var barCalled = false;
    function Bar() {
      barCalled = true;
      return
Hello World
;
    }

    var fooCalled = false;
    function Foo() {
      fooCalled = true;
      return [
        <Bar isBar={true} />,
        <Bar isBar={true} />,
      ];
    }

    ReactNoop.render(<Foo />);
    expect(fooCalled).toBe(false);
    expect(barCalled).toBe(false);
    // Do one step of work.
    ReactNoop.flushLowPri(7);
    expect(fooCalled).toBe(true);
    expect(barCalled).toBe(false);
    // Do the rest of the work.
    ReactNoop.flushLowPri(50);
    expect(fooCalled).toBe(true);
    expect(barCalled).toBe(true);
  });

  it('updates a previous render', function() {

    var ops = [];

    function Header() {
      ops.push('Header');
      return
Hi
;
    }

    function Content(props) {
      ops.push('Content');
      return
{props.children}
;
    }

    function Footer() {
      ops.push('Footer');
      return Bye;
    }

    var header = ;
    var footer = ;

    function Foo(props) {
      ops.push('Foo');
      return (

          {header}
          <Content>{props.text}</Content>
          {footer}

      );
    }

    ReactNoop.render(<Foo text="foo" />);
    ReactNoop.flush();

    expect(ops).toEqual(['Foo', 'Header', 'Content', 'Footer']);

    ops = [];

    ReactNoop.render(<Foo text="bar" />);
    ReactNoop.flush();

    // Since this is an update, it should bail out and reuse the work from
    // Header and Content.
    expect(ops).toEqual(['Foo', 'Content']);

  });

  it('can cancel partially rendered work and restart', function() {

    var ops = [];

    function Bar(props) {
      ops.push('Bar');
      return
{props.children}
;
    }

    function Foo(props) {
      ops.push('Foo');
      return (

          <Bar>{props.text}</Bar>
          <Bar>{props.text}</Bar>

      );
    }

    // Init
    ReactNoop.render(<Foo text="foo" />);
    ReactNoop.flush();

    ops = [];

    ReactNoop.render(<Foo text="bar" />);
    // Flush part of the work
    ReactNoop.flushLowPri(20);

    expect(ops).toEqual(['Foo', 'Bar']);

    ops = [];

    // This will abort the previous work and restart
    ReactNoop.render(<Foo text="baz" />);

    // Flush part of the new work
    ReactNoop.flushLowPri(20);

    expect(ops).toEqual(['Foo', 'Bar']);

    // Flush the rest of the work which now includes the low priority
    ReactNoop.flush(20);

    expect(ops).toEqual(['Foo', 'Bar', 'Bar']);

    // TODO: Test the ability for a subtree to resume if it has lower priority.

  });

});
<|endoftext|>


<commit_before>$(document).ready(function(){
  var keyword = "";
  var resultArea = $("#results");
  var searchBar = $("#searchBar");
  var searchButton = $(".glyphicon-search");
  var searchUrl = "https://en.wikipedia.org/w/api.php";
  var displayResults = function(){
    $.ajax({
      url: searchUrl,
      dataType: 'jsonp',
      data: {
        action: 'query',
        format: 'json',
        generator: 'search',
          gsrsearch: keyword,
          gsrnamespace: 0,
          gsrlimit: 10,
        prop:'extracts|pageimages',
          exchars: 200,
          exlimit: 'max',
          explaintext: true,
          exintro: true,
          piprop: 'thumbnail',
          pilimit: 'max',
          pithumbsize: 200
      },
      success: function(json){
        var results = json.query.pages;
        $.map(results, function(result){
          var elem1 = $('');
          var elem2 = $('
');
          elem2.append($('
').text(result.title));
          //if(result.thumbnail) elem.append($('').attr('width',150).attr('src',result.thumbnail.source));
          elem2.append($('
').text(result.extract));
          elem1.append(elem2);
          resultArea.append(elem1);
        });
      }
    });
  };
 /*
  searchBar.autocomplete({
        source: function (request, response) {
            $.ajax({
                url: searchUrl,
                dataType: 'jsonp',
                data: {
                    'action': "opensearch",
                    'format': "json",
                    'search': request.term
                },
                success: function (data) {
                    response(data[1]);
                }
            });
        }
    });
  */
  searchButton.click(function(){
    keyword = searchBar.val();
    resultArea.empty();
    $("#searchBox").animate({'padding-top':"0"}, 600);
    $(".container-fluid").animate({height:"30vh"}, 600);
    displayResults();
  });
});
<commit_msg>final commit<commit_after>$(document).ready(function(){
  var keyword = "";
  var resultArea = $("#results");
  var searchBar = $("#searchBar");
  var searchButton = $(".glyphicon-search");
  var searchUrl = "https://en.wikipedia.org/w/api.php";
  var displayResults = function(){
    $.ajax({
      url: searchUrl,
      dataType: 'jsonp',
      data: {
        action: 'query',
        format: 'json',
        generator: 'search',
          gsrsearch: keyword,
          gsrnamespace: 0,
          gsrlimit: 10,
        prop:'extracts|pageimages',
          exchars: 200,
          exlimit: 'max',
          explaintext: true,
          exintro: true,
          piprop: 'thumbnail',
          pilimit: 'max',
          pithumbsize: 200
      },
      success: function(json){
        var results = json.query.pages;
        $.map(results, function(result){
          var link = "http://en.wikipedia.org/?curid"+result.pageid;
          var elem1 = $('');
          var elem2 = $('
');
          elem2.append($('
').text(result.title));
          //if(result.thumbnail) elem.append($('').attr('width',150).attr('src',result.thumbnail.source));
          elem2.append($('
').text(result.extract));
          elem1.append(elem2);
          resultArea.append(elem1);
        });
        $("footer").append("
----x--------x----
");
      }
    });
  };
 /*
  searchBar.autocomplete({
        source: function (request, response) {
            $.ajax({
                url: searchUrl,
                dataType: 'jsonp',
                data: {
                    'action': "opensearch",
                    'format': "json",
                    'search': request.term
                },
                success: function (data) {
                    response(data[1]);
                }
            });
        }
    });
  */
  searchButton.click(function(){
    keyword = searchBar.val();
    resultArea.empty();
    displayResults();
    $("#searchBox").animate({'padding-top':"0"}, 600);
    $(".container-fluid").animate({height:"30vh"}, 600);
  });
});
<|endoftext|>


<commit_before>/*
 * This RESTlet covers the operations for interacting with Netsuite data.
*/

/*
 * Constants
*/
var METHOD_ACCESS = { 'initializeRecord': 'GET',
                      'loadRecord':       'GET',
                      'getSavedSearch':   'GET',
                      'searchRecords':    'POST',
                      'upsertRecords':    'POST',
                      'deleteRecords':    'POST' }

/*
 * **Utility Functions**
*/
function evalOperation(method, operation, request) {
    /*
     * Description: Evalutes the function call passed in by the client
     * Params:
     *              request: Request object from the REST client
     *
     * Return:      Passes up the values produced by API wrapper functions
    */
    if(method == METHOD_ACCESS[operation]) {
    	return(eval(operation + "(request);"));
    }
    else {
    	var errorMessage = "The function [" + operation + "] cannot be accessed via the REST method " +
    		               "requested. Methods allowed: [" + METHOD_ACCESS[operation] + "]";
    	throw new Error(errorMessage);
    }
}

function formatException(exception) {
	/*
	 * Description: Format an exception to send to the client
	 * Params:
	 *              exception: An exception object
	 *
	 * Return:      A serialized exception object
	*/
	var serializedException = [exception.name.toString(), exception.message];

	try {
		return(serializedException.concat([exception.getStackTrace()]));
	}
	catch(stack_fetch_error) {
		return(serializedException.concat([[stack_fetch_error.message]]));
	}
}

/*
 * Netsuite API Call Wrapper Functions
*/
function initializeRecord(request) {
	/*
	 * Description: Retrieves an initialized object with the given parameters
	 * Params:
	 *              request.recordType:      String matching a record type
	 *
	 * Return:      An instantiated object of the given type
	*/
	var recordType = request.record_type;

    return(nlapiCreateRecord(recordType));
}

function loadRecord(request) {
	/*
	 * Description: Retrieves a single record based on query fields
	 * Params:
	 *              recordType: String matching a record type
	 *              internalId: String matching the internal id of a record
	 *
	 * Return:      Record of given type with given id
	*/
	var recordType = request.record_type;
	var internalId = request.internal_id;

    return(nlapiLoadRecord(recordType, internalId));
}

function searchRecords(request) {
	/*
	 * Description: Runs a search based on the given field->value criteria
	 * Params:
	 *              request['record_type']:    The type of record to be covered by the search
	 *              request['search_filters']: List of fields with the values to be matched
	 *              request['return_columns']: List of the columns names to be returned for each record
	 *              request['batch_size']:     Size of the batch to be returned upon completion
	 *              request['start_id']:       Id to determine the lower bound of the batch, results
	 *                                         returned will all have ids greater than the value given
	 *
	 * Return:      A list of results with ids and columns to match the results filter
	*/
	var recordType         = request['record_type'];
	var batchSize          = request['batch_size'];
	var lowerBound         = request['start_id'];
	var rawFilters         = request['search_filters'];
	var rawColumns         = request['return_columns'];
	var searchFilters      = [new nlobjSearchFilter('internalidnumber', null, 'greaterthan', lowerBound)];
	var returnColumns      = [new nlobjSearchColumn('internalid', null).setSort()];
	var accumulatedResults = [];

	for(var filter in rawFilters) {
		searchFilters[searchFilters.length]  = new nlobjSearchFilter(filter, null,
																	 rawFilters[filter]['operator'],
																	 rawFilters[filter]['value']);
	}

	for(var column in rawColumns) {
		returnColumns[returnColumns.length]  = new nlobjSearchColumn(column,
																	 rawColumns[column]);
	}

	do {
		var tempItems = nlapiSearchRecord(recordType, null, searchFilters, returnColumns);
		if(tempItems) {
			lowerBound = tempItems[tempItems.length - 1].getId();
			accumulatedResults = accumulatedResults.concat(tempItems);
		}
	} while(tempItems && tempItems.length == 1000 && accumulatedResults.length < batchSize);

	return([accumulatedResults, lowerBound]);
}

function upsertRecords(request) {
	/*
	 * Description: Updates a record with given field values, can ignore validations if requested
	 * Params:
	 *              request['record_type']:      String matching a valid record type
	 *              request['record_data']:      Raw Record data
	 *              request['update_only']:      Boolean value that, if true, only allows updates to occur,
	 *                                           no new records will be created
	 *              request['do_sourcing']:      Boolean value to set sourcing (the hell is this?)
	 *              request['ignore_mandatory']: Boolean value to set ignoring of validations for mandatory fields
	 *
	 * Return:      Internal ids of the comitted records and errors for uncommitted records
	*/
	var recordType      = request['record_type'];
	var recordData      = request['record_data'];
    var updateOnly      = request['update_only'];
    var doSourcing      = request['do_sourcing'];
    var ignoreMandatory = request['ignore_mandatory'];
    var writeResults    = [];

    return writeResults.concat([nlapiSubmitRecord(recordData[0], doSourcing, ignoreMandatory)]);

    for(var record in recordData) {
    	try {
    		record = nlapiCreateRecord(recordType);
    		for(var field in record) {

    		}
    		writeResults.concat([nlapiSubmitRecord(record, doSourcing, ignoreMandatory)]);
    	}
		catch(write_exception) {
			writeResults.concat([formatException(write_exception)]);
		}
    }

    return writeResults;
}

function deleteRecords(request) {
	/*
	 * Description: Deletes a record of given type with given id
	 * Params:
	 *              request['recordType']: String matching a record type
	 *              request['record_ids']: Array of record ids
	 *
	 * Return:      True if successful, exception if not
	*/
	var recordType = request.record_type;
	var internalId = request.internal_id;

	nlapiDeleteRecord(recordType, internalId);
}

function getSavedSearch(request) {
    /*
     * Description: Retrieves results from a given saved search of the defined batch size rounded up to the next
     *              one thousand records
     * Params:
     *              request.search_id:   Id of the saved search to run
     *              request.record_type: String of the record type to fetch
     *              request.batch_size:  Size of the batch to be returned upon completion
     *              request.start_id:    Id to determine the lower bound of the batch, results
     *                                   returned will all have ids greater than the value given
     *
     * Return:      List of result rows with internal ids from the given start_id up through a count of the given
     *              batch size or next highest multiple of one thousand from the given batch size if the given size
     *              is not a multiple of one thousand
    */
    var searchId           = request.search_id;
    var recordType         = request.record_type;
    var batchSize          = request.batch_size;
    var lowerBound         = request.start_id;
    var accumulatedResults = [];
    var searchFilters      = [new nlobjSearchFilter('internalidnumber', null, 'greaterthan', lowerBound)];
    var returnColumns      = [new nlobjSearchColumn('internalid', null).setSort()];

    do {
        var tempItems = nlapiSearchRecord(recordType, searchId, searchFilters, returnColumns);
        if(tempItems) {
            lowerBound = tempItems[tempItems.length - 1].getId();
            accumulatedResults = accumulatedResults.concat(tempItems);
        }
    } while(tempItems && tempItems.length == 1000 && accumulatedResults.length < batchSize);

    return([accumulatedResults, lowerBound]);
}

/*
 * Handler Functions
*/
function getHandler(request) {
	/*
	 * Description: Method to handle requests over GET
	 * Params:
	 *              request: Request object from the REST client
	 *
	 * Return:      JSON response
    */
    try {
    	return(evalOperation('GET', request.operation, request))
    }
    catch(exception) {
    	return(formatException(exception));
    }
}

function postHandler(request) {
	/*
	 * Description: Method to handle requests over POST
	 * Params:
	 *              request: Request object from the REST client
	 *
	 * Return:      JSON response
    */
	try {
    	return(evalOperation('POST', request['operation'], request))
    }
    catch(exception) {
    	return(formatException(exception));
    }
}
<commit_msg>Upsert almost/kind actually works.<commit_after>/*
 * This RESTlet covers the operations for interacting with Netsuite data.
*/

/*
 * Constants
*/
var METHOD_ACCESS = { 'initializeRecord': 'GET',
                      'loadRecord':       'GET',
                      'getSavedSearch':   'GET',
                      'searchRecords':    'POST',
                      'upsertRecords':    'POST',
                      'deleteRecords':    'POST' }

/*
 * **Utility Functions**
*/
function evalOperation(method, operation, request) {
    /*
     * Description: Evalutes the function call passed in by the client
     * Params:
     *              request: Request object from the REST client
     *
     * Return:      Passes up the values produced by API wrapper functions
    */
    if(method == METHOD_ACCESS[operation]) {
    	return(eval(operation + "(request);"));
    }
    else {
    	var errorMessage = "The function [" + operation + "] cannot be accessed via the REST method " +
    		               "requested. Methods allowed: [" + METHOD_ACCESS[operation] + "]";
    	throw new Error(errorMessage);
    }
}

function formatException(exception) {
	/*
	 * Description: Format an exception to send to the client
	 * Params:
	 *              exception: An exception object
	 *
	 * Return:      A serialized exception object
	*/
	var serializedException = [exception.name.toString(), exception.message];

	try {
		return(serializedException.concat([exception.getStackTrace()]));
	}
	catch(stack_fetch_error) {
		return(serializedException.concat([[stack_fetch_error.message]]));
	}
}

/*
 * Netsuite API Call Wrapper Functions
*/
function initializeRecord(request) {
	/*
	 * Description: Retrieves an initialized object with the given parameters
	 * Params:
	 *              request.recordType:      String matching a record type
	 *
	 * Return:      An instantiated object of the given type
	*/
	var recordType = request.record_type;

    return(nlapiCreateRecord(recordType));
}

function loadRecord(request) {
	/*
	 * Description: Retrieves a single record based on query fields
	 * Params:
	 *              recordType: String matching a record type
	 *              internalId: String matching the internal id of a record
	 *
	 * Return:      Record of given type with given id
	*/
	var recordType = request.record_type;
	var internalId = request.internal_id;

    return(nlapiLoadRecord(recordType, internalId));
}

function searchRecords(request) {
	/*
	 * Description: Runs a search based on the given field->value criteria
	 * Params:
	 *              request['record_type']:    The type of record to be covered by the search
	 *              request['search_filters']: List of fields with the values to be matched
	 *              request['return_columns']: List of the columns names to be returned for each record
	 *              request['batch_size']:     Size of the batch to be returned upon completion
	 *              request['start_id']:       Id to determine the lower bound of the batch, results
	 *                                         returned will all have ids greater than the value given
	 *
	 * Return:      A list of results with ids and columns to match the results filter
	*/
	var recordType         = request['record_type'];
	var batchSize          = request['batch_size'];
	var lowerBound         = request['start_id'];
	var rawFilters         = request['search_filters'];
	var rawColumns         = request['return_columns'];
	var searchFilters      = [new nlobjSearchFilter('internalidnumber', null, 'greaterthan', lowerBound)];
	var returnColumns      = [new nlobjSearchColumn('internalid', null).setSort()];
	var accumulatedResults = [];

	for(var filter in rawFilters) {
		searchFilters[searchFilters.length]  = new nlobjSearchFilter(filter, null,
																	 rawFilters[filter]['operator'],
																	 rawFilters[filter]['value']);
	}

	for(var column in rawColumns) {
		returnColumns[returnColumns.length]  = new nlobjSearchColumn(column,
																	 rawColumns[column]);
	}

	do {
		var tempItems = nlapiSearchRecord(recordType, null, searchFilters, returnColumns);
		if(tempItems) {
			lowerBound         = tempItems[tempItems.length - 1].getId();
			accumulatedResults = accumulatedResults.concat(tempItems);
		}
	} while(tempItems && tempItems.length == 1000 && accumulatedResults.length < batchSize);

	return([accumulatedResults, lowerBound]);
}

function upsertRecords(request) {
	/*
	 * Description: Updates a record with given field values, can ignore validations if requested
	 * Params:
	 *              request['record_type']:      String matching a valid record type
	 *              request['record_data']:      Raw Record data
	 *              request['update_only']:      Boolean value that, if true, only allows updates to occur,
	 *                                           no new records will be created
	 *              request['do_sourcing']:      Boolean value to set sourcing (the hell is this?)
	 *              request['ignore_mandatory']: Boolean value to set ignoring of validations for mandatory fields
	 *
	 * Return:      Internal ids of the comitted records and errors for uncommitted records
	*/
	var recordType      = request['record_type'];
	var recordData      = request['record_data'];
    var updateOnly      = request['update_only'];
    var doSourcing      = request['do_sourcing'];
    var ignoreMandatory = request['ignore_mandatory'];
    var writeResults    = [];

    for(var record in recordData) {
    	try {
    		record = nlapiCreateRecord(recordType);
    		for(var field in recordData) {
    			record.setFieldValue(field, recordData[field]);
    		}
    		writeResults = writeResults.concat([nlapiSubmitRecord(record, doSourcing, ignoreMandatory)]);
    	}
		catch(write_exception) {
			writeResults = writeResults.concat([formatException(write_exception)]);
		}
    }

    return(writeResults);
}

function deleteRecords(request) {
	/*
	 * Description: Deletes a record of given type with given id
	 * Params:
	 *              request['recordType']: String matching a record type
	 *              request['record_ids']: Array of record ids
	 *
	 * Return:      True if successful, exception if not
	*/
	var recordType = request.record_type;
	var internalId = request.internal_id;

	nlapiDeleteRecord(recordType, internalId);
}

function getSavedSearch(request) {
    /*
     * Description: Retrieves results from a given saved search of the defined batch size rounded up to the next
     *              one thousand records
     * Params:
     *              request.search_id:   Id of the saved search to run
     *              request.record_type: String of the record type to fetch
     *              request.batch_size:  Size of the batch to be returned upon completion
     *              request.start_id:    Id to determine the lower bound of the batch, results
     *                                   returned will all have ids greater than the value given
     *
     * Return:      List of result rows with internal ids from the given start_id up through a count of the given
     *              batch size or next highest multiple of one thousand from the given batch size if the given size
     *              is not a multiple of one thousand
    */
    var searchId           = request.search_id;
    var recordType         = request.record_type;
    var batchSize          = request.batch_size;
    var lowerBound         = request.start_id;
    var accumulatedResults = [];
    var searchFilters      = [new nlobjSearchFilter('internalidnumber', null, 'greaterthan', lowerBound)];
    var returnColumns      = [new nlobjSearchColumn('internalid', null).setSort()];

    do {
        var tempItems = nlapiSearchRecord(recordType, searchId, searchFilters, returnColumns);
        if(tempItems) {
            lowerBound = tempItems[tempItems.length - 1].getId();
            accumulatedResults = accumulatedResults.concat(tempItems);
        }
    } while(tempItems && tempItems.length == 1000 && accumulatedResults.length < batchSize);

    return([accumulatedResults, lowerBound]);
}

/*
 * Handler Functions
*/
function getHandler(request) {
	/*
	 * Description: Method to handle requests over GET
	 * Params:
	 *              request: Request object from the REST client
	 *
	 * Return:      JSON response
    */
    try {
    	return(evalOperation('GET', request.operation, request))
    }
    catch(exception) {
    	return(formatException(exception));
    }
}

function postHandler(request) {
	/*
	 * Description: Method to handle requests over POST
	 * Params:
	 *              request: Request object from the REST client
	 *
	 * Return:      JSON response
    */
	try {
    	return(evalOperation('POST', request['operation'], request))
    }
    catch(exception) {
    	return(formatException(exception));
    }
}
<|endoftext|>


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

/**
 * @fileoverview Logging and debugging utilities.
 *

 * @see ../demos/debug.html
 */

goog.provide('goog.debug');

goog.require('goog.array');
goog.require('goog.string');
goog.require('goog.structs.Set');
goog.require('goog.userAgent');

/**
 * Catches onerror events fired by windows and similar objects.
 * @param {function(Object)} logFunc The function to call with the error
 *    information.
 * @param {boolean=} opt_cancel Whether to stop the error from reaching the
 *    browser.
 * @param {Object=} opt_target Object that fires onerror events.
 */
goog.debug.catchErrors = function(logFunc, opt_cancel, opt_target) {
  var target = opt_target || goog.global;
  var oldErrorHandler = target.onerror;
  // Chrome interprets onerror return value backwards (http://crbug.com/92062).
  // Safari doesn't support onerror at all.
  var retVal = goog.userAgent.WEBKIT ? !opt_cancel : !!opt_cancel;
  target.onerror = function(message, url, line) {
    if (oldErrorHandler) {
      oldErrorHandler(message, url, line);
    }
    logFunc({
      message: message,
      fileName: url,
      line: line
    });
    return retVal;
  };
};

/**
 * Creates a string representing an object and all its properties.
 * @param {Object|null|undefined} obj Object to expose.
 * @param {boolean=} opt_showFn Show the functions as well as the properties,
 *     default is false.
 * @return {string} The string representation of {@code obj}.
 */
goog.debug.expose = function(obj, opt_showFn) {
  if (typeof obj == 'undefined') {
    return 'undefined';
  }
  if (obj == null) {
    return 'NULL';
  }
  var str = [];

  for (var x in obj) {
    if (!opt_showFn && goog.isFunction(obj[x])) {
      continue;
    }
    var s = x + ' = ';
    /** @preserveTry */
    try {
      s += obj[x];
    } catch (e) {
      s += '*** ' + e + ' ***';
    }
    str.push(s);
  }
  return str.join('\n');
};

/**
 * Creates a string representing a given primitive or object, and for an
 * object, all its properties and nested objects.  WARNING: If an object is
 * given, it and all its nested objects will be modified.  To detect reference
 * cycles, this method identifies objects using goog.getUid() which mutates the
 * object.
 * @param {*} obj Object to expose.
 * @param {boolean=} opt_showFn Also show properties that are functions (by
 *     default, functions are omitted).
 * @return {string} A string representation of {@code obj}.
 */
goog.debug.deepExpose = function(obj, opt_showFn) {
  var previous = new goog.structs.Set();
  var str = [];

  var helper = function(obj, space) {
    var nestspace = space + '  ';

    var indentMultiline = function(str) {
      return str.replace(/\n/g, '\n' + space);
    };

    /** @preserveTry */
    try {
      if (!goog.isDef(obj)) {
        str.push('undefined');
      } else if (goog.isNull(obj)) {
        str.push('NULL');
      } else if (goog.isString(obj)) {
        str.push('"' + indentMultiline(obj) + '"');
      } else if (goog.isFunction(obj)) {
        str.push(indentMultiline(String(obj)));
      } else if (goog.isObject(obj)) {
        if (previous.contains(obj)) {
          // TODO(user): This is a bug; it falsely detects non-loops as loops
          // when the reference tree contains two references to the same object.
          str.push('*** reference loop detected ***');
        } else {
          previous.add(obj);
          str.push('{');
          for (var x in obj) {
            if (!opt_showFn && goog.isFunction(obj[x])) {
              continue;
            }
            str.push('\n');
            str.push(nestspace);
            str.push(x + ' = ');
            helper(obj[x], nestspace);
          }
          str.push('\n' + space + '}');
        }
      } else {
        str.push(obj);
      }
    } catch (e) {
      str.push('*** ' + e + ' ***');
    }
  };

  helper(obj, '');
  return str.join('');
};

/**
 * Recursively outputs a nested array as a string.
 * @param {Array} arr The array.
 * @return {string} String representing nested array.
 */
goog.debug.exposeArray = function(arr) {
  var str = [];
  for (var i = 0; i < arr.length; i++) {
    if (goog.isArray(arr[i])) {
      str.push(goog.debug.exposeArray(arr[i]));
    } else {
      str.push(arr[i]);
    }
  }
  return '[ ' + str.join(', ') + ' ]';
};

/**
 * Exposes an exception that has been caught by a try...catch and outputs the
 * error with a stack trace.
 * @param {Object} err Error object or string.
 * @param {Function=} opt_fn Optional function to start stack trace from.
 * @return {string} Details of exception.
 */
goog.debug.exposeException = function(err, opt_fn) {
  /** @preserveTry */
  try {
    var e = goog.debug.normalizeErrorObject(err);

    // Create the error message
    var error = 'Message: ' + goog.string.htmlEscape(e.message) +
        '\nUrl: ' +
        e.fileName + '\nLine: ' + e.lineNumber + '\n\nBrowser stack:\n' +
        goog.string.htmlEscape(e.stack + '-> ') +
        '[end]\n\nJS stack traversal:\n' + goog.string.htmlEscape(
            goog.debug.getStacktrace(opt_fn) + '-> ');
    return error;
  } catch (e2) {
    return 'Exception trying to expose exception! You win, we lose. ' + e2;
  }
};

/**
 * Normalizes the error/exception object between browsers.
 * @param {Object} err Raw error object.
 * @return {Object} Normalized error object.
 */
goog.debug.normalizeErrorObject = function(err) {
  var href = goog.getObjectByName('window.location.href');
  if (goog.isString(err)) {
    return {
      'message': err,
      'name': 'Unknown error',
      'lineNumber': 'Not available',
      'fileName': href,
      'stack': 'Not available'
    };
  }

  var lineNumber, fileName;
  var threwError = false;

  try {
    lineNumber = err.lineNumber || err.line || 'Not available';
  } catch (e) {
    // Firefox 2 sometimes throws an error when accessing 'lineNumber':
    // Message: Permission denied to get property UnnamedClass.lineNumber
    lineNumber = 'Not available';
    threwError = true;
  }

  try {
    fileName = err.fileName || err.filename || err.sourceURL || href;
  } catch (e) {
    // Firefox 2 may also throw an error when accessing 'filename'.
    fileName = 'Not available';
    threwError = true;
  }

  // The IE Error object contains only the name and the message.
  // The Safari Error object uses the line and sourceURL fields.
  if (threwError || !err.lineNumber || !err.fileName || !err.stack) {
    return {
      'message': err.message,
      'name': err.name,
      'lineNumber': lineNumber,
      'fileName': fileName,
      'stack': err.stack || 'Not available'
    };
  }

  // Standards error object
  return err;
};

/**
 * Converts an object to an Error if it's a String,
 * adds a stacktrace if there isn't one,
 * and optionally adds an extra message.
 * @param {Error|string} err  the original thrown object or string.
 * @param {string=} opt_message  optional additional message to add to the
 *     error.
 * @return {Error} If err is a string, it is used to create a new Error,
 *     which is enhanced and returned.  Otherwise err itself is enhanced
 *     and returned.
 */
goog.debug.enhanceError = function(err, opt_message) {
  var error = typeof err == 'string' ? Error(err) : err;
  if (!error.stack) {
    error.stack = goog.debug.getStacktrace(arguments.callee.caller);
  }
  if (opt_message) {
    // find the first unoccupied 'messageX' property
    var x = 0;
    while (error['message' + x]) {
      ++x;
    }
    error['message' + x] = String(opt_message);
  }
  return error;
};

/**
 * Gets the current stack trace. Simple and iterative - doesn't worry about
 * catching circular references or getting the args.
 * @param {number=} opt_depth Optional maximum depth to trace back to.
 * @return {string} A string with the function names of all functions in the
 *     stack, separated by \n.
 */
goog.debug.getStacktraceSimple = function(opt_depth) {
  var sb = [];
  var fn = arguments.callee.caller;
  var depth = 0;

  while (fn && (!opt_depth || depth < opt_depth)) {
    sb.push(goog.debug.getFunctionName(fn));
    sb.push('()\n');
    /** @preserveTry */
    try {
      fn = fn.caller;
    } catch (e) {
      sb.push('[exception trying to get caller]\n');
      break;
    }
    depth++;
    if (depth >= goog.debug.MAX_STACK_DEPTH) {
      sb.push('[...long stack...]');
      break;
    }
  }
  if (opt_depth && depth >= opt_depth) {
    sb.push('[...reached max depth limit...]');
  } else {
    sb.push('[end]');
  }

  return sb.join('');
};

/**
 * Max length of stack to try and output
 * @type {number}
 */
goog.debug.MAX_STACK_DEPTH = 50;

/**
 * Gets the current stack trace, either starting from the caller or starting
 * from a specified function that's currently on the call stack.
 * @param {Function=} opt_fn Optional function to start getting the trace from.
 *     If not provided, defaults to the function that called this.
 * @return {string} Stack trace.
 */
goog.debug.getStacktrace = function(opt_fn) {
  return goog.debug.getStacktraceHelper_(opt_fn || arguments.callee.caller, []);
};

/**
 * Private helper for getStacktrace().
 * @param {Function} fn Function to start getting the trace from.
 * @param {Array} visited List of functions visited so far.
 * @return {string} Stack trace starting from function fn.
 * @private
 */
goog.debug.getStacktraceHelper_ = function(fn, visited) {
  var sb = [];

  // Circular reference, certain functions like bind seem to cause a recursive
  // loop so we need to catch circular references
  if (goog.array.contains(visited, fn)) {
    sb.push('[...circular reference...]');

  // Traverse the call stack until function not found or max depth is reached
  } else if (fn && visited.length < goog.debug.MAX_STACK_DEPTH) {
    sb.push(goog.debug.getFunctionName(fn) + '(');
    var args = fn.arguments;
    for (var i = 0; i < args.length; i++) {
      if (i > 0) {
        sb.push(', ');
      }
      var argDesc;
      var arg = args[i];
      switch (typeof arg) {
        case 'object':
          argDesc = arg ? 'object' : 'null';
          break;

        case 'string':
          argDesc = arg;
          break;

        case 'number':
          argDesc = String(arg);
          break;

        case 'boolean':
          argDesc = arg ? 'true' : 'false';
          break;

        case 'function':
          argDesc = goog.debug.getFunctionName(arg);
          argDesc = argDesc ? argDesc : '[fn]';
          break;

        case 'undefined':
        default:
          argDesc = typeof arg;
          break;
      }

      if (argDesc.length > 40) {
        argDesc = argDesc.substr(0, 40) + '...';
      }
      sb.push(argDesc);
    }
    visited.push(fn);
    sb.push(')\n');
    /** @preserveTry */
    try {
      sb.push(goog.debug.getStacktraceHelper_(fn.caller, visited));
    } catch (e) {
      sb.push('[exception trying to get caller]\n');
    }

  } else if (fn) {
    sb.push('[...long stack...]');
  } else {
    sb.push('[end]');
  }
  return sb.join('');
};

/**
 * Set a custom function name resolver.
 * @param {function(Function): string} resolver Resolves functions to their
 *     names.
 */
goog.debug.setFunctionResolver = function(resolver) {
  goog.debug.fnNameResolver_ = resolver;
};

/**
 * Gets a function name
 * @param {Function} fn Function to get name of.
 * @return {string} Function's name.
 */
goog.debug.getFunctionName = function(fn) {
  if (goog.debug.fnNameCache_[fn]) {
    return goog.debug.fnNameCache_[fn];
  }
  if (goog.debug.fnNameResolver_) {
    var name = goog.debug.fnNameResolver_(fn);
    if (name) {
      goog.debug.fnNameCache_[fn] = name;
      return name;
    }
  }

  // Heuristically determine function name based on code.
  var functionSource = String(fn);
  if (!goog.debug.fnNameCache_[functionSource]) {
    var matches = /function ([^\(]+)/.exec(functionSource);
    if (matches) {
      var method = matches[1];
      goog.debug.fnNameCache_[functionSource] = method;
    } else {
      goog.debug.fnNameCache_[functionSource] = '[Anonymous]';
    }
  }

  return goog.debug.fnNameCache_[functionSource];
};

/**
 * Makes whitespace visible by replacing it with printable characters.
 * This is useful in finding diffrences between the expected and the actual
 * output strings of a testcase.
 * @param {string} string whose whitespace needs to be made visible.
 * @return {string} string whose whitespace is made visible.
 */
goog.debug.makeWhitespaceVisible = function(string) {
  return string.replace(/ /g, '[_]')
      .replace(/\f/g, '[f]')
      .replace(/\n/g, '[n]\n')
      .replace(/\r/g, '[r]')
      .replace(/\t/g, '[t]');
};

/**
 * Hash map for storing function names that have already been looked up.
 * @type {Object}
 * @private
 */
goog.debug.fnNameCache_ = {};

/**
 * Resolves functions to their names.  Resolved function names will be cached.
 * @type {function(Function):string}
 * @private
 */
goog.debug.fnNameResolver_;
<commit_msg><commit_after>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Logging and debugging utilities.
 *

 * @see ../demos/debug.html
 */

goog.provide('goog.debug');

goog.require('goog.array');
goog.require('goog.string');
goog.require('goog.structs.Set');
goog.require('goog.userAgent');

/**
 * Catches onerror events fired by windows and similar objects.
 * @param {function(Object)} logFunc The function to call with the error
 *    information.
 * @param {boolean=} opt_cancel Whether to stop the error from reaching the
 *    browser.
 * @param {Object=} opt_target Object that fires onerror events.
 */
goog.debug.catchErrors = function(logFunc, opt_cancel, opt_target) {
  var target = opt_target || goog.global;
  var oldErrorHandler = target.onerror;
  var retVal = !!opt_cancel;

  // Chrome interprets onerror return value backwards (http://crbug.com/92062)
  // until it was fixed in webkit revision r94061 (Webkit 535.3). This
  // workaround still needs to be skipped in Safari after the webkit change
  // gets pushed out in Safari.
  // See https://bugs.webkit.org/show_bug.cgi?id=67119
  if (goog.userAgent.WEBKIT && !goog.userAgent.isVersion('535.3')) {
    retVal = !retVal;
  }
  target.onerror = function(message, url, line) {
    if (oldErrorHandler) {
      oldErrorHandler(message, url, line);
    }
    logFunc({
      message: message,
      fileName: url,
      line: line
    });
    return retVal;
  };
};

/**
 * Creates a string representing an object and all its properties.
 * @param {Object|null|undefined} obj Object to expose.
 * @param {boolean=} opt_showFn Show the functions as well as the properties,
 *     default is false.
 * @return {string} The string representation of {@code obj}.
 */
goog.debug.expose = function(obj, opt_showFn) {
  if (typeof obj == 'undefined') {
    return 'undefined';
  }
  if (obj == null) {
    return 'NULL';
  }
  var str = [];

  for (var x in obj) {
    if (!opt_showFn && goog.isFunction(obj[x])) {
      continue;
    }
    var s = x + ' = ';
    /** @preserveTry */
    try {
      s += obj[x];
    } catch (e) {
      s += '*** ' + e + ' ***';
    }
    str.push(s);
  }
  return str.join('\n');
};

/**
 * Creates a string representing a given primitive or object, and for an
 * object, all its properties and nested objects.  WARNING: If an object is
 * given, it and all its nested objects will be modified.  To detect reference
 * cycles, this method identifies objects using goog.getUid() which mutates the
 * object.
 * @param {*} obj Object to expose.
 * @param {boolean=} opt_showFn Also show properties that are functions (by
 *     default, functions are omitted).
 * @return {string} A string representation of {@code obj}.
 */
goog.debug.deepExpose = function(obj, opt_showFn) {
  var previous = new goog.structs.Set();
  var str = [];

  var helper = function(obj, space) {
    var nestspace = space + '  ';

    var indentMultiline = function(str) {
      return str.replace(/\n/g, '\n' + space);
    };

    /** @preserveTry */
    try {
      if (!goog.isDef(obj)) {
        str.push('undefined');
      } else if (goog.isNull(obj)) {
        str.push('NULL');
      } else if (goog.isString(obj)) {
        str.push('"' + indentMultiline(obj) + '"');
      } else if (goog.isFunction(obj)) {
        str.push(indentMultiline(String(obj)));
      } else if (goog.isObject(obj)) {
        if (previous.contains(obj)) {
          // TODO(user): This is a bug; it falsely detects non-loops as loops
          // when the reference tree contains two references to the same object.
          str.push('*** reference loop detected ***');
        } else {
          previous.add(obj);
          str.push('{');
          for (var x in obj) {
            if (!opt_showFn && goog.isFunction(obj[x])) {
              continue;
            }
            str.push('\n');
            str.push(nestspace);
            str.push(x + ' = ');
            helper(obj[x], nestspace);
          }
          str.push('\n' + space + '}');
        }
      } else {
        str.push(obj);
      }
    } catch (e) {
      str.push('*** ' + e + ' ***');
    }
  };

  helper(obj, '');
  return str.join('');
};

/**
 * Recursively outputs a nested array as a string.
 * @param {Array} arr The array.
 * @return {string} String representing nested array.
 */
goog.debug.exposeArray = function(arr) {
  var str = [];
  for (var i = 0; i < arr.length; i++) {
    if (goog.isArray(arr[i])) {
      str.push(goog.debug.exposeArray(arr[i]));
    } else {
      str.push(arr[i]);
    }
  }
  return '[ ' + str.join(', ') + ' ]';
};

/**
 * Exposes an exception that has been caught by a try...catch and outputs the
 * error with a stack trace.
 * @param {Object} err Error object or string.
 * @param {Function=} opt_fn Optional function to start stack trace from.
 * @return {string} Details of exception.
 */
goog.debug.exposeException = function(err, opt_fn) {
  /** @preserveTry */
  try {
    var e = goog.debug.normalizeErrorObject(err);

    // Create the error message
    var error = 'Message: ' + goog.string.htmlEscape(e.message) +
        '\nUrl: ' +
        e.fileName + '\nLine: ' + e.lineNumber + '\n\nBrowser stack:\n' +
        goog.string.htmlEscape(e.stack + '-> ') +
        '[end]\n\nJS stack traversal:\n' + goog.string.htmlEscape(
            goog.debug.getStacktrace(opt_fn) + '-> ');
    return error;
  } catch (e2) {
    return 'Exception trying to expose exception! You win, we lose. ' + e2;
  }
};

/**
 * Normalizes the error/exception object between browsers.
 * @param {Object} err Raw error object.
 * @return {Object} Normalized error object.
 */
goog.debug.normalizeErrorObject = function(err) {
  var href = goog.getObjectByName('window.location.href');
  if (goog.isString(err)) {
    return {
      'message': err,
      'name': 'Unknown error',
      'lineNumber': 'Not available',
      'fileName': href,
      'stack': 'Not available'
    };
  }

  var lineNumber, fileName;
  var threwError = false;

  try {
    lineNumber = err.lineNumber || err.line || 'Not available';
  } catch (e) {
    // Firefox 2 sometimes throws an error when accessing 'lineNumber':
    // Message: Permission denied to get property UnnamedClass.lineNumber
    lineNumber = 'Not available';
    threwError = true;
  }

  try {
    fileName = err.fileName || err.filename || err.sourceURL || href;
  } catch (e) {
    // Firefox 2 may also throw an error when accessing 'filename'.
    fileName = 'Not available';
    threwError = true;
  }

  // The IE Error object contains only the name and the message.
  // The Safari Error object uses the line and sourceURL fields.
  if (threwError || !err.lineNumber || !err.fileName || !err.stack) {
    return {
      'message': err.message,
      'name': err.name,
      'lineNumber': lineNumber,
      'fileName': fileName,
      'stack': err.stack || 'Not available'
    };
  }

  // Standards error object
  return err;
};

/**
 * Converts an object to an Error if it's a String,
 * adds a stacktrace if there isn't one,
 * and optionally adds an extra message.
 * @param {Error|string} err  the original thrown object or string.
 * @param {string=} opt_message  optional additional message to add to the
 *     error.
 * @return {Error} If err is a string, it is used to create a new Error,
 *     which is enhanced and returned.  Otherwise err itself is enhanced
 *     and returned.
 */
goog.debug.enhanceError = function(err, opt_message) {
  var error = typeof err == 'string' ? Error(err) : err;
  if (!error.stack) {
    error.stack = goog.debug.getStacktrace(arguments.callee.caller);
  }
  if (opt_message) {
    // find the first unoccupied 'messageX' property
    var x = 0;
    while (error['message' + x]) {
      ++x;
    }
    error['message' + x] = String(opt_message);
  }
  return error;
};

/**
 * Gets the current stack trace. Simple and iterative - doesn't worry about
 * catching circular references or getting the args.
 * @param {number=} opt_depth Optional maximum depth to trace back to.
 * @return {string} A string with the function names of all functions in the
 *     stack, separated by \n.
 */
goog.debug.getStacktraceSimple = function(opt_depth) {
  var sb = [];
  var fn = arguments.callee.caller;
  var depth = 0;

  while (fn && (!opt_depth || depth < opt_depth)) {
    sb.push(goog.debug.getFunctionName(fn));
    sb.push('()\n');
    /** @preserveTry */
    try {
      fn = fn.caller;
    } catch (e) {
      sb.push('[exception trying to get caller]\n');
      break;
    }
    depth++;
    if (depth >= goog.debug.MAX_STACK_DEPTH) {
      sb.push('[...long stack...]');
      break;
    }
  }
  if (opt_depth && depth >= opt_depth) {
    sb.push('[...reached max depth limit...]');
  } else {
    sb.push('[end]');
  }

  return sb.join('');
};

/**
 * Max length of stack to try and output
 * @type {number}
 */
goog.debug.MAX_STACK_DEPTH = 50;

/**
 * Gets the current stack trace, either starting from the caller or starting
 * from a specified function that's currently on the call stack.
 * @param {Function=} opt_fn Optional function to start getting the trace from.
 *     If not provided, defaults to the function that called this.
 * @return {string} Stack trace.
 */
goog.debug.getStacktrace = function(opt_fn) {
  return goog.debug.getStacktraceHelper_(opt_fn || arguments.callee.caller, []);
};

/**
 * Private helper for getStacktrace().
 * @param {Function} fn Function to start getting the trace from.
 * @param {Array} visited List of functions visited so far.
 * @return {string} Stack trace starting from function fn.
 * @private
 */
goog.debug.getStacktraceHelper_ = function(fn, visited) {
  var sb = [];

  // Circular reference, certain functions like bind seem to cause a recursive
  // loop so we need to catch circular references
  if (goog.array.contains(visited, fn)) {
    sb.push('[...circular reference...]');

  // Traverse the call stack until function not found or max depth is reached
  } else if (fn && visited.length < goog.debug.MAX_STACK_DEPTH) {
    sb.push(goog.debug.getFunctionName(fn) + '(');
    var args = fn.arguments;
    for (var i = 0; i < args.length; i++) {
      if (i > 0) {
        sb.push(', ');
      }
      var argDesc;
      var arg = args[i];
      switch (typeof arg) {
        case 'object':
          argDesc = arg ? 'object' : 'null';
          break;

        case 'string':
          argDesc = arg;
          break;

        case 'number':
          argDesc = String(arg);
          break;

        case 'boolean':
          argDesc = arg ? 'true' : 'false';
          break;

        case 'function':
          argDesc = goog.debug.getFunctionName(arg);
          argDesc = argDesc ? argDesc : '[fn]';
          break;

        case 'undefined':
        default:
          argDesc = typeof arg;
          break;
      }

      if (argDesc.length > 40) {
        argDesc = argDesc.substr(0, 40) + '...';
      }
      sb.push(argDesc);
    }
    visited.push(fn);
    sb.push(')\n');
    /** @preserveTry */
    try {
      sb.push(goog.debug.getStacktraceHelper_(fn.caller, visited));
    } catch (e) {
      sb.push('[exception trying to get caller]\n');
    }

  } else if (fn) {
    sb.push('[...long stack...]');
  } else {
    sb.push('[end]');
  }
  return sb.join('');
};

/**
 * Set a custom function name resolver.
 * @param {function(Function): string} resolver Resolves functions to their
 *     names.
 */
goog.debug.setFunctionResolver = function(resolver) {
  goog.debug.fnNameResolver_ = resolver;
};

/**
 * Gets a function name
 * @param {Function} fn Function to get name of.
 * @return {string} Function's name.
 */
goog.debug.getFunctionName = function(fn) {
  if (goog.debug.fnNameCache_[fn]) {
    return goog.debug.fnNameCache_[fn];
  }
  if (goog.debug.fnNameResolver_) {
    var name = goog.debug.fnNameResolver_(fn);
    if (name) {
      goog.debug.fnNameCache_[fn] = name;
      return name;
    }
  }

  // Heuristically determine function name based on code.
  var functionSource = String(fn);
  if (!goog.debug.fnNameCache_[functionSource]) {
    var matches = /function ([^\(]+)/.exec(functionSource);
    if (matches) {
      var method = matches[1];
      goog.debug.fnNameCache_[functionSource] = method;
    } else {
      goog.debug.fnNameCache_[functionSource] = '[Anonymous]';
    }
  }

  return goog.debug.fnNameCache_[functionSource];
};

/**
 * Makes whitespace visible by replacing it with printable characters.
 * This is useful in finding diffrences between the expected and the actual
 * output strings of a testcase.
 * @param {string} string whose whitespace needs to be made visible.
 * @return {string} string whose whitespace is made visible.
 */
goog.debug.makeWhitespaceVisible = function(string) {
  return string.replace(/ /g, '[_]')
      .replace(/\f/g, '[f]')
      .replace(/\n/g, '[n]\n')
      .replace(/\r/g, '[r]')
      .replace(/\t/g, '[t]');
};

/**
 * Hash map for storing function names that have already been looked up.
 * @type {Object}
 * @private
 */
goog.debug.fnNameCache_ = {};

/**
 * Resolves functions to their names.  Resolved function names will be cached.
 * @type {function(Function):string}
 * @private
 */
goog.debug.fnNameResolver_;
<|endoftext|>


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

/**
 * @fileoverview Defines the goog.dom.TagName enum.  This enumerates
 * all html tag names specified by the W3C HTML 4.01 Specification.
 * Reference http://www.w3.org/TR/html401/index/elements.html.
 *
 */
goog.provide('goog.dom.TagName');

/**
 * Enum of all html tag names specified by the W3C HTML 4.01 Specification.
 * Reference http://www.w3.org/TR/html401/index/elements.html
 * @enum {string}
 */
goog.dom.TagName = {
  A: 'A',
  ABBR: 'ABBR',
  ACRONYM: 'ACRONYM',
  ADDRESS: 'ADDRESS',
  APPLET: 'APPLET',
  AREA: 'AREA',
  B: 'B',
  BASE: 'BASE',
  BASEFONT: 'BASEFONT',
  BDO: 'BDO',
  BIG: 'BIG',
  BLOCKQUOTE: 'BLOCKQUOTE',
  BODY: 'BODY',
  BR: 'BR',
  BUTTON: 'BUTTON',
  CANVAS: 'CANVAS',
  CAPTION: 'CAPTION',
  CENTER: 'CENTER',
  CITE: 'CITE',
  CODE: 'CODE',
  COL: 'COL',
  COLGROUP: 'COLGROUP',
  DD: 'DD',
  DEL: 'DEL',
  DFN: 'DFN',
  DIR: 'DIR',
  DIV: 'DIV',
  DL: 'DL',
  DT: 'DT',
  EM: 'EM',
  FIELDSET: 'FIELDSET',
  FONT: 'FONT',
  FORM: 'FORM',
  FRAME: 'FRAME',
  FRAMESET: 'FRAMESET',
  H1: 'H1',
  H2: 'H2',
  H3: 'H3',
  H4: 'H4',
  H5: 'H5',
  H6: 'H6',
  HEAD: 'HEAD',
  HR: 'HR',
  HTML: 'HTML',
  I: 'I',
  IFRAME: 'IFRAME',
  IMG: 'IMG',
  INPUT: 'INPUT',
  INS: 'INS',
  ISINDEX: 'ISINDEX',
  KBD: 'KBD',
  LABEL: 'LABEL',
  LEGEND: 'LEGEND',
  LI: 'LI',
  LINK: 'LINK',
  MAP: 'MAP',
  MENU: 'MENU',
  META: 'META',
  NOFRAMES: 'NOFRAMES',
  NOSCRIPT: 'NOSCRIPT',
  OBJECT: 'OBJECT',
  OL: 'OL',
  OPTGROUP: 'OPTGROUP',
  OPTION: 'OPTION',
  P: 'P',
  PARAM: 'PARAM',
  PRE: 'PRE',
  Q: 'Q',
  S: 'S',
  SAMP: 'SAMP',
  SCRIPT: 'SCRIPT',
  SELECT: 'SELECT',
  SMALL: 'SMALL',
  SPAN: 'SPAN',
  STRIKE: 'STRIKE',
  STRONG: 'STRONG',
  STYLE: 'STYLE',
  SUB: 'SUB',
  SUP: 'SUP',
  TABLE: 'TABLE',
  TBODY: 'TBODY',
  TD: 'TD',
  TEXTAREA: 'TEXTAREA',
  TFOOT: 'TFOOT',
  TH: 'TH',
  THEAD: 'THEAD',
  TITLE: 'TITLE',
  TR: 'TR',
  TT: 'TT',
  U: 'U',
  UL: 'UL',
  VAR: 'VAR'
};
<commit_msg><commit_after>// Copyright 2007 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Defines the goog.dom.TagName enum.  This enumerates
 * all html tag names specified by the W3C HTML 4.01 Specification.
 * Reference http://www.w3.org/TR/html401/index/elements.html.
 *
 */
goog.provide('goog.dom.TagName');

/**
 * Enum of all html tag names specified by the W3C HTML 4.01 Specification.
 * Reference http://www.w3.org/TR/html401/index/elements.html
 * @enum {string}
 */
goog.dom.TagName = {
  A: 'A',
  ABBR: 'ABBR',
  ACRONYM: 'ACRONYM',
  ADDRESS: 'ADDRESS',
  APPLET: 'APPLET',
  AREA: 'AREA',
  B: 'B',
  BASE: 'BASE',
  BASEFONT: 'BASEFONT',
  BDO: 'BDO',
  BIG: 'BIG',
  BLOCKQUOTE: 'BLOCKQUOTE',
  BODY: 'BODY',
  BR: 'BR',
  BUTTON: 'BUTTON',
  CAPTION: 'CAPTION',
  CENTER: 'CENTER',
  CITE: 'CITE',
  CODE: 'CODE',
  COL: 'COL',
  COLGROUP: 'COLGROUP',
  DD: 'DD',
  DEL: 'DEL',
  DFN: 'DFN',
  DIR: 'DIR',
  DIV: 'DIV',
  DL: 'DL',
  DT: 'DT',
  EM: 'EM',
  FIELDSET: 'FIELDSET',
  FONT: 'FONT',
  FORM: 'FORM',
  FRAME: 'FRAME',
  FRAMESET: 'FRAMESET',
  H1: 'H1',
  H2: 'H2',
  H3: 'H3',
  H4: 'H4',
  H5: 'H5',
  H6: 'H6',
  HEAD: 'HEAD',
  HR: 'HR',
  HTML: 'HTML',
  I: 'I',
  IFRAME: 'IFRAME',
  IMG: 'IMG',
  INPUT: 'INPUT',
  INS: 'INS',
  ISINDEX: 'ISINDEX',
  KBD: 'KBD',
  LABEL: 'LABEL',
  LEGEND: 'LEGEND',
  LI: 'LI',
  LINK: 'LINK',
  MAP: 'MAP',
  MENU: 'MENU',
  META: 'META',
  NOFRAMES: 'NOFRAMES',
  NOSCRIPT: 'NOSCRIPT',
  OBJECT: 'OBJECT',
  OL: 'OL',
  OPTGROUP: 'OPTGROUP',
  OPTION: 'OPTION',
  P: 'P',
  PARAM: 'PARAM',
  PRE: 'PRE',
  Q: 'Q',
  S: 'S',
  SAMP: 'SAMP',
  SCRIPT: 'SCRIPT',
  SELECT: 'SELECT',
  SMALL: 'SMALL',
  SPAN: 'SPAN',
  STRIKE: 'STRIKE',
  STRONG: 'STRONG',
  STYLE: 'STYLE',
  SUB: 'SUB',
  SUP: 'SUP',
  TABLE: 'TABLE',
  TBODY: 'TBODY',
  TD: 'TD',
  TEXTAREA: 'TEXTAREA',
  TFOOT: 'TFOOT',
  TH: 'TH',
  THEAD: 'THEAD',
  TITLE: 'TITLE',
  TR: 'TR',
  TT: 'TT',
  U: 'U',
  UL: 'UL',
  VAR: 'VAR'
};
<|endoftext|>


<commit_before>angular.module('starter.controllers')

.controller('QuestionRepliesCtrl', ['$scope', '$stateParams', 'Processes', 'Users', function($scope, $stateParams, Processes, Users) {

  Processes.getQuestion($stateParams.processId, $stateParams.ruleId, $stateParams.questionId)
    .success(function (response) {
      $scope.replies = response;
    })

    .error(function (error) {
      console.log(error);
    });

  $scope.addReply = function (reply) {
    var data = {from: Users.getUser()['name'], text: reply}

    Processes.setRuleQuestionReply($stateParams.processId, $stateParams.ruleId, $stateParams.questionId, data)
      .success(function (response) {
        $scope.replies.push(response)
      })
      .error(function(error) {
        console.log(error)
      });
  };

  $scope.like = function (replyId) {
    Processes.setRuleQuestionReplyLikes($stateParams.processId, $stateParams.ruleId, $stateParams.questionId, replyId)
      .success(function (response) {
        console.log(response)
        $scope.replies = response
      })
      .error(function(error) {
        console.log(error)
      });
  };
}]);
<commit_msg>Retira console.log<commit_after>angular.module('starter.controllers')

.controller('QuestionRepliesCtrl', ['$scope', '$stateParams', 'Processes', 'Users', function($scope, $stateParams, Processes, Users) {

  Processes.getQuestion($stateParams.processId, $stateParams.ruleId, $stateParams.questionId)
    .success(function (response) {
      $scope.replies = response;
    })

    .error(function (error) {
      console.log(error);
    });

  $scope.addReply = function (reply) {
    var data = {from: Users.getUser()['name'], text: reply}

    Processes.setRuleQuestionReply($stateParams.processId, $stateParams.ruleId, $stateParams.questionId, data)
      .success(function (response) {
        $scope.replies.push(response)
      })
      .error(function(error) {
        console.log(error)
      });
  };

  $scope.like = function (replyId) {
    Processes.setRuleQuestionReplyLikes($stateParams.processId, $stateParams.ruleId, $stateParams.questionId, replyId)
      .success(function (response) {
        $scope.replies = response
      })
      .error(function(error) {
        console.log(error)
      });
  };
}]);
<|endoftext|>


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

/**
 * @fileoverview Constant declarations for common key values.
 *
 */

goog.provide('goog.events.Keys');

/**
 * Key values for common characters.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
 * @enum {string}
 */
goog.events.Keys = {
  ALT: 'Meta',
  ALTGRAPH: 'AltGraph',
  CTRL: 'Control',
  DOWN: 'ArrowDown',
  END: 'End',
  ENTER: 'Enter',
  HOME: 'Home',
  LEFT: 'ArrowLeft',
  RIGHT: 'ArrowRight',
  SHIFT: 'Shift',
  UP: 'ArrowUp',
};
<commit_msg>Expand Keys enum to include all whitespace keys and all navigation keys: added tab, space, page down, page up.<commit_after>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Constant declarations for common key values.
 *
 */

goog.provide('goog.events.Keys');

/**
 * Key values for common characters.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
 * @enum {string}
 */
goog.events.Keys = {
  ALT: 'Meta',
  ALTGRAPH: 'AltGraph',
  CTRL: 'Control',
  DOWN: 'ArrowDown',
  END: 'End',
  ENTER: 'Enter',
  HOME: 'Home',
  LEFT: 'ArrowLeft',
  PAGE_DOWN: 'PageDown',
  PAGE_UP: 'PageUp',
  RIGHT: 'ArrowRight',
  SHIFT: 'Shift',
  SPACE: ' ',
  TAB: 'Tab',
  UP: 'ArrowUp',
};
<|endoftext|>