<commit_before>// takes an IR function object and returns a list of Scratch blocks

module.exports.ffi = {};

module.exports.generateFunctionHat = function(functionContext, func) {
	var spec = func.funcName;
	var inputs = [];
	var defaults = [];

	functionContext.params = [];

	for(var i = 0; i < func.paramList.length; ++i) {
		var pName = "param" + i;

		if(func.paramList[i][1])
			pName = func.paramList[i][1];

		inputs.push(pName);
		functionContext.params.push(pName);

		defaults.push(defaultForType(func.paramList[i][0]));
		spec += " "+specifierForType(func.paramList[i][0]);
	}

	return ["procDef", spec, inputs, defaults, false];

}

module.exports.compileFunction = function(func, IR) {
	console.log("Compiling "+JSON.stringify(func)+"...");

	var functionContext = {
		locals: {},
		globalLocalDepth: 0,
		scopedLocalDepth: 0,
		params: [],
		gotoInit: false,
		globalToFree: 0,
		scopeToFree: 0,
		scoped: false,
		globals: IR.globals,
		rootGlobal: IR.rootGlobal
	}

	var blockList = [module.exports.generateFunctionHat(functionContext, func)];

	if(func.inGotoComplex) {
		blockList = blockList.concat(initGotoComplex());
	}

	for(var i = 0; i < func.code.length;) {
		console.log(func.code[i]);

		var iGain = 1;

		var hasGotoComplex = functionContext.gotoComplex && functionContext.gotoComplex.okToUse && functionContext.gotoComplex.active; // this MUST be before compileInstruction for branching to work

		// optimize out alloca calls
		if(func.code[i].type == "set" && func.code[i].computation == [] && func.code[i].value == 0 &&
			func.code[i+1].type == "store" && func.code[i+1].destination.value == func.code[i].name) {

			func.code[i].value = func.code[i+1].src.value;
			iGain++;
		}

		// optimize out icmp in conditional branch
		if(func.code[i].type == "set" && func.code[i].val.type == "comparison" &&
			func.code[i+1].type == "branch" && func.code[i+1].conditional && func.code[i+1].condition == func.code[i].name) {

			func.code[i] = {
				type: "branch",
				conditional: true,
				dest: func.code[i+1].dest,
				falseDest: func.code[i+1].falseDest,
				condition: icmpBlock(functionContext, func.code[i]),
				rawCondition: true
			};

			iGain++;
		}

		var instruction = compileInstruction(functionContext, func.code[i]);

		if(!functionContext.gotoInit && functionContext.gotoComplex && functionContext.gotoComplex.okToUse) {
			blockList = blockList.concat([functionContext.gotoComplex.forever]);
			functionContext.gotoInit = true;
		}
		if(hasGotoComplex) {
			if(functionContext.gotoComplex.currentContext[2]) {
				functionContext.gotoComplex.currentContext[2] =
					functionContext.gotoComplex.currentContext[2].concat(instruction);
			} else {
				functionContext.gotoComplex.currentContext[2] = instruction;
			}
		} else {
			blockList = blockList.concat(instruction);
		}

		i += iGain;
	}

	//blockList = blockList.concat(returnBlock());

	return blockList;
}

function compileInstruction(ctx, block) {
	if(block.type == "call") {
		// calling a (potentially foreign) function
		return callBlock(ctx, block);
	} else if(block.type == "ffi") {
		// FFI block
		// load the code from the options
		return module.exports.ffi[block.ffiBlock];
	} else if(block.type == "set") {
		var val = 0;

		console.log("SET: "+JSON.stringify(block));

		if(block.val.type == "return value") {
			val = ["readVariable", "return value"];
		} else if(block.val.type == "variable") {
			val = fetchByName(ctx, block.val.name);
		} else if(block.val.type == "arithmetic") {
			val = [block.val.operation, fetchByName(ctx, block.val.operand1), fetchByName(ctx, block.val.operand2)];
		} else if(block.val.type == "comparison") {
			val = icmpBlock(ctx, val);
		}

		return compileInstruction(ctx, block.computation)
				.concat(allocateLocal(ctx, val, block.name));
	} else if(block.type == "ret") {
		return returnBlock(ctx, block.value);
	} else if(block.type == "store") {
		return dereferenceAndSet(ctx, block.destination.value, block.src.value);
	} else if(block.type == "gotoComplex") {
		ctx.gotoComplex = {
			context: [],
			okToUse: false,
			forever: ["doForever", []],
			active: true
		}

		//return [ctx.gotoComplex.forever];
	} else if(block.type == "label") {
		if(ctx.scoped) {
			ctx.gotoComplex.currentContext[2] =
				ctx.gotoComplex.currentContext[2].concat(freeLocals(ctx));
		}

		ctx.scoped = true;

		var chunk = ["doIfElse", ["=", getCurrentLabel(), block.label], [], []];

		ctx.gotoComplex.okToUse = true;
		ctx.gotoComplex.active = true;

		if(ctx.gotoComplex.currentContext) {
			ctx.gotoComplex.currentContext[3] = [chunk];
			ctx.gotoComplex.currentContext = ctx.gotoComplex.currentContext[3][0];
		} else {
			ctx.gotoComplex.currentContext = chunk;
			ctx.gotoComplex.context = ctx.gotoComplex.currentContext;
			ctx.gotoComplex.forever[1] = [ctx.gotoComplex.context];
		}

	} else if(block.type == "branch") {
		ctx.gotoComplex.active = false;

		if(block.conditional) {
			var cond = block.rawCondition ? block.condition : ["=", fetchByName(ctx, block.condition), 1];

			return [
				["doIfElse", cond, absoluteBranch(block.dest.slice(1)), absoluteBranch(block.falseDest.slice(1))]
			];
		} else {
			return absoluteBranch(block.dest);
		}
	}

	return [];
}

// fixme: stub
function defaultForType(type) {
	console.log(type);
	return 0;
}

// fixme: stub
function specifierForType(type) {
	return "%s";
}

// fixme: stub
function formatValue(ctx, type, value) {
	console.log("FORMAT: "+type+","+value);

	if(typeof value == "object") {
		if(value.type == "getelementptr") {
			// fixme: necessary and proper implementation
			return addressOf(ctx, value.base.val);
		}
	}

	if(value[0] == '%') {
		return fetchByName(ctx, value);
	}

	return value;
}

function getOffset(ctx, value) {
	return ctx.globalLocalDepth + ctx.scopedLocalDepth - ctx.locals[value];
}

function stackPtr() {
	return ["readVariable", "sp"];
}

function stackPosFromOffset(offset) {
	// optimize zero-index
	/*if(offset == 0) {
		return stackPtr();
	}*/

	return ["+", stackPtr(), offset + 1];
}

// higher-level code generation

function allocateLocal(ctx, val, name) {
	if(name) {
		console.log(name+","+val);

		var depth = 0;

		if(ctx.scoped) {
			depth = ctx.globalLocalDepth + (++ctx.scopedLocalDepth);
		} else {
			depth = ctx.globalLocalDepth;
		}

		ctx.locals[name] = depth;
	}

	ctx.globalToFree++;

	if(ctx.scoped) {
		ctx.scopeToFree++;
	}

	return [
		["setLine:ofList:to:", stackPtr(), "DATA", val],
		["changeVar:by:", "sp", -1]
	];
}

function freeStack(num) {
	console.log("Freeing stack");
	return [
		["changeVar:by:", "sp", num]
		//["doRepeat", num, [["deleteLine:ofList:", "last", "Stack"]]],
	];
}

function freeLocals(ctx) {
	var numToFree = ctx.globalToFree;

	if(ctx.scoped) {
		numToFree = ctx.scopeToFree;
		ctx.scopeToFree = 0;
		ctx.scopedLocalDepth = 0;
	}

	return freeStack(numToFree);
}

function fetchByName(ctx, n) {
	if(ctx.locals[n] !== undefined)
		return ["getLine:ofList:", stackPosFromOffset(getOffset(ctx, n)), "DATA"];
	else if(ctx.params.indexOf(n) > -1)
		return ["getParam", n, "r"];
	else if( (n * 1) == n)
		return n
	else
		return ["undefined"];
}

function addressOf(ctx, n) {
	console.log(ctx.rootGlobal[n.slice(1)]);
	if(ctx.rootGlobal[n.slice(1)])
		return ctx.rootGlobal[n.slice(1)].ptr;
	else
		return ["undefined"];
}

function returnBlock(ctx, val) {
	var proc = freeLocals(ctx);

	if(ctx.gotoComplex) {
		proc = proc.concat(cleanGotoComplex());
	}

	if(val) {
		proc.push(["setVar:to:", "return value", formatValue(ctx, val[0], val[1])]);
	}

	proc.push(["stopScripts", "this script"]);

	return proc;
}

function callBlock(ctx, block) {
	var spec = block.funcName;
	var args = [];

	for(var a = 0; a < block.paramList.length; ++a) {
		args.push(formatValue(ctx, block.paramList[a][0], block.paramList[a][1]));
		spec += " "+specifierForType(block.paramList[a][0]);
	}

	return [
		["call", spec].concat(args)
	];
}

// TODO: more robust implementation to support heap

function dereferenceAndSet(ctx, ptr, content) {
	return [
		[
			"setLine:ofList:to:",
			stackPosFromOffset(getOffset(ctx, ptr)),
			"DATA",
			fetchByName(ctx, content)
		]
	];
}

function specForComparison(comp) {
	if(comp == "eq") {
		return "=";
	} else if(comp == "ne") {
		return "!=";
	} else if(comp == "slt" || comp == "ult") {
		return "<";
	} else if(comp == "sgt" || comp == "ugt") {
		return ">";
	}
	return "undefined";
}

function initGotoComplex() {
	return [
		["append:toList:", 0, "Label Stack"]
	];
}

function getCurrentLabel() {
	return ["getLine:ofList:", "last", "Label Stack"];
}

function cleanGotoComplex() {
	return [
		["deleteLine:ofList:", "last", "Label Stack"]
	];
}

function absoluteBranch(dest) {
	return [
		["setLine:ofList:to:", "last", "Label Stack", dest]
	];
}

function castToNumber(b) {
	return ["*", b, 1];
}

function icmpBlock(ctx, block) {
	var spec = specForComparison(block.val.operation);
	var negate = false;

	if(spec[0] == "!") {
		negate = true;
		spec = spec.slice(1);
	}

	var b = [spec, fetchByName(ctx, block.val.left), fetchByName(ctx, block.val.right)];

	if(negate) {
		b = ["not", b];
	}

	return castToNumber(b);
}<commit_msg>signext backend<commit_after>// takes an IR function object and returns a list of Scratch blocks

module.exports.ffi = {};

module.exports.generateFunctionHat = function(functionContext, func) {
	var spec = func.funcName;
	var inputs = [];
	var defaults = [];

	functionContext.params = [];

	for(var i = 0; i < func.paramList.length; ++i) {
		var pName = "param" + i;

		if(func.paramList[i][1])
			pName = func.paramList[i][1];

		inputs.push(pName);
		functionContext.params.push(pName);

		defaults.push(defaultForType(func.paramList[i][0]));
		spec += " "+specifierForType(func.paramList[i][0]);
	}

	return ["procDef", spec, inputs, defaults, false];

}

module.exports.compileFunction = function(func, IR) {
	console.log("Compiling "+JSON.stringify(func)+"...");

	var functionContext = {
		locals: {},
		globalLocalDepth: 0,
		scopedLocalDepth: 0,
		params: [],
		gotoInit: false,
		globalToFree: 0,
		scopeToFree: 0,
		scoped: false,
		globals: IR.globals,
		rootGlobal: IR.rootGlobal
	}

	var blockList = [module.exports.generateFunctionHat(functionContext, func)];

	if(func.inGotoComplex) {
		blockList = blockList.concat(initGotoComplex());
	}

	for(var i = 0; i < func.code.length;) {
		console.log(func.code[i]);

		var iGain = 1;

		var hasGotoComplex = functionContext.gotoComplex && functionContext.gotoComplex.okToUse && functionContext.gotoComplex.active; // this MUST be before compileInstruction for branching to work

		// optimize out alloca calls
		if(func.code[i].type == "set" && func.code[i].computation == [] && func.code[i].value == 0 &&
			func.code[i+1].type == "store" && func.code[i+1].destination.value == func.code[i].name) {

			func.code[i].value = func.code[i+1].src.value;
			iGain++;
		}

		// optimize out icmp in conditional branch
		if(func.code[i].type == "set" && func.code[i].val.type == "comparison" &&
			func.code[i+1].type == "branch" && func.code[i+1].conditional && func.code[i+1].condition == func.code[i].name) {

			func.code[i] = {
				type: "branch",
				conditional: true,
				dest: func.code[i+1].dest,
				falseDest: func.code[i+1].falseDest,
				condition: icmpBlock(functionContext, func.code[i]),
				rawCondition: true
			};

			iGain++;
		}

		var instruction = compileInstruction(functionContext, func.code[i]);

		if(!functionContext.gotoInit && functionContext.gotoComplex && functionContext.gotoComplex.okToUse) {
			blockList = blockList.concat([functionContext.gotoComplex.forever]);
			functionContext.gotoInit = true;
		}
		if(hasGotoComplex) {
			if(functionContext.gotoComplex.currentContext[2]) {
				functionContext.gotoComplex.currentContext[2] =
					functionContext.gotoComplex.currentContext[2].concat(instruction);
			} else {
				functionContext.gotoComplex.currentContext[2] = instruction;
			}
		} else {
			blockList = blockList.concat(instruction);
		}

		i += iGain;
	}

	//blockList = blockList.concat(returnBlock());

	return blockList;
}

function compileInstruction(ctx, block) {
	if(block.type == "call") {
		// calling a (potentially foreign) function
		return callBlock(ctx, block);
	} else if(block.type == "ffi") {
		// FFI block
		// load the code from the options
		return module.exports.ffi[block.ffiBlock];
	} else if(block.type == "set") {
		var val = 0;

		console.log("SET: "+JSON.stringify(block));

		if(block.val.type == "return value") {
			val = ["readVariable", "return value"];
		} else if(block.val.type == "variable") {
			val = fetchByName(ctx, block.val.name);
		} else if(block.val.type == "arithmetic") {
			val = [block.val.operation, fetchByName(ctx, block.val.operand1), fetchByName(ctx, block.val.operand2)];
		} else if(block.val.type == "comparison") {
			val = icmpBlock(ctx, val);
		} else if(block.val.type == "sext") {
			val = signExtend(ctx, block.val);
		}

		return compileInstruction(ctx, block.computation)
				.concat(allocateLocal(ctx, val, block.name));
	} else if(block.type == "ret") {
		return returnBlock(ctx, block.value);
	} else if(block.type == "store") {
		return dereferenceAndSet(ctx, block.destination.value, block.src.value);
	} else if(block.type == "gotoComplex") {
		ctx.gotoComplex = {
			context: [],
			okToUse: false,
			forever: ["doForever", []],
			active: true
		}

		//return [ctx.gotoComplex.forever];
	} else if(block.type == "label") {
		if(ctx.scoped) {
			ctx.gotoComplex.currentContext[2] =
				ctx.gotoComplex.currentContext[2].concat(freeLocals(ctx));
		}

		ctx.scoped = true;

		var chunk = ["doIfElse", ["=", getCurrentLabel(), block.label], [], []];

		ctx.gotoComplex.okToUse = true;
		ctx.gotoComplex.active = true;

		if(ctx.gotoComplex.currentContext) {
			ctx.gotoComplex.currentContext[3] = [chunk];
			ctx.gotoComplex.currentContext = ctx.gotoComplex.currentContext[3][0];
		} else {
			ctx.gotoComplex.currentContext = chunk;
			ctx.gotoComplex.context = ctx.gotoComplex.currentContext;
			ctx.gotoComplex.forever[1] = [ctx.gotoComplex.context];
		}

	} else if(block.type == "branch") {
		ctx.gotoComplex.active = false;

		if(block.conditional) {
			var cond = block.rawCondition ? block.condition : ["=", fetchByName(ctx, block.condition), 1];

			return [
				["doIfElse", cond, absoluteBranch(block.dest.slice(1)), absoluteBranch(block.falseDest.slice(1))]
			];
		} else {
			return absoluteBranch(block.dest);
		}
	}

	return [];
}

// fixme: stub
function defaultForType(type) {
	console.log(type);
	return 0;
}

// fixme: stub
function specifierForType(type) {
	return "%s";
}

// fixme: stub
function formatValue(ctx, type, value) {
	console.log("FORMAT: "+type+","+value);

	if(typeof value == "object") {
		if(value.type == "getelementptr") {
			// fixme: necessary and proper implementation
			return addressOf(ctx, value.base.val);
		}
	}

	if(value[0] == '%') {
		return fetchByName(ctx, value);
	}

	return value;
}

function getOffset(ctx, value) {
	return ctx.globalLocalDepth + ctx.scopedLocalDepth - ctx.locals[value];
}

function stackPtr() {
	return ["readVariable", "sp"];
}

function stackPosFromOffset(offset) {
	// optimize zero-index
	/*if(offset == 0) {
		return stackPtr();
	}*/

	return ["+", stackPtr(), offset + 1];
}

// higher-level code generation

function allocateLocal(ctx, val, name) {
	if(name) {
		console.log(name+","+val);

		var depth = 0;

		if(ctx.scoped) {
			depth = ctx.globalLocalDepth + (++ctx.scopedLocalDepth);
		} else {
			depth = ctx.globalLocalDepth;
		}

		ctx.locals[name] = depth;
	}

	ctx.globalToFree++;

	if(ctx.scoped) {
		ctx.scopeToFree++;
	}

	return [
		["setLine:ofList:to:", stackPtr(), "DATA", val],
		["changeVar:by:", "sp", -1]
	];
}

function freeStack(num) {
	console.log("Freeing stack");
	return [
		["changeVar:by:", "sp", num]
		//["doRepeat", num, [["deleteLine:ofList:", "last", "Stack"]]],
	];
}

function freeLocals(ctx) {
	var numToFree = ctx.globalToFree;

	if(ctx.scoped) {
		numToFree = ctx.scopeToFree;
		ctx.scopeToFree = 0;
		ctx.scopedLocalDepth = 0;
	}

	return freeStack(numToFree);
}

function fetchByName(ctx, n) {
	if(ctx.locals[n] !== undefined)
		return ["getLine:ofList:", stackPosFromOffset(getOffset(ctx, n)), "DATA"];
	else if(ctx.params.indexOf(n) > -1)
		return ["getParam", n, "r"];
	else if( (n * 1) == n)
		return n
	else
		return ["undefined"];
}

function addressOf(ctx, n) {
	console.log(ctx.rootGlobal[n.slice(1)]);
	if(ctx.rootGlobal[n.slice(1)])
		return ctx.rootGlobal[n.slice(1)].ptr;
	else
		return ["undefined"];
}

function returnBlock(ctx, val) {
	var proc = freeLocals(ctx);

	if(ctx.gotoComplex) {
		proc = proc.concat(cleanGotoComplex());
	}

	if(val) {
		proc.push(["setVar:to:", "return value", formatValue(ctx, val[0], val[1])]);
	}

	proc.push(["stopScripts", "this script"]);

	return proc;
}

function callBlock(ctx, block) {
	var spec = block.funcName;
	var args = [];

	for(var a = 0; a < block.paramList.length; ++a) {
		args.push(formatValue(ctx, block.paramList[a][0], block.paramList[a][1]));
		spec += " "+specifierForType(block.paramList[a][0]);
	}

	return [
		["call", spec].concat(args)
	];
}

// TODO: more robust implementation to support heap

function dereferenceAndSet(ctx, ptr, content) {
	return [
		[
			"setLine:ofList:to:",
			stackPosFromOffset(getOffset(ctx, ptr)),
			"DATA",
			fetchByName(ctx, content)
		]
	];
}

function specForComparison(comp) {
	if(comp == "eq") {
		return "=";
	} else if(comp == "ne") {
		return "!=";
	} else if(comp == "slt" || comp == "ult") {
		return "<";
	} else if(comp == "sgt" || comp == "ugt") {
		return ">";
	}
	return "undefined";
}

function initGotoComplex() {
	return [
		["append:toList:", 0, "Label Stack"]
	];
}

function getCurrentLabel() {
	return ["getLine:ofList:", "last", "Label Stack"];
}

function cleanGotoComplex() {
	return [
		["deleteLine:ofList:", "last", "Label Stack"]
	];
}

function absoluteBranch(dest) {
	return [
		["setLine:ofList:to:", "last", "Label Stack", dest]
	];
}

function castToNumber(b) {
	return ["*", b, 1];
}

function icmpBlock(ctx, block) {
	var spec = specForComparison(block.val.operation);
	var negate = false;

	if(spec[0] == "!") {
		negate = true;
		spec = spec.slice(1);
	}

	var b = [spec, fetchByName(ctx, block.val.left), fetchByName(ctx, block.val.right)];

	if(negate) {
		b = ["not", b];
	}

	return castToNumber(b);
}

function signExtend(ctx, block) {
	// TODO: once we support typing correctly, sign extend will need a proper implementation too
	return [fetchByName(block.source)];
}<|endoftext|>


<commit_before>
<commit_msg>Delete index.js<commit_after><|endoftext|>


<commit_before>module.exports = function(io){
  var express = require('express')
  var router = express.Router();
  var gcm = require('node-gcm')
  var push_auths = require('./push_auths.js')

  var sender = new gcm.Sender(push_auths.gcm);
  var registrationIds = [];
  var regIdx = 0;
  var tweet_queue = [];
  var RATE_LIMIT = 1000;
  function genID(){
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    var ID = '';
    for(var i=0; i < 12; i++)
      ID += chars.charAt(Math.floor(Math.random()*chars.length));
    return ID;
  }
  function send_tweet_socket(tweet,socket){
    socket.emit('tweet',tweet);
  }
  function send_tweet_gcm(tweet,id){
    var message = new gcm.Message();
    message.addData('title', 'TREC RTS Mobile Judger');
    message.addData('message','There are pending tweets to judge.')
    message.addData('tweetid',String(tweet.tweetid))
    message.addData('topid',String(tweet.topid))
    message.addData('topic',String(tweet.topic))
    message.addData('content-available', '1');
    sender.send(message, { registrationTokens: [ id ] }, function (err, response) {
        if(err) console.error(err);
       //else    console.log(response);
    });
    //var message = new gcm.Message({"content-available":1});
 /*   message.addData('message',"You have pending tweets to judge.");
    message.addData('title','TREC RTS CrowdJudge' );
    message.addData('tweetid',String(tweet.tweetid))
    message.addData('topid',String(tweet.topid))
    message.addData('topic',String(tweet.topic))
    message.addData('msgcnt','1'); // Shows up in the notification in the status bar
    message.addData('content-available',1);
    message.timeToLive = 3000;// Duration in seconds to hold in GCM and retry before timing out. Default 4 weeks (2,419,200 seconds) if not specified.
    message.delayWhileIdle = false;
    message.addNotification({title: 'TREC RTS CrowdJudge','content-available':1, body : 'You have pending tweets to judge.', icon: 'ic_launcher'});
    sender.send(message, id, 4, function (result) {
      console.log(id,result);
    });*/
  }
  //TODO: Add Apple Push

  function send_tweet(tweet){
    var currDevice = registrationIds[regIdx++];
    if(currDevice['type'] === 'gcm')
      send_tweet_gcm(tweet,currDevice['conn']);
    else if(currDevice['type'] === 'socket'){
      send_tweet_socket(tweet,currDevice['conn']);
    }

    if (regIdx >= registrationIds.length) regIdx = 0;
  }

  function validate(db,table,col, id,cb){
    db.query('select * from '+table+' where '+col+' = ?;',[id],cb);
  }

  function validate_group(db,groupid,cb){
    validate(db,'groups','groupid',groupid,cb);
  }

  function validate_client(db,clientid,cb){
    validate(db,'clients','clientid',clientid,cb);
  }

  function isValidTweet(str){
    return str.match('[0-9]=') !== null
  }

  router.post('/register/mobile/',function(req,res){
    var regid = req.body.regid;
    // At least one reg id required
    if ( registrationIds.indexOf(regid) === -1){
      registrationIds.push({'type':'gcm','conn':regid});
    }
    res.status(204).send();
    // Definitely need to do something better here
    if(tweet_queue.length > 0){
      for(var i = 0; i < tweet_queue.length; i++){
        send_tweet(tweet_queue[i]);
      }
      tweet_queue = [];
    }
  });

  router.post('/tweets/:topid/:clientid',function(req,res){
    var topid = req.params.topid;
    var clientid  = req.params.clientid;
    var tweets = req.body.tweets;
    validate_client(db,clientid,function(errors,results){
      if (errors || results.length === 0){
        res.status(500).json({'message': 'Unable to validate client: ' + clientid})
        return;
      }
      stmt = ""
      for (var i = 0; i < tweets.length; i++){
        if (! isValidTweetID(tweets[i])){
          res.status(404).json({'message': 'Invalid tweetid: ' + tweets[i]});
        }
        if (i !== 0){
          stmt += ',(\'' + tweets[i] + '\',\'' + topid + '\')';
        } else {
          stmt += '(\'' + tweets[i] + '\',\'' + topid + '\')';
        }
      }
      db.query('insert into requests_digest_' + clientid + ' (docid,topid) values ' + [stmt],function(errors0,results0){
        if (errors)
          res.status(500).json({'message': 'Unable to insert tweets for end of day digest'});
        res.status(204).send()
      });
    });
  });
  // TODO: Need to enforce topid is valid
  router.post('/tweet/:topid/:tweetid/:clientid',function(req,res){
    var topid = req.params.topid;
    var tweetid = req.params.tweetid;
    var clientid = req.params.clientid;
    var db = req.db;
    validate_client(db,clientid,function(errors,results){
      if(errors || results.length === 0){
        res.status(500).json({'message':'Could not validate client: ' + clientid})
        return;
      }
      db.query('select count(*) as cnt from requests_'+clientid+' where topid = ? and submitted between CURDATE() and date_add(CURDATE(),INTERVAL 1 day);', [topid], function(errors0,results0){
        if(errors0 || results0.length === 0){
          res.status(500).json({'message':'Could not process request for topid: ' + topid + ' and ' + tweetid});
          return;
        }else if(results0[0].cnt >= RATE_LIMIT){
          res.status(429).json({'message':'Rate limit exceeded for topid: ' + topid});
          return;
        }
        db.query('insert requests_' + clientid + ' (topid,tweetid) values (?,?);',[topid,tweetid], function(errors1,results1){
          if(errors1 || results1.length === 0){
            res.status(500).json({'message':'Could not process request for topid: ' + topid + ' and ' + tweetid});
            return;
           }
          db.query('select query from topics where topid = ?;',topid,function(errors2,results2){

            if(registrationIds.length > 0){
              send_tweet({"tweetid":tweetid,"topid":topid,"topic":results2[0].query});
            }else{
               tweet_queue.push({"tweetid":tweetid,"topid":topid,"topic":results2[0].query});
            }
          })

          res.status(204).send();
        });
      });
    });
  });

  router.post('/judge/:topid/:tweetid/:rel', function(req,res){
    var topid = req.params.topid;
    var tweetid = req.params.tweetid;
    var rel = req.params.rel;
    //var partid = req.body.partid;
    var partid = "foo";
    var db = req.db;
    db.query('insert judgements_'+topid+'(assessor,tweetid,rel) values (?,?,?);',[partid,tweetid,rel],function(errors,results){
      if(errors){
        console.log(errors)
        console.log("Unable to log: ",topid," ",tweetid," ",rel);
        res.status(500).json({message : 'Unable to relevance assessment'})
      }else{
        console.log("Logged: ",topid," ",tweetid," ",rel);
        res.status(204).send()
      }
    });
  });

  router.get('/judge/:topid/:tweetid/:clientid', function(req,res){
    var clientid = req.params.clientid;
    var topid = req.params.topid;
    var tweetid = req.params.tweetid;
    var db = req.db;
    validate_client(db,clientid,function(errors,results){
      if(errors || results.length === 0){
        res.status(500).json({'message':'Could not validate client: ' + clientid})
        return;
      }
      db.query('select rel from judgements_'+topid+' where tweetid = ?;'[tweetid],function(errors1,results1){
        if(errors1){
          res.status(500).json({'message':'Error retrieving judgement for : '+ tweetid + ' on ' + topid});
        }else if (results1.length ===0){
          res.status(500).json({'message':'No judgement for : '+ tweetid + ' on ' + topid});
        }
        res.json({'tweetid':tweetid,'topid':topid,'rel':results[0].rel});
      });
    });
  });

  router.post('/register/system/', function(req,res){
    var groupid = req.body.groupid;
    var db = req.db;
    var clientid = genID();
    validate_group(db,groupid,function(errors,results){
      if(errors || results.length === 0){
        res.status(500).json({'message':'Unable to register a client for group: ' + groupid});
        return;
      }
      db.query('insert clients (groupid,clientid,ip) values (?,?,?);',[groupid,clientid,req.ip], function(errors1,results1){
        if(errors1){
          res.status(500).json({'message':'Unable to register system.'});
          return;
        }
        db.query('create table requests_'+clientid+' like requests_template;'); // Assume this works for now
        db.query('create table requests_digest_'+clientid+' like requests_template;'); // Assume this works for now
        res.json({'clientid':clientid});
      });
    });
  });

  router.get('/topics/:clientid', function(req,res){
    var clientid = req.params.clientid;
    var db = req.db;
    validate_client(db,clientid,function(errors,results){
      if(errors || results.length === 0){
        console.log(errors);
        res.status(500).json({'message':'Unable to validate client: ' + clientid});
        return;
      }
      db.query('select topid,query from topics;',function(errors1,results1){
        if(errors1){
          res.status(500).json({'message':'Unable to retrieve topics for client: ' + clientid});
        }else{
          res.json(results1);
        }
      });
    });
  });
  router.delete('/unregister/mobile/:regid',function(req,res){
    var regid = req.params.regid
    var idx = registrationIds.indexOf({"type":"gcm","conn":regid})
    if (idx > -1) registrationIds.splice(idx,1)
  })
  io.on('connection', function(socket){
    socket.on('register',function(){
      console.log("Registered")
      registrationIds.push({'type':'socket','conn':socket});
    });
    socket.on('judge',function(msg){
      console.log('Judged: ', msg.topid, msg.tweetid,msg.rel);
    });
    socket.once('disconnect',function(){
      console.log("Disconnect");
      var idx = registrationIds.indexOf(socket);
      if (idx > -1) registrationIds.splice(idx,1);
    });
  });
  return router;
}
<commit_msg>Specd out candidate endpoints for topic assignment and topic assessment<commit_after>module.exports = function(io){
  var express = require('express')
  var router = express.Router();
  var gcm = require('node-gcm')
  var push_auths = require('./push_auths.js')

  var sender = new gcm.Sender(push_auths.gcm);
  var registrationIds = [];
  var regIdx = 0;
  var tweet_queue = [];
  var RATE_LIMIT = 1000;
  function genID(){
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    var ID = '';
    for(var i=0; i < 12; i++)
      ID += chars.charAt(Math.floor(Math.random()*chars.length));
    return ID;
  }
  function send_tweet_socket(tweet,socket){
    socket.emit('tweet',tweet);
  }
  function send_tweet_gcm(tweet,id){
    var message = new gcm.Message();
    message.addData('title', 'TREC RTS Mobile Judger');
    message.addData('message','There are pending tweets to judge.')
    message.addData('tweetid',String(tweet.tweetid))
    message.addData('topid',String(tweet.topid))
    message.addData('topic',String(tweet.topic))
    message.addData('content-available', '1');
    sender.send(message, { registrationTokens: [ id ] }, function (err, response) {
        if(err) console.error(err);
       //else    console.log(response);
    });
  }
  //TODO: Add Apple Push

  function send_tweet(tweet){
    var currDevice = registrationIds[regIdx++];
    if(currDevice['type'] === 'gcm')
      send_tweet_gcm(tweet,currDevice['conn']);
    else if(currDevice['type'] === 'socket'){
      send_tweet_socket(tweet,currDevice['conn']);
    }

    if (regIdx >= registrationIds.length) regIdx = 0;
  }

  function validate(db,table,col, id,cb){
    db.query('select * from '+table+' where '+col+' = ?;',[id],cb);
  }

  function validate_group(db,groupid,cb){
    validate(db,'groups','groupid',groupid,cb);
  }

  function validate_client(db,clientid,cb){
    validate(db,'clients','clientid',clientid,cb);
  }

  function validate_participant(db,partid,cb){
    validate(db,'participants','partid',partid,cb);
  }
  function validate_client_or_participant(db,uniqid,cb){
    validate_client(db,uniqid,function(errors,results){
      if(errors || results.length === 0){
        validate_participant(db,partid,cb);
      }else{
        cb(errors,results);
      }
    });
  }
  function isValidTweet(str){
    return str.match('[0-9]=') !== null
  }

  router.get('/validate/part/:partid',function{req,res}{
    var partid = req.params.partid;
    var db = req.db;
    validate_participant(db,partid,function(errors0,results0){
      if (errors || results.length === 0){
        res.status(500).json({'message': 'Unable to validate client: ' + clientid})
        return;
      }else{
        res.status(204).send()
      }
    });
  });

  router.post('/register/mobile/',function(req,res){
    var regid = req.body.regid;
    var partid = req.body.partid;
    // At least one reg id required
    if ( registrationIds.indexOf(regid) === -1){
      registrationIds.push({'type':'gcm','conn':regid});
    }
    res.status(204).send();
    // Definitely need to do something better here
    if(tweet_queue.length > 0){
      for(var i = 0; i < tweet_queue.length; i++){
        send_tweet(tweet_queue[i]);
      }
      tweet_queue = [];
    }
  });

  router.post('/tweets/:topid/:clientid',function(req,res){
    var topid = req.params.topid;
    var clientid  = req.params.clientid;
    var tweets = req.body.tweets;
    var db = req.db;
    validate_client(db,clientid,function(errors,results){
      if (errors || results.length === 0){
        res.status(500).json({'message': 'Unable to validate client: ' + clientid})
        return;
      }
      stmt = ""
      for (var i = 0; i < tweets.length; i++){
        if (! isValidTweetID(tweets[i])){
          res.status(404).json({'message': 'Invalid tweetid: ' + tweets[i]});
        }
        if (i !== 0){
          stmt += ',(\'' + tweets[i] + '\',\'' + topid + '\')';
        } else {
          stmt += '(\'' + tweets[i] + '\',\'' + topid + '\')';
        }
      }
      db.query('insert into requests_digest_' + clientid + ' (docid,topid) values ' + [stmt],function(errors0,results0){
        if (errors)
          res.status(500).json({'message': 'Unable to insert tweets for end of day digest'});
        res.status(204).send()
      });
    });
  });
  // TODO: Need to enforce topid is valid
  router.post('/tweet/:topid/:tweetid/:clientid',function(req,res){
    var topid = req.params.topid;
    var tweetid = req.params.tweetid;
    var clientid = req.params.clientid;
    var db = req.db;
    validate_client(db,clientid,function(errors,results){
      if(errors || results.length === 0){
        res.status(500).json({'message':'Could not validate client: ' + clientid})
        return;
      }
      db.query('select count(*) as cnt from requests_'+clientid+' where topid = ? and submitted between CURDATE() and date_add(CURDATE(),INTERVAL 1 day);', [topid], function(errors0,results0){
        if(errors0 || results0.length === 0){
          res.status(500).json({'message':'Could not process request for topid: ' + topid + ' and ' + tweetid});
          return;
        }else if(results0[0].cnt >= RATE_LIMIT){
          res.status(429).json({'message':'Rate limit exceeded for topid: ' + topid});
          return;
        }
        db.query('insert requests_' + clientid + ' (topid,tweetid) values (?,?);',[topid,tweetid], function(errors1,results1){
          if(errors1 || results1.length === 0){
            res.status(500).json({'message':'Could not process request for topid: ' + topid + ' and ' + tweetid});
            return;
           }
          db.query('select query from topics where topid = ?;',topid,function(errors2,results2){

            if(registrationIds.length > 0){
              send_tweet({"tweetid":tweetid,"topid":topid,"topic":results2[0].query});
            }else{
               tweet_queue.push({"tweetid":tweetid,"topid":topid,"topic":results2[0].query});
            }
          })

          res.status(204).send();
        });
      });
    });
  });

  router.post('/judge/:topid/:tweetid/:rel', function(req,res){
    var topid = req.params.topid;
    var tweetid = req.params.tweetid;
    var rel = req.params.rel;
    //var partid = req.body.partid;
    var partid = "foo";
    var db = req.db;
    db.query('insert judgements_'+topid+'(assessor,tweetid,rel) values (?,?,?);',[partid,tweetid,rel],function(errors,results){
      if(errors){
        console.log(errors)
        console.log("Unable to log: ",topid," ",tweetid," ",rel);
        res.status(500).json({message : 'Unable to relevance assessment'})
      }else{
        console.log("Logged: ",topid," ",tweetid," ",rel);
        res.status(204).send()
      }
    });
  });

  router.get('/judge/:topid/:tweetid/:clientid', function(req,res){
    var clientid = req.params.clientid;
    var topid = req.params.topid;
    var tweetid = req.params.tweetid;
    var db = req.db;
    validate_client(db,clientid,function(errors,results){
      if(errors || results.length === 0){
        res.status(500).json({'message':'Could not validate client: ' + clientid})
        return;
      }
      db.query('select rel from judgements_'+topid+' where tweetid = ?;'[tweetid],function(errors1,results1){
        if(errors1){
          res.status(500).json({'message':'Error retrieving judgement for : '+ tweetid + ' on ' + topid});
        }else if (results1.length ===0){
          res.status(500).json({'message':'No judgement for : '+ tweetid + ' on ' + topid});
        }
        res.json({'tweetid':tweetid,'topid':topid,'rel':results[0].rel});
      });
    });
  });

  router.post('/register/system/', function(req,res){
    var groupid = req.body.groupid;
    var db = req.db;
    var clientid = genID();
    validate_group(db,groupid,function(errors,results){
      if(errors || results.length === 0){
        res.status(500).json({'message':'Unable to register a client for group: ' + groupid});
        return;
      }
      db.query('insert clients (groupid,clientid,ip) values (?,?,?);',[groupid,clientid,req.ip], function(errors1,results1){
        if(errors1){
          res.status(500).json({'message':'Unable to register system.'});
          return;
        }
        db.query('create table requests_'+clientid+' like requests_template;'); // Assume this works for now
        db.query('create table requests_digest_'+clientid+' like requests_template;'); // Assume this works for now
        res.json({'clientid':clientid});
      });
    });
  });

  router.get('/topics/:uniqid', function(req,res){
    var uniqid = req.params.uniqid;
    var db = req.db;
    validate_client_or_participant(db,uniqid,function(errors,results){
      if(errors || results.length === 0){
        console.log(errors);
        res.status(500).json({'message':'Unable to validate client: ' + uniqid});
        return;
      }
      db.query('select topid,query from topics;',function(errors1,results1){
        if(errors1){
          res.status(500).json({'message':'Unable to retrieve topics for client: ' + uniqid});
        }else{
          res.json(results1);
        }
      });
    });
  });
  router.post('/topics/interest/:partid',function(req,res){
    var partid = req.body.partid;
    var topids = req.body.topids;
    var db = req.db;
    validate_participant(db,partid,function(errors0,results0){
      if(errors0 || results0.length === 0){
        res.status(500).json({'message':'Unable to validate participant:'+partid});
        return
      }
      stmt = ""
      for (var i = 0; i < topids.length; i++){
        if (i !== 0){
          stmt += ',(\'' + topids[i] + '\',\'' + partid + '\')';
        } else {
          stmt += '(\'' + topids[i] + '\',\'' + partid + '\')';
        }
      }
      db.query('insert into topic_assignments (topid,partid) values ' + [stmt],function(errors0,results0){
        if (errors)
          res.status(500).json({'message': 'Unable to insert topics for partid:' + partid});
        res.status(204).send()
      });
    });
  });
  router.get('/topics/interest/:partid',function(req,res){
    var partid = req.params.partid;
    var topids = req.body.topids;
    var db = req.db;
    validate_participant(db,partid,function(errors0,results0){
      if(errors0 || results0.length === 0){
        res.status(500).json({'message':'Unable to validate participant:'+partid});
        return
      }
      db.query('select topid from topic_assignments where partid = ?;',partid,function(errors1,results1){
        if(errors1){
          res.status(500).json({'message':'Unable to fetch assigned topics for: ' + partid})
          return;
        };
        res.json(results)
      });
    });
  });
  router.post('/topics/suggest/:uniqid',function(req,res){
    var db = req.db;
    var uniqid = req.params.uniqid;
    var topics = req.body.topics;
    validate_client_or_participant(db,uniqid,function(errors0,results0){
      if(errors0 || results0.length === 0){
        res.status(500).json({'message':'Unable to validate: ' + uniqid})
        return;
      }
      stmt = ""
      for (var i = 0; i < topics.length; i++){
        if (i !== 0){
          stmt += ',(\'' + topics[i].title + '\',\'' + topics[i].desc + '\')';
        } else {
          stmt += '(\'' + topics[i].title + '\',\'' + topics[i].desc + '\')';
        }
      }
      db.query('insert into candidate_topics (title,desc) values ' + [stmt],function(errors0,results0){
        if (errors)
          res.status(500).json({'message': 'Unable to insert topic suggestions for:' + partid});
        res.status(204).send()
      });
    });
  });
  router.delete('/unregister/mobile/:regid',function(req,res){
    var regid = req.params.regid
    var idx = registrationIds.indexOf({"type":"gcm","conn":regid})
    if (idx > -1) registrationIds.splice(idx,1)
  })

  io.on('connection', function(socket){
    socket.on('register',function(){
      console.log("Registered")
      registrationIds.push({'type':'socket','conn':socket});
    });
    socket.on('judge',function(msg){
      console.log('Judged: ', msg.topid, msg.tweetid,msg.rel);
    });
    socket.once('disconnect',function(){
      console.log("Disconnect");
      var idx = registrationIds.indexOf(socket);
      if (idx > -1) registrationIds.splice(idx,1);
    });
  });
  return router;
}
<|endoftext|>


<commit_before>/* jshint esversion:6, node: true */

/*
 * Loblaws Messenger - action_handler.js
 *
 * Handles incoming data from the user sent to the server.
 */

const index = require('./index.js');
const request = require('request');
const search = require('./actions/search.js');
const recipe = require('./actions/recipe.js');
const cart = require('./cart_handler.js');

let State = {
	IDLE: 0,
	WAITING_FOR_SEARCH_TYPE: 1, // The server is waiting search selection (ie product or recipe)
	WAITING_FOR_PRODUCT: 2, // The server is waiting product search
	WAITING_FOR_RECIPE: 3 // The server is waiting recipe search
};

let currentState = State.IDLE;

/* Hanldes when a user sends a message. */
function handleMessageReceive(sender, text) {
	console.log("[EVENT] " + sender + ": Received message from user: \'" + text + "\'");

	// If the user has requested to search for product by name..
	if (currentState == State.WAITING_FOR_PRODUCT) {
		search_handler.requestProduct(sender, text);

	// If the user has requested to search for a recipe..
	} else if (currentState == State.WAITING_FOR_RECIPE) {
		recipe_handler.requestRecipe(sender, text);

	} else if (currentState == State.IDLE) {
		promptUserSearch(sender);
	}
}

/* Hanldes when a user pressed a button. */
function handleButton(sender, payload) {
	console.log("[EVENT] " + sender + ": Received postback (button click) from user");
	console.log("[EVENT] " + sender + ":     -> postback data: " + payload);

	if (payload.includes("recipeSelected")) {
		loadIngredients(payload);
		ingredientsActive = true;
	}

	switch (payload) {
		case "searchProduct":
			console.log("[EVENT] " + sender + ": Requested to search for products by name");
			sendTextMessage(sender, "Please enter a product name to search for");
			action_handler.currentState = action_handler.State.WAITING_FOR_PRODUCT;
			break;

		case "searchRecipe":
			console.log("[EVENT] " + sender + ": Requested to search for recipes");
			sendTextMessage(sender, "Search by recipe");
			action_handler.currentState = action_handler.State.WAITING_FOR_RECIPE;
			break;
	}
}

/* Prompts the user to select the type of search (ie product or recipe). */
function promptUserSearch(sender) {
	let messageData = {
		"attachment": {
			"type": "template",
			"payload": {
				"template_type": "button",
				"text": "How would you like to search?",
				"buttons": [
					{
						"type": "postback",
						"title": "By Product",
						"payload": "searchProduct",
					}, {
						"type": "postback",
						"title": "By Recipe",
						"payload": "searchRecipe",
					}
				]
	  		}
		}
	};

	console.log("[INFO] " + sender + ": Greeted bot");

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: { access_token: index.AUTH_TOKEN },
		method: 'POST',
		json: {
			recipient: { id:sender },
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

/* Sends a text emesssage to the user. */
function sendTextMessage(sender, text) {
	let messageData = { text: text };

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: { access_token: index.AUTH_TOKEN },
		method: 'POST',
		json: {
			recipient: { id: sender },
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

module.exports = {
	handleMessageReceive: handleMessageReceive,
	handleButton: handleButton,
    sendTextMessage: sendTextMessage
};
<commit_msg>Fix unnecessary module calls<commit_after>/* jshint esversion:6, node: true */

/*
 * Loblaws Messenger - action_handler.js
 *
 * Handles incoming data from the user sent to the server.
 */

const index = require('./index.js');
const request = require('request');
const search = require('./actions/search.js');
const recipe = require('./actions/recipe.js');
const cart = require('./cart_handler.js');

let State = {
	IDLE: 0,
	WAITING_FOR_SEARCH_TYPE: 1, // The server is waiting search selection (ie product or recipe)
	WAITING_FOR_PRODUCT: 2, // The server is waiting product search
	WAITING_FOR_RECIPE: 3 // The server is waiting recipe search
};

let currentState = State.IDLE;

/* Hanldes when a user sends a message. */
function handleMessageReceive(sender, text) {
	console.log("[EVENT] " + sender + ": Received message from user: \'" + text + "\'");

	// If the user has requested to search for product by name..
	if (currentState == State.WAITING_FOR_PRODUCT) {
		search_handler.requestProduct(sender, text);

	// If the user has requested to search for a recipe..
	} else if (currentState == State.WAITING_FOR_RECIPE) {
		recipe_handler.requestRecipe(sender, text);

	} else if (currentState == State.IDLE) {
		promptUserSearch(sender);
	}
}

/* Hanldes when a user pressed a button. */
function handleButton(sender, payload) {
	console.log("[EVENT] " + sender + ": Received postback (button click) from user");
	console.log("[EVENT] " + sender + ":     -> postback data: " + payload);

	if (payload.includes("recipeSelected")) {
		loadIngredients(payload);
		ingredientsActive = true;
	}

	switch (payload) {
		case "searchProduct":
			console.log("[EVENT] " + sender + ": Requested to search for products by name");
			sendTextMessage(sender, "Please enter a product name to search for");
			currentState = State.WAITING_FOR_PRODUCT;
			break;

		case "searchRecipe":
			console.log("[EVENT] " + sender + ": Requested to search for recipes");
			sendTextMessage(sender, "Search by recipe");
			currentState = State.WAITING_FOR_RECIPE;
			break;
	}
}

/* Prompts the user to select the type of search (ie product or recipe). */
function promptUserSearch(sender) {
	let messageData = {
		"attachment": {
			"type": "template",
			"payload": {
				"template_type": "button",
				"text": "How would you like to search?",
				"buttons": [
					{
						"type": "postback",
						"title": "By Product",
						"payload": "searchProduct",
					}, {
						"type": "postback",
						"title": "By Recipe",
						"payload": "searchRecipe",
					}
				]
	  		}
		}
	};

	console.log("[INFO] " + sender + ": Greeted bot");

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: { access_token: index.AUTH_TOKEN },
		method: 'POST',
		json: {
			recipient: { id:sender },
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

/* Sends a text emesssage to the user. */
function sendTextMessage(sender, text) {
	let messageData = { text: text };

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: { access_token: index.AUTH_TOKEN },
		method: 'POST',
		json: {
			recipient: { id: sender },
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

module.exports = {
	handleMessageReceive: handleMessageReceive,
	handleButton: handleButton,
    sendTextMessage: sendTextMessage
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 */

module.exports = {
  title: 'Searchkit',
  tagline: 'Search, made easy',
  url: 'https://searchkit.co',
  baseUrl: '/',
  onBrokenLinks: 'warn',
  favicon: 'img/favicon.ico',
  organizationName: 'searchkit', // Usually your GitHub org/user name.
  projectName: 'searchkit', // Usually your repo name.
  themeConfig: {
    disableSwitch: true,
    defaultMode: 'dark',

    announcementBar: {
      id: 'searchkit_classic', // Any value that will identify this message.
      content:
        'Searchkit V2 Docs are accessible here',
      backgroundColor: 'rgb(26,32,44)', // Defaults to `#fff`.
      textColor: '#fff', // Defaults to `#000`.
      isCloseable: false, // Defaults to `true`.
    },
    sidebarCollapsible: false,
    respectPrefersColorScheme: false,
    gtag: {
      trackingID: 'G-Y1LWVCFZQK',
    },
    navbar: {
      title: 'Searchkit',
      items: [
        {
          to: 'docs',
          label: "Docs",
        },
        {
          to: 'docs/your-own-components',
          activeBasePath: 'docs/your-own-components',
          label: "Customising UI",
        },
        {
          to: 'docs/examples/next',
          activeBasePath: 'docs/examples',
          label: "Examples",
        },
        {
          href: 'https://github.com/searchkit/searchkit',
          label: 'GitHub',
          position: 'right',
        }
      ],
    },
    footer: {
      style: 'dark',
      links: [

      ],
      // Please do not remove the credits, help to publicize Docusaurus :)
      copyright: `Copyright © ${new Date().getFullYear()} Ten Eleven, Inc. Built with Docusaurus.`,
    },
  },
  presets: [
    [
      '@docusaurus/preset-classic',
      {
        docs: {
          sidebarPath: require.resolve('./sidebars.js'),
          // Please change this to your repo.
          editUrl:
            'https://github.com/searchkit/searchkit/tree/next/docs/',
        },
        blog: {
          showReadingTime: true,
          // Please change this to your repo.
          editUrl:
            'https://github.com/facebook/docusaurus/edit/master/website/blog/',
        },
        theme: {
          customCss: [require.resolve('./src/css/custom.css')],
        },
      },
    ],
  ],
  plugins: [
    require.resolve('@cmfcmf/docusaurus-search-local')
  ]
};
<commit_msg>fix examples link in docs<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 */

module.exports = {
  title: 'Searchkit',
  tagline: 'Search, made easy',
  url: 'https://searchkit.co',
  baseUrl: '/',
  onBrokenLinks: 'warn',
  favicon: 'img/favicon.ico',
  organizationName: 'searchkit', // Usually your GitHub org/user name.
  projectName: 'searchkit', // Usually your repo name.
  themeConfig: {
    disableSwitch: true,
    defaultMode: 'dark',

    announcementBar: {
      id: 'searchkit_classic', // Any value that will identify this message.
      content:
        'Searchkit V2 Docs are accessible here',
      backgroundColor: 'rgb(26,32,44)', // Defaults to `#fff`.
      textColor: '#fff', // Defaults to `#000`.
      isCloseable: false, // Defaults to `true`.
    },
    sidebarCollapsible: false,
    respectPrefersColorScheme: false,
    gtag: {
      trackingID: 'G-Y1LWVCFZQK',
    },
    navbar: {
      title: 'Searchkit',
      items: [
        {
          to: 'docs',
          label: "Docs",
        },
        {
          to: 'docs/your-own-components',
          activeBasePath: 'docs/your-own-components',
          label: "Customising UI",
        },
        {
          to: 'docs/examples/nextjs-graphql-elasticsearch-boilerplate',
          activeBasePath: 'docs/examples',
          label: "Examples",
        },
        {
          href: 'https://github.com/searchkit/searchkit',
          label: 'GitHub',
          position: 'right',
        }
      ],
    },
    footer: {
      style: 'dark',
      links: [

      ],
      // Please do not remove the credits, help to publicize Docusaurus :)
      copyright: `Copyright © ${new Date().getFullYear()} Ten Eleven, Inc. Built with Docusaurus.`,
    },
  },
  presets: [
    [
      '@docusaurus/preset-classic',
      {
        docs: {
          sidebarPath: require.resolve('./sidebars.js'),
          // Please change this to your repo.
          editUrl:
            'https://github.com/searchkit/searchkit/tree/next/docs/',
        },
        blog: {
          showReadingTime: true,
          // Please change this to your repo.
          editUrl:
            'https://github.com/facebook/docusaurus/edit/master/website/blog/',
        },
        theme: {
          customCss: [require.resolve('./src/css/custom.css')],
        },
      },
    ],
  ],
  plugins: [
    require.resolve('@cmfcmf/docusaurus-search-local')
  ]
};
<|endoftext|>


<commit_before>function Character(id, imageFile, startYPosition){
  "use strict";

  var self                  = this;
  this.alive                = true;
  this.img                  = new Image();
  this.id                   = "";
  this.canvas               = document.createElement("canvas");
  this.context              = "";
  this.drawSpeed            = 100;
  this.spriteMapXPosition   = 384;
  this.spriteMapYPosition   = 0;
  this.spriteImageWidth     = 48;
  this.spriteImageHeight    = 48;
  this.xPosition            = 0;
  this.yPosition            = 0;

  //Physic settings
  this.xVelocity            = 0;
  this.yVelocity            = 0;
  this.xAcceleration        = 2;
  this.yAcceleration        = 2;
  this.speedLimit           = 8;
  this.friction             = 0.90;
  this.rebound              = -0.7;
  this.jumpForce            = -20;
  this.gravity              = 2;
  this.toggleDirection      = false;
  this.left                 = false;
  this.right                = false;
  this.jump                 = false;
  this.onGround             = undefined;

  var container = document.getElementById("container");

  this.id = id;
  this.canvas.id = id;
  container.appendChild(this.canvas);
  this.context = document.getElementById(this.id).getContext("2d");
  this.canvas.width = this.canvas.clientWidth;
  this.canvas.height = this.canvas.clientHeight;

  this.img.src = imageFile;
  this.yPosition = startYPosition - this.spriteImageHeight;
  this.canvas.style.zIndex = "1";
  this.bounce();
};

Character.prototype.bounce = function(){
  "use strict";

  var self                  = this;
  this.context.clearRect(0, 0, this.context.canvas.clientWidth, this.context.canvas.clientHeight);

  if(this.spriteMapXPosition <= 240){
    this.toggleDirection = true;
  }else if(this.spriteMapXPosition >= 384){
    this.toggleDirection = false;
  }

  if(this.toggleDirection){
    this.spriteMapXPosition += this.spriteImageWidth;
  }else{
    this.spriteMapXPosition -= this.spriteImageWidth;
  }

  if(!this.onGround){
    this.spriteMapXPosition = 288;
    this.toggleDirection = false;
  }

  this.draw();
  if(this.alive){
    setTimeout(function(){ self.bounce(); }, this.drawSpeed);
  }
};

Character.prototype.draw = function(){
  "use strict";
  var friction;

  if(!this.left && !this.right){
    friction = this.friction;
  }else{
    friction = 1;
  }

  if(this.jump && this.onGround){
    this.yVelocity += this.jumpForce;
    this.onGround = false;
    friction = 1;
  }

  if(this.left && !this.right){
    this.xVelocity -= this.xAcceleration;
  }else if(this.right && !this.left){
    this.xVelocity += this.xAcceleration;
  }

  if(this.onGround){
    this.xVelocity *= friction;
  }
  this.yVelocity += this.gravity;

  if(this.xVelocity > this.speedLimit){
    this.xVelocity = this.speedLimit;
  }else if(this.xVelocity < -this.speedLimit){
    this.xVelocity = -this.speedLimit;
  }else if(this.yVelocity > this.speedLimit * 2){
    this.yVelocity = this.speedLimit * 2;
  }

  var checkMoveX = this.xPosition + this.xVelocity;
  var checkMoveY = this.yPosition + this.yVelocity;

  if(checkMoveX < 0){
    this.xVelocity *= this.rebound;
    this.xPosition = 0;
  }else if(checkMoveX > this.canvas.width - this.spriteImageWidth){
    this.xVelocity *= this.rebound;
    this.xPosition = this.canvas.width - this.spriteImageWidth;
  }else{
    this.xPosition = checkMoveX;
  }

  if(checkMoveY < 0){
    this.yVelocity *= this.rebound;
    this.yPosition = 0;
  }else if(checkMoveY > this.canvas.height - this.spriteImageHeight){
    this.yPosition = this.canvas.height - this.spriteImageHeight;
    this.yVelocity = -this.gravity;
    this.onGround = true;
  }else{
    this.yPosition = checkMoveY;
  }

  this.context.drawImage(
      this.img,
      this.spriteMapXPosition, 0, this.spriteImageWidth, this.spriteImageHeight,
      this.xPosition, this.yPosition, this.spriteImageWidth, this.spriteImageHeight
  );
};
<commit_msg>Add comments<commit_after>function Character(id, imageFile, startYPosition){
  "use strict";

  var self                  = this;
  this.alive                = true;
  this.img                  = new Image();
  this.id                   = "";
  this.canvas               = document.createElement("canvas");
  this.context              = "";
  this.drawSpeed            = 100;
  this.spriteMapXPosition   = 384;
  this.spriteMapYPosition   = 0;
  this.spriteImageWidth     = 48;
  this.spriteImageHeight    = 48;
  this.xPosition            = 0;
  this.yPosition            = 0;

  //Physics & movement settings
  this.xVelocity            = 0;
  this.yVelocity            = 0;
  this.xAcceleration        = 2;
  this.yAcceleration        = 2;
  this.speedLimit           = 8;
  this.friction             = 0.90;
  this.rebound              = -0.7;
  this.jumpForce            = -20;
  this.gravity              = 2;
  this.toggleDirection      = false;
  this.left                 = false;
  this.right                = false;
  this.jump                 = false;
  this.onGround             = undefined;

  var container = document.getElementById("container");

  // Setup canvas and it's parameters, then create the context.
  this.id = id;
  this.canvas.id = id;
  container.appendChild(this.canvas);
  this.context = document.getElementById(this.id).getContext("2d");
  this.canvas.width = this.canvas.clientWidth;
  this.canvas.height = this.canvas.clientHeight;

  this.img.src = imageFile;
  this.yPosition = startYPosition - this.spriteImageHeight;
  this.canvas.style.zIndex = "1";

  // Start animation.
  this.bounce();
};

/*
 * Cycles through the sprite sheet printing the bounce animation.
 * Then calls the draw function to redraw the canvas.
 *
 */
Character.prototype.bounce = function(){
  "use strict";

  var self                  = this;

  //Clear the canvas
  this.context.clearRect(0, 0, this.context.canvas.clientWidth, this.context.canvas.clientHeight);

  //Toggle which way the sprite sheet is being read and as a result the direction of the bounce
  if(this.spriteMapXPosition <= 240){
    this.toggleDirection = true;
  }else if(this.spriteMapXPosition >= 384){
    this.toggleDirection = false;
  }

  if(this.toggleDirection){
    this.spriteMapXPosition += this.spriteImageWidth;
  }else{
    this.spriteMapXPosition -= this.spriteImageWidth;
  }

  // Stop animation if in the air, instead show a single sprite image.
  if(!this.onGround){
    this.spriteMapXPosition = 288;
    this.toggleDirection = false;
  }

  // Draw and recall itself to repeat.
  this.draw();
  if(this.alive){
    setTimeout(function(){ self.bounce(); }, this.drawSpeed);
  }
};

/*
 * Controls where the image is placed on the canvas and the outputs it to the canvas.
 * Placement is determined by keyboard interaction.
 */

Character.prototype.draw = function(){
  "use strict";
  var friction;

  // If no left/right input has been pressed set friction to slow down.
  if(!this.left && !this.right){
    friction = this.friction;
  }else{
    friction = 1;
  }

  // If jump was pressed while on the ground,
  // Jump and let everyone know we aren't on the ground.
  // Also cancel friction while in the air (gravity is all
  // that matters).
  if(this.jump && this.onGround){
    this.yVelocity += this.jumpForce;
    this.onGround = false;
    friction = 1;
  }

  // Increment the acceleration left/right for a smoother experience.
  if(this.left && !this.right){
    this.xVelocity -= this.xAcceleration;
  }else if(this.right && !this.left){
    this.xVelocity += this.xAcceleration;
  }

  //Apply friction if we are on the ground.
  if(this.onGround){
    this.xVelocity *= friction;
  }
  this.yVelocity += this.gravity;

  // Check if we are travelling at the maximum speed and
  // if so refrain from increasing further.
  // For jumping be more relaxed
  if(this.xVelocity > this.speedLimit){
    this.xVelocity = this.speedLimit;
  }else if(this.xVelocity < -this.speedLimit){
    this.xVelocity = -this.speedLimit;
  }else if(this.yVelocity > this.speedLimit * 2){
    this.yVelocity = this.speedLimit * 2;
  }

  // Set the new positions.
  var checkMoveX = this.xPosition + this.xVelocity;
  var checkMoveY = this.yPosition + this.yVelocity;

  // Check whether the new X-positions exceed boundaries.
  // If the do rebound
  if(checkMoveX < 0){
    this.xVelocity *= this.rebound;
    this.xPosition = 0;
  }else if(checkMoveX > this.canvas.width - this.spriteImageWidth){
    this.xVelocity *= this.rebound;
    this.xPosition = this.canvas.width - this.spriteImageWidth;
  }else{
    this.xPosition = checkMoveX;
  }

  // Check whether the new Y-positions exceed boundaries.
  // Rebound if it's the roof.
  // Stop falling if it's the ground and tell everyone we've landed
  if(checkMoveY < 0){
    this.yVelocity *= this.rebound;
    this.yPosition = 0;
  }else if(checkMoveY > this.canvas.height - this.spriteImageHeight){
    this.yPosition = this.canvas.height - this.spriteImageHeight;
    this.yVelocity = -this.gravity;
    this.onGround = true;
  }else{
    this.yPosition = checkMoveY;
  }

  // Draw it!!!!!
  this.context.drawImage(
      this.img,
      this.spriteMapXPosition, 0, this.spriteImageWidth, this.spriteImageHeight,
      this.xPosition, this.yPosition, this.spriteImageWidth, this.spriteImageHeight
  );
};
<|endoftext|>


<commit_before>/* TinySort 1.5.5
* Copyright (c) 2008-2013 Ron Valstar http://tinysort.sjeiti.com/
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*/
(function(e,c){var i=!1,l=null,p=parseFloat,m=Math.min,n=/(-?\d+\.?\d*)$/g,h=/(\d+\.?\d*)$/g,k=[],g=[],b=function(q){return typeof q=="string"},f=function(u,t){var q=u.length,s=q,r;while(s--){r=q-s-1;t(u[r],r)}},o=Array.prototype.indexOf||function(s){var q=this.length,r=Number(arguments[1])||0;r=r<0?Math.ceil(r):Math.floor(r);if(r<0){r+=q}for(;r<q;r++){if(r in this&&this[r]===s){return r}}return -1};e.tinysort={id:"TinySort",version:"1.5.5",copyright:"Copyright (c) 2008-2013 Ron Valstar",uri:"http://tinysort.sjeiti.com/",licensed:{MIT:"http://www.opensource.org/licenses/mit-license.php",GPL:"http://www.gnu.org/licenses/gpl.html"},plugin:(function(){var q=function(r,s){k.push(r);g.push(s)};q.indexOf=o;return q})(),defaults:{order:"asc",attr:l,data:l,useVal:i,place:"start",returns:i,cases:i,forceStrings:i,ignoreDashes:i,sortFunction:l}};e.fn.extend({tinysort:function(){var E,D,G=this,t=[],s=[],H=[],I=[],w=0,r,C=[],y=[],z=function(J){f(k,function(K){K.call(K,J)})},A=function(K,J){if(typeof J=="string"){if(!K.cases){J=a(J)}J=J.replace(/^\s*(.*?)\s*$/i,"$1")}return J},x=function(U,S){var J=0;if(w!==0){w=0}while(J===0&&w<r){var Q=I[w],N=Q.oSettings,R=N.ignoreDashes?h:n;z(N);if(N.sortFunction){J=N.sortFunction(U,S)}else{if(N.order=="rand"){J=Math.random()<0.5?1:-1}else{var T=i,M=A(N,U.s[w]),L=A(N,S.s[w]);if(!N.forceStrings){var K=b(M)?M&&M.match(R):i,V=b(L)?L&&L.match(R):i;if(K&&V){var P=M.substr(0,M.length-K[0].length),O=L.substr(0,L.length-V[0].length);if(P==O){T=!i;M=p(K[0]);L=p(V[0])}}}J=Q.iAsc*(M<L?-1:(M>L?1:0))}}f(g,function(W){J=W.call(W,T,M,L,J)});if(J===0){w++}}return J};for(E=0,D=arguments.length;E<D;E++){var B=arguments[E];if(b(B)){if(C.push(B)-1>y.length){y.length=C.length-1}}else{if(y.push(B)>C.length){C.length=y.length}}}if(C.length>y.length){y.length=C.length}r=C.length;if(r===0){r=C.length=1;y.push({})}for(E=0,D=r;E<D;E++){var F=C[E],u=e.extend({},e.tinysort.defaults,y[E]),v=!(!F||F==""),q=v&&F[0]==":";I.push({sFind:F,oSettings:u,bFind:v,bAttr:!(u.attr===l||u.attr==""),bData:u.data!==l,bFilter:q,$Filter:q?G.filter(F):G,fnSort:u.sortFunction,iAsc:u.order=="asc"?1:-1})}G.each(function(Q,J){var M=e(J),K=M.parent().get(0),L,P=[];for(j=0;j<r;j++){var R=I[j],N=R.bFind?(R.bFilter?R.$Filter.filter(J):M.find(R.sFind)):M;P.push(R.bData?N.data(R.oSettings.data):(R.bAttr?N.attr(R.oSettings.attr):(R.oSettings.useVal?N.val():N.text())));if(L===c){L=N}}var O=o.call(H,K);if(O<0){O=H.push(K)-1;s[O]={s:[],n:[]}}if(L.length>0){s[O].s.push({s:P,e:M,n:Q})}else{s[O].n.push({e:M,n:Q})}});f(s,function(J){J.s.sort(x)});f(s,function(K){var Q=K.s,J=K.n,S=Q.length,O=J.length,T=S+O,L=[],N=T,M=[0,0];switch(u.place){case"first":f(Q,function(V){N=m(N,V.n)});break;case"org":f(Q,function(V){L.push(V.n)});break;case"end":N=O;break;default:N=0}for(E=0;E<T;E++){var P=d(L,E)?!i:E>=N&&E<N+S,R=P?0:1,U=(P?Q:J)[M[R]].e;U.parent().append(U);if(P||!u.returns){t.push(U.get(0))}M[R]++}});G.length=0;Array.prototype.push.apply(G,t);return G}});function a(q){return q&&q.toLowerCase?q.toLowerCase():q}function d(r,t){for(var s=0,q=r.length;s<q;s++){if(r[s]==t){return !i}}return i}e.fn.TinySort=e.fn.Tinysort=e.fn.tsort=e.fn.tinysort})(jQuery);<commit_msg>Got rid of an unneeded JS file.<commit_after><|endoftext|>


<commit_before>// Development API path
export const kGlobalConstants = {
    API: 'http://ec2-54-173-199-34.compute-1.amazonaws.com:80/v1/',
    LOCAL_ROOT : '',
    GITHUB: 'https://github.com/fedspendingtransparency/data-act-validator/tree/development',
    GA_TRACKING_ID: 'UA-75081254-1',
    LOCAL: false
};
<commit_msg>Updating API URL for demo<commit_after>// Development API path
export const kGlobalConstants = {
    API: 'http://ec2-52-90-172-215.compute-1.amazonaws.com:80/v1/',
    LOCAL_ROOT : '',
    GITHUB: 'https://github.com/fedspendingtransparency/data-act-validator/tree/development',
    GA_TRACKING_ID: 'UA-75081254-1',
    LOCAL: false
};
<|endoftext|>


<commit_before>const GH_RESERVED_USER_NAMES = [
  'settings', 'orgs', 'organizations',
  'site', 'blog', 'about', 'explore',
  'styleguide', 'showcases', 'trending',
  'stars', 'dashboard', 'notifications',
  'search', 'developer', 'account',
  'pulls', 'issues', 'features', 'contact',
  'security', 'join', 'login', 'watching',
  'new', 'integrations'
]
const GH_RESERVED_REPO_NAMES = ['followers', 'following', 'repositories']
const GH_404_SEL = '#parallax_wrapper'
const GH_PJAX_CONTAINER_SEL = '#js-repo-pjax-container, .context-loader-container, [data-pjax-container]'
const GH_CONTAINERS = '.container'

class GitHub extends Adapter {

  constructor() {
    super(['jquery.pjax.js'])

    $(document)
      .on('pjax:send', () => $(document).trigger(EVENT.REQ_START))
      .on('pjax:end', () => $(document).trigger(EVENT.REQ_END))
      .on('pjax:timeout', (event) => event.preventDefault())
  }

  // @override
  init($sidebar) {
    super.init($sidebar)

    if (!window.MutationObserver) return

    // Fix #151 by detecting when page layout is updated.
    // In this case, split-diff page has a wider layout, so need to recompute margin.
    // Note that couldn't do this in response to URL change, since new DOM via pjax might not be ready.
    const diffModeObserver = new window.MutationObserver((mutations) => {
      for (const mutation of mutations) {
        if (~mutation.oldValue.indexOf('split-diff') ||
            ~mutation.target.className.indexOf('split-diff')) {
          return $(document).trigger(EVENT.LAYOUT_CHANGE)
        }
      }
    })

    diffModeObserver.observe(document.body, {
      attributes: true,
      attributeFilter: ['class'],
      attributeOldValue: true
    })

    // GitHub switch pages using pjax. This observer detects if the pjax container
    // has been updated with new contents and trigger layout.
    const pageChangeObserver = new window.MutationObserver(() => {
      // Trigger location change, can't just relayout as Octotree might need to
      // hide/show depending on whether the current page is a code page or not.
      return $(document).trigger(EVENT.LOC_CHANGE)
    })

    const pjaxContainer = $(GH_PJAX_CONTAINER_SEL)[0]

    if (pjaxContainer) {
      pageChangeObserver.observe(pjaxContainer, {
        childList: true,
      })
    }
    else { // Fall back if DOM has been changed
      let firstLoad = true, href, hash

      function detectLocChange() {
        if (location.href !== href || location.hash !== hash) {
          href = location.href
          hash = location.hash

          // If this is the first time this is called, no need to notify change as
          // Octotree does its own initialization after loading options.
          if (firstLoad) {
            firstLoad = false
          }
          else {
            setTimeout(() => {
              $(document).trigger(EVENT.LOC_CHANGE)
            }, 300) // Wait a bit for pjax DOM change
          }
        }
        setTimeout(detectLocChange, 200)
      }

      detectLocChange()
    }
  }

  // @override
  getCssClass() {
    return 'octotree_github_sidebar'
  }

  // @override
  canLoadEntireTree() {
    return true
  }

  // @override
  getCreateTokenUrl() {
    return `${location.protocol}//${location.host}/settings/tokens/new`
  }

  // @override
  updateLayout(togglerVisible, sidebarVisible, sidebarWidth) {
    const SPACING = 10
    const $containers = $(GH_CONTAINERS)
    const autoMarginLeft = ($(document).width() - $containers.width()) / 2
    const shouldPushLeft = sidebarVisible && (autoMarginLeft <= sidebarWidth + SPACING)

    $('html').css('margin-left', shouldPushLeft ? sidebarWidth : '')
    $containers.css('margin-left', shouldPushLeft ? SPACING : '')
  }

  // @override
  getRepoFromPath(showInNonCodePage, currentRepo, token, cb) {

    // 404 page, skip
    if ($(GH_404_SEL).length) {
      return cb()
    }

    // (username)/(reponame)[/(type)]
    const match = window.location.pathname.match(/([^\/]+)\/([^\/]+)(?:\/([^\/]+))?/)
    if (!match) {
      return cb()
    }

    const username = match[1]
    const reponame = match[2]

    // Not a repository, skip
    if (~GH_RESERVED_USER_NAMES.indexOf(username) ||
        ~GH_RESERVED_REPO_NAMES.indexOf(reponame)) {
      return cb()
    }

    // Skip non-code page unless showInNonCodePage is true
    if (!showInNonCodePage && match[3] && !~['tree', 'blob'].indexOf(match[3])) {
      return cb()
    }

    // Get branch by inspecting page, quite fragile so provide multiple fallbacks
    const GH_BRANCH_SEL_1 = '[aria-label="Switch branches or tags"]'
    const GH_BRANCH_SEL_2 = '.repo-root a[data-branch]'

    const branch =
      // Detect branch in code page (don't care about non-code pages, let them use the next fallback)
      $(GH_BRANCH_SEL_1).attr('title') || $(GH_BRANCH_SEL_2).data('branch') ||
      // Reuse last selected branch if exist
      (currentRepo.username === username && currentRepo.reponame === reponame && currentRepo.branch)
      // Get default branch from cache
      this._defaultBranch[username + '/' + reponame]

    // Still no luck, get default branch for real
    const repo = {username: username, reponame: reponame, branch: branch}

    if (repo.branch) {
      cb(null, repo)
    }
    else {
      this._get(null, {repo, token}, (err, data) => {
        if (err) return cb(err)
        repo.branch = this._defaultBranch[username + '/' + reponame] = data.default_branch || 'master'
        cb(null, repo)
      })
    }
  }

  // @override
  selectFile(path) {
    const $pjaxContainer = $(GH_PJAX_CONTAINER_SEL)

    if ($pjaxContainer.length) {
      $.pjax({
        // needs full path for pjax to work with Firefox as per cross-domain-content setting
        url: location.protocol + '//' + location.host + path,
        container: $pjaxContainer
      })
    }
    else { // falls back
      super.selectFile(path)
    }
  }

  // @override
  loadCodeTree(opts, cb) {
    opts.encodedBranch = encodeURIComponent(decodeURIComponent(opts.repo.branch))
    opts.path = (opts.node && (opts.node.sha || opts.encodedBranch)) ||
                (opts.encodedBranch + '?recursive=1')
    this._loadCodeTree(opts, null, cb)
  }

  // @override
  _getTree(path, opts, cb) {
    this._get(`/git/trees/${path}`, opts, (err, res) => {
      if (err) return cb(err)
      cb(null, res.tree)
    })
  }

  // @override
  _getSubmodules(tree, opts, cb) {
    const item = tree.filter((item) => /^\.gitmodules$/i.test(item.path))[0]
    if (!item) return cb()

    this._get(`/git/blobs/${item.sha}`, opts, (err, res) => {
      if (err) return cb(err)
      const data = atob(res.content.replace(/\n/g,''))
      cb(null, parseGitmodules(data))
    })
  }

  _get(path, opts, cb) {
    const host = location.protocol + '//' +
      (location.host === 'github.com' ? 'api.github.com' : (location.host + '/api/v3'))
    const url = `${host}/repos/${opts.repo.username}/${opts.repo.reponame}${path || ''}`
    const cfg  = { url, method: 'GET', cache: false }

    if (opts.token) {
      cfg.headers = { Authorization: 'token ' + opts.token }
    }

    $.ajax(cfg)
      .done((data) => cb(null, data))
      .fail((jqXHR) => this._handleError(jqXHR, cb))
  }
}
<commit_msg>Add back branch matching in non-code page<commit_after>const GH_RESERVED_USER_NAMES = [
  'settings', 'orgs', 'organizations',
  'site', 'blog', 'about', 'explore',
  'styleguide', 'showcases', 'trending',
  'stars', 'dashboard', 'notifications',
  'search', 'developer', 'account',
  'pulls', 'issues', 'features', 'contact',
  'security', 'join', 'login', 'watching',
  'new', 'integrations'
]
const GH_RESERVED_REPO_NAMES = ['followers', 'following', 'repositories']
const GH_404_SEL = '#parallax_wrapper'
const GH_PJAX_CONTAINER_SEL = '#js-repo-pjax-container, .context-loader-container, [data-pjax-container]'
const GH_CONTAINERS = '.container'

class GitHub extends Adapter {

  constructor() {
    super(['jquery.pjax.js'])

    $(document)
      .on('pjax:send', () => $(document).trigger(EVENT.REQ_START))
      .on('pjax:end', () => $(document).trigger(EVENT.REQ_END))
      .on('pjax:timeout', (event) => event.preventDefault())
  }

  // @override
  init($sidebar) {
    super.init($sidebar)

    if (!window.MutationObserver) return

    // Fix #151 by detecting when page layout is updated.
    // In this case, split-diff page has a wider layout, so need to recompute margin.
    // Note that couldn't do this in response to URL change, since new DOM via pjax might not be ready.
    const diffModeObserver = new window.MutationObserver((mutations) => {
      for (const mutation of mutations) {
        if (~mutation.oldValue.indexOf('split-diff') ||
            ~mutation.target.className.indexOf('split-diff')) {
          return $(document).trigger(EVENT.LAYOUT_CHANGE)
        }
      }
    })

    diffModeObserver.observe(document.body, {
      attributes: true,
      attributeFilter: ['class'],
      attributeOldValue: true
    })

    // GitHub switch pages using pjax. This observer detects if the pjax container
    // has been updated with new contents and trigger layout.
    const pageChangeObserver = new window.MutationObserver(() => {
      // Trigger location change, can't just relayout as Octotree might need to
      // hide/show depending on whether the current page is a code page or not.
      return $(document).trigger(EVENT.LOC_CHANGE)
    })

    const pjaxContainer = $(GH_PJAX_CONTAINER_SEL)[0]

    if (pjaxContainer) {
      pageChangeObserver.observe(pjaxContainer, {
        childList: true,
      })
    }
    else { // Fall back if DOM has been changed
      let firstLoad = true, href, hash

      function detectLocChange() {
        if (location.href !== href || location.hash !== hash) {
          href = location.href
          hash = location.hash

          // If this is the first time this is called, no need to notify change as
          // Octotree does its own initialization after loading options.
          if (firstLoad) {
            firstLoad = false
          }
          else {
            setTimeout(() => {
              $(document).trigger(EVENT.LOC_CHANGE)
            }, 300) // Wait a bit for pjax DOM change
          }
        }
        setTimeout(detectLocChange, 200)
      }

      detectLocChange()
    }
  }

  // @override
  getCssClass() {
    return 'octotree_github_sidebar'
  }

  // @override
  canLoadEntireTree() {
    return true
  }

  // @override
  getCreateTokenUrl() {
    return `${location.protocol}//${location.host}/settings/tokens/new`
  }

  // @override
  updateLayout(togglerVisible, sidebarVisible, sidebarWidth) {
    const SPACING = 10
    const $containers = $(GH_CONTAINERS)
    const autoMarginLeft = ($(document).width() - $containers.width()) / 2
    const shouldPushLeft = sidebarVisible && (autoMarginLeft <= sidebarWidth + SPACING)

    $('html').css('margin-left', shouldPushLeft ? sidebarWidth : '')
    $containers.css('margin-left', shouldPushLeft ? SPACING : '')
  }

  // @override
  getRepoFromPath(showInNonCodePage, currentRepo, token, cb) {

    // 404 page, skip
    if ($(GH_404_SEL).length) {
      return cb()
    }

    // (username)/(reponame)[/(type)]
    const match = window.location.pathname.match(/([^\/]+)\/([^\/]+)(?:\/([^\/]+))?/)
    if (!match) {
      return cb()
    }

    const username = match[1]
    const reponame = match[2]

    // Not a repository, skip
    if (~GH_RESERVED_USER_NAMES.indexOf(username) ||
        ~GH_RESERVED_REPO_NAMES.indexOf(reponame)) {
      return cb()
    }

    // Skip non-code page unless showInNonCodePage is true
    if (!showInNonCodePage && match[3] && !~['tree', 'blob'].indexOf(match[3])) {
      return cb()
    }

    // Get branch by inspecting page, quite fragile so provide multiple fallbacks
    const GH_BRANCH_SEL_1 = '[aria-label="Switch branches or tags"]'
    const GH_BRANCH_SEL_2 = '.repo-root a[data-branch]'
    const GH_BRANCH_SEL_3 = '.repository-sidebar a[aria-label="Code"]'
    const GH_BRANCH_SEL_4 = 'link[title*="Recent Commits to"]'

    const branch =
      // Detect branch in code page (don't care about non-code pages, let them use the next fallback)
      $(GH_BRANCH_SEL_1).attr('title') || $(GH_BRANCH_SEL_2).data('branch') ||
      // Non-code page
      ($(GH_BRANCH_SEL_3).attr('href') || ' ').match(/([^\/]+)/g)[3] ||
      // Non-code page (new design)
      ($(GH_BRANCH_SEL_4).attr('title') || ' ').match(/([^\:]+)/g)[1] ||
      // Reuse last selected branch if exist
      (currentRepo.username === username && currentRepo.reponame === reponame && currentRepo.branch)
      // Get default branch from cache
      this._defaultBranch[username + '/' + reponame]

    // Still no luck, get default branch for real
    const repo = {username: username, reponame: reponame, branch: branch}

    if (repo.branch) {
      cb(null, repo)
    }
    else {
      this._get(null, {repo, token}, (err, data) => {
        if (err) return cb(err)
        repo.branch = this._defaultBranch[username + '/' + reponame] = data.default_branch || 'master'
        cb(null, repo)
      })
    }
  }

  // @override
  selectFile(path) {
    const $pjaxContainer = $(GH_PJAX_CONTAINER_SEL)

    if ($pjaxContainer.length) {
      $.pjax({
        // needs full path for pjax to work with Firefox as per cross-domain-content setting
        url: location.protocol + '//' + location.host + path,
        container: $pjaxContainer
      })
    }
    else { // falls back
      super.selectFile(path)
    }
  }

  // @override
  loadCodeTree(opts, cb) {
    opts.encodedBranch = encodeURIComponent(decodeURIComponent(opts.repo.branch))
    opts.path = (opts.node && (opts.node.sha || opts.encodedBranch)) ||
                (opts.encodedBranch + '?recursive=1')
    this._loadCodeTree(opts, null, cb)
  }

  // @override
  _getTree(path, opts, cb) {
    this._get(`/git/trees/${path}`, opts, (err, res) => {
      if (err) return cb(err)
      cb(null, res.tree)
    })
  }

  // @override
  _getSubmodules(tree, opts, cb) {
    const item = tree.filter((item) => /^\.gitmodules$/i.test(item.path))[0]
    if (!item) return cb()

    this._get(`/git/blobs/${item.sha}`, opts, (err, res) => {
      if (err) return cb(err)
      const data = atob(res.content.replace(/\n/g,''))
      cb(null, parseGitmodules(data))
    })
  }

  _get(path, opts, cb) {
    const host = location.protocol + '//' +
      (location.host === 'github.com' ? 'api.github.com' : (location.host + '/api/v3'))
    const url = `${host}/repos/${opts.repo.username}/${opts.repo.reponame}${path || ''}`
    const cfg  = { url, method: 'GET', cache: false }

    if (opts.token) {
      cfg.headers = { Authorization: 'token ' + opts.token }
    }

    $.ajax(cfg)
      .done((data) => cb(null, data))
      .fail((jqXHR) => this._handleError(jqXHR, cb))
  }
}
<|endoftext|>


<commit_before>const esprima = require('esprima');
const escodegen = require('escodegen');
const pathModule = require('path');
const instrumentAst = require('./instrumentAst');
const ignore = require('ignore')();
const pkgUp = require('pkg-up');
const fs = require('fs');
let ignoreDirectivesRelativeTo;

function addDefaultIgnores() {
    ignore.add([
        'node_modules/unexpected*',
        'node_modules/array-changes',
        'node_modules/arraydiff-papandreou',
        'node_modules/array-changes-async',
        'node_modules/arraydiff-async',
        'node_modules/greedy-interval-packer',
        'node_modules/magicpen',
        'node_modules/mocha',
        'node_modules/jest',
        'node_modules/jasmine',
        'node_modules/chance',
        'node_modules/chance-generators',
        'node_modules/sinon',
        'test',
        '*.spec.js'
    ]);
}

if (process.env.DFL_IGNORE) {
    // Root-relative paths will be interpreted as absolute
    ignore.add(process.env.DFL_IGNORE);
} else {
    const closestPackageJson = pkgUp.sync();
    if (closestPackageJson) {
        try {
            const packageDirName = pathModule.dirname(closestPackageJson);
            ignoreDirectivesRelativeTo = packageDirName;

            const dflIgnorePath = pathModule.resolve(
                packageDirName,
                '.dflignore'
            );
            // Root-relative paths will be interpreted as relative
            // to the .dflignore file, as per the .gitignore convention:
            ignore.add(fs.readFileSync(dflIgnorePath, 'utf-8'));
        } catch (err) {
            addDefaultIgnores();
        }
    } else {
        addDefaultIgnores();
    }
}

let locations;
let prevLocation;

function initialize() {
    global.recordLocation.locations = locations = {};
    prevLocation = 0;
}

global.recordLocation = (location) => {
    const key = location ^ prevLocation;
    locations[key] = (locations[key] || 0) + 1;
    prevLocation = location >> 1;
};

initialize();

global.recordLocation.reset = initialize;
global.recordLocation.magicValues = new Set();

var nextLocationNumber = 1;
function getNextLocationNumber() {
    return nextLocationNumber++;
}

const oldRequireHook = require.extensions['.js'];
require.extensions['.js'] = function (module, absoluteFileName) {
    let code;
    oldRequireHook(
        Object.create(module, {
            _compile: {
                value: _code => code = _code
            }
        }),
        absoluteFileName
    );
    let fileNameToCheck;
    if (ignoreDirectivesRelativeTo) {
        fileNameToCheck = pathModule.relative(ignoreDirectivesRelativeTo, absoluteFileName);
    } else {
        fileNameToCheck = absoluteFileName;
    }

    if (ignore.ignores(fileNameToCheck) || (module.parent && module.parent._unexpectedCheckIgnored)) {
        module._unexpectedCheckIgnored = true;
    } else {
        console.log('instrument', fileNameToCheck);
        const ast = esprima.parseScript(code, {
            source: pathModule.relative(process.cwd(), absoluteFileName)
        });
        const { instrumentedAst, magicValues } = instrumentAst(ast, getNextLocationNumber);
        code = escodegen.generate(instrumentedAst);
        for (const magicValue of magicValues) {
            global.recordLocation.magicValues.add(magicValue);
        }
    }
    module._compile(code, absoluteFileName);
};
<commit_msg>Do not ignore files required by test and *.spec.js<commit_after>const esprima = require('esprima');
const escodegen = require('escodegen');
const pathModule = require('path');
const instrumentAst = require('./instrumentAst');
const createIgnore = require('ignore');
const deepIgnore = createIgnore();
const shallowIgnore = createIgnore();
const pkgUp = require('pkg-up');
const fs = require('fs');
let ignoreDirectivesRelativeTo;

function addDefaultIgnores() {
    deepIgnore.add([
        'node_modules/unexpected*',
        'node_modules/array-changes',
        'node_modules/arraydiff-papandreou',
        'node_modules/array-changes-async',
        'node_modules/arraydiff-async',
        'node_modules/greedy-interval-packer',
        'node_modules/magicpen',
        'node_modules/mocha',
        'node_modules/jest',
        'node_modules/jasmine',
        'node_modules/chance',
        'node_modules/chance-generators',
        'node_modules/sinon'
    ]);
    shallowIgnore.add([
        'test',
        '*.spec.js'
    ]);
}

if (process.env.DFL_IGNORE) {
    // Root-relative paths will be interpreted as absolute
    shallowIgnore.add(process.env.DFL_IGNORE);
} else {
    const closestPackageJson = pkgUp.sync();
    if (closestPackageJson) {
        try {
            const packageDirName = pathModule.dirname(closestPackageJson);
            ignoreDirectivesRelativeTo = packageDirName;

            const dflIgnorePath = pathModule.resolve(
                packageDirName,
                '.dflignore'
            );
            // Root-relative paths will be interpreted as relative
            // to the .dflignore file, as per the .gitignore convention:
            shallowIgnore.add(fs.readFileSync(dflIgnorePath, 'utf-8'));
        } catch (err) {
            addDefaultIgnores();
        }
    } else {
        addDefaultIgnores();
    }
}

let locations;
let prevLocation;

function initialize() {
    global.recordLocation.locations = locations = {};
    prevLocation = 0;
}

global.recordLocation = (location) => {
    const key = location ^ prevLocation;
    locations[key] = (locations[key] || 0) + 1;
    prevLocation = location >> 1;
};

initialize();

global.recordLocation.reset = initialize;
global.recordLocation.magicValues = new Set();

var nextLocationNumber = 1;
function getNextLocationNumber() {
    return nextLocationNumber++;
}

const oldRequireHook = require.extensions['.js'];
require.extensions['.js'] = function (module, absoluteFileName) {
    let code;
    oldRequireHook(
        Object.create(module, {
            _compile: {
                value: _code => code = _code
            }
        }),
        absoluteFileName
    );
    let fileNameToCheck;
    if (ignoreDirectivesRelativeTo) {
        fileNameToCheck = pathModule.relative(ignoreDirectivesRelativeTo, absoluteFileName);
    } else {
        fileNameToCheck = absoluteFileName;
    }

    if (deepIgnore.ignores(fileNameToCheck) || (module.parent && module.parent._unexpectedCheckDeepIgnored)) {
        module._unexpectedCheckDeepIgnored = true;
    } else if (!shallowIgnore.ignores(fileNameToCheck)) {
        console.log('instrument', fileNameToCheck);
        const ast = esprima.parseScript(code, {
            source: pathModule.relative(process.cwd(), absoluteFileName)
        });
        const { instrumentedAst, magicValues } = instrumentAst(ast, getNextLocationNumber);
        code = escodegen.generate(instrumentedAst);
        for (const magicValue of magicValues) {
            global.recordLocation.magicValues.add(magicValue);
        }
    }
    module._compile(code, absoluteFileName);
};
<|endoftext|>


<commit_before>// Elf Lag Fix

var pattern = scan('CC 55 8B EC 56 57 8B F9 8B 07 8B 50 04 FF D2 8B C8 E8');

if (debug)
	send(pattern);

if (pattern == NULL)
	send('Failed to apply patch.');
else
{
	patch(pattern.add(1), 0x32);
	patch(pattern.add(2), 0xC0);
	patch(pattern.add(3), 0xC2);
	patch(pattern.add(4), 0x04);
	patch(pattern.add(5), 0x00);
}
<commit_msg>Update ElfLagFix.js<commit_after>// Elf Lag Fix

var pattern = scan('CC 55 8B EC 56 57 8B F9 8B 07 8B 50 04 FF D2 8B C8 E8');

if (pattern == NULL)
	send('Failed to apply patch.');
else
{
	patch(pattern.add(1), 0x32);
	patch(pattern.add(2), 0xC0);
	patch(pattern.add(3), 0xC2);
	patch(pattern.add(4), 0x04);
	patch(pattern.add(5), 0x00);
}
<|endoftext|>