<commit_before>var util = require('util');
var net = require('net');
var EventEmitter = require('events').EventEmitter;

/**
 * A server that listens for incoming mail via SMTP with the options provided,
 * else the default options.
 *
 * @param {Object} options The options for the server, as a JSON Object
 * @constructor
 */
function SmtpServer(options) {
	EventEmitter.call(this)
	this.options = options;
	this.ip = options["ip"];
	this.clients = [];
	this.server = net.createServer(this.createClient.bind(this));
}

util.inherits(SmtpServer, EventEmitter);

//Create a new instance of a client
SmtpServer.prototype.createClient = function(c) {
	this.clients.push(new Client(this, c));
}

SmtpServer.prototype.removeClient = function(c) {
	var index = this.clients.indexOf(c);
	if(index > -1) this.clients.splice(index, 1);
	console.log("client removed" + this.clients)
}

SmtpServer.prototype.listen = function(port, options, callback) {
	this.server.listen(port, callback);
}

function Client(smtpServer, client) {
	//Parent
	this.parent = smtpServer;
	//Net Server Instance (net.Server)
	this.netServer = this.parent.server;
	//Socket instance (net.Socket)
	this.client = client;
	//TODO: Harry you need to add to the template
	this.mail = {
		sender: null,
		recipient: null,
		body: []
	}
	this.hasSaidHelo = false;
	this.acceptingData = false;
	//TODO: Move responses to a separate module
	//"" is where the command is handled by a different function. might be better to include the function in this object!
	this.responses = {
		READY:	["220 Why hello & welcome to clifton.js :}\n", null],
		HELO: 	["250 127.0.0.1\n", this._handleHELO.bind(this)],
		NOOP: 	["204 Alright mate?\n", null],
		QUIT: 	["", this._closeConnection.bind(this)],
		MAIL: 	["", this._handleIncoming.bind(this)],
		RCPT: 	["", this._handleIncoming.bind(this)],
		DATA: 	["", this._handleIncoming.bind(this)]
	}
	this.connectHandler();
	this.config({encoding: 'utf8'});
	this.bindEvents();
}

//Configuration for the socket //
Client.prototype.config = function(options) {
	this.client.setEncoding(options["encoding"]);
}

//Binds all the socket events we need //
Client.prototype.bindEvents = function() {
	this.client.on("data", this.data.bind(this));
	this.client.on("end", this._connectionEnd.bind(this))
}

Client.prototype._connectionEnd = function(d) {
	console.log("Socket closed!");
}

Client.prototype._closeConnection = function(data) {
	this.write("221 Closing our connection :(\n");
	this.client.end(function(err) {
		if(err) console.warn(err)
	});
	this.parent.removeClient(this);
}

/* Decides what to respond to the client */
Client.prototype.respond = function(command) {
	var code = command[0];
	var response = this.responses[code];
	if(response == undefined) {
		this.write("500 Malformed command ;{\n");
		return false;
	} else {
		if(typeof this.responses[code][1] == "function") {
			this.responses[code][1](command, this.responses[code][0]);

		} else {
			this.write(this.responses[code][0]);
		}
	}
};

Client.prototype._handleIncoming = function(command) {
	if(!this.hasSaidHelo) {
		this.write("503 HELO/EHLO first pl0x\n");
		return false;
	}
	var splittedCommand = command[1].split(":");
	//If there is a space fallback to what we know is real
	if(splittedCommand[1] == "") splittedCommand[1] = command[2];
	if(command[0] == "MAIL") {
		this.mail.sender = null
		//TODO: handle this better, what if it's not a valid sender address :o

		if(splittedCommand[0].toLowerCase() == "from") {
			this.mail.sender = splittedCommand[1];
			if(splittedCommand[1]) {
				this.write("250 " + this.mail.sender + "... Sender is Legit 420\n");
			} else {
				this.write("Please include the sender shit\n");
			}

		} else {
			this.write("Non legit sender\n");
		}
	} else if(command[0] == "RCPT") {
		if(!this.mail.sender) {
			this.write("503 Please specify a sender first using MAIL\n");
			return false;
		}
		this.mail.recipient = null;
		//TODO: handle this better, what if it's not a valid sender address :o;
		if(splittedCommand[0].toLowerCase() == "to") {
			this.mail.recipient = splittedCommand[1];
			if(splittedCommand[1]) {
				this.write("250 " + this.mail.recipient + "... Recipient is Legit 420\n");
			} else {
				this.write("Please include the recipient shit\n");
			}

		} else {
			this.write("Non legit recipient\n");
		}
	} else {	}

	if(command[0] == "DATA") {
		if(!this.mail.sender || !this.mail.recipient) {
			this.write("503 You haven't specified a sender, recipient or both :/\n");
			return false;
		}
		this.write("354 Accepting mail, end with '.' on a line all by itself :|\n");
		this.acceptingData = true;
	}

}

Client.prototype._buildMessage = function(command, data) {
        //Credit to many stack overflow people (for the regexii)

       for(var i = 0; i < command.length; i++) {
        var regexed = command[i].replace(/\r?\n/g, "");
	if(regexed == ".") {
                this.write("250 Message accepted for delivery\n");
		//TODO: Rename this emit and shove them all in one place \o/
		this.parent.emit('mail-received', [this.mail]);
		this.acceptingData = false;
        } else {
		this.mail.body[this.mail.body.length+1] = command[i];
	}

}

}

Client.prototype._handleHELO = function(command, msg) {
	this.write(msg);
	//TODO: make sure the HELO url is legit
	if(command[1]) {
		console.log("HELO with the url: " + command[1]);
		this.incomingUrl = command[1];
	} else {
		console.log("HELO url not provided, best guess: " + this.client.remoteAddress);
		this.incomingUrl = this.client.remoteAddress;
	}
	this.hasSaidHelo = true;
}

/* Writes out to the client */
Client.prototype.write = function(data) {
	this.client.write(data, function(err) {
		if(err) console.warn(err);
	});
}

/* Handles the connection event */
Client.prototype.connectHandler = function(d) {
	console.log("Incoming shemale");
	//Tell the client that we're open
	this.respond(["READY"]);
}

/* Handles incoming data */
Client.prototype.data = function(data) {
	var command = data.split(/\s+/g);
	if(command.length <= 2) console.log(command);
	if(this.acceptingData) {
		this._buildMessage(command, data);
	} else {
		this.respond(command);

	}
}

module.exports = exports = SmtpServer;
<commit_msg>Implemented<commit_after>var util = require('util');
var net = require('net');
var EventEmitter = require('events').EventEmitter;

/**
 * A server that listens for incoming mail via SMTP with the options provided,
 * else the default options.
 *
 * @param {Object} options The options for the server, as a JSON Object
 * @constructor
 */
function SmtpServer(options) {
	EventEmitter.call(this)
	this.options = options;
	this.ip = options["ip"];
	this.clients = [];
	this.server = net.createServer(this.createClient.bind(this));
}

util.inherits(SmtpServer, EventEmitter);

//Create a new instance of a client
SmtpServer.prototype.createClient = function(c) {
	this.clients.push(new Client(this, c));
}

SmtpServer.prototype.removeClient = function(c) {
	var index = this.clients.indexOf(c);
	if(index > -1) this.clients.splice(index, 1);
	console.log("client removed" + this.clients)
}

SmtpServer.prototype.listen = function(port, options, callback) {
	this.server.listen(port, callback);
}

function Client(smtpServer, client) {
	//Parent
	this.parent = smtpServer;
	//Net Server Instance (net.Server)
	this.netServer = this.parent.server;
	//Socket instance (net.Socket)
	this.client = client;
	//TODO: Harry you need to add to the template
	this.mail = {
		sender: null,
		recipient: null,
		body: []
	}
	this.hasSaidHelo = false;
	this.acceptingData = false;
	//TODO: Move responses to a separate module
	this.responses = {
		READY:	["220 Why hello & welcome to clifton.js :}\n", null],
		HELO: 	["250 127.0.0.1\n", this._handleHELO.bind(this)],
		NOOP: 	["204 Alright mate?\n", null],
		QUIT: 	["", this._closeConnection.bind(this)],
		MAIL: 	["", this._handleIncoming.bind(this)],
		RCPT: 	["", this._handleIncoming.bind(this)],
		DATA: 	["", this._handleIncoming.bind(this)]
	}
	this.connectHandler();
	this.config({encoding: 'utf8'});
	this.bindEvents();
}

//Configuration for the socket //
Client.prototype.config = function(options) {
	this.client.setEncoding(options["encoding"]);
}

//Binds all the socket events we need //
Client.prototype.bindEvents = function() {
	this.client.on("data", this.data.bind(this));
	this.client.on("end", this._connectionEnd.bind(this))
}

Client.prototype._connectionEnd = function(d) {
	console.log("Socket closed!");
}

Client.prototype._closeConnection = function(data) {
	this.write("221 Closing our connection :(\n");
	this.client.end(function(err) {
		if(err) console.warn(err)
	});
	this.parent.removeClient(this);
}

/* Decides what to respond to the client */
Client.prototype.respond = function(command) {
	var code = command[0];
	var response = this.responses[code];
	if(response == undefined) {
		this.write("500 Malformed command ;{\n");
		return false;
	} else {
		if(typeof this.responses[code][1] == "function") {
			this.responses[code][1](command, this.responses[code][0]);

		} else {
			this.write(this.responses[code][0]);
		}
	}
};

Client.prototype._handleIncoming = function(command) {
	if(!this.hasSaidHelo) {
		this.write("503 HELO/EHLO first pl0x\n");
		return false;
	}
	var splittedCommand = command[1].split(":");
	//If there is a space fallback to what we know is real
	if(splittedCommand[1] == "") splittedCommand[1] = command[2];
	if(command[0] == "MAIL") {
		this.mail.sender = null
		//TODO: handle this better, what if it's not a valid sender address :o

		if(splittedCommand[0].toLowerCase() == "from") {
			this.mail.sender = splittedCommand[1];
			if(splittedCommand[1]) {
				this.write("250 " + this.mail.sender + "... Sender is Legit 420\n");
			} else {
				this.write("Please include the sender shit\n");
			}

		} else {
			this.write("Non legit sender\n");
		}
	} else if(command[0] == "RCPT") {
		if(!this.mail.sender) {
			this.write("503 Please specify a sender first using MAIL\n");
			return false;
		}
		this.mail.recipient = null;
		//TODO: handle this better, what if it's not a valid sender address :o;
		if(splittedCommand[0].toLowerCase() == "to") {
			this.mail.recipient = splittedCommand[1];
			if(splittedCommand[1]) {
				this.write("250 " + this.mail.recipient + "... Recipient is Legit 420\n");
			} else {
				this.write("Please include the recipient shit\n");
			}

		} else {
			this.write("Non legit recipient\n");
		}
	} else {	}

	if(command[0] == "DATA") {
		if(!this.mail.sender || !this.mail.recipient) {
			this.write("503 You haven't specified a sender, recipient or both :/\n");
			return false;
		}
		this.write("354 Accepting mail, end with '.' on a line all by itself :|\n");
		this.acceptingData = true;
	}

}

Client.prototype._buildMessage = function(command, data) {
        //Credit to many stack overflow people (for the regexii)

       for(var i = 0; i < command.length; i++) {
        var regexed = command[i].replace(/\r?\n/g, "");
	if(regexed == ".") {
                this.write("250 Message accepted for delivery\n");
		//TODO: Rename this emit and shove them all in one place \o/
		this.parent.emit('mail-received', [this.mail]);
		this.acceptingData = false;
        } else {
		this.mail.body[this.mail.body.length+1] = command[i];
	}

}

}

Client.prototype._handleHELO = function(command, msg) {
	this.write(msg);
	//TODO: make sure the HELO url is legit
	if(command[1]) {
		console.log("HELO with the url: " + command[1]);
		this.incomingUrl = command[1];
	} else {
		console.log("HELO url not provided, best guess: " + this.client.remoteAddress);
		this.incomingUrl = this.client.remoteAddress;
	}
	this.hasSaidHelo = true;
}

/* Writes out to the client */
Client.prototype.write = function(data) {
	this.client.write(data, function(err) {
		if(err) console.warn(err);
	});
}

/* Handles the connection event */
Client.prototype.connectHandler = function(d) {
	console.log("Incoming shemale");
	//Tell the client that we're open
	this.respond(["READY"]);
}

/* Handles incoming data */
Client.prototype.data = function(data) {
	var command = data.split(/\s+/g);
	if(command.length <= 2) console.log(command);
	if(this.acceptingData) {
		this._buildMessage(command, data);
	} else {
		this.respond(command);

	}
}

module.exports = exports = SmtpServer;
<|endoftext|>


<commit_before>// Copyright (c) 2011-2012 UX Productivity Pty Ltd. All rights reserved.

// FIXME: place a limit on the number of undo steps recorded - say, 30-50?

var UndoManager_getLength;
var UndoManager_getIndex;
var UndoManager_setIndex;
var UndoManager_print;
var UndoManager_undo;
var UndoManager_redo;
var UndoManager_addAction;
var UndoManager_newGroup;
var UndoManager_groupType;
var UndoManager_disableWhileExecuting;

(function() {

    function UndoGroup(type)
    {
        this.type = type;
        this.actions = new Array();
    }

    function UndoAction(fun,args)
    {
        this.fun = fun;
        this.args = args;
    }

    UndoAction.prototype.toString = function()
    {
        if (this.fun.wrappedName != null)
            return this.fun.wrappedName + "(" + this.args.toString() + ")";
        else
            return this.fun.name + "(" + this.args.toString() + ")";
    }

    var undoStack = new Array();
    var redoStack = new Array();
    var inUndo = false;
    var inRedo = false;
    var currentGroup = null;
    var disabled = 0;

    // public
    UndoManager_getLength = trace(function getLength()
    {
        return undoStack.length + redoStack.length;
    });

    // public
    UndoManager_getIndex = trace(function getIndex()
    {
        return undoStack.length;
    });

    // public
    UndoManager_setIndex = trace(function setIndex(index)
    {
        while (undoStack.length > index)
            UndoManager_undo();
        while (undoStack.length < index)
            UndoManager_redo();
    });

    // public
    UndoManager_print = trace(function print()
    {
        debug("");
        debug("--------------------------------------------------------------------");
        debug("Undo stack:");
        for (var groupIndex = 0; groupIndex < undoStack.length; groupIndex++) {
            var group = undoStack[groupIndex];
            debug("    "+group.type);
            for (var actionIndex = 0; actionIndex < group.actions.length; actionIndex++) {
                var action = group.actions[actionIndex];
                debug("        "+action);
            }
        }
        debug("Redo stack:");
        for (var groupIndex = 0; groupIndex < redoStack.length; groupIndex++) {
            var group = redoStack[groupIndex];
            debug("    "+group.type);
            for (var actionIndex = 0; actionIndex < group.actions.length; actionIndex++) {
                var action = group.actions[actionIndex];
                debug("        "+action);
            }
        }
        debug("Current group = "+currentGroup);
        debug("--------------------------------------------------------------------");
        debug("");
    });

    // public
    UndoManager_undo = trace(function undo()
    {
        currentGroup = null;
        if (undoStack.length > 0) {
            var group = undoStack.pop();
            inUndo = true;
            for (var i = group.actions.length-1; i >= 0; i--)
                group.actions[i].fun.apply(null,group.actions[i].args);
            inUndo = false;
        }
        currentGroup = null;
    });

    // public
    UndoManager_redo = trace(function redo()
    {
        currentGroup = null;
        if (redoStack.length > 0) {
            var group = redoStack.pop();
            inRedo = true;
            for (var i = group.actions.length-1; i >= 0; i--)
                group.actions[i].fun.apply(null,group.actions[i].args);
            inRedo = false;
        }
        currentGroup = null;
    });

    // public
    UndoManager_addAction = trace(function addAction(fun)
    {
        if (disabled > 0)
            return;

        // remaining parameters after fun are arguments to be supplied to fun
        var args = new Array();
        for (var i = 1; i < arguments.length; i++)
            args.push(arguments[i]);

        if (!inUndo && !inRedo && (redoStack.length > 0))
            redoStack.length = 0;

        var stack = inUndo ? redoStack : undoStack;
        if (currentGroup == null)
            UndoManager_newGroup(null);

        // Only add a group to the undo stack one it has at least one action, to avoid having
        // empty groups present.
        if (currentGroup.actions.length == 0)
            stack.push(currentGroup);

        currentGroup.actions.push(new UndoAction(fun,args));
    });

    // public
    UndoManager_newGroup = trace(function newGroup(type)
    {
        if (disabled > 0)
            return;

        // We don't actually add the group to the undo stack until the first request to add an
        // action to it. This way we don't end up with empty groups in the undo stack, which
        // simplifies logic for moving back and forward through the undo history.

        if ((type == null) || (type == ""))
            type = "Anonymous";
        currentGroup = new UndoGroup(type);
    });

    // public
    UndoManager_groupType = trace(function groupType()
    {
        if (undoStack.length > 0)
            return undoStack[undoStack.length-1].type;
        else
            return null;
    });

    UndoManager_disableWhileExecuting = trace(function disableWhileExecuting(fun) {
        disabled++;
        try {
            return fun();
        }
        finally {
            disabled--;
        }
    });

})();

window.undoSupported = true;
<commit_msg>Changed UndoAction.prototype.toString() to return the nodeString() of node arguments<commit_after>// Copyright (c) 2011-2012 UX Productivity Pty Ltd. All rights reserved.

// FIXME: place a limit on the number of undo steps recorded - say, 30-50?

var UndoManager_getLength;
var UndoManager_getIndex;
var UndoManager_setIndex;
var UndoManager_print;
var UndoManager_undo;
var UndoManager_redo;
var UndoManager_addAction;
var UndoManager_newGroup;
var UndoManager_groupType;
var UndoManager_disableWhileExecuting;

(function() {

    function UndoGroup(type)
    {
        this.type = type;
        this.actions = new Array();
    }

    function UndoAction(fun,args)
    {
        this.fun = fun;
        this.args = args;
    }

    UndoAction.prototype.toString = function()
    {
        var name;
        if (this.fun.wrappedName != null)
            name = this.fun.wrappedName;
        else
            name = this.fun.name;

        var argStrings = new Array();
        for (var i = 0; i < this.args.length; i++) {
            if (this.args[i] instanceof Node)
                argStrings.push(nodeString(this.args[i]));
            else if (this.args[i] == null)
                argStrings.push("null");
            else
                argStrings.push(this.args[i].toString());
        }

        return name + "(" + argStrings.join(",") + ")";
    }

    var undoStack = new Array();
    var redoStack = new Array();
    var inUndo = false;
    var inRedo = false;
    var currentGroup = null;
    var disabled = 0;

    // public
    UndoManager_getLength = trace(function getLength()
    {
        return undoStack.length + redoStack.length;
    });

    // public
    UndoManager_getIndex = trace(function getIndex()
    {
        return undoStack.length;
    });

    // public
    UndoManager_setIndex = trace(function setIndex(index)
    {
        while (undoStack.length > index)
            UndoManager_undo();
        while (undoStack.length < index)
            UndoManager_redo();
    });

    // public
    UndoManager_print = trace(function print()
    {
        debug("");
        debug("--------------------------------------------------------------------");
        debug("Undo stack:");
        for (var groupIndex = 0; groupIndex < undoStack.length; groupIndex++) {
            var group = undoStack[groupIndex];
            debug("    "+group.type);
            for (var actionIndex = 0; actionIndex < group.actions.length; actionIndex++) {
                var action = group.actions[actionIndex];
                debug("        "+action);
            }
        }
        debug("Redo stack:");
        for (var groupIndex = 0; groupIndex < redoStack.length; groupIndex++) {
            var group = redoStack[groupIndex];
            debug("    "+group.type);
            for (var actionIndex = 0; actionIndex < group.actions.length; actionIndex++) {
                var action = group.actions[actionIndex];
                debug("        "+action);
            }
        }
        debug("Current group = "+currentGroup);
        debug("--------------------------------------------------------------------");
        debug("");
    });

    // public
    UndoManager_undo = trace(function undo()
    {
        currentGroup = null;
        if (undoStack.length > 0) {
            var group = undoStack.pop();
            inUndo = true;
            for (var i = group.actions.length-1; i >= 0; i--)
                group.actions[i].fun.apply(null,group.actions[i].args);
            inUndo = false;
        }
        currentGroup = null;
    });

    // public
    UndoManager_redo = trace(function redo()
    {
        currentGroup = null;
        if (redoStack.length > 0) {
            var group = redoStack.pop();
            inRedo = true;
            for (var i = group.actions.length-1; i >= 0; i--)
                group.actions[i].fun.apply(null,group.actions[i].args);
            inRedo = false;
        }
        currentGroup = null;
    });

    // public
    UndoManager_addAction = trace(function addAction(fun)
    {
        if (disabled > 0)
            return;

        // remaining parameters after fun are arguments to be supplied to fun
        var args = new Array();
        for (var i = 1; i < arguments.length; i++)
            args.push(arguments[i]);

        if (!inUndo && !inRedo && (redoStack.length > 0))
            redoStack.length = 0;

        var stack = inUndo ? redoStack : undoStack;
        if (currentGroup == null)
            UndoManager_newGroup(null);

        // Only add a group to the undo stack one it has at least one action, to avoid having
        // empty groups present.
        if (currentGroup.actions.length == 0)
            stack.push(currentGroup);

        currentGroup.actions.push(new UndoAction(fun,args));
    });

    // public
    UndoManager_newGroup = trace(function newGroup(type)
    {
        if (disabled > 0)
            return;

        // We don't actually add the group to the undo stack until the first request to add an
        // action to it. This way we don't end up with empty groups in the undo stack, which
        // simplifies logic for moving back and forward through the undo history.

        if ((type == null) || (type == ""))
            type = "Anonymous";
        currentGroup = new UndoGroup(type);
    });

    // public
    UndoManager_groupType = trace(function groupType()
    {
        if (undoStack.length > 0)
            return undoStack[undoStack.length-1].type;
        else
            return null;
    });

    UndoManager_disableWhileExecuting = trace(function disableWhileExecuting(fun) {
        disabled++;
        try {
            return fun();
        }
        finally {
            disabled--;
        }
    });

})();

window.undoSupported = true;
<|endoftext|>


<commit_before>'use strict';

var httpReq = require('http-request');

// The class itself
// Stolen from https://github.com/kkamkou/node-akamai-http-api
var solus = Object.create(null, {
  base_config: {
    writable: false,
    value: {
      apiId: null,
      apiKey: null,
      host: null,
      port: 80,
      ssl: false,
      verbose: false
    }
  },
  config: {
    writable: true,
    value: {}
  }
});

// The string formatter
// Stolen from http://stackoverflow.com/a/4673436
solus.strFormat = function(format) {
  var args = Array.prototype.slice.call(arguments, 1);
  return format.replace(/{(\d+)}/g, function(match, number) {
    return typeof args[number] != 'undefined'
      ? args[number]
      : match
    ;
  });
};

// Stolen from http://stackoverflow.com/a/1714899
solus.serializeParams = function(obj, prefix) {
  var str = [];
  for(var p in obj) {
    if (obj.hasOwnProperty(p)) {
      var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
      str.push(typeof v == "object" ?
        serialize(v, k) :
        encodeURIComponent(k) + "=" + encodeURIComponent(v));
    }
  }
  return str.join("&");
};

solus.generateHostUrl = function(params) {
  if (solus.config.host === null) {
    // "Exception" throwing
    // Stolen from http://stackoverflow.com/a/1137209
    throw {
      name:     "ConfigError",
      level:    "FATAL",
      message:  "No 'host' value provided.",
      toString: function(){return this.name + ": " + this.message;}
    }
  };

  var schema = solus.config.ssl ? 'https' : 'http',
      suffix = 'api/admin/command.php',
      host = solus.config.host,
      port = solus.config.port;

  return solus.strFormat('{0}://{1}:{2}/{3}?{4}',
                         schema, host, port, suffix,
                         solus.serializeParams(params));
};

solus.sQuery = function(action, params) {
  // Set Query defaults
  params['rdtype'] = 'json';
  params['id'] = solus.config.apiId;
  params['key'] = solus.config.apiKey;

  // execute response
  httpReq.get(solus.generateHostUrl(params), function (err, res) {
    if (err) {
      console.error(err);
      return 2;
    } else {
      console.log(res);
      return res
    };

    console.log(res.code, res.headers, res.buffer.toString());
  });
}

solus.setConfig = function (conf) {
  conf = typeof conf !== 'undefined' ? conf : {};

  for (var k in this.base_config) {
    this.config[k] = this.base_config[k]
  };
  for (var k in conf) {
    this.config[k] = conf[k]
  };

  return this;
};

<commit_msg>Simplifying sQuery<commit_after>'use strict';

request = require('request');

// The class itself
// Stolen from https://github.com/kkamkou/node-akamai-http-api
var solus = Object.create(null, {
  base_config: {
    writable: false,
    value: {
      apiId: null,
      apiKey: null,
      host: null,
      port: 80,
      ssl: false,
      verbose: false
    }
  },
  config: {
    writable: true,
    value: {}
  }
});

// The string formatter
// Stolen from http://stackoverflow.com/a/4673436
solus.strFormat = function(format) {
  var args = Array.prototype.slice.call(arguments, 1);
  return format.replace(/{(\d+)}/g, function(match, number) {
    return typeof args[number] != 'undefined'
      ? args[number]
      : match
    ;
  });
};

// Stolen from http://stackoverflow.com/a/1714899
solus.serializeParams = function(obj, prefix) {
  var str = [];
  for(var p in obj) {
    if (obj.hasOwnProperty(p)) {
      var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
      str.push(typeof v == "object" ?
        serialize(v, k) :
        encodeURIComponent(k) + "=" + encodeURIComponent(v));
    }
  }
  return str.join("&");
};

solus.generateHostUrl = function(params) {
  if (solus.config.host === null) {
    // "Exception" throwing
    // Stolen from http://stackoverflow.com/a/1137209
    throw {
      name:     "ConfigError",
      level:    "FATAL",
      message:  "No 'host' value provided.",
      toString: function(){return this.name + ": " + this.message;}
    }
  };

  var schema = solus.config.ssl ? 'https' : 'http',
      suffix = 'api/admin/command.php',
      host = solus.config.host,
      port = solus.config.port;

  return solus.strFormat('{0}://{1}:{2}/{3}?{4}',
                         schema, host, port, suffix,
                         solus.serializeParams(params));
};

solus.sQuery = function(params) {
  // Set Query defaults
  params['rdtype'] = 'json';
  params['id'] = solus.config.apiId;
  params['key'] = solus.config.apiKey;

  // execute response
  return request.get(solus.generateHostUrl(params))
};

solus.setConfig = function (conf) {
  conf = typeof conf !== 'undefined' ? conf : {};

  for (var k in this.base_config) {
    this.config[k] = this.base_config[k]
  };
  for (var k in conf) {
    this.config[k] = conf[k]
  };

  return this;
};
<|endoftext|>


<commit_before>'use strict';
var processors = require('../processors'),
    _ = require('underscore'),
    replify = require('replify'),
    undefsafe = require('undefsafe'),
    binModel = require('../models').createModels().bin;

var utils = {},
    sessions = {},
    sessionsFromUser = {},
    pending = {},
    pendingToKillStreaming = {};

var metrics = require('../metrics'),
    openSpikes = 0;

setInterval(function () {
  pending = {};
}, 15 * 60 * 1000);

replify('spike', {
  utils: utils,
  sessions: sessions,
  sessionsFromUser: sessionsFromUser,
  pending: function () {
    return pending;
  },
  openSpikes: function () {
    return openSpikes;
  }
});

// keep checking the sessions we have, and if any of the response objects
// are no longer writable, then we removed them from our list
setInterval(function () {
  Object.keys(sessions).forEach(function (id) {
    sessions[id].res.forEach(function (res) {
      if (!res.connection || !res.connection.writable) {
        utils.removeConnection(id, res);
      }
    });
  });
}, 1000 * 60);

/**
 * Remove a response object from the list associated with the id passed.
 */
utils.removeConnection = function (id, res) {
  if (!sessions[id]) { return; }
  var responses = sessions[id].res,
      index = responses.indexOf(res);

  if (index === -1) { return; }

  responses.splice(index, 1);

  // Update the metrics
  openSpikes -= 1;
  if (openSpikes < 0) {
    openSpikes = 0;
  }
  metrics.gauge('spike.open', openSpikes);

  // Remove any user spikes following
  Object.keys(sessionsFromUser).forEach(function (username) {
    sessionsFromUser[username] = sessionsFromUser[username].filter(function (session) {
      return session.key !== id;
    });
  });

  // ping stats
  spike.ping(res.req.bin, {}, true);

  // Remove the object if we're not using it.
  if (!responses.length) {
    delete sessions[id];
  }
};

utils.keyForBin = function (bin) {
  return bin.url + '/' + bin.revision;
};

utils.sessionForBin = function (bin, create) {
  var key = utils.keyForBin(bin),
      session = sessions[key];

  if (!session && create === true) {
    session = sessions[key] = { res: [], log: [] };
  }

  return session || null;
};

function isOwnerWithWrite(session, bin, checksum) {
  var user = undefsafe(session, 'user.name'),
      owner = undefsafe(bin, 'metadata.name'),
      streamingKey = undefsafe(bin, 'streaming_key');

  return (user === owner && streamingKey === checksum);
}

/**
 * Turn some data (a string or object) into an event-source data & event string.
 */
utils.makeEvent = function (eventName, data) {
  if (!eventName) { return ''; }
  var str = '';
  if (typeof data !== 'string') {
    data = JSON.stringify(data);
  }
  if (data) {
    str += 'data: ' + (''+data).split('\n').join('\ndata: ');
  }
  return 'event: ' + eventName + '\n' + str + '\n\n';
};

/**
 * Process a spike data object with the relevant preprocessor. Takes an object
 * and a bin's settings object.
 *
 * Returns an object with the same keys but with processed data.
 */
utils.process = function(data, settings) {
  data = data || {};
  data.raw = data.content;
  settings = settings || {};
  // Grab the processor settings
  var processorSettings = settings.processors;
  if (!processorSettings) {
    return data;
  }
  // Get the name of the currently used processor
  var processorName = processorSettings[data.panelId];
  if (!processorName) {
    return data;
  }
  // Find this processor in the list of processors
  if (!processors[processorName]) {
    return newData;
  }
  // And process!
  var newData = _.clone(data);
  newData.raw = data.content;
  newData.content = processors[processorName](data.content);
  return newData;
};

var spike = module.exports = {
  getLog: function (req, res) {
    // TODO: Work out what the hell to do with this.
    var session = utils.sessionForBin(req.bin), log;
    res.writeHead(200, {'Content-Type': 'text/html', 'Cache-Control': 'no-cache'});
    log = session ? session.log.join('\n
') : 'No session';
    res.end('<!DOCTYPE html><title>\n' + req.bin.url + '</title>

' + log);
  },

  postLog: function (req, res, next) {
    var session = utils.sessionForBin(req.bin, true);

    // passed over to Server Sent Events on jsconsole.com
    if (session) {
      session.log.push('message: ' + req.body.data);
      res.send(200);
    } else {
      next();
    }
  },

  /**
   * Setup an event stream for the client. This is hit on all bin endpoints.
   */
  getStream: function (req, res, next) {

    // Check request's accepts header for event-stream. Move on if it doesn't
    // support it.
    if (!req.headers.accept || req.headers.accept.indexOf('text/event-stream') === -1) {
      return next();
    }

    // Restore or create a session for the bin
    var session = utils.sessionForBin(req.bin, true),
        key = utils.keyForBin(req.bin),
        userSession = req.session,
        checksum = req.param('checksum'),
        // cache the bin because req.bin is just a reference and gets changed when
        // the revision gets bumped.
        bin = req.bin,
        keepalive = null,
        close, closeTimer;

    if (isOwnerWithWrite(userSession, bin, checksum) && pendingToKillStreaming[key]) {
      clearTimeout(pendingToKillStreaming[key] || null);
    }

    openSpikes += 1;
    metrics.gauge('spike.open', openSpikes);

    console.log('STREAM ACCEPTED', req.originalUrl);

    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache'
    });
    res.write('id: 0\n\n');

    session.res.push(res);

    if (req.keepLatest) {
      if (!sessionsFromUser[req.user.name]) {
        sessionsFromUser[req.user.name] = [];
      }
      sessionsFromUser[req.user.name].push({ key: key, res: res });
    }

    keepalive = setInterval(function () {
      if (!res.connection.writable) {
        return close();
      }
      res.write('id: 0\n\n');
    }, 15 * 1000);

    // FIXME this will break when using /rem/last/ as req.bin won't be the same bin anymore.
    var closed = false;

    close = function () {
      if (closed) {
        return;
      }
      closed = true;

      if (isOwnerWithWrite(userSession, bin, checksum)) {
        // this means the owner has disconnected from jsbin, and it's possible
        // that we can remove their write access to the bin (and thus not add
        // streaming to full previews). So we set a timer, and if this eventsource
        // isn't reopened then we assume it's closed. If this eventsource *does*
        // reopen, then we clear the timer, and they can continue to stream.
        pendingToKillStreaming[key] = setTimeout(function () {

          binModel.updateBinData(req.bin, {streaming_key: ''}, function (error) {
            if (error) {
              console.error(error);
            }
          });
        }, 24 * 60 * 1000); // leave it open for 24 hours
      }
      clearInterval(keepalive);
      clearTimeout(closeTimer);
      utils.removeConnection(utils.keyForBin(req.bin), res);
      // ping stats
      spike.ping(req.bin, {}, true);
    };

    // every 5 minutes, let's let them reconnect
    closeTimer = setTimeout(function () {
      res.end();
      req.emit('close');
    }, 15 * 60 * 1000);

    res.socket.on('close', close);
    req.on('close', close);
    res.req = req;

    // ping stats
    spike.ping(req.bin, {}, true);
  },

  /**
   * Reload all connected clients
   */
  reload: function (bin) {
    var session = utils.sessionForBin(bin);

    if (session) {
      session.res.forEach(function (res) {
        res.write('event: reload\ndata: 0\n\n');

        if (res.ajax) {
          res.end(); // lets older browsers finish their xhr request
          res.req.emit('close');
        }
      });
    }
  },

  /**
   * Update spikes for URLs like /rem/last to keep the clients up to date with
   * the correct bin. It disassociates the connection (userSession.res) from the
   * old bin's pool via removeConnection. It then gets or creates a session for
   * the new bin and updates the userSession's key.
   */
  updateUserSpikes: function (user, newBin) {
    var newKey = utils.keyForBin(newBin);

    if (!sessionsFromUser[user]) { return; }

    // Update sessions for the user bins if the bin has changed
    sessionsFromUser[user].forEach(function (userSession) {
      var oldBinKey = userSession.key;
      // Is this the same bin? If so, keep it, we're cool.
      if (oldBinKey === newKey) { return; }
      utils.removeConnection(oldBinKey, userSession.res);
      // Create/get a new session for the new bin and add the connection to the
      // new session's res pool
      var newSession = utils.sessionForBin(newBin, true);
      newSession.res.push(userSession.res);
      // Upgrade the user session with the new bin and key
      userSession.res.req.bin = newBin;
      userSession.key = newKey;
    });

  },

  /**
   * Update spikes when a new revision is created.
   */
  bumpRevision: function (oldBin, newBin) {

    if (!newBin || !newBin.url) {
      // FIXME this is just patching a problem, the source of which I'm not sure
      console.error('spike/index.js#bump-revision - missing newBin', newBin);
      return;
    }

    var oldSession = utils.sessionForBin(oldBin),
        oldKey = utils.keyForBin(oldBin),
        newSession = utils.sessionForBin(newBin, true),
        newKey = utils.keyForBin(newBin);

    if (!oldSession) { return; }

    // Move connections from one session to another
    oldSession.res.forEach(function (res) {
      // Add the connection to the new session's list
      newSession.res.push(res);
      // Upgrade the connection with the new bin
      res.req.bin = newBin;
      // Tell the client to bump their revision
      res.write(utils.makeEvent('bump-revision', newKey));
      if (res.ajax) {
        // lets older browsers finish their xhr request
        res.end();
        res.req.emit('close');
      }
      return false;
    });

    // There should be no more connections to this bin, so byebye!
    oldSession.res = [];
    delete sessions[oldKey];

  },

  /**
   * Notify connected clients of an update to a bin
   */
  ping: function (bin, data, statsRequest) {
    var id = bin.id,
        delayTrigger = 500;

    if (!pending[id]) {
      pending[id] = {};
    }

    pending[id].bin = bin;
    pending[id][data.panelId] = utils.process(data, bin.settings);

    // Clear the previous ping
    clearTimeout(pending[id].timer);

    // NOTE: this will only fire once per jsbin session -
    // not for every panel sent - because we clear the timer
    pending[id].timer = setTimeout(function () {
      var session = utils.sessionForBin(bin),
          data = null,
          ping = pending[id];

      if (!ping) { return; }

      // Javascript and HTML cause reloads. CSS is injected.
      data = ping.javascript || ping.html || ping.css || (statsRequest ? {} : false);

      // Forget this ping, it's done with now
      delete pending[id];

      if (!data) { return; }
      if (!session) { return; }

      // Send the update to all connected sessions in original and raw flavours
      session.res.forEach(function (res) {
        var raw = data.raw || data.content;
        if (!res.req.stats) {
          res.write(utils.makeEvent(data.panelId, raw));
          res.write(utils.makeEvent(data.panelId + ':processed', data.content));
        }
        res.write(utils.makeEvent('stats', { connections: session.res.filter(function (res) {
          return !res.req.stats;
        }).length }));
        if (res.ajax && !statsRequest) {
          res.end(); // lets older browsers finish their xhr request
          res.req.emit('close');
        }
      });

    }, delayTrigger);
  },

  appendScripts: function (version, scripts) {
    // TODO this should really detect that there's an active session going
    // on and the user is saving, and therefore include the spike intelligently
    scripts.push('js/vendor/eventsource.js?' + version);
    scripts.push('js/spike.js?' + version);
  },

  utils: utils
};
<commit_msg>Update check for processors<commit_after>'use strict';
var processors = require('../processors'),
    _ = require('underscore'),
    replify = require('replify'),
    undefsafe = require('undefsafe'),
    binModel = require('../models').createModels().bin;

var utils = {},
    sessions = {},
    sessionsFromUser = {},
    pending = {},
    pendingToKillStreaming = {};

var metrics = require('../metrics'),
    openSpikes = 0;

setInterval(function () {
  pending = {};
}, 15 * 60 * 1000);

replify('spike', {
  utils: utils,
  sessions: sessions,
  sessionsFromUser: sessionsFromUser,
  pending: function () {
    return pending;
  },
  openSpikes: function () {
    return openSpikes;
  }
});

// keep checking the sessions we have, and if any of the response objects
// are no longer writable, then we removed them from our list
setInterval(function () {
  Object.keys(sessions).forEach(function (id) {
    sessions[id].res.forEach(function (res) {
      if (!res.connection || !res.connection.writable) {
        utils.removeConnection(id, res);
      }
    });
  });
}, 1000 * 60);

/**
 * Remove a response object from the list associated with the id passed.
 */
utils.removeConnection = function (id, res) {
  if (!sessions[id]) { return; }
  var responses = sessions[id].res,
      index = responses.indexOf(res);

  if (index === -1) { return; }

  responses.splice(index, 1);

  // Update the metrics
  openSpikes -= 1;
  if (openSpikes < 0) {
    openSpikes = 0;
  }
  metrics.gauge('spike.open', openSpikes);

  // Remove any user spikes following
  Object.keys(sessionsFromUser).forEach(function (username) {
    sessionsFromUser[username] = sessionsFromUser[username].filter(function (session) {
      return session.key !== id;
    });
  });

  // ping stats
  spike.ping(res.req.bin, {}, true);

  // Remove the object if we're not using it.
  if (!responses.length) {
    delete sessions[id];
  }
};

utils.keyForBin = function (bin) {
  return bin.url + '/' + bin.revision;
};

utils.sessionForBin = function (bin, create) {
  var key = utils.keyForBin(bin),
      session = sessions[key];

  if (!session && create === true) {
    session = sessions[key] = { res: [], log: [] };
  }

  return session || null;
};

function isOwnerWithWrite(session, bin, checksum) {
  var user = undefsafe(session, 'user.name'),
      owner = undefsafe(bin, 'metadata.name'),
      streamingKey = undefsafe(bin, 'streaming_key');

  return (user === owner && streamingKey === checksum);
}

/**
 * Turn some data (a string or object) into an event-source data & event string.
 */
utils.makeEvent = function (eventName, data) {
  if (!eventName) { return ''; }
  var str = '';
  if (typeof data !== 'string') {
    data = JSON.stringify(data);
  }
  if (data) {
    str += 'data: ' + (''+data).split('\n').join('\ndata: ');
  }
  return 'event: ' + eventName + '\n' + str + '\n\n';
};

/**
 * Process a spike data object with the relevant preprocessor. Takes an object
 * and a bin's settings object.
 *
 * Returns an object with the same keys but with processed data.
 */
utils.process = function(data, settings) {
  data = data || {};
  data.raw = data.content;
  settings = settings || {};
  // Grab the processor settings
  var processorSettings = settings.processors;
  if (!processorSettings) {
    return data;
  }
  // Get the name of the currently used processor
  var processorName = processorSettings[data.panelId];
  if (!processorName) {
    return data;
  }
  // Find this processor in the list of processors
  if (!processors.support(processorName)) {
    return data;
  }
  // And process!
  var newData = _.clone(data);
  newData.raw = data.content;
  newData.content = processors[processorName](data.content);
  return newData;
};

var spike = module.exports = {
  getLog: function (req, res) {
    // TODO: Work out what the hell to do with this.
    var session = utils.sessionForBin(req.bin), log;
    res.writeHead(200, {'Content-Type': 'text/html', 'Cache-Control': 'no-cache'});
    log = session ? session.log.join('\n
') : 'No session';
    res.end('<!DOCTYPE html><title>\n' + req.bin.url + '</title>

' + log);
  },

  postLog: function (req, res, next) {
    var session = utils.sessionForBin(req.bin, true);

    // passed over to Server Sent Events on jsconsole.com
    if (session) {
      session.log.push('message: ' + req.body.data);
      res.send(200);
    } else {
      next();
    }
  },

  /**
   * Setup an event stream for the client. This is hit on all bin endpoints.
   */
  getStream: function (req, res, next) {

    // Check request's accepts header for event-stream. Move on if it doesn't
    // support it.
    if (!req.headers.accept || req.headers.accept.indexOf('text/event-stream') === -1) {
      return next();
    }

    // Restore or create a session for the bin
    var session = utils.sessionForBin(req.bin, true),
        key = utils.keyForBin(req.bin),
        userSession = req.session,
        checksum = req.param('checksum'),
        // cache the bin because req.bin is just a reference and gets changed when
        // the revision gets bumped.
        bin = req.bin,
        keepalive = null,
        close, closeTimer;

    if (isOwnerWithWrite(userSession, bin, checksum) && pendingToKillStreaming[key]) {
      clearTimeout(pendingToKillStreaming[key] || null);
    }

    openSpikes += 1;
    metrics.gauge('spike.open', openSpikes);

    console.log('STREAM ACCEPTED', req.originalUrl);

    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache'
    });
    res.write('id: 0\n\n');

    session.res.push(res);

    if (req.keepLatest) {
      if (!sessionsFromUser[req.user.name]) {
        sessionsFromUser[req.user.name] = [];
      }
      sessionsFromUser[req.user.name].push({ key: key, res: res });
    }

    keepalive = setInterval(function () {
      if (!res.connection.writable) {
        return close();
      }
      res.write('id: 0\n\n');
    }, 15 * 1000);

    // FIXME this will break when using /rem/last/ as req.bin won't be the same bin anymore.
    var closed = false;

    close = function () {
      if (closed) {
        return;
      }
      closed = true;

      if (isOwnerWithWrite(userSession, bin, checksum)) {
        // this means the owner has disconnected from jsbin, and it's possible
        // that we can remove their write access to the bin (and thus not add
        // streaming to full previews). So we set a timer, and if this eventsource
        // isn't reopened then we assume it's closed. If this eventsource *does*
        // reopen, then we clear the timer, and they can continue to stream.
        pendingToKillStreaming[key] = setTimeout(function () {

          binModel.updateBinData(req.bin, {streaming_key: ''}, function (error) {
            if (error) {
              console.error(error);
            }
          });
        }, 24 * 60 * 1000); // leave it open for 24 hours
      }
      clearInterval(keepalive);
      clearTimeout(closeTimer);
      utils.removeConnection(utils.keyForBin(req.bin), res);
      // ping stats
      spike.ping(req.bin, {}, true);
    };

    // every 5 minutes, let's let them reconnect
    closeTimer = setTimeout(function () {
      res.end();
      req.emit('close');
    }, 15 * 60 * 1000);

    res.socket.on('close', close);
    req.on('close', close);
    res.req = req;

    // ping stats
    spike.ping(req.bin, {}, true);
  },

  /**
   * Reload all connected clients
   */
  reload: function (bin) {
    var session = utils.sessionForBin(bin);

    if (session) {
      session.res.forEach(function (res) {
        res.write('event: reload\ndata: 0\n\n');

        if (res.ajax) {
          res.end(); // lets older browsers finish their xhr request
          res.req.emit('close');
        }
      });
    }
  },

  /**
   * Update spikes for URLs like /rem/last to keep the clients up to date with
   * the correct bin. It disassociates the connection (userSession.res) from the
   * old bin's pool via removeConnection. It then gets or creates a session for
   * the new bin and updates the userSession's key.
   */
  updateUserSpikes: function (user, newBin) {
    var newKey = utils.keyForBin(newBin);

    if (!sessionsFromUser[user]) { return; }

    // Update sessions for the user bins if the bin has changed
    sessionsFromUser[user].forEach(function (userSession) {
      var oldBinKey = userSession.key;
      // Is this the same bin? If so, keep it, we're cool.
      if (oldBinKey === newKey) { return; }
      utils.removeConnection(oldBinKey, userSession.res);
      // Create/get a new session for the new bin and add the connection to the
      // new session's res pool
      var newSession = utils.sessionForBin(newBin, true);
      newSession.res.push(userSession.res);
      // Upgrade the user session with the new bin and key
      userSession.res.req.bin = newBin;
      userSession.key = newKey;
    });

  },

  /**
   * Update spikes when a new revision is created.
   */
  bumpRevision: function (oldBin, newBin) {

    if (!newBin || !newBin.url) {
      // FIXME this is just patching a problem, the source of which I'm not sure
      console.error('spike/index.js#bump-revision - missing newBin', newBin);
      return;
    }

    var oldSession = utils.sessionForBin(oldBin),
        oldKey = utils.keyForBin(oldBin),
        newSession = utils.sessionForBin(newBin, true),
        newKey = utils.keyForBin(newBin);

    if (!oldSession) { return; }

    // Move connections from one session to another
    oldSession.res.forEach(function (res) {
      // Add the connection to the new session's list
      newSession.res.push(res);
      // Upgrade the connection with the new bin
      res.req.bin = newBin;
      // Tell the client to bump their revision
      res.write(utils.makeEvent('bump-revision', newKey));
      if (res.ajax) {
        // lets older browsers finish their xhr request
        res.end();
        res.req.emit('close');
      }
      return false;
    });

    // There should be no more connections to this bin, so byebye!
    oldSession.res = [];
    delete sessions[oldKey];

  },

  /**
   * Notify connected clients of an update to a bin
   */
  ping: function (bin, data, statsRequest) {
    var id = bin.id,
        delayTrigger = 500;

    if (!pending[id]) {
      pending[id] = {};
    }

    pending[id].bin = bin;
    pending[id][data.panelId] = utils.process(data, bin.settings);

    // Clear the previous ping
    clearTimeout(pending[id].timer);

    // NOTE: this will only fire once per jsbin session -
    // not for every panel sent - because we clear the timer
    pending[id].timer = setTimeout(function () {
      var session = utils.sessionForBin(bin),
          data = null,
          ping = pending[id];

      if (!ping) { return; }

      // Javascript and HTML cause reloads. CSS is injected.
      data = ping.javascript || ping.html || ping.css || (statsRequest ? {} : false);

      // Forget this ping, it's done with now
      delete pending[id];

      if (!data) { return; }
      if (!session) { return; }

      // Send the update to all connected sessions in original and raw flavours
      session.res.forEach(function (res) {
        var raw = data.raw || data.content;
        if (!res.req.stats) {
          res.write(utils.makeEvent(data.panelId, raw));
          res.write(utils.makeEvent(data.panelId + ':processed', data.content));
        }
        res.write(utils.makeEvent('stats', { connections: session.res.filter(function (res) {
          return !res.req.stats;
        }).length }));
        if (res.ajax && !statsRequest) {
          res.end(); // lets older browsers finish their xhr request
          res.req.emit('close');
        }
      });

    }, delayTrigger);
  },

  appendScripts: function (version, scripts) {
    // TODO this should really detect that there's an active session going
    // on and the user is saving, and therefore include the spike intelligently
    scripts.push('js/vendor/eventsource.js?' + version);
    scripts.push('js/spike.js?' + version);
  },

  utils: utils
};
<|endoftext|>


<commit_before>define(["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "dojo/query",
		"dojo/_base/connect", "dojo/_base/Color", "./Legend", "dijit/form/CheckBox", "../action2d/Highlight",
		"dojox/lang/functional", "dojox/gfx/fx", "dojo/keys", "dojo/_base/event", "dojo/dom-construct",
		"dojo/dom-prop"],
	function(lang, arrayUtil, declare, query, hub, Color, Legend, CheckBox,
			 Highlight, df, fx, keys, event, dom, domProp){

	var FocusManager = declare(null, {
		// summary:
		//		It will take legend as a tab stop, and using
		//		cursor keys to navigate labels within the legend.
		// tags:
		//		private
		constructor: function(legend){
			this.legend = legend;
			this.index = 0;
			this.horizontalLength = this._getHrizontalLength();
			arrayUtil.forEach(legend.legends, function(item, i){
				if(i > 0){
					query("input", item).attr("tabindex", -1);
				}
			});
			this.firstLabel = query("input", legend.legends[0])[0];
			hub.connect(this.firstLabel, "focus", this, function(){this.legend.active = true;});
			hub.connect(this.legend.domNode, "keydown", this, "_onKeyEvent");
		},
		_getHrizontalLength: function(){
			var horizontal = this.legend.horizontal;
			if(typeof horizontal == "number"){
				return Math.min(horizontal, this.legend.legends.length);
			}else if(!horizontal){
				return 1;
			}else{
				return this.legend.legends.length;
			}
		},
		_onKeyEvent: function(e){
			//	if not focused
			if(!this.legend.active){
				return;
			}
			//	lose focus
			if(e.keyCode == keys.TAB){
				this.legend.active = false;
				return;
			}
			//	handle with arrow keys
			var max = this.legend.legends.length;
			switch(e.keyCode){
				case keys.LEFT_ARROW:
					this.index--;
					if(this.index < 0){
						this.index += max;
					}
					break;
				case keys.RIGHT_ARROW:
					this.index++;
					if(this.index >= max){
						this.index -= max;
					}
					break;
				case keys.UP_ARROW:
					if(this.index - this.horizontalLength >= 0){
						this.index -= this.horizontalLength;
					}
					break;
				case keys.DOWN_ARROW:
					if(this.index + this.horizontalLength < max){
						this.index += this.horizontalLength;
					}
					break;
				default:
					return;
			}
			this._moveToFocus();
			Event.stop(e);
		},
		_moveToFocus: function(){
			query("input", this.legend.legends[this.index])[0].focus();
		}
	});

	declare("dojox.charting.widget.SelectableLegend", Legend, {
		// summary:
		//		An enhanced chart legend supporting interactive events on data series

		//	theme component
		outline:			false,	//	outline of vanished data series
		transitionFill:		null,	//	fill of deselected data series
		transitionStroke:	null,	//	stroke of deselected data series

		postCreate: function(){
			this.legends = [];
			this.legendAnim = {};
			this.inherited(arguments);
		},
		refresh: function(){
			this.legends = [];
			this.inherited(arguments);
			this._applyEvents();
			new FocusManager(this);
		},
		_addLabel: function(dyn, label){
			this.inherited(arguments);
			//	create checkbox
			var legendNodes = query("td", this.legendBody);
			var currentLegendNode = legendNodes[legendNodes.length - 1];
			this.legends.push(currentLegendNode);
			var checkbox = new CheckBox({checked: true});
			dom.place(checkbox.domNode, currentLegendNode, "first");
			// connect checkbox and existed label
			var clabel = query("label", currentLegendNode)[0];
			domProp.set(clabel, "for", checkbox.id);
		},
		_applyEvents: function(){
			// summary:
			//		Apply click-event on checkbox and hover-event on legend icon,
			//		highlight data series or toggle it.

			// if the chart has not yet been refreshed it will crash here (targetData.group == null)
			if(this.chart.dirty){
				return;
			}
			arrayUtil.forEach(this.legends, function(legend, i){
				var targetData, shapes = [], plotName, seriesName;
				if(this._isPie()){
					targetData = this.chart.stack[0];
					shapes.push(targetData.group.children[i]);
					plotName = targetData.name;
					seriesName = this.chart.series[0].name;
				}else{
					targetData = this.chart.series[i];
					shapes = targetData.group.children;
					plotName = targetData.plot;
					seriesName = targetData.name;
				}
				var originalDyn = {
					fills : df.map(shapes, "x.getFill()"),
					strokes: df.map(shapes, "x.getStroke()")
				};
				//	toggle action
				var legendCheckBox = query(".dijitCheckBox", legend)[0];
				hub.connect(legendCheckBox, "onclick", this, function(e){
					this._toggle(shapes, i, legend.vanished, originalDyn, seriesName, plotName);
					legend.vanished = !legend.vanished;
					e.stopPropagation();
				});

				//	highlight action
				var legendIcon = query(".dojoxLegendIcon", legend)[0],
					iconShape = this._getFilledShape(this._surfaces[i].children);
				arrayUtil.forEach(["onmouseenter", "onmouseleave"], function(event){
					hub.connect(legendIcon, event, this, function(e){
						this._highlight(e, iconShape, shapes, i, legend.vanished, originalDyn, seriesName, plotName);
					});
				}, this);
			},this);
		},
		_toggle: function(shapes, index, isOff, dyn, seriesName, plotName){
			arrayUtil.forEach(shapes, function(shape, i){
				var startFill = dyn.fills[i],
					endFill = this._getTransitionFill(plotName),
					startStroke = dyn.strokes[i],
					endStroke = this.transitionStroke;
				if(startFill){
					if(endFill && (typeof startFill == "string" || startFill instanceof Color)){
						fx.animateFill({
							shape: shape,
							color: {
								start: isOff ? endFill : startFill,
								end: isOff ? startFill : endFill
							}
						}).play();
					}else{
						shape.setFill(isOff ? startFill : endFill);
					}
				}
				if(startStroke && !this.outline){
					shape.setStroke(isOff ? startStroke : endStroke);
				}
			}, this);
		},
		_highlight: function(e, iconShape, shapes, index, isOff, dyn, seriesName, plotName){
			if(!isOff){
				var anim = this._getAnim(plotName),
					isPie = this._isPie(),
					type = formatEventType(e.type);
				//	highlight the label icon,
				var label = {
					shape: iconShape,
					index: isPie ? "legend" + index : "legend",
					run: {name: seriesName},
					type: type
				};
				anim.process(label);
				//	highlight the data items
				arrayUtil.forEach(shapes, function(shape, i){
					shape.setFill(dyn.fills[i]);
					var o = {
						shape: shape,
						index: isPie ? index : i,
						run: {name: seriesName},
						type: type
					};
					anim.duration = 100;
					anim.process(o);
				});
			}
		},
		_getAnim: function(plotName){
			if(!this.legendAnim[plotName]){
				this.legendAnim[plotName] = new Highlight(this.chart, plotName);
				// calling this is marking the plot dirty however here this is a "fake" highlight action
				// we don't want to re-render the chart, _highlight is the in charge of running the animation
				this.chart.getPlot(plotName).dirty = false;
			}
			return this.legendAnim[plotName];
		},
		_getTransitionFill: function(plotName){
			// Since series of stacked charts all start from the base line,
			// fill the "front" series with plotarea color to make it disappear .
			if(this.chart.stack[this.chart.plots[plotName]].declaredClass.indexOf("dojox.charting.plot2d.Stacked") != -1){
				return this.chart.theme.plotarea.fill;
			}
			return null;
		},
		_getFilledShape: function(shapes){
			// summary:
			//		Get filled shape in legend icon which would be highlighted when hovered
			var i = 0;
			while(shapes[i]){
				if(shapes[i].getFill())return shapes[i];
				i++;
			}
			return null;
		},
		_isPie: function(){
			return this.chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie";
		}
	});

	function formatEventType(type){
		if(type == "mouseenter")return "onmouseover";
		if(type == "mouseleave")return "onmouseout";
		return "on" + type;
	}

	return dojox.charting.widget.SelectableLegend;
});
<commit_msg>fixes #15516. Fixes leaking child widgets with !SelectableLegend. Thanks Ben Hockey (CCLA).<commit_after>define(["dojo/_base/array", "dojo/_base/declare", "dojo/query",
		"dojo/_base/connect", "dojo/_base/Color", "./Legend", "dijit/form/CheckBox", "../action2d/Highlight",
		"dojox/lang/functional", "dojox/gfx/fx", "dojo/keys", "dojo/dom-construct",
		"dojo/dom-prop"],
	function(arrayUtil, declare, query, hub, Color, Legend, CheckBox,
			 Highlight, df, fx, keys, dom, domProp){

	var FocusManager = declare(null, {
		// summary:
		//		It will take legend as a tab stop, and using
		//		cursor keys to navigate labels within the legend.
		// tags:
		//		private
		constructor: function(legend){
			this.legend = legend;
			this.index = 0;
			this.horizontalLength = this._getHrizontalLength();
			arrayUtil.forEach(legend.legends, function(item, i){
				if(i > 0){
					query("input", item).attr("tabindex", -1);
				}
			});
			this.firstLabel = query("input", legend.legends[0])[0];
			hub.connect(this.firstLabel, "focus", this, function(){this.legend.active = true;});
			hub.connect(this.legend.domNode, "keydown", this, "_onKeyEvent");
		},
		_getHrizontalLength: function(){
			var horizontal = this.legend.horizontal;
			if(typeof horizontal == "number"){
				return Math.min(horizontal, this.legend.legends.length);
			}else if(!horizontal){
				return 1;
			}else{
				return this.legend.legends.length;
			}
		},
		_onKeyEvent: function(e){
			//	if not focused
			if(!this.legend.active){
				return;
			}
			//	lose focus
			if(e.keyCode == keys.TAB){
				this.legend.active = false;
				return;
			}
			//	handle with arrow keys
			var max = this.legend.legends.length;
			switch(e.keyCode){
				case keys.LEFT_ARROW:
					this.index--;
					if(this.index < 0){
						this.index += max;
					}
					break;
				case keys.RIGHT_ARROW:
					this.index++;
					if(this.index >= max){
						this.index -= max;
					}
					break;
				case keys.UP_ARROW:
					if(this.index - this.horizontalLength >= 0){
						this.index -= this.horizontalLength;
					}
					break;
				case keys.DOWN_ARROW:
					if(this.index + this.horizontalLength < max){
						this.index += this.horizontalLength;
					}
					break;
				default:
					return;
			}
			this._moveToFocus();
			Event.stop(e);
		},
		_moveToFocus: function(){
			query("input", this.legend.legends[this.index])[0].focus();
		}
	});

	declare("dojox.charting.widget.SelectableLegend", Legend, {
		// summary:
		//		An enhanced chart legend supporting interactive events on data series

		//	theme component
		outline:			false,	//	outline of vanished data series
		transitionFill:		null,	//	fill of deselected data series
		transitionStroke:	null,	//	stroke of deselected data series

		postCreate: function(){
			this.legends = [];
			this.legendAnim = {};
			this._cbs = [];
			this.inherited(arguments);
		},
		refresh: function(){
			this.legends = [];
			this._clearLabels();
			this.inherited(arguments);
			this._applyEvents();
			new FocusManager(this);
		},
		_clearLabels: function(){
			var cbs = this._cbs;
			while(cbs.length){
				cbs.pop().destroyRecursive();
			}
		},
		_addLabel: function(dyn, label){
			this.inherited(arguments);
			//	create checkbox
			var legendNodes = query("td", this.legendBody);
			var currentLegendNode = legendNodes[legendNodes.length - 1];
			this.legends.push(currentLegendNode);
			var checkbox = new CheckBox({checked: true});
			this._cbs.push(checkbox);
			dom.place(checkbox.domNode, currentLegendNode, "first");
			// connect checkbox and existed label
			var clabel = query("label", currentLegendNode)[0];
			domProp.set(clabel, "for", checkbox.id);
		},
		_applyEvents: function(){
			// summary:
			//		Apply click-event on checkbox and hover-event on legend icon,
			//		highlight data series or toggle it.

			// if the chart has not yet been refreshed it will crash here (targetData.group == null)
			if(this.chart.dirty){
				return;
			}
			arrayUtil.forEach(this.legends, function(legend, i){
				var targetData, shapes = [], plotName, seriesName;
				if(this._isPie()){
					targetData = this.chart.stack[0];
					shapes.push(targetData.group.children[i]);
					plotName = targetData.name;
					seriesName = this.chart.series[0].name;
				}else{
					targetData = this.chart.series[i];
					shapes = targetData.group.children;
					plotName = targetData.plot;
					seriesName = targetData.name;
				}
				var originalDyn = {
					fills : df.map(shapes, "x.getFill()"),
					strokes: df.map(shapes, "x.getStroke()")
				};
				//	toggle action
				var legendCheckBox = query(".dijitCheckBox", legend)[0];
				hub.connect(legendCheckBox, "onclick", this, function(e){
					this._toggle(shapes, i, legend.vanished, originalDyn, seriesName, plotName);
					legend.vanished = !legend.vanished;
					e.stopPropagation();
				});

				//	highlight action
				var legendIcon = query(".dojoxLegendIcon", legend)[0],
					iconShape = this._getFilledShape(this._surfaces[i].children);
				arrayUtil.forEach(["onmouseenter", "onmouseleave"], function(event){
					hub.connect(legendIcon, event, this, function(e){
						this._highlight(e, iconShape, shapes, i, legend.vanished, originalDyn, seriesName, plotName);
					});
				}, this);
			},this);
		},
		_toggle: function(shapes, index, isOff, dyn, seriesName, plotName){
			arrayUtil.forEach(shapes, function(shape, i){
				var startFill = dyn.fills[i],
					endFill = this._getTransitionFill(plotName),
					startStroke = dyn.strokes[i],
					endStroke = this.transitionStroke;
				if(startFill){
					if(endFill && (typeof startFill == "string" || startFill instanceof Color)){
						fx.animateFill({
							shape: shape,
							color: {
								start: isOff ? endFill : startFill,
								end: isOff ? startFill : endFill
							}
						}).play();
					}else{
						shape.setFill(isOff ? startFill : endFill);
					}
				}
				if(startStroke && !this.outline){
					shape.setStroke(isOff ? startStroke : endStroke);
				}
			}, this);
		},
		_highlight: function(e, iconShape, shapes, index, isOff, dyn, seriesName, plotName){
			if(!isOff){
				var anim = this._getAnim(plotName),
					isPie = this._isPie(),
					type = formatEventType(e.type);
				//	highlight the label icon,
				var label = {
					shape: iconShape,
					index: isPie ? "legend" + index : "legend",
					run: {name: seriesName},
					type: type
				};
				anim.process(label);
				//	highlight the data items
				arrayUtil.forEach(shapes, function(shape, i){
					shape.setFill(dyn.fills[i]);
					var o = {
						shape: shape,
						index: isPie ? index : i,
						run: {name: seriesName},
						type: type
					};
					anim.duration = 100;
					anim.process(o);
				});
			}
		},
		_getAnim: function(plotName){
			if(!this.legendAnim[plotName]){
				this.legendAnim[plotName] = new Highlight(this.chart, plotName);
				// calling this is marking the plot dirty however here this is a "fake" highlight action
				// we don't want to re-render the chart, _highlight is the in charge of running the animation
				this.chart.getPlot(plotName).dirty = false;
			}
			return this.legendAnim[plotName];
		},
		_getTransitionFill: function(plotName){
			// Since series of stacked charts all start from the base line,
			// fill the "front" series with plotarea color to make it disappear .
			if(this.chart.stack[this.chart.plots[plotName]].declaredClass.indexOf("dojox.charting.plot2d.Stacked") != -1){
				return this.chart.theme.plotarea.fill;
			}
			return null;
		},
		_getFilledShape: function(shapes){
			// summary:
			//		Get filled shape in legend icon which would be highlighted when hovered
			var i = 0;
			while(shapes[i]){
				if(shapes[i].getFill())return shapes[i];
				i++;
			}
			return null;
		},
		_isPie: function(){
			return this.chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie";
		},
		destroy: function(){
			this._clearLabels();
			this.inherited(arguments);
		}
	});

	function formatEventType(type){
		if(type == "mouseenter")return "onmouseover";
		if(type == "mouseleave")return "onmouseout";
		return "on" + type;
	}

	return dojox.charting.widget.SelectableLegend;
});
<|endoftext|>


<commit_before>/**
 * @file textUnMute command
 * @author Sankarsan Kampa (a.k.a k3rn31p4nic)
 * @license MIT
 */

exports.exec = async (Bastion, message, args) => {
  try {
    let user;
    if (message.mentions.users.size) {
      user = message.mentions.users.first();
    }
    else if (args.id) {
      user = await Bastion.fetchUser(args.id);
    }
    if (!user) {
      /**
       * The command was ran with invalid parameters.
       * @fires commandUsage
       */
      return Bastion.emit('commandUsage', message, this.help);
    }

    let member = await message.guild.fetchMember(user.id);
    if (message.author.id !== message.guild.ownerID && message.member.highestRole.comparePositionTo(member.highestRole) <= 0) return Bastion.log.info(Bastion.strings.error(message.guild.language, 'lowerRole', true));

    if (args.server) {
      let mutedRole = message.guild.roles.find('name', 'Bastion:mute');
      await member.removeRole(mutedRole, args.reason).catch(() => {});
    }
    else {
      let permissionOverwrites = message.channel.permissionOverwrites.get(user.id);
      if (permissionOverwrites) {
        await permissionOverwrites.delete();
      }
    }

    args.reason = args.reason.join(' ');

    message.channel.send({
      embed: {
        color: Bastion.colors.GREEN,
        description: Bastion.strings.info(message.guild.language, 'textUnmute', message.author.tag, user.tag, args.reason)
      }
    }).catch(e => {
      Bastion.log.error(e);
    });

    /**
     * Logs moderation events if it is enabled
     * @fires moderationLog
     */
    Bastion.emit('moderationLog', message.guild, message.author, this.help.name, user, args.reason, {
      channel: message.channel
    });
  }
  catch (e) {
    Bastion.log.error(e);
  }
};

exports.config = {
  aliases: [ 'tum' ],
  enabled: true,
  argsDefinitions: [
    { name: 'id', type: String, defaultOption: true },
    { name: 'reason', alias: 'r', type: String, multiple: true, defaultValue: [ 'No reason given.' ] },
    { name: 'server', type: Boolean, alias: 's' }
  ]
};

exports.help = {
  name: 'textUnMute',
  botPermission: 'MANAGE_ROLES',
  userTextPermission: 'MANAGE_ROLES',
  userVoicePermission: '',
  usage: 'textUnMute <@USER_MENTION | USER_ID> [-r Reason] [--server]',
  example: [ 'textUnMute @user#001 -r Apologized', 'textUnMute 167147569575323761 -r Forgiven --server' ]
};
<commit_msg>commands: fix textUnMute ignoring errors with removeRole<commit_after>/**
 * @file textUnMute command
 * @author Sankarsan Kampa (a.k.a k3rn31p4nic)
 * @license MIT
 */

exports.exec = async (Bastion, message, args) => {
  try {
    let user;
    if (message.mentions.users.size) {
      user = message.mentions.users.first();
    }
    else if (args.id) {
      user = await Bastion.fetchUser(args.id);
    }
    if (!user) {
      /**
       * The command was ran with invalid parameters.
       * @fires commandUsage
       */
      return Bastion.emit('commandUsage', message, this.help);
    }

    let member = await message.guild.fetchMember(user.id);
    if (message.author.id !== message.guild.ownerID && message.member.highestRole.comparePositionTo(member.highestRole) <= 0) return Bastion.log.info(Bastion.strings.error(message.guild.language, 'lowerRole', true));

    if (args.server) {
      let mutedRole = message.guild.roles.find('name', 'Bastion:mute');
      await member.removeRole(mutedRole, args.reason);
    }
    else {
      let permissionOverwrites = message.channel.permissionOverwrites.get(user.id);
      if (permissionOverwrites) {
        await permissionOverwrites.delete();
      }
    }

    args.reason = args.reason.join(' ');

    message.channel.send({
      embed: {
        color: Bastion.colors.GREEN,
        description: Bastion.strings.info(message.guild.language, 'textUnmute', message.author.tag, user.tag, args.reason)
      }
    }).catch(e => {
      Bastion.log.error(e);
    });

    /**
     * Logs moderation events if it is enabled
     * @fires moderationLog
     */
    Bastion.emit('moderationLog', message.guild, message.author, this.help.name, user, args.reason, {
      channel: message.channel
    });
  }
  catch (e) {
    Bastion.log.error(e);
  }
};

exports.config = {
  aliases: [ 'tum' ],
  enabled: true,
  argsDefinitions: [
    { name: 'id', type: String, defaultOption: true },
    { name: 'reason', alias: 'r', type: String, multiple: true, defaultValue: [ 'No reason given.' ] },
    { name: 'server', type: Boolean, alias: 's' }
  ]
};

exports.help = {
  name: 'textUnMute',
  botPermission: 'MANAGE_ROLES',
  userTextPermission: 'MANAGE_ROLES',
  userVoicePermission: '',
  usage: 'textUnMute <@USER_MENTION | USER_ID> [-r Reason] [--server]',
  example: [ 'textUnMute @user#001 -r Apologized', 'textUnMute 167147569575323761 -r Forgiven --server' ]
};
<|endoftext|>


<commit_before>
// Bootstrap-selcct - http://silviomoreto.github.io/bootstrap-select
$('.selectpicker').selectpicker();

// http://getbootstrap.com/javascript/#popovers
$('[data-bbs="popover"]').popover({
    placement : 'auto',
    html: 'true',
    container: '.rb-bbs',
    content: '

홍길동 (대한이)

가입일 : 2009.06.12 (2312일전)
마지막접속 : 2015.10.12 (0일전)
포인트 : 11,966 , 등급 : 비기너++ 10

함께아는 친구 16명

',
    template: '

<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 친구 </button>

친구 끊기

<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 팔로잉 </button>

팔로잉 취소

<button type="button" class="btn btn-default btn-sm">메시지</button>

'
});

// http://mattlockyer.com/2013/04/08/close-a-twitter-bootstrap-popover-when-clicking-outside/
$('body').on('click', function (e) {
    $('[data-bbs="popover"]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            $(this).popover('hide');
        }
    });
});

$('#popupBottom').modalPopover()<commit_msg>popover profile 관련<commit_after>$(document).ready(function() {

    // Bootstrap-selcct - http://silviomoreto.github.io/bootstrap-select
    $('.selectpicker').selectpicker();

    // http://getbootstrap.com/javascript/#popovers
    $('[data-profile="popover"]').popover({
        placement : 'auto',
        html: 'true',
        container: '.rb-bbs',
        content: '

홍길동 (대한이)

가입일 : 2009.06.12 (2312일전)
마지막접속 : 2015.10.12 (0일전)
포인트 : 11,966 , 등급 : 비기너++ 10

함께아는 친구 16명

',
        template: '

<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 친구 </button>

친구 끊기

<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 팔로잉 </button>

팔로잉 취소

<button type="button" class="btn btn-default btn-sm">메시지</button>

'
    });

    // http://mattlockyer.com/2013/04/08/close-a-twitter-bootstrap-popover-when-clicking-outside/
    $('body').on('click', function (e) {
        $('[data-profile="popover"]').each(function () {
            //the 'is' for buttons that trigger popups
            //the 'has' for icons within a button that triggers a popup
            if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
                $(this).popover('hide');
            }
        });
    });

});<|endoftext|>


<commit_before>import React from 'react';
import merge from 'lodash/merge';

import {
  isObjectOrArray,
  isMember,
} from '../elements/element';

class Value extends React.Component {
  static propTypes = {
    value: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number,
      React.PropTypes.bool,
    ]),
    element: React.PropTypes.object,
    style: React.PropTypes.object,
  };

  static contextTypes = {
    theme: React.PropTypes.object,
  };

  renderStyles() {
    const {
      VALUE_COLOR,
      VALUE_BACKGROUND_COLOR,
      VALUE_BORDER_RADIUS,
    } = this.context.theme;

    const styles = {
      float: 'left',
      width: 'auto',
      height: 'auto',
      margin: '0px',
      padding: '0px',
      fontWeight: '600',
      backgroundColor: VALUE_BACKGROUND_COLOR,
      borderRadius: VALUE_BORDER_RADIUS,
      paddingTop: '2px',
      paddingBottom: '2px',
      paddingLeft: '4px',
      paddingRight: '4px',
      fontFamily: 'Source Sans Pro',
      fontSize: '15px',
      color: VALUE_COLOR,
      lineHeight: '19px',
    };

    return merge(styles, this.props.style || {});
  }

  render() {
    if (this.props.value) {
      return (

          {this.props.value.toString()}

      );
    }

    if (this.props.element) {
      const element = this.props.element;
      let value;

      if (isObjectOrArray(element.element)) {
        return false;
      } else if (isMember(element.element)) {
        if (isObjectOrArray(element.content.value.element)) {
          return false;
        } else if (element.content.value.content) {
          value = element.content.value.content;
        } else {
          return false;
        }
      } else if (element.content) {
        value = element.content;
      }

      if (!value) {
        return false;
      }

      return (

          {value.toString()}

      );
    }

    return null;
  }
}

export default Value;
<commit_msg>Change font size of the ‘Value’ component.<commit_after>import React from 'react';
import merge from 'lodash/merge';

import {
  isObjectOrArray,
  isMember,
} from '../elements/element';

class Value extends React.Component {
  static propTypes = {
    value: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number,
      React.PropTypes.bool,
    ]),
    element: React.PropTypes.object,
    style: React.PropTypes.object,
  };

  static contextTypes = {
    theme: React.PropTypes.object,
  };

  renderStyles() {
    const {
      VALUE_COLOR,
      VALUE_BACKGROUND_COLOR,
      VALUE_BORDER_RADIUS,
    } = this.context.theme;

    const styles = {
      float: 'left',
      width: 'auto',
      height: 'auto',
      margin: '0px',
      padding: '0px',
      fontWeight: '600',
      backgroundColor: VALUE_BACKGROUND_COLOR,
      borderRadius: VALUE_BORDER_RADIUS,
      paddingTop: '2px',
      paddingBottom: '2px',
      paddingLeft: '4px',
      paddingRight: '4px',
      fontFamily: 'Source Sans Pro',
      fontSize: '13px',
      color: VALUE_COLOR,
      lineHeight: '17px',
    };

    return merge(styles, this.props.style || {});
  }

  render() {
    if (this.props.value) {
      return (

          {this.props.value.toString()}

      );
    }

    if (this.props.element) {
      const element = this.props.element;
      let value;

      if (isObjectOrArray(element.element)) {
        return false;
      } else if (isMember(element.element)) {
        if (isObjectOrArray(element.content.value.element)) {
          return false;
        } else if (element.content.value.content) {
          value = element.content.value.content;
        } else {
          return false;
        }
      } else if (element.content) {
        value = element.content;
      }

      if (!value) {
        return false;
      }

      return (

          {value.toString()}

      );
    }

    return null;
  }
}

export default Value;
<|endoftext|>


<commit_before>'use strict';

/**
 * ### Route Graph Query Functions
 * These functions query the `rt_route_graph` table in the Right Track Database.
 * @module query/routegraph
 */

const cache = require('memory-cache');
const Stop = require('../gtfs/Stop.js');

// ==== QUERY FUNCTIONS ==== //

/**
 * Get the possible next stops from the Route Graph.
 *
 * This will return a list of all Stops that directly proceed the specified
 * Stop in the specified direction on at least 1 Trip in the GTFS schedule
 * (regardless of the day/time).
 *
 * @param {RightTrackDB} db The Right Track Database to query
 * @param {string} id Stop ID
 * @param {int} direction Direction ID
 * @param {function} callback Callback function
 * @param {Error} callback.error Database Query Error
 * @param {Stop[]} [callback.stops] List of possible next Stops
 *
 * @deprecated The rt_route_graph table is likely to be removed in the future
 */
function getNextStops(db, id, direction, callback) {

  // Check cache for stops
  let cacheKey = db.id + "-" + id + "-" + direction;
  let cache = cache_nextStops.get(cacheKey);
  if ( cache !== null ) {
    return callback(null, cache);
  }

  // Build Select Statement
  let select = "SELECT gtfs_stops.stop_id, gtfs_stops.stop_name, gtfs_stops.stop_lat, " +
    "gtfs_stops.stop_lon, gtfs_stops.stop_url, gtfs_stops.wheelchair_boarding, " +
    "rt_stops_extra.status_id, rt_stops_extra.display_name, rt_stops_extra.transfer_weight " +
    "FROM gtfs_stops, rt_stops_extra " +
    "WHERE gtfs_stops.stop_id=rt_stops_extra.stop_id AND " +
    "gtfs_stops.stop_id IN (" +
    "SELECT stop2_id FROM rt_route_graph " +
    "WHERE stop1_id='" + id + "' AND direction_id=" + direction + "" +
    ");";

  // Query the database
  db.select(select, function(err, results) {

    // Database Query Error
    if ( err ) {
      return callback(err);
    }

    // List of Stops to return
    let rtn = [];

    // Parse each returned stop...
    for ( let i = 0; i < results.length; i++ ) {
      let row = results[i];

      // Use rt display_name if provided
      let final_name = row.stop_name;
      if (row.display_name !== undefined && row.display_name !== "") {
        final_name = row.display_name;
      }

      // Set wheelchair boarding to unknown if status not in database
      let wheelchair_boarding = row.wheelchair_boarding;
      if (row.wheelchair_boarding === null) {
        wheelchair_boarding = Stop.WHEELCHAIR_BOARDING_UNKNOWN;
      }

      // build the Stop
      let stop = new Stop(
        row.stop_id,
        final_name,
        row.stop_lat,
        row.stop_lon,
        row.stop_url,
        wheelchair_boarding,
        row.status_id,
        row.transfer_weight
      );

      // Add stop to list
      rtn.push(stop);

    }

    // Return Stop(s)
    cache_nextStops.put(cacheKey, rtn);
    return callback(null, rtn);

  });

}

// ==== SETUP CACHES ==== //
let cache_nextStops = new cache.Cache();

/**
 * Clear the RouteGraphTable caches
 * @private
 */
function clearCache() {
  cache_nextStops.clear();
}

// Export Functions
module.exports = {
  getNextStops: getNextStops,
  clearCache: clearCache
};<commit_msg>BUG: RouteGraph - use new Stop constructor format<commit_after>'use strict';

/**
 * ### Route Graph Query Functions
 * These functions query the `rt_route_graph` table in the Right Track Database.
 * @module query/routegraph
 */

const cache = require('memory-cache');
const Stop = require('../gtfs/Stop.js');

// ==== QUERY FUNCTIONS ==== //

/**
 * Get the possible next stops from the Route Graph.
 *
 * This will return a list of all Stops that directly proceed the specified
 * Stop in the specified direction on at least 1 Trip in the GTFS schedule
 * (regardless of the day/time).
 *
 * @param {RightTrackDB} db The Right Track Database to query
 * @param {string} id Stop ID
 * @param {int} direction Direction ID
 * @param {function} callback Callback function
 * @param {Error} callback.error Database Query Error
 * @param {Stop[]} [callback.stops] List of possible next Stops
 *
 * @deprecated The rt_route_graph table is likely to be removed in the future
 */
function getNextStops(db, id, direction, callback) {

  // Check cache for stops
  let cacheKey = db.id + "-" + id + "-" + direction;
  let cache = cache_nextStops.get(cacheKey);
  if ( cache !== null ) {
    return callback(null, cache);
  }

  // Build Select Statement
  let select = "SELECT gtfs_stops.stop_id, gtfs_stops.stop_name, gtfs_stops.stop_lat, " +
    "gtfs_stops.stop_lon, gtfs_stops.stop_url, gtfs_stops.wheelchair_boarding, " +
    "rt_stops_extra.status_id, rt_stops_extra.display_name, rt_stops_extra.transfer_weight " +
    "FROM gtfs_stops, rt_stops_extra " +
    "WHERE gtfs_stops.stop_id=rt_stops_extra.stop_id AND " +
    "gtfs_stops.stop_id IN (" +
    "SELECT stop2_id FROM rt_route_graph " +
    "WHERE stop1_id='" + id + "' AND direction_id=" + direction + "" +
    ");";

  // Query the database
  db.select(select, function(err, results) {

    // Database Query Error
    if ( err ) {
      return callback(err);
    }

    // List of Stops to return
    let rtn = [];

    // Parse each returned stop...
    for ( let i = 0; i < results.length; i++ ) {
      let row = results[i];

      // Use rt display_name if provided
      let final_name = row.stop_name;
      if (row.display_name !== undefined && row.display_name !== "") {
        final_name = row.display_name;
      }

      // Set wheelchair boarding to unknown if status not in database
      let wheelchair_boarding = row.wheelchair_boarding;
      if (row.wheelchair_boarding === null) {
        wheelchair_boarding = Stop.WHEELCHAIR_BOARDING_UNKNOWN;
      }

      // build the Stop
      let stop = new Stop(
        row.stop_id,
        final_name,
        row.stop_lat,
        row.stop_lon,
        {
          url: row.stop_url,
          wheelchairBoarding: wheelchair_boarding,
          statusId: row.status_id,
          transferWeight: row.transfer_weight
        }
      );

      // Add stop to list
      rtn.push(stop);

    }

    // Return Stop(s)
    cache_nextStops.put(cacheKey, rtn);
    return callback(null, rtn);

  });

}

// ==== SETUP CACHES ==== //
let cache_nextStops = new cache.Cache();

/**
 * Clear the RouteGraphTable caches
 * @private
 */
function clearCache() {
  cache_nextStops.clear();
}

// Export Functions
module.exports = {
  getNextStops: getNextStops,
  clearCache: clearCache
};<|endoftext|>


<commit_before>'use strict';

const Promise = require('bluebird');
const pid = require('../src/util/pid');
const connection = require('../src/mongo/connection');

pid.start();

const source = require('../src/source/source');
const config = require('../src/config/config').globalConfig;

const sources = Object.keys(config.source);

if (sources.length === 0) {
    console.log('no source found in config');
}

Promise.coroutine(function* () {
    yield connection();
    for (const collection of sources) {
        const options = config.source[collection];
        try{
            yield source.copy(Object.assign({collection}, options));
        }catch(e){
            console.error(e);
        }
    }
})().then(function () {
    console.log('finished');
    return 0;
}, function (e) {
    console.error(e);
    return 1;
}).then(pid.stop);
<commit_msg>add trace by step<commit_after>'use strict';

const Promise = require('bluebird');
const pid = require('../src/util/pid');
const connection = require('../src/mongo/connection');
const debug = require('../src/util/debug')('bin:source');

pid.start();

const source = require('../src/source/source');
const config = require('../src/config/config').globalConfig;

const sources = Object.keys(config.source);

if (sources.length === 0) {
    console.log('no source found in config');
}

Promise.coroutine(function* () {
    yield connection();
    for (const collection of sources) {
        let start = new Date().getTime();
        debug(`Begin sourcing of ${collection}`);
        const options = config.source[collection];
        try{
            yield source.copy(Object.assign({collection}, options));
        }catch(e){
            console.error(e);
        }
        let end = new Date().getTime();
        let time = end - start;
        debug(`End sourcing of ${collection} in ${time}ms`);
    }
})().then(function () {
    console.log('finished');
    return 0;
}, function (e) {
    console.error(e);
    return 1;
}).then(pid.stop);
<|endoftext|>


<commit_before>var clip = function() {
  var nw = map.containerPointToLayerPoint([0, 0]),
      se = map.containerPointToLayerPoint(map.getSize()),
      clipX = nw.x + (se.x - nw.x) * range.value;
  cmp.getContainer().style.clip =
    'rect(' + [nw.y, clipX, se.y, nw.x].join('px,') + 'px)';
}

var main_loop = function() {
  gsimaps = 'http://maps.gsi.go.jp/?ll=' +
    LAT + ',' + LNG + '&z=16&base=std&cd=f2%2Ff2_6&vs=c1j0l0u0&d=l';
  attr = "地理院地図";
  ort = L.tileLayer(BG_URL, {
    attribution: attr, maxNativeZoom: 18, maxZoom: 20
  });
  cmp = L.tileLayer(FG_URL, {
    attribution: attr, maxNativeZoom: 18, maxZoom: 20
  });
  map = L.map('mapdiv', {
    center: [LAT, LNG], zoom: 16, minZoom: 10,
    layers: [ort, cmp], zoomControl: false});
  new L.Control.Zoom({ position: 'bottomright' }).addTo(map);
  var hash = L.hash(map);
  var range = document.getElementById('range');

  range['oninput' in range ? 'oninput' : 'onchange'] = clip;
  map.on('move', clip);
  clip();

  if(L.Browser.ie) {
    if(L.Browser.ielt9) {
      alert("被災前後比較はお使いのブラウザに対応していません。\nChrome, Firefox, Safari でアクセスしてください。\n地理院地図に移動します。");
      window.location = gsimaps;
    }
    alert("お使いのブラウザでは写真の境をスライダで調整できません。\nスライダが必要な場合、Chrome, Firefox, Safari でアクセスしてください。");
  }
}
<commit_msg>Update<commit_after>var clip = function() {
  var nw = map.containerPointToLayerPoint([0, 0]),
      se = map.containerPointToLayerPoint(map.getSize()),
      clipX = nw.x + (se.x - nw.x) * range.value;
  cmp.getContainer().style.clip =
    'rect(' + [nw.y, clipX, se.y, nw.x].join('px,') + 'px)';
}

var main_loop = function() {
  gsimaps = 'http://maps.gsi.go.jp/?ll=' +
    LAT + ',' + LNG + '&z=16&base=std&cd=f2%2Ff2_6&vs=c1j0l0u0&d=l';
  attr = "地理院地図";
  ort = L.tileLayer(BG_URL, {
    attribution: attr, maxNativeZoom: 18, maxZoom: 20
  });
  cmp = L.tileLayer(FG_URL, {
    attribution: attr, maxNativeZoom: 18, maxZoom: 20
  });
  map = L.map('mapdiv', {
    center: [LAT, LNG], zoom: 16, minZoom: 10,
    layers: [ort, cmp], zoomControl: false});
  new L.Control.Zoom({ position: 'bottomright' }).addTo(map);
  var hash = L.hash(map);
  var range = document.getElementById('range');

  range['oninput' in range ? 'oninput' : 'onchange'] = clip;
  map.on('move', clip);
  clip();

  if(L.Browser.ie) {
    if(L.Browser.ielt9) {
      alert("被災前後比較はお使いのブラウザに対応していません。\nChrome, Firefox, Safari でアクセスしてください。\n地理院地図に移動します。");
    } else {
      alert("お使いのブラウザでは写真の境をスライダで調整できません。\nスライダが必要な場合、Chrome, Firefox, Safari でアクセスしてください。");
    }
    if(L.Browser.ielt9) document.location.href = gsimaps;
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

const { format, supportedDialects } = require('../lib/sqlFormatter');
const fs = require('fs');
const { version } = require('../package.json');
const { ArgumentParser } = require('argparse');

function getParser() {
	const parser = new ArgumentParser({
		add_help: true,
		description: 'SQL Formatter',
	});

	parser.add_argument('file', {
		metavar: 'FILE',
		nargs: '?',
		help: 'Input SQL file (defaults to stdin)',
	});

	parser.add_argument('-o', '--output', {
		help: 'File to write SQL output (defaults to stdout)',
	});

	parser.add_argument('-l', '--language', {
		help: 'SQL Formatter dialect (defaults to basic sql)',
		choices: supportedDialects,
		default: 'sql',
	});

	parser.add_argument('-c', '--config', {
		help: 'Path to config json file (will use default configs if unspecified)',
	});

	parser.add_argument('--version', {
		action: 'version',
		version,
	});

	return parser;
}

function readConfig(parser, args) {
	if (Object.entries(args).every(([k, v]) => k === 'language' || v === undefined)) {
		parser.print_help();
		process.exit(0);
	}

	if (args.config)
		try {
			const configFile = fs.readFileSync(args.config);
			const configJson = JSON.parse(configFile);
			return { language: args.language, ...configJson };
		} catch (e) {
			if (e instanceof SyntaxError) {
				console.error(`Error: unable to parse JSON at file ${args.config}`);
				process.exit(1);
			}
			if (e.code === 'ENOENT') {
				console.error(`Error: could not open file ${args.config}`);
				process.exit(1);
			}
			throw e;
		}
	return {
		language: args.language,
	};
}

function getInput(file) {
	const infile = file || process.stdin.fd;
	try {
		return fs.readFileSync(infile, 'utf-8');
	} catch (e) {
		if (e.code === 'EAGAIN') {
			console.error('Error: no file specified and no data in stdin');
			process.exit(1);
		}
		if (e.code === 'ENOENT') {
			console.error(`Error: could not open file ${infile}`);
			process.exit(1);
		}
		throw e;
	}
}

function writeOutput(file, query) {
	if (!file) {
		// No output file, write to console
		console.log(query);
	} else {
		fs.writeFileSync(file, query);
	}
}

const parser = getParser();
const args = parser.parse_args();
const cfg = readConfig(parser, args);
const query = getInput(args.file);
const formattedQuery = format(query, cfg).trim() + '\n';
writeOutput(args.output, formattedQuery);
<commit_msg>convert cli tool to cladd<commit_after>#!/usr/bin/env node

'use strict';

const { format, supportedDialects } = require('../lib/sqlFormatter');
const fs = require('fs');
const { version } = require('../package.json');
const { ArgumentParser } = require('argparse');

class PrettierSQLArgs {
	constructor() {
		this.parser = this.getParser();
		this.args = this.parser.parse_args();
		this.cfg = this.readConfig();

		this.query = this.getInput();
		const formattedQuery = format(this.query, this.cfg).trim() + '\n';
		this.writeOutput(this.args.output, formattedQuery);
	}

	getParser() {
		const parser = new ArgumentParser({
			add_help: true,
			description: 'SQL Formatter',
		});

		parser.add_argument('file', {
			metavar: 'FILE',
			nargs: '?',
			help: 'Input SQL file (defaults to stdin)',
		});

		parser.add_argument('-o', '--output', {
			help: 'File to write SQL output (defaults to stdout)',
		});

		parser.add_argument('-l', '--language', {
			help: 'SQL Formatter dialect (defaults to basic sql)',
			choices: supportedDialects,
			default: 'sql',
		});

		parser.add_argument('-c', '--config', {
			help: 'Path to config json file (will use default configs if unspecified)',
		});

		parser.add_argument('--version', {
			action: 'version',
			version,
		});

		return parser;
	}

	readConfig() {
		if (Object.entries(this.args).every(([k, v]) => k === 'language' || v === undefined)) {
			this.parser.print_help();
			process.exit(0);
		}

		if (this.args.config)
			try {
				const configFile = fs.readFileSync(this.args.config);
				const configJson = JSON.parse(configFile);
				return { language: this.args.language, ...configJson };
			} catch (e) {
				if (e instanceof SyntaxError) {
					console.error(`Error: unable to parse JSON at file ${this.args.config}`);
					process.exit(1);
				}
				if (e.code === 'ENOENT') {
					console.error(`Error: could not open file ${this.args.config}`);
					process.exit(1);
				}
				throw e;
			}
		return {
			language: this.args.language,
		};
	}

	getInput() {
		const infile = this.args.file || process.stdin.fd;
		try {
			return fs.readFileSync(infile, 'utf-8');
		} catch (e) {
			if (e.code === 'EAGAIN') {
				console.error('Error: no file specified and no data in stdin');
				process.exit(1);
			}
			if (e.code === 'ENOENT') {
				console.error(`Error: could not open file ${infile}`);
				process.exit(1);
			}
			throw e;
		}
	}

	writeOutput(file, query) {
		if (!file) {
			// No output file, write to console
			console.log(query);
		} else {
			fs.writeFileSync(file, query);
		}
	}
}

new PrettierSQLArgs();
<|endoftext|>