<commit_before>
import { Stream } from '../../fn/module.js';
import Event from './event.js';
import features from './features.js';

const assign  = Object.assign;
const rspaces = /\s+/;

function prefixType(type) {
	return features.events[type] || type ;
}

/* Handle event types */

var clickTimeStamp = 0;

function listen(source, type) {
    // DOM click events may be simulated on inputs when their labels are
    // clicked. The tell-tale is they have the same timeStamp. Ignore
    // simulated clicks with the same timeStamp as previous clicks.
    if (type === 'click') {
        source.clickUpdate = function click(e) {
            if (e.timeStamp <= clickTimeStamp) { return; }
            clickTimeStamp = e.timeStamp;
            source.update(e);
        };

        source.node.addEventListener(type, source.clickUpdate, source.options);
        return source;
    }

    source.node.addEventListener(type, source.update, source.options);
    return source;
}

function unlisten(source, type) {
    source.node.removeEventListener(type, type === 'click' ?
        source.clickUpdate :
        source.update
    );

    return source;
}

window.addEventListener('click', function(e) {
    clickTimeStamp = e.timeStamp;
});

/* Stream of events */

function Source(notify, stop, type, options, node) {
	const types  = type.split(rspaces).map(prefixType);
	const buffer = [];

	function update(value) {
		buffer.push(value);
		notify('push');
	}

	this._stop    = stop;
	this.types   = types;
	this.node    = node;
	this.buffer  = buffer;
	this.update  = update;
	this.options = options;

	// Potential hard-to-find error here if type has repeats, ie 'click click'.
	// Lets assume nobody is dumb enough to do this, I dont want to have to
	// check for that every time.
	types.reduce(listen, this);
}

assign(Source.prototype, {
	shift: function shiftEvent() {
		const buffer = this.buffer;
		return buffer.shift();
	},

	stop: function stopEvent() {
console.log('STOP');
		types.reduce(unlisten, this);
		this._stop(buffer.length);
	}
});

export default function events(type, node) {
	let options;

	if (typeof type === 'object') {
		options = type;
		type    = options.type;
	}

	return new Stream(function setup(notify, stop) {
		return new Source(notify, stop, type, options, node);
	});
}

// -----------------

export function isPrimaryButton(e) {
	// Ignore mousedowns on any button other than the left (or primary)
	// mouse button, or when a modifier key is pressed.
	return (e.which === 1 && !e.ctrlKey && !e.altKey && !e.shiftKey);
}

export function preventDefault(e) {
	e.preventDefault();
}

export function isTargetEvent(e) {
	return e.target === e.currentTarget;
}

// -----------------

const A = Array.prototype;
const eventsSymbol = Symbol('events');

function bindTail(fn) {
	// Takes arguments 1 and up and appends them to arguments
	// passed to fn.
	var args = A.slice.call(arguments, 1);
	return function() {
		A.push.apply(arguments, args);
		fn.apply(null, arguments);
	};
}

export function on(node, type, fn, data) {
	var options;

	if (typeof type === 'object') {
		options = type;
		type    = options.type;
	}

	var types   = type.split(rspaces);
	var events  = node[eventsSymbol] || (node[eventsSymbol] = {});
	var handler = data ? bindTail(fn, data) : fn ;
	var handlers;

	var n = -1;
	while (++n < types.length) {
		type = types[n];
		handlers = events[type] || (events[type] = []);
		handlers.push([fn, handler]);
		node.addEventListener(type, handler, options);
	}

	return node;
}

export function once(node, types, fn, data) {
	on(node, types, function once() {
		off(node, types, once);
		fn.apply(null, arguments);
	}, data);
}

export function off(node, type, fn) {
	var options;

	if (typeof type === 'object') {
		options = type;
		type    = options.type;
	}

	var types   = type.split(rspaces);
	var events  = node[eventsSymbol];
	var handlers, i;

	if (!events) { return node; }

	var n = -1;
	while (n++ < types.length) {
		type = types[n];
		handlers = events[type];
		if (!handlers) { continue; }
		i = handlers.length;
		while (i--) {
			if (handlers[i][0] === fn) {
				node.removeEventListener(type, handlers[i][1]);
				handlers.splice(i, 1);
			}
		}
	}

	return node;
}

export function trigger(node, type, properties) {
	// Don't cache events. It prevents you from triggering an event of a
	// given type from inside the handler of another event of that type.
	var event = Event(type, properties);
	node.dispatchEvent(event);
}
<commit_msg>Stoip<commit_after>
import { Stream } from '../../fn/module.js';
import Event from './event.js';
import features from './features.js';

const assign  = Object.assign;
const rspaces = /\s+/;

function prefixType(type) {
	return features.events[type] || type ;
}

/* Handle event types */

var clickTimeStamp = 0;

function listen(source, type) {
    // DOM click events may be simulated on inputs when their labels are
    // clicked. The tell-tale is they have the same timeStamp. Ignore
    // simulated clicks with the same timeStamp as previous clicks.
    if (type === 'click') {
        source.clickUpdate = function click(e) {
            if (e.timeStamp <= clickTimeStamp) { return; }
            clickTimeStamp = e.timeStamp;
            source.update(e);
        };

        source.node.addEventListener(type, source.clickUpdate, source.options);
        return source;
    }

    source.node.addEventListener(type, source.update, source.options);
    return source;
}

function unlisten(source, type) {
    source.node.removeEventListener(type, type === 'click' ?
        source.clickUpdate :
        source.update
    );

    return source;
}

window.addEventListener('click', function(e) {
    clickTimeStamp = e.timeStamp;
});

/* Stream of events */

function Source(notify, stop, type, options, node) {
	const types  = type.split(rspaces).map(prefixType);
	const buffer = [];

	function update(value) {
		buffer.push(value);
		notify('push');
	}

	this._stop    = stop;
	this.types   = types;
	this.node    = node;
	this.buffer  = buffer;
	this.update  = update;
	this.options = options;

	// Potential hard-to-find error here if type has repeats, ie 'click click'.
	// Lets assume nobody is dumb enough to do this, I dont want to have to
	// check for that every time.
	types.reduce(listen, this);
}

assign(Source.prototype, {
	shift: function shiftEvent() {
		const buffer = this.buffer;
		return buffer.shift();
	},

	stop: function stopEvent() {
console.log('STOP');
		this.types.reduce(unlisten, this);
		this._stop(buffer.length);
	}
});

export default function events(type, node) {
	let options;

	if (typeof type === 'object') {
		options = type;
		type    = options.type;
	}

	return new Stream(function setup(notify, stop) {
		return new Source(notify, stop, type, options, node);
	});
}

// -----------------

export function isPrimaryButton(e) {
	// Ignore mousedowns on any button other than the left (or primary)
	// mouse button, or when a modifier key is pressed.
	return (e.which === 1 && !e.ctrlKey && !e.altKey && !e.shiftKey);
}

export function preventDefault(e) {
	e.preventDefault();
}

export function isTargetEvent(e) {
	return e.target === e.currentTarget;
}

// -----------------

const A = Array.prototype;
const eventsSymbol = Symbol('events');

function bindTail(fn) {
	// Takes arguments 1 and up and appends them to arguments
	// passed to fn.
	var args = A.slice.call(arguments, 1);
	return function() {
		A.push.apply(arguments, args);
		fn.apply(null, arguments);
	};
}

export function on(node, type, fn, data) {
	var options;

	if (typeof type === 'object') {
		options = type;
		type    = options.type;
	}

	var types   = type.split(rspaces);
	var events  = node[eventsSymbol] || (node[eventsSymbol] = {});
	var handler = data ? bindTail(fn, data) : fn ;
	var handlers;

	var n = -1;
	while (++n < types.length) {
		type = types[n];
		handlers = events[type] || (events[type] = []);
		handlers.push([fn, handler]);
		node.addEventListener(type, handler, options);
	}

	return node;
}

export function once(node, types, fn, data) {
	on(node, types, function once() {
		off(node, types, once);
		fn.apply(null, arguments);
	}, data);
}

export function off(node, type, fn) {
	var options;

	if (typeof type === 'object') {
		options = type;
		type    = options.type;
	}

	var types   = type.split(rspaces);
	var events  = node[eventsSymbol];
	var handlers, i;

	if (!events) { return node; }

	var n = -1;
	while (n++ < types.length) {
		type = types[n];
		handlers = events[type];
		if (!handlers) { continue; }
		i = handlers.length;
		while (i--) {
			if (handlers[i][0] === fn) {
				node.removeEventListener(type, handlers[i][1]);
				handlers.splice(i, 1);
			}
		}
	}

	return node;
}

export function trigger(node, type, properties) {
	// Don't cache events. It prevents you from triggering an event of a
	// given type from inside the handler of another event of that type.
	var event = Event(type, properties);
	node.dispatchEvent(event);
}
<|endoftext|>


<commit_before>const execFile = require('child_process').execFile;
const colors = require('colors');
const request = require('request');
const portscanner = require('portscanner');

module.exports = function () {
    var self = this;

    /**
     * --- INTERNAL ---
     */

    this.statuses = {

        "logon": {
            "status": false,
            "last_updated": null,
            "timer": 60,
            "interval": false,
            "memory": []
        },
        "website": {
            "status": false,
            "last_updated": null,
            "timer": 60,
            "interval": false,
            "memory": []
        },
        "elysium_pvp": {
            "status": false,
            "last_updated": null,
            "interval": false,
            "memory": []
        },
        "nostalrius_pvp": {
            "status": false,
            "last_updated": null,
            "interval": false,
            "memory": []
        },
        "nostalrius_pve": {
            "status": false,
            "last_updated": null,
            "interval": false,
            "memory": []
        }

    };

    this.memory = {};

    this.memory.addMemory = function (name, status) {
        var stat = self.statuses[name];

        stat.memory.push(status);
        if (stat.memory.length > 20) stat.memory.splice(0, 1);

        //end Keeper.memory.addMemory
    }

    this.memory.isMemoryBad = function (name) {

        var stat = self.statuses[name];
        var foundFalse = false;

        for (var i = 0; i < stat.memory.length; i++) {
            var memPiece = stat.memory[i];
            if (memPiece === false) {
                foundFalse = true;
                break;
            }
        }

        if (foundFalse) return true;
        return false;

        //end
    }

    this.processes = {};

    this.processes['logon'] = function () {

        //LOGON
        portscanner.checkPortStatus(3724, 'logon.elysium-project.org', function (error, status) {

            if (status === 'open') {
                self.memory.addMemory('logon', true);
                self.statuses.logon.status = (self.memory.isMemoryBad('logon') ? 'unstable' : true);
                self.statuses.logon.last_updated = new Date();
                console.log(new Date().toString() + ' - Logon ' + colors.green('UP'));
                return;
            }

            //status was not open..
            self.memory.addMemory('logon', false);
            self.statuses.logon.status = false;
            self.statuses.logon.last_updated = new Date();
            console.log(new Date().toString() + ' - Logon ' + colors.red('DOWN'));
            return;

        });

        //end Keeper.processes['logon']
    }

    this.processes['website'] = function () {

        request.get('https://elysium-project.org/status', {

            timeout: (10 * 1000)

        }, function (err, response, body) {

            if (err != null || response.statusCode != 200) {
                self.statuses.website.status = false;
                self.statuses.website.last_updated = new Date();
                console.log(new Date().toString() + ' - Website ' + colors.red('DOWN'));

                //MARK REALMS AS UNKNOWN
                self.statuses['elysium_pvp'].status = 'unknown';
                self.statuses['nostalrius_pvp'].status = 'unknown';
                self.statuses['nostalrius_pve'].status = 'unknown';

                self.statuses['elysium_pvp'].last_updated = new Date();
                self.statuses['nostalrius_pvp'].last_updated = new Date();
                self.statuses['nostalrius_pve'].last_updated = new Date();

                return;
            }

            self.statuses.website.status = true;
            self.statuses.website.last_updated = new Date();
            console.log(new Date().toString() + ' - Website ' + colors.green('UP'));

            self.processes['servers'](body);

        });

        //end Keeper.processes['logon']
    }

    this.processes['servers'] = function (body) {

        function getRealmStatus(realm) {
            var realmRes = (body.split('
\n' +
                realm)[1].split('
')[0]).toLowerCase().indexOf('online') != -1;
            return realmRes;

            //end getRealmStatus
        }

        self.statuses['elysium_pvp'].status = getRealmStatus('Elysium PvP');
        self.statuses['nostalrius_pvp'].status = getRealmStatus('Nostalrius PvP');
        self.statuses['nostalrius_pve'].status = getRealmStatus('Nostalrius PvE');

        self.statuses['elysium_pvp'].last_updated = new Date();
        self.statuses['nostalrius_pvp'].last_updated = new Date();
        self.statuses['nostalrius_pve'].last_updated = new Date();

        //end Keeper.processes['servers']
    }

    this.process = function () {

        self.statuses['logon'].interval = setInterval(self.processes['logon'], (self.statuses['logon'].timer * 1000));
        self.statuses['website'].interval = setInterval(self.processes['website'], (self.statuses['website'].timer * 1000));

        self.processes['logon']();
        self.processes['website']();

        //end process
    }

    /**
     * --- PUBLIC ---
     */

    this.get = function () {

        var outStatuses = {};

        for (var server in self.statuses) {
            var srv = self.statuses[server];

            outStatuses[server] = {
                'status': srv.status,
                'last_updated': srv['last_updated']
            };

        }

        return {
            time: new Date(),
            statuses: outStatuses
        };

        //end Keeper.get
    }

    //end Keeper
}<commit_msg>Memory limit set to 10<commit_after>const execFile = require('child_process').execFile;
const colors = require('colors');
const request = require('request');
const portscanner = require('portscanner');

module.exports = function () {
    var self = this;

    /**
     * --- INTERNAL ---
     */

    this.statuses = {

        "logon": {
            "status": false,
            "last_updated": null,
            "timer": 60,
            "interval": false,
            "memory": []
        },
        "website": {
            "status": false,
            "last_updated": null,
            "timer": 60,
            "interval": false,
            "memory": []
        },
        "elysium_pvp": {
            "status": false,
            "last_updated": null,
            "interval": false,
            "memory": []
        },
        "nostalrius_pvp": {
            "status": false,
            "last_updated": null,
            "interval": false,
            "memory": []
        },
        "nostalrius_pve": {
            "status": false,
            "last_updated": null,
            "interval": false,
            "memory": []
        }

    };

    this.memory = {};

    this.memory.addMemory = function (name, status) {
        var stat = self.statuses[name];

        stat.memory.push(status);
        if (stat.memory.length > 10) stat.memory.splice(0, 1);

        //end Keeper.memory.addMemory
    }

    this.memory.isMemoryBad = function (name) {

        var stat = self.statuses[name];
        var foundFalse = false;

        for (var i = 0; i < stat.memory.length; i++) {
            var memPiece = stat.memory[i];
            if (memPiece === false) {
                foundFalse = true;
                break;
            }
        }

        if (foundFalse) return true;
        return false;

        //end
    }

    this.processes = {};

    this.processes['logon'] = function () {

        //LOGON
        portscanner.checkPortStatus(3724, 'logon.elysium-project.org', function (error, status) {

            if (status === 'open') {
                self.memory.addMemory('logon', true);
                self.statuses.logon.status = (self.memory.isMemoryBad('logon') ? 'unstable' : true);
                self.statuses.logon.last_updated = new Date();
                console.log(new Date().toString() + ' - Logon ' + colors.green('UP'));
                return;
            }

            //status was not open..
            self.memory.addMemory('logon', false);
            self.statuses.logon.status = false;
            self.statuses.logon.last_updated = new Date();
            console.log(new Date().toString() + ' - Logon ' + colors.red('DOWN'));
            return;

        });

        //end Keeper.processes['logon']
    }

    this.processes['website'] = function () {

        request.get('https://elysium-project.org/status', {

            timeout: (10 * 1000)

        }, function (err, response, body) {

            if (err != null || response.statusCode != 200) {
                self.statuses.website.status = false;
                self.statuses.website.last_updated = new Date();
                console.log(new Date().toString() + ' - Website ' + colors.red('DOWN'));

                //MARK REALMS AS UNKNOWN
                self.statuses['elysium_pvp'].status = 'unknown';
                self.statuses['nostalrius_pvp'].status = 'unknown';
                self.statuses['nostalrius_pve'].status = 'unknown';

                self.statuses['elysium_pvp'].last_updated = new Date();
                self.statuses['nostalrius_pvp'].last_updated = new Date();
                self.statuses['nostalrius_pve'].last_updated = new Date();

                return;
            }

            self.statuses.website.status = true;
            self.statuses.website.last_updated = new Date();
            console.log(new Date().toString() + ' - Website ' + colors.green('UP'));

            self.processes['servers'](body);

        });

        //end Keeper.processes['logon']
    }

    this.processes['servers'] = function (body) {

        function getRealmStatus(realm) {
            var realmRes = (body.split('
\n' +
                realm)[1].split('
')[0]).toLowerCase().indexOf('online') != -1;
            return realmRes;

            //end getRealmStatus
        }

        self.statuses['elysium_pvp'].status = getRealmStatus('Elysium PvP');
        self.statuses['nostalrius_pvp'].status = getRealmStatus('Nostalrius PvP');
        self.statuses['nostalrius_pve'].status = getRealmStatus('Nostalrius PvE');

        self.statuses['elysium_pvp'].last_updated = new Date();
        self.statuses['nostalrius_pvp'].last_updated = new Date();
        self.statuses['nostalrius_pve'].last_updated = new Date();

        //end Keeper.processes['servers']
    }

    this.process = function () {

        self.statuses['logon'].interval = setInterval(self.processes['logon'], (self.statuses['logon'].timer * 1000));
        self.statuses['website'].interval = setInterval(self.processes['website'], (self.statuses['website'].timer * 1000));

        self.processes['logon']();
        self.processes['website']();

        //end process
    }

    /**
     * --- PUBLIC ---
     */

    this.get = function () {

        var outStatuses = {};

        for (var server in self.statuses) {
            var srv = self.statuses[server];

            outStatuses[server] = {
                'status': srv.status,
                'last_updated': srv['last_updated']
            };

        }

        return {
            time: new Date(),
            statuses: outStatuses
        };

        //end Keeper.get
    }

    //end Keeper
}<|endoftext|>


<commit_before>// Construstor
var Parser = function() {
  this.init()
}

/**
 * Init parser. One time call
 */
Parser.prototype.init = function() {

}

/**
 * Before parse callback
 */
Parser.prototype.beforeParse = function () {}

/**
 * After parse callback
 * @param {Object} data
 */
Parser.prototype.afterParse = function (data) {}

/**
 * When error happens execute this callback
 * @param {String} message
 */
Parser.prototype.onError = function (message) {}

/**
 * Parser starting point
 * @param  {String} repository_uri - username:reponame
 */
Parser.prototype.parse = function(repository_uri) {
  var that = this

  this.beforeParse()
  var github = this.auth()
  var repository_uri_splitted = repository_uri.split("/")
  var username = repository_uri_splitted[0]
  var reponame = repository_uri_splitted[1]

  var repo = github.getRepo(username, reponame);
  var final_repo_info = {}
  repo.show(function(err, repo) {
    final_repo_info.name = repo.name
    final_repo_info.created_at = formatDate(new Date(repo.created_at))
    final_repo_info.url = repo.url
  })

  // Send afterParse after 500 ms
  setTimeout(function(){
    // Once in a while fake an error
    if (Math.random() > 0.9) {
      that.onError()
    } else {
      that.afterParse({
        name: 'Repository Title',
        created_at: '2011-01-26',
        url: 'https://github.com/TUM-FAF/FAFSite',
        labels: [
          {
            url: 'https://github.com/TUM-FAF/FAFSite/labels/suggestion',
            name: 'Suggestion',
            color: '#FFDC00'
          },
          {
            url: 'https://github.com/TUM-FAF/FAFSite/labels/front-end',
            name: 'Front-end',
            color: '#02e10c'
          }
        ],
        issues: [
          {
            number: 40,
            url: 'https://github.com/TUM-FAF/FAFSite/issues/40',
            title: 'Create a site monitor',
            state: 'open',
            open: [
              {
                from: '2011-01-27',
                to: '2011-01-29'
              },
              {
                from: '2011-02-04',
                to: '2011-03-24'
              },
              {
                from: '2012-03-12',
                to: null
              }
            ],
            labels: [
              {
                url: 'https://github.com/TUM-FAF/FAFSite/labels/suggestion',
                name: 'Suggestion',
                color: '#FFDC00',
                assigned: [
                  {
                    from: '2011-01-27',
                    to: null
                  }
                ]
              },{
                url: 'https://github.com/TUM-FAF/FAFSite/labels/front-end',
                name: 'Front-end',
                color: '#02e10c',
                assigned: [
                  {
                    from: '2011-02-04',
                    to: '2012-03-12'
                  },{
                    from: '2014-02-02',
                    to: null
                  }
                ]
              }
            ]
          },{
            number: 39,
            url: 'https://github.com/TUM-FAF/FAFSite/issues/39',
            title: 'Deploy site to new host',
            state: 'open',
            open: [
              {
                from: '2012-02-12',
                to: null
              }
            ]
          },{
            number: 28,
            url: 'https://github.com/TUM-FAF/FAFSite/issues/28',
            title: 'jQuery update',
            state: 'closed',
            open: [
              {
                from: '2013-07-20',
                to: '2014-02-04'
              }
            ]
          }
        ]
      })
    }
  }, 500)
}

/**
 * Github authentication
 * @return {Object}
 */
Parser.prototype.auth = function() {
  var github = new Github({
    // insert here github token
    // can't be set as env vars, because it's client-side javascript
    // therefore hardcode all the tokens!
    token: ""
    , auth: "oauth"
  })
  return github
}

/**
 * Return a string representation of the date in format year-date-month
 * @param  {Date} date_obj
 * @return {String}
 */
function formatDate(date_obj) {
  var date = date_obj.getDate()
  var month = date_obj.getMonth()
  var year = date_obj.getFullYear()
  return year + "-" + date + "-" + month
}

/**
 * Helper function to debug prints
 * @param  {Object} value
 */
function c(value) {
  console.log(value)
}
<commit_msg>get all labels of a repo<commit_after>// Construstor
var Parser = function() {
  this.init()
}

/**
 * Init parser. One time call
 */
Parser.prototype.init = function() {

}

/**
 * Before parse callback
 */
Parser.prototype.beforeParse = function () {}

/**
 * After parse callback
 * @param {Object} data
 */
Parser.prototype.afterParse = function (data) {}

/**
 * When error happens execute this callback
 * @param {String} message
 */
Parser.prototype.onError = function (message) {}

/**
 * Parser starting point
 * @param  {String} repository_uri - username:reponame
 */
Parser.prototype.parse = function(repository_uri) {
  var that = this

  this.beforeParse()
  var github = this.auth()
  var repository_uri_splitted = repository_uri.split("/")
  var username = repository_uri_splitted[0]
  var reponame = repository_uri_splitted[1]

  var repo = github.getRepo(username, reponame);
  var final_repo_info = {}
  repo.show(function(err, repo) {
    final_repo_info.name = repo.name
    final_repo_info.created_at = formatDate(new Date(repo.created_at))
    final_repo_info.url = repo.url
  })

  var issues = github.getIssues(username, reponame)
  issues.list({}, function(err, issues) {
    final_repo_info.labels = that.get_labels(issues)
  })

  // Send afterParse after 500 ms
  setTimeout(function(){
    // Once in a while fake an error
    if (Math.random() > 0.9) {
      that.onError()
    } else {
      that.afterParse({
        name: 'Repository Title',
        created_at: '2011-01-26',
        url: 'https://github.com/TUM-FAF/FAFSite',
        labels: [
          {
            url: 'https://github.com/TUM-FAF/FAFSite/labels/suggestion',
            name: 'Suggestion',
            color: '#FFDC00'
          },
          {
            url: 'https://github.com/TUM-FAF/FAFSite/labels/front-end',
            name: 'Front-end',
            color: '#02e10c'
          }
        ],
        issues: [
          {
            number: 40,
            url: 'https://github.com/TUM-FAF/FAFSite/issues/40',
            title: 'Create a site monitor',
            state: 'open',
            open: [
              {
                from: '2011-01-27',
                to: '2011-01-29'
              },
              {
                from: '2011-02-04',
                to: '2011-03-24'
              },
              {
                from: '2012-03-12',
                to: null
              }
            ],
            labels: [
              {
                url: 'https://github.com/TUM-FAF/FAFSite/labels/suggestion',
                name: 'Suggestion',
                color: '#FFDC00',
                assigned: [
                  {
                    from: '2011-01-27',
                    to: null
                  }
                ]
              },{
                url: 'https://github.com/TUM-FAF/FAFSite/labels/front-end',
                name: 'Front-end',
                color: '#02e10c',
                assigned: [
                  {
                    from: '2011-02-04',
                    to: '2012-03-12'
                  },{
                    from: '2014-02-02',
                    to: null
                  }
                ]
              }
            ]
          },{
            number: 39,
            url: 'https://github.com/TUM-FAF/FAFSite/issues/39',
            title: 'Deploy site to new host',
            state: 'open',
            open: [
              {
                from: '2012-02-12',
                to: null
              }
            ]
          },{
            number: 28,
            url: 'https://github.com/TUM-FAF/FAFSite/issues/28',
            title: 'jQuery update',
            state: 'closed',
            open: [
              {
                from: '2013-07-20',
                to: '2014-02-04'
              }
            ]
          }
        ]
      })
    }
  }, 500)
}

/**
 * Github authentication
 * @return {Object}
 */
Parser.prototype.auth = function() {
  var github = new Github({
    // insert here github token
    // can't be set as env vars, because it's client-side javascript
    // therefore hardcode all the tokens!
    token: ""
    , auth: "oauth"
  })
  return github
}

/**
 * Get all issues' labels from a repo
 * @param  {Object} issues
 * @return {Array}
 */
Parser.prototype.get_labels = function(issues) {
  var labels = []
  for (var i = 0; i < issues.length; i++) {
    var issue_labels = issues[i].labels
    for (var j = 0; j < issue_labels.length; j++) {
      if (!inArrayByName(labels, issue_labels[j].name))
        labels.push(issue_labels[j])
    }
  }
  return labels
}

/**
 * Check if a value is in an array of objects with property "name"
 * @param  {Array} list
 * @param  {String} name
 * @return {Boolean}
 */
function inArrayByName(list, value) {
  for (var i = 0; i < list.length; i++) {
    if (list[i].name === value)
      return true
  }
  return false
}

/**
 * Return a string representation of the date in format year-date-month
 * @param  {Date} date_obj
 * @return {String}
 */
function formatDate(date_obj) {
  var date = date_obj.getDate()
  var month = date_obj.getMonth()
  var year = date_obj.getFullYear()
  return year + "-" + date + "-" + month
}

/**
 * Helper function to debug prints
 * @param  {Object} value
 */
function c(value) {
  console.log(value)
}
<|endoftext|>


<commit_before>/**
 * Some random quotes
 */

/* jslint node: true */
/* global BOT_DIR, LIBS_DIR, MODULES_DIR */
'use strict';

var quotes = [
	"I could clear the sky in 10 seconds flat!",
	"Are you a SPY?",
	"All the ponies in this town are CRAZY!",
	"Scarf? Check. Saddle? Check. Boots? Check. 'Spike refusing to get up and go back to sleep'? Check. It's a good thing I'm so organized. I'm ready!",
	"You've got a real problem all right, and a banjo is the only answer!",
	"You look like you'd be good at eating cupcakes!",
	"Well, well, well. It seems we have some 'neigh-sayers' in the audience.",
	"Beware! Beware you pony folk! Those leaves of blue are not a joke!",
	"I love fun things!",
	"*(squeak)*",
	"Whining? I am not \"whining\". I am complaining. Do you want to hear \"whining\"? *(whines obnoxiously)* This is whining! Ooohhhh! This harness is too tight! It's going to chafe! Can't you loosen it?! OH! It hurts and it's so rusty! Why didn't you clean it first?! It's gonna leave a stain, and the wagon's getting heavy! Why do I have to pull it?!",
	"FOREVER!!!",
	"It's no use. No matter what we try we always end up without our cutie marks; and surprisingly often covered in tree sap.",
	"I'm just glad I haven't been replaced by a bucket of turnips.",
	"Secrets and lies! It's all secrets and lies with those ponies!",
	"*(angrily)* You're... GOING TO LOVE ME!!!",
	"What fun is there in making sense?",
	"Hold on a second! Eternal chaos comes with chocolate rain, guys! Chocolate rain!",
	"Get back! All of you! This is my book. And I'm going to READ IT!",
	"I never thought it would happen. My friends... have turned into complete JERKS!",
	"Out of all things that could happen, this is THE WORST. POSSIBLE. THING.",
	"I really like her... mane?",
	"Too old for free candy?! NEVER!",
	"I'm going to do what I do best: lecture her!",
	"Ha, ha! The fun has been doubled!",
	"I never leave home without my party cannon!",
	"I'm not giving him cake! I'm ASSAULTING him with cake!",
	"Hold on to your hooves, I'm about to be BRILLIANT!",
	"I just don't know what went wrong!",
	"*(sadly)* I'm the monster.",
	"And that's how Equestria was made!",
	"It needs to be about 20% cooler.",
	"Forgive me if I withhold my enthusiasm!",
	"Oatmeal!? Are you crazy?",
	"The Great & Powerful Trixie doesn't trust wheels.",
	"You even look good when you're chewing! Who looks good when they're chewing?",
	"You ruined my horn!!"];

exports.init = function() {
	function q(source) {
		source.respond(quotes[Math.floor(Math.random() * quotes.length)]);
	}

	this.addCommand('quote', q).addCommand('quotes', q).addCommand('q', q);
	this.addAction('quote', q, /^(quotes|quote|q)$/i, []);
};<commit_msg>more quotes<commit_after>/**
 * Some random quotes
 */

/* jslint node: true */
/* global BOT_DIR, LIBS_DIR, MODULES_DIR */
'use strict';

var quotes = [
	"I could clear the sky in 10 seconds flat!",
	"Are you a SPY?",
	"All the ponies in this town are CRAZY!",
	"Scarf? Check. Saddle? Check. Boots? Check. 'Spike refusing to get up and go back to sleep'? Check. It's a good thing I'm so organized. I'm ready!",
	"You've got a real problem all right, and a banjo is the only answer!",
	"You look like you'd be good at eating cupcakes!",
	"Well, well, well. It seems we have some 'neigh-sayers' in the audience.",
	"Beware! Beware you pony folk! Those leaves of blue are not a joke!",
	"I love fun things!",
	"*squeak*",
	"Whining? I am not \"whining\". I am complaining. Do you want to hear \"whining\"? *(whines obnoxiously)* This is whining! Ooohhhh! This harness is too tight! It's going to chafe! Can't you loosen it?! OH! It hurts and it's so rusty! Why didn't you clean it first?! It's gonna leave a stain, and the wagon's getting heavy! Why do I have to pull it?!",
	"FOREVER!!!",
	"It's no use. No matter what we try we always end up without our cutie marks; and surprisingly often covered in tree sap.",
	"I'm just glad I haven't been replaced by a bucket of turnips.",
	"Secrets and lies! It's all secrets and lies with those ponies!",
	"*angrily* You're... GOING TO LOVE ME!!!",
	"What fun is there in making sense?",
	"Hold on a second! Eternal chaos comes with chocolate rain, guys! Chocolate rain!",
	"Get back! All of you! This is my book. And I'm going to READ IT!",
	"I never thought it would happen. My friends... have turned into complete JERKS!",
	"Out of all things that could happen, this is THE! WORST! POSSIBLE! THING!",
	"I really like her... mane?",
	"Too old for free candy?! NEVER!",
	"I'm going to do what I do best: lecture her!",
	"Ha, ha! The fun has been doubled!",
	"I never leave home without my party cannon!",
	"I'm not giving him cake! I'm ASSAULTING him with cake!",
	"Hold on to your hooves, I'm about to be BRILLIANT!",
	"I just don't know what went wrong!",
	"*sadly* I'm the monster.",
	"And that's how Equestria was made!",
	"It needs to be about 20% cooler.",
	"Forgive me if I withhold my enthusiasm!",
	"Oatmeal!? Are you crazy?",
	"The Great & Powerful Trixie doesn't trust wheels.",
	"You even look good when you're chewing! Who looks good when they're chewing?",
	"You ruined my horn!!",
	"Don't you use your fancy mathematics to muddy the issue!",
	"Cross my heart and hope to fly, stick a cupcake in my eye!",
	"Twilight, you shouldn't hit the books, you should just read them.",
	"I'd like to be a tree.",
	"Whoa ho there, loverboy!",
	"Okie Dokie Lokie",
	"Huh. You may have vanquished an Ursa Minor, but you will never have the amazing, show-stopping ability of the Great and Powerful Trixie!",
	"Can you do that? Can you explode twice?",
	"Somepony needs to put this thing out of its misery.",
	"Necklace. Necklace. Necklace. Necklace. AND... BIG Crown thingy!",
	"Dumb Rock",
	"I don't wanna talk about it.",
	"Alright Applejack. Your applebucking hasn’t just caused you problems, its overpropelled pegasus, practically poisoned plenty of ponies, and terrorized bushels of brand new bouncing baby bunnies.",
	"Oh well, if anyone needs me I'll be outside in the chocolate puddles with a giant swizzle straw.",
	"I know where you live.",
	"Don't call me things I don't know what they mean!",
	"I thought we agreed to never speak of it.",
	"Can I have more of that mushy stuff? Whatever it was?",
	"Scoot-scootalooooooo!",
	"It was under EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
	"Who?",
	"Eeyup.",
	"Yay!",
	"Hmm, nah",
	"If I can't find a problem I am going to have to make one.",
	"This may look like fun, but it's NOT."];

function quote(source) {
	source.respond(quotes[Math.floor(Math.random() * quotes.length)]);
}

exports.init = function() {
	this.addCommand('quote', quote).addCommand('quotes', quote).addCommand('q', quote);
	this.addAction('quote', quote, /^(quotes|quote|q)$/i, []);
};<|endoftext|>


<commit_before>var quotes = function(dbot) {
    var quotes = dbot.db.quoteArrs;
    var addStack = [];
    var rmAllowed = true;

    // Retrieve a random quote from a given category, interpolating any quote references (~~QUOTE CATEGORY~~) within it
    var interpolatedQuote = function(key, quoteTree, params) {
        if(quoteTree !== undefined && quoteTree.indexOf(key) != -1) {
            return '';
        } else if(quoteTree === undefined) {
            quoteTree = [];
        }

        var quoteString = quotes[key].random();

        // Parse quote interpolations
        var quoteRefs = quoteString.match(/~~([\d\w\s-]*)~~/g);
        var thisRef;

        while(quoteRefs && (thisRef = quoteRefs.shift()) !== undefined) {
            var cleanRef = dbot.cleanNick(thisRef.replace(/^~~/,'').replace(/~~$/,'').trim());
            if (quotes.hasOwnProperty(cleanRef)) {
                quoteTree.push(key);
                quoteString = quoteString.replace("~~" + cleanRef + "~~",
                        interpolatedQuote(cleanRef, quoteTree.slice()));
                quoteTree.pop();
            }
        }

        // Parse quote parameters
        /*
        var paramRefs = quoteString.match(/~~\$([1-9])~~/g);
        var thisParam;

        while(paramRefs && (thisParam = paramRefs.shift()) !== undefined) {
            thisParam = thisParam[1];
            console.log(thisParam);
            if(thisParam < params.length) {
                quoteString = quoteString.replace("~~$" + thisParam + "~~", params[thisParam]);
            }
        }
        */

        return quoteString;
    };

    var commands = {
        '~q': function(data, params) {
            var q = data.message.valMatch(/^~q ([\d\w\s-]*)/, 2);
            if(q) {
                q[1] = q[1].trim();
                key = q[1].toLowerCase();
                if(quotes.hasOwnProperty(key)) {
                    dbot.say(data.channel, q[1] + ': ' + interpolatedQuote(key, params));
                } else {
                    dbot.say(data.channel, 'Nobody loves ' + q[1]);
                }
            }
        },

        // shows the biggest categories
        '~qstats': function(data, params) {
            var qSizes = [];
            for(var cat in quotes) {
                if(quotes[cat].length != 0) {
                    qSizes.push([cat, quotes[cat].length]);
                }
            }

            qSizes = qSizes.sort(function(a, b) { return a[1] - b[1]; });
            qSizes = qSizes.slice(qSizes.length - 10).reverse();

            var qString = "Largest categories: ";

            for(var i=0;i<qSizes.length;i++) {
                qString += qSizes[i][0] + " (" + qSizes[i][1] + "), ";
            }

            dbot.say(data.channel, qString.slice(0, -2));
        },

        '~qsearch': function(data, params) {
            if(params[2] === undefined) {
                dbot.say(data.channel, 'Next time provide a search parameter. Commence incineration.');
            } else {
                params[1].trim();
                key = params[1].toLowerCase();
                if(!quotes.hasOwnProperty(key)) {
                    dbot.say(data.channel, 'That category has no quotes in it. Commence incineration.');
                } else {
                    var matches = [];

                    quotes[key].each(function(quote) {
                        if(quote.indexOf(params[2]) != -1) {
                            matches.push(quote);
                        }
                    }.bind(this));

                    if(matches.length == 0) {
                        dbot.say(data.channel, 'No results found.');
                    } else {
                        dbot.say(data.channel, params[1] + ' (' + params[2] + '): ' + matches.random() + ' [' + matches.length + ' results]');
                    }
                }
            }
        },

        '~rmlast': function(data, params) {
            if(rmAllowed == true || dbot.admin.include(data.user)) {
                var q = data.message.valMatch(/^~rmlast ([\d\w\s-]*)/, 2);
                if(q) {
                    q[1] = q[1].trim()
                    key = q[1].toLowerCase();
                    if(quotes.hasOwnProperty(q[1])) {
                        if(!dbot.db.locks.include(q[1]) || dbot.admin.include(data.user)) {
                            var quote = quotes[key].pop();
                            if(quotes[key].length === 0) {
                                delete quotes[key];
                            }
                            rmAllowed = false;
                            dbot.say(data.channel, '\'' + quote + '\' removed from ' + q[1]);
                        } else {
                            dbot.say(data.channel, q[1] + ' is locked. Commence incineration.');
                        }
                    } else {
                        dbot.say(data.channel, 'No quotes exist under ' + q[1]);
                    }
                } else {
                    var last = addStack.pop();
                    if(last) {
                        if(!dbot.db.locks.include(last)) {
                            quotes[last].pop();
                            rmAllowed = false;
                            dbot.say(data.channel, 'Last quote removed from ' + last + '.');
                        } else {
                            dbot.say(data.channel, last + ' is locked. Commence incineration.');
                        }
                    } else {
                        dbot.say(data.channel, 'No quotes were added recently.');
                    }
                }
            } else {
                dbot.say(data.channel, 'No spamming that shit. Try again in a few minutes...');
            }
        },

        '~rm': function(data, params) {
            if(rmAllowed == true || dbot.admin.include(data.user)) {
                var q = data.message.valMatch(/^~rm ([\d\w\s-]*) (.+)$/, 3);
                if(q) {
                    if(quotes.hasOwnProperty(q[1])) {
                        if(!dbot.db.locks.include(q[1])) {
                            var index = quotes[q[1]].indexOf(q[2]);
                            if(index != -1) {
                                quotes[q[1]].splice(index, 1);
                                if(quotes[q[1]].length === 0) {
                                    delete quotes[q[1]];
                                }
                                rmAllowed = false;
                                dbot.say(data.channel, '\'' + q[2] + '\' removed from ' + q[1]);
                            } else {
                                dbot.say(data.channel, '\'' + q[2] + '\' doesn\'t exist under user \'' + q[1] + '\'.');
                            }
                        } else {
                            dbot.say(data.channel, q[1] + ' is locked. Initiate incineration.');
                        }
                    } else {
                        dbot.say(data.channel, 'No quotes exist under ' + q[1]);
                    }
                } else {
                    dbot.say(data.channel, 'Invalid syntax. Initiate incineration.');
                }
            } else {
                dbot.say(data.channel, 'No spamming that shit. Try again in a few minutes...');
            }
        },

        '~qcount': function(data, params) {
            var q = data.message.valMatch(/^~qcount ([\d\w\s-]*)/, 2);
            if(q) {
                q[1] = q[1].trim();
                key = q[1].toLowerCase();
                if(quotes.hasOwnProperty(key)) {
                    dbot.say(data.channel, q[1] + ' has ' + quotes[key].length + ' quotes.');
                } else {
                    dbot.say(data.channel, 'No quotes under ' + q[1]);
                }
            } else { // Give total quote count
                var totalQuoteCount = 0;
                for(var category in quotes) {
                    totalQuoteCount += category.length;
                }
                dbot.say(data.channel, 'There are ' + totalQuoteCount + ' quotes in total.');
            }
        },

        '~qadd': function(data, params) {
            var q = data.message.valMatch(/^~qadd ([\d\w\s-]+?)[ ]?=[ ]?(.+)$/, 3);
            if(q) {
                key = q[1].toLowerCase();
                if(!Object.isArray(quotes[key])) {
                    quotes[key] = [];
                } else {
                    if (q[2] in quotes[key]) {
                        dbot.say(data.channel, 'Quote already in DB. Initiate incineration.');
                        return;
                    }
                }
                quotes[key].push(q[2]);
                addStack.push(q[1]);
                rmAllowed = true;
                dbot.say(data.channel, 'Quote saved in \'' + q[1] + '\' (' + quotes[key].length + ')');
            } else {
                dbot.say(data.channel, 'Invalid syntax. Initiate incineration.');
            }
        },

        '~qset': function(data, params) {
            var q = data.message.valMatch(/^~qset ([\d\w\s-]*)=(.+)$/, 3);
            if(q) {
                q[1] = q[1].trim();
                key = q[1].toLowerCase();
                if(!quotes.hasOwnProperty(key) || (quotes.hasOwnProperty(key) &&
                        quotes[key].length == 1)) {
                    quotes[key] = [q[2]];
                    dbot.say(data.channel, 'Quote saved as ' + q[1]);
                } else {
                    dbot.say(data.channel, 'No replacing arrays, you whore.');
                }
            }
        },

        '~rq': function(data, params) {
            var rQuote = Object.keys(quotes).random();
            dbot.say(data.channel, rQuote + ': ' + interpolatedQuote(rQuote, params));
        },

        '~d': function(data, params) {
            dbot.say(data.channel,  data.user + ': ' + interpolatedQuote(dbot.name, params));
        },

        '~link': function(data, params) {
            if(params[1] === undefined || !quotes.hasOwnProperty(params[1].toLowerCase())) {
                dbot.say(data.channel, 'Syntax error. Commence incineration.');
            } else {
                dbot.say(data.channel, 'Link to "'+params[1]+'" - http://nc.no.de:443/quotes/'+params[1]);
            }
        },

        '~qprune': function(data) {
            var pruned = []
            for(key in quotes) {
                if(quotes.hasOwnProperty(key)) {
                    if(quotes[key].length == 0) {
                        delete quotes[key];
                        pruned.push(key);
                    }
                }
            }
            if(pruned.length > 0) {
                dbot.say(data.channel, "Pruning empty quote categories: " + pruned.join(", "));
            } else {
                dbot.say(data.channel, "No empty quote categories. Commence incineration.");
            }
        }
    };

    return {
        'onLoad': function() {
            dbot.timers.addTimer(1000 * 60 * 3, function() {
                rmAllowed = true;
            });
            return commands;
        },

        // For automatic quote retrieval
        'listener': function(data, params) {
            if(data.user == 'reality') {
                var once = data.message.valMatch(/^I ([\d\w\s,'-]* once)/, 2);
            } else {
                var once = data.message.valMatch(/^reality ([\d\w\s,'-]* once)/, 2);
            }

            if(once) {
                if((dbot.db.bans.hasOwnProperty('~qadd') &&
                dbot.db.bans['~qadd'].include(data.user)) ||
                dbot.db.bans['*'].include(data.user)) {
                    dbot.say(data.channel, data.user + ' is banned from using this command. Commence incineration.');
                } else {
                    if(!dbot.db.quoteArrs.hasOwnProperty('realityonce')) {
                        dbot.db.quoteArrs['realityonce'] = [];
                    }
                    dbot.db.quoteArrs['realityonce'].push('reality ' + once[1] + '.');
                    addStack.push('realityonce');
                    rmAllowed = true;
                    dbot.instance.say(data.channel, '\'reality ' + once[1] + '.\' saved.');
                }
            }
        },

        'on': 'PRIVMSG'
    };
};

exports.fetch = function(dbot) {
    return quotes(dbot);
};
<commit_msg>params argument was being passed as the quoteTree, breaking quotes FOREVER<commit_after>var quotes = function(dbot) {
    var quotes = dbot.db.quoteArrs;
    var addStack = [];
    var rmAllowed = true;

    // Retrieve a random quote from a given category, interpolating any quote references (~~QUOTE CATEGORY~~) within it
    var interpolatedQuote = function(key, quoteTree) {
        if(quoteTree !== undefined && quoteTree.indexOf(key) != -1) {
            return '';
        } else if(quoteTree === undefined) {
            quoteTree = [];
        }

        var quoteString = quotes[key].random();

        // Parse quote interpolations
        var quoteRefs = quoteString.match(/~~([\d\w\s-]*)~~/g);
        var thisRef;

        while(quoteRefs && (thisRef = quoteRefs.shift()) !== undefined) {
            var cleanRef = dbot.cleanNick(thisRef.replace(/^~~/,'').replace(/~~$/,'').trim());
            if (quotes.hasOwnProperty(cleanRef)) {
                quoteTree.push(key);
                quoteString = quoteString.replace("~~" + cleanRef + "~~",
                        interpolatedQuote(cleanRef, quoteTree.slice()));
                quoteTree.pop();
            }
        }

        // Parse quote parameters
        /*
        var paramRefs = quoteString.match(/~~\$([1-9])~~/g);
        var thisParam;

        while(paramRefs && (thisParam = paramRefs.shift()) !== undefined) {
            thisParam = thisParam[1];
            console.log(thisParam);
            if(thisParam < params.length) {
                quoteString = quoteString.replace("~~$" + thisParam + "~~", params[thisParam]);
            }
        }
        */

        return quoteString;
    };

    var commands = {
        '~q': function(data, params) {
            var q = data.message.valMatch(/^~q ([\d\w\s-]*)/, 2);
            if(q) {
                q[1] = q[1].trim();
                key = q[1].toLowerCase();
                if(quotes.hasOwnProperty(key)) {
                    dbot.say(data.channel, q[1] + ': ' + interpolatedQuote(key));
                } else {
                    dbot.say(data.channel, 'Nobody loves ' + q[1]);
                }
            }
        },

        // shows the biggest categories
        '~qstats': function(data, params) {
            var qSizes = [];
            for(var cat in quotes) {
                if(quotes[cat].length != 0) {
                    qSizes.push([cat, quotes[cat].length]);
                }
            }

            qSizes = qSizes.sort(function(a, b) { return a[1] - b[1]; });
            qSizes = qSizes.slice(qSizes.length - 10).reverse();

            var qString = "Largest categories: ";

            for(var i=0;i<qSizes.length;i++) {
                qString += qSizes[i][0] + " (" + qSizes[i][1] + "), ";
            }

            dbot.say(data.channel, qString.slice(0, -2));
        },

        '~qsearch': function(data, params) {
            if(params[2] === undefined) {
                dbot.say(data.channel, 'Next time provide a search parameter. Commence incineration.');
            } else {
                params[1].trim();
                key = params[1].toLowerCase();
                if(!quotes.hasOwnProperty(key)) {
                    dbot.say(data.channel, 'That category has no quotes in it. Commence incineration.');
                } else {
                    var matches = [];

                    quotes[key].each(function(quote) {
                        if(quote.indexOf(params[2]) != -1) {
                            matches.push(quote);
                        }
                    }.bind(this));

                    if(matches.length == 0) {
                        dbot.say(data.channel, 'No results found.');
                    } else {
                        dbot.say(data.channel, params[1] + ' (' + params[2] + '): ' + matches.random() + ' [' + matches.length + ' results]');
                    }
                }
            }
        },

        '~rmlast': function(data, params) {
            if(rmAllowed == true || dbot.admin.include(data.user)) {
                var q = data.message.valMatch(/^~rmlast ([\d\w\s-]*)/, 2);
                if(q) {
                    q[1] = q[1].trim()
                    key = q[1].toLowerCase();
                    if(quotes.hasOwnProperty(q[1])) {
                        if(!dbot.db.locks.include(q[1]) || dbot.admin.include(data.user)) {
                            var quote = quotes[key].pop();
                            if(quotes[key].length === 0) {
                                delete quotes[key];
                            }
                            rmAllowed = false;
                            dbot.say(data.channel, '\'' + quote + '\' removed from ' + q[1]);
                        } else {
                            dbot.say(data.channel, q[1] + ' is locked. Commence incineration.');
                        }
                    } else {
                        dbot.say(data.channel, 'No quotes exist under ' + q[1]);
                    }
                } else {
                    var last = addStack.pop();
                    if(last) {
                        if(!dbot.db.locks.include(last)) {
                            quotes[last].pop();
                            rmAllowed = false;
                            dbot.say(data.channel, 'Last quote removed from ' + last + '.');
                        } else {
                            dbot.say(data.channel, last + ' is locked. Commence incineration.');
                        }
                    } else {
                        dbot.say(data.channel, 'No quotes were added recently.');
                    }
                }
            } else {
                dbot.say(data.channel, 'No spamming that shit. Try again in a few minutes...');
            }
        },

        '~rm': function(data, params) {
            if(rmAllowed == true || dbot.admin.include(data.user)) {
                var q = data.message.valMatch(/^~rm ([\d\w\s-]*) (.+)$/, 3);
                if(q) {
                    if(quotes.hasOwnProperty(q[1])) {
                        if(!dbot.db.locks.include(q[1])) {
                            var index = quotes[q[1]].indexOf(q[2]);
                            if(index != -1) {
                                quotes[q[1]].splice(index, 1);
                                if(quotes[q[1]].length === 0) {
                                    delete quotes[q[1]];
                                }
                                rmAllowed = false;
                                dbot.say(data.channel, '\'' + q[2] + '\' removed from ' + q[1]);
                            } else {
                                dbot.say(data.channel, '\'' + q[2] + '\' doesn\'t exist under user \'' + q[1] + '\'.');
                            }
                        } else {
                            dbot.say(data.channel, q[1] + ' is locked. Initiate incineration.');
                        }
                    } else {
                        dbot.say(data.channel, 'No quotes exist under ' + q[1]);
                    }
                } else {
                    dbot.say(data.channel, 'Invalid syntax. Initiate incineration.');
                }
            } else {
                dbot.say(data.channel, 'No spamming that shit. Try again in a few minutes...');
            }
        },

        '~qcount': function(data, params) {
            var q = data.message.valMatch(/^~qcount ([\d\w\s-]*)/, 2);
            if(q) {
                q[1] = q[1].trim();
                key = q[1].toLowerCase();
                if(quotes.hasOwnProperty(key)) {
                    dbot.say(data.channel, q[1] + ' has ' + quotes[key].length + ' quotes.');
                } else {
                    dbot.say(data.channel, 'No quotes under ' + q[1]);
                }
            } else { // Give total quote count
                var totalQuoteCount = 0;
                for(var category in quotes) {
                    totalQuoteCount += category.length;
                }
                dbot.say(data.channel, 'There are ' + totalQuoteCount + ' quotes in total.');
            }
        },

        '~qadd': function(data, params) {
            var q = data.message.valMatch(/^~qadd ([\d\w\s-]+?)[ ]?=[ ]?(.+)$/, 3);
            if(q) {
                key = q[1].toLowerCase();
                if(!Object.isArray(quotes[key])) {
                    quotes[key] = [];
                } else {
                    if (q[2] in quotes[key]) {
                        dbot.say(data.channel, 'Quote already in DB. Initiate incineration.');
                        return;
                    }
                }
                quotes[key].push(q[2]);
                addStack.push(q[1]);
                rmAllowed = true;
                dbot.say(data.channel, 'Quote saved in \'' + q[1] + '\' (' + quotes[key].length + ')');
            } else {
                dbot.say(data.channel, 'Invalid syntax. Initiate incineration.');
            }
        },

        '~qset': function(data, params) {
            var q = data.message.valMatch(/^~qset ([\d\w\s-]*)=(.+)$/, 3);
            if(q) {
                q[1] = q[1].trim();
                key = q[1].toLowerCase();
                if(!quotes.hasOwnProperty(key) || (quotes.hasOwnProperty(key) &&
                        quotes[key].length == 1)) {
                    quotes[key] = [q[2]];
                    dbot.say(data.channel, 'Quote saved as ' + q[1]);
                } else {
                    dbot.say(data.channel, 'No replacing arrays, you whore.');
                }
            }
        },

        '~rq': function(data, params) {
            var rQuote = Object.keys(quotes).random();
            dbot.say(data.channel, rQuote + ': ' + interpolatedQuote(rQuote));
        },

        '~d': function(data, params) {
            dbot.say(data.channel,  data.user + ': ' + interpolatedQuote(dbot.name));
        },

        '~link': function(data, params) {
            if(params[1] === undefined || !quotes.hasOwnProperty(params[1].toLowerCase())) {
                dbot.say(data.channel, 'Syntax error. Commence incineration.');
            } else {
                dbot.say(data.channel, 'Link to "'+params[1]+'" - http://nc.no.de:443/quotes/'+params[1]);
            }
        },

        '~qprune': function(data) {
            var pruned = []
            for(key in quotes) {
                if(quotes.hasOwnProperty(key)) {
                    if(quotes[key].length == 0) {
                        delete quotes[key];
                        pruned.push(key);
                    }
                }
            }
            if(pruned.length > 0) {
                dbot.say(data.channel, "Pruning empty quote categories: " + pruned.join(", "));
            } else {
                dbot.say(data.channel, "No empty quote categories. Commence incineration.");
            }
        }
    };

    return {
        'onLoad': function() {
            dbot.timers.addTimer(1000 * 60 * 3, function() {
                rmAllowed = true;
            });
            return commands;
        },

        // For automatic quote retrieval
        'listener': function(data, params) {
            if(data.user == 'reality') {
                var once = data.message.valMatch(/^I ([\d\w\s,'-]* once)/, 2);
            } else {
                var once = data.message.valMatch(/^reality ([\d\w\s,'-]* once)/, 2);
            }

            if(once) {
                if((dbot.db.bans.hasOwnProperty('~qadd') &&
                dbot.db.bans['~qadd'].include(data.user)) ||
                dbot.db.bans['*'].include(data.user)) {
                    dbot.say(data.channel, data.user + ' is banned from using this command. Commence incineration.');
                } else {
                    if(!dbot.db.quoteArrs.hasOwnProperty('realityonce')) {
                        dbot.db.quoteArrs['realityonce'] = [];
                    }
                    dbot.db.quoteArrs['realityonce'].push('reality ' + once[1] + '.');
                    addStack.push('realityonce');
                    rmAllowed = true;
                    dbot.instance.say(data.channel, '\'reality ' + once[1] + '.\' saved.');
                }
            }
        },

        'on': 'PRIVMSG'
    };
};

exports.fetch = function(dbot) {
    return quotes(dbot);
};
<|endoftext|>


<commit_before>"use strict";
module.exports = function (app){

	var globals = require("./globals");
	var sender = require("./sendThings");
	var messageHandler = require("./messagingEventHandler");

	app.get("/", function(req, res){
		res.send("hello there!");
	});

	app.get("/test", function(req, res){
		sender.sendTextMessage("1347063515338436", "TEST TEST TEST!!!!");
		res.send("I got your test: " + process.env.VALIDATION_TOKEN + process.env.PAGE_ACCESS_TOKEN);
	});

	app.get("/webhook", function(req, res){
		console.log("GET at webhook");
		if (req.query["hub.mode"] === "subscribe" &&
			req.query["hub.verify_token"] == process.env.VALIDATION_TOKEN){

				console.log("validating webhook");
				res.status(200).send(req.query["hub.challenge"]);
			} else{
				console.log("failed validation. validation tokens don't match");
				res.sendStatus(403);
			}
	});

	app.post("/webhook", function(req, res){
		console.log("POST at webhook");
		var data = req.body;

		sender.sendTextMessage("1347063515338436", "TEST TEST TEST!!!!");
		console.log(data);

		if(data.object === "page"){
			data.entry.forEach(function(pageEntry) {

				var pageID = pageEntry.id;
			  var timeOfEvent = pageEntry.time;

				pageEntry.messaging.forEach(function (messagingEvent){
					if (messagingEvent.optin) {
						console.log("got option event");
						messageHandler.receivedAuthentication(messagingEvent);

					} else if (messagingEvent.message) {
						console.log("got message event");
						messageHandler.onMessage(messagingEvent);

					} else if (messagingEvent.delivery) {
						console.log("got delivery event");
						messageHandler.onDeliveryConfirmation(messagingEvent);

					} else if (messagingEvent.postback) {
						console.log("got postback event");
						messageHandler.onPostback(messagingEvent);

					} else if (messagingEvent.read) {
						console.log("got messageRead event");
						messageHandler.onMessageRead(messagingEvent);

					} else if (messagingEvent.account_linking) {
						console.log("got accountLInking event");
						messageHandler.onAccountLicking(messagingEvent);

					} else {
						console.log("Webhook received unknown messagingEvent: ", messagingEvent);
					}
				});

			});
		}
	});

	app.get("/authorize", function(req, res){
		var accountLinkingToken = req.query.account_linking_token;
		var redirectURI = req.query.redirect_uri;

		var authCode = "1234567890";

		var redirectURISuccess = redirectURI + "&authorization_code=" + authCode;

		res.render("authorize",{
			accountLinkingToken: accountLinkingToken,
			redirectURI: redirectURI,
			redirectURISuccess: redirectURISuccess
		});
	});

	app.get("/privacy", function(req, res){
		res.send("some info about privacy goes here!!");
	});
};
<commit_msg>nice nice nice<commit_after>"use strict";
module.exports = function (app){

	var globals = require("./globals");
	var sender = require("./sendThings");
	var messageHandler = require("./messagingEventHandler");

	app.get("/", function(req, res){
		res.send("hello there!");
	});

	app.get("/test", function(req, res){
		sender.sendTextMessage("1347063515338436", "TEST TEST TEST!!!!");
		res.send("I got your test: " + process.env.VALIDATION_TOKEN + process.env.PAGE_ACCESS_TOKEN);
	});

	app.get("/webhook", function(req, res){
		console.log("GET at webhook");
		if (req.query["hub.mode"] === "subscribe" &&
			req.query["hub.verify_token"] == process.env.VALIDATION_TOKEN){

				console.log("validating webhook");
				res.status(200).send(req.query["hub.challenge"]);
			} else{
				console.log("failed validation. validation tokens don't match");
				res.sendStatus(403);
			}
	});

	app.post("/webhook", function(req, res){
		console.log("POST at webhook");
		var data = req.body;

		if(data.object === "page"){
			data.entry.forEach(function(pageEntry) {

				var pageID = pageEntry.id;
			  var timeOfEvent = pageEntry.time;

				pageEntry.messaging.forEach(function (messagingEvent){
					if (messagingEvent.optin) {
						console.log("got option event");
						messageHandler.receivedAuthentication(messagingEvent);

					} else if (messagingEvent.message) {
						console.log("got message event");
						messageHandler.onMessage(messagingEvent);

					} else if (messagingEvent.delivery) {
						console.log("got delivery event");
						messageHandler.onDeliveryConfirmation(messagingEvent);

					} else if (messagingEvent.postback) {
						console.log("got postback event");
						messageHandler.onPostback(messagingEvent);

					} else if (messagingEvent.read) {
						console.log("got messageRead event");
						messageHandler.onMessageRead(messagingEvent);

					} else if (messagingEvent.account_linking) {
						console.log("got accountLInking event");
						messageHandler.onAccountLicking(messagingEvent);

					} else {
						console.log("Webhook received unknown messagingEvent: ", messagingEvent);
					}
				});

			});
		}
	});

	app.get("/authorize", function(req, res){
		var accountLinkingToken = req.query.account_linking_token;
		var redirectURI = req.query.redirect_uri;

		var authCode = "1234567890";

		var redirectURISuccess = redirectURI + "&authorization_code=" + authCode;

		res.render("authorize",{
			accountLinkingToken: accountLinkingToken,
			redirectURI: redirectURI,
			redirectURISuccess: redirectURISuccess
		});
	});

	app.get("/privacy", function(req, res){
		res.send("some info about privacy goes here!!");
	});
};
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict"

const {classes: Cc, interfaces: Ci, utils: Cu} = Components;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, 'Services', 'resource://gre/modules/Services.jsm');

var EXPORTED_SYMBOLS = ['utils'];

var utils = {
  getContentFromURL: function getContentFromURL(url) {
    var ioService = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
    var scriptableStream = Cc['@mozilla.org/scriptableinputstream;1'].getService(Ci.nsIScriptableInputStream);

    var channel = ioService.newChannel(url, null, null);
    var input = channel.open();
    scriptableStream.init(input);
    var str = scriptableStream.read(input.available());
    scriptableStream.close()
    input.close();

    var utf8Converter = Components.classes["@mozilla.org/intl/utf8converterservice;1"].
    getService(Components.interfaces.nsIUTF8ConverterService);
    return utf8Converter.convertURISpecToUTF8 (str, "UTF-8");
  },

  exposeReadOnly: function exposeReadOnly(obj) {
    if (null == obj) {
      return obj;
    }

    if (typeof obj !== "object") {
      return obj;
    }

    if (obj["__exposedProps__"]) {
      return obj;
    }

    // If the obj is a navite wrapper, can not modify the attribute.
    try {
      obj.__exposedProps__ = {};
    } catch (e) {
      return;
    }

    var exposedProps = obj.__exposedProps__;
    for (let i in obj) {
      if (i === "__exposedProps__") {
        continue;
      }

      if (i[0] === "_") {
        continue;
      }

      exposedProps[i] = "r";

      exposeReadOnly(obj[i]);
    }

    return obj;
  },

  md5: function md5(str) {
    var data = str.split('');
    var ch = Cc["@mozilla.org/security/hash;1"]
               .createInstance(Ci.nsICryptoHash);
    ch.init(ch.MD5);
    ch.update(data, data.length);
    var hash = ch.finish(true);

    // return the two-digit hexadecimal code for a byte
    function toHexString(charCode) {
      return ("0" + charCode.toString(16)).slice(-2);
    }

    // convert the binary hash data to a hex string.
    return [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
  },

  getChromeFileURI: function getChromeFileURI(uri) {
    let fileURI = Services.io.newURI(uri, null, null);
    if (!(fileURI instanceof Ci.nsIFileURL)) {
      return null;
    }

    return fileURI;
  },

  emptyFunction: function emptyFunction() { }
};

(function() {
  function extend(destination, source) {
    for (var property in source)
      destination[property] = source[property];
    return destination;
  }

  extend(utils, {
    extend: extend
  });
})();

<commit_msg>Add getStrFromFile to utils.jsm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict"

const {classes: Cc, interfaces: Ci, utils: Cu} = Components;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, 'Services', 'resource://gre/modules/Services.jsm');

var EXPORTED_SYMBOLS = ['utils'];

var utils = {
  getContentFromURL: function getContentFromURL(url) {
    var ioService = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
    var scriptableStream = Cc['@mozilla.org/scriptableinputstream;1'].getService(Ci.nsIScriptableInputStream);

    var channel = ioService.newChannel(url, null, null);
    var input = channel.open();
    scriptableStream.init(input);
    var str = scriptableStream.read(input.available());
    scriptableStream.close()
    input.close();

    var utf8Converter = Components.classes["@mozilla.org/intl/utf8converterservice;1"].
    getService(Components.interfaces.nsIUTF8ConverterService);
    return utf8Converter.convertURISpecToUTF8 (str, "UTF-8");
  },

  readStrFromFile: function(file) {
    if (!file) {
      return '';
    }

    var data = '';
    var fstream = Cc['@mozilla.org/network/file-input-stream;1']
      .createInstance(Ci.nsIFileInputStream);
    var cstream = Cc['@mozilla.org/intl/converter-input-stream;1']
      .createInstance(Ci.nsIConverterInputStream);

    try {
      fstream.init(file, -1, 0, 0);
      cstream.init(fstream, 'UTF-8', 0, 0);

      var str = {};
      var read = 0;
      do {
        read = cstream.readString(0xffffffff, str);  // read as much as we can and  put it in str.value
        data += str.value;
      } while (read != 0);
    } catch(err) {
      dump('Error occured when reading file: ' + err);
    } finally {
      if (cstream) {
        try {
          cstream.close();
        } catch (err) {
          dump('Error occured when closing file : ' + err);
        }
      }
    }

    return data;
  },

  exposeReadOnly: function exposeReadOnly(obj) {
    if (null == obj) {
      return obj;
    }

    if (typeof obj !== "object") {
      return obj;
    }

    if (obj["__exposedProps__"]) {
      return obj;
    }

    // If the obj is a navite wrapper, can not modify the attribute.
    try {
      obj.__exposedProps__ = {};
    } catch (e) {
      return;
    }

    var exposedProps = obj.__exposedProps__;
    for (let i in obj) {
      if (i === "__exposedProps__") {
        continue;
      }

      if (i[0] === "_") {
        continue;
      }

      exposedProps[i] = "r";

      exposeReadOnly(obj[i]);
    }

    return obj;
  },

  md5: function md5(str) {
    var data = str.split('');
    var ch = Cc["@mozilla.org/security/hash;1"]
               .createInstance(Ci.nsICryptoHash);
    ch.init(ch.MD5);
    ch.update(data, data.length);
    var hash = ch.finish(true);

    // return the two-digit hexadecimal code for a byte
    function toHexString(charCode) {
      return ("0" + charCode.toString(16)).slice(-2);
    }

    // convert the binary hash data to a hex string.
    return [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
  },

  getChromeFileURI: function getChromeFileURI(uri) {
    let fileURI = Services.io.newURI(uri, null, null);
    if (!(fileURI instanceof Ci.nsIFileURL)) {
      return null;
    }

    return fileURI;
  },

  emptyFunction: function emptyFunction() { }
};

(function() {
  function extend(destination, source) {
    for (var property in source)
      destination[property] = source[property];
    return destination;
  }

  extend(utils, {
    extend: extend
  });
})();

<|endoftext|>


<commit_before><script type="text/javascript">
$(document).ready(function() {
//	$(".fancybox-thumb").fancybox({
//		prevEffect	: 'none',
//		nextEffect	: 'none',
//		helpers	: {
//			title	: {
//				type: 'outside'
//			},
//			thumbs	: {
//				width	: 50,
//				height	: 50
//			}
//		}
//	});

	$('.fancybox-thumb').fancybox();

	$('.link_to_fancy').click(function(){
		$(".fancybox-thumb:first").trigger('click');
	});

});
</script><commit_msg>when in any project page, PROJECTS nav menu should remain selected<commit_after>
$(document).ready(function() {
//	$(".fancybox-thumb").fancybox({
//		prevEffect	: 'none',
//		nextEffect	: 'none',
//		helpers	: {
//			title	: {
//				type: 'outside'
//			},
//			thumbs	: {
//				width	: 50,
//				height	: 50
//			}
//		}
//	});

	$('.fancybox-thumb').fancybox();

	$('.link_to_fancy').click(function(){
		$(".fancybox-thumb:first").trigger('click');
	});

	if ($('body').hasClass('PageType_ProjectPage')){
		$('li.navtext a:contains("PROJECTS")').addClass('current');
	}

});
<|endoftext|>


<commit_before>/*    Copyright 2016 Rottiesoft LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';
var log;
var config;

// TODO: Read this from config file
var firewallaHome = process.env.FIREWALLA_HOME || "/home/pi/firewalla"

module.exports = class {
    getFirewallaHome() {
        return firewallaHome;
    }

    getUserHome() {
      return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
    }

    getFirewallaConfigFolder() {
      return this.getUserHome() + "/.firewalla/";
    }

    isProduction() {
      // if either of condition matches, this is production environment
      return process.env.FWPRODUCTION != null || require('fs').existsSync("/tmp/FWPRODUCTION");
    }
};
<commit_msg>making isProduction() much faster<commit_after>/*    Copyright 2016 Rottiesoft LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';
var log;
var config;

// TODO: Read this from config file
var firewallaHome = process.env.FIREWALLA_HOME || "/home/pi/firewalla"

module.exports = class {
    getFirewallaHome() {
        return firewallaHome;
    }

    getUserHome() {
      return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
    }

    getFirewallaConfigFolder() {
      return this.getUserHome() + "/.firewalla/";
    }

    isProduction() {
      // if either of condition matches, this is production environment
      if (this._isProduction==null) {
        this._isProduction =  process.env.FWPRODUCTION != null || require('fs').existsSync("/tmp/FWPRODUCTION");
      }
      return this._isProduction;
    }
};
<|endoftext|>


<commit_before>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';
var ip = require('ip');
var spawn = require('child_process').spawn;

const log = require('./logger.js')(__filename);

var running = false;
var workqueue = [];

const Promise = require('bluebird')

exports.allow = function (rule, callback) {
    rule.target = 'ACCEPT';
    if (!rule.action) rule.action = '-A';
    newRule(rule, callback);
}

exports.drop = function (rule, callback) {
    rule.target = 'DROP';
    if (!rule.action) rule.action = '-A';
    newRule(rule, callback);
}

exports.reject = function (rule, callback) {
    rule.target = 'REJECT';
    if (!rule.action) rule.action = '-A';
    newRule(rule, callback);
}

exports.newRule = newRule;
exports.deleteRule = deleteRule;

function iptables(rule, callback) {
  log.debug("IPTABLE6: rule:",rule);
  running = true;

  let cmd = 'ip6tables';
  let args = iptablesArgs(rule);

  if (rule.sudo) {
    args = ['sudo', 'ip6tables', '-w'].concat(args);
    cmd = args.join(" ")
  }

  if (rule.checkBeforeAction) {
    let checkRule = JSON.parse(JSON.stringify(rule))
    checkRule.action = '-C'
    let checkArgs = iptablesArgs(checkRule)
    let checkCmd = ['sudo', 'ip6tables', '-w'].concat(checkArgs).join(" ")

    switch(rule.action) {
    case "-A":
      // check if exits before insertion
      cmd = `${checkCmd} || ${cmd}`
      break
    case "-D":
      cmd = `${checkCmd} && ${cmd}`
      break
    default:
      break
    }
  }

  log.debug("IPTABLE6:", cmd, workqueue.length);

  // for testing purpose only
  if(exports.test && typeof exports.test === 'function') {
    exports.test(cmd, args.join(" "))
    if (callback) {
      callback(null, null);
    }
    running = false;
    newRule(null, null);
    return
  }

  const proc = spawn(cmd, {shell: true});
    proc.stderr.on('data', function (buf) {
        log.error("IP6TABLE6:", buf.toString());
    });
    proc.on('exit', (code) => {
        if (callback) {
            callback(null, code);
        }
        running = false;
        newRule(null, null);
    });
    return proc;
}

function iptablesArgs(rule) {
    var args = [];

    if (!rule.chain) rule.chain = 'INPUT';
  if(rule.table) args = args.concat(["-t", rule.table])
    if (rule.chain) args = args.concat([rule.action, rule.chain]);
    if (rule.protocol) args = args.concat(["-p", rule.protocol]);
    if (rule.src) args = args.concat(["--source", rule.src]);
    if (rule.dst) args = args.concat(["--destination", rule.dst]);
    if (rule.sport) args = args.concat(["--sport", rule.sport]);
    if (rule.dport) args = args.concat(["--dport", rule.dport]);
    if (rule.in) args = args.concat(["-i", rule.in]);
    if (rule.out) args = args.concat(["-o", rule.out]);
    if (rule.target) args = args.concat(["-j", rule.target]);
    if (rule.list) args = args.concat(["-n", "-v"]);
  if (rule.mac) args = args.concat(["-m","mac","--mac-source",rule.mac]);
  if(rule.todest) args = args.concat(["--to-destination", rule.todest])

    return args;
}

function newRule(rule, callback) {
    // always make a copy
    if (rule) {
        rule = JSON.parse(JSON.stringify(rule));
        rule.callback = callback;
    }
    if (running == true) {
      if (rule) {
            workqueue.push(rule);
        }
        return;
    } else {
        if (rule) {
            workqueue.push(rule);
        }
        let nextRule = workqueue.splice(0, 1);
        if (nextRule && nextRule.length > 0) {
            iptables(nextRule[0], nextRule[0].callback);
        }
    }
}

function deleteRule(rule, callback) {
    rule.action = '-D';
    iptables(rule, callback);
}

function flush(callback) {
    this.process = require('child_process')
        .exec("sudo ip6tables -w -F && sudo ip6tables -w -F -t nat && sudo ip6tables -w -F -t raw", (err, out, code) => {
            if (err) {
                log.error("IP6TABLE:FLUSH:Unable to flush", err, out);
            }
            if (callback) {
                callback(err, null);
            }
        });
}

// run() is deleted as same functionality is provided in Iptables.run()

function dnsRedirectAsync(server, port) {
  return new Promise((resolve, reject) => {
    dnsRedirect(server, port, (err) => {
      if(err) {
        reject(err)
      } else {
        resolve()
      }
    })
  })
}

function dnsRedirect(server, port, cb) {
  let rule = {
    sudo: true,
    chain: 'PREROUTING',
    action: '-A',
    table: 'nat',
    protocol: 'udp',
    dport: '53',
    target: 'DNAT',
    todest: `[${server}]:${port}`,
    checkBeforeAction: true
  }

  newRule(rule, (err) => {
    if(err) {
      log.error("Failed to apply rule:", rule, {})
      cb(err)
    } else {
      rule.protocol = 'tcp'
      newRule(rule, cb)
    }
  })
}

function dnsUnredirectAsync(server, port) {
  return new Promise((resolve, reject) => {
    dnsUnredirect(server, port, (err) => {
      if(err) {
        reject(err)
      } else {
        resolve()
      }
    })
  })
}

function dnsUnredirect(server, port, cb) {
  let rule = {
    sudo: true,
    chain: 'PREROUTING',
    action: '-D',
    table: 'nat',
    protocol: 'udp',
    dport: '53',
    target: 'DNAT',
    todest: `[${server}]:${port}`,
    checkBeforeAction: true
  }

  newRule(rule, (err) => {
    if(err) {
      log.error("Failed to apply rule:", rule, {})
      cb(err)
    } else {
      rule.protocol = 'tcp'
      newRule(rule, cb)
    }
  })
}

exports.dnsRedirectAsync = dnsRedirectAsync
exports.dnsUnredirectAsync = dnsUnredirectAsync
exports.flush = flush
<commit_msg>fix ip6tables.iptables()<commit_after>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';
var ip = require('ip');
var spawn = require('child_process').spawn;

const log = require('./logger.js')(__filename);

var running = false;
var workqueue = [];

const Promise = require('bluebird')

exports.allow = function (rule, callback) {
    rule.target = 'ACCEPT';
    if (!rule.action) rule.action = '-A';
    newRule(rule, callback);
}

exports.drop = function (rule, callback) {
    rule.target = 'DROP';
    if (!rule.action) rule.action = '-A';
    newRule(rule, callback);
}

exports.reject = function (rule, callback) {
    rule.target = 'REJECT';
    if (!rule.action) rule.action = '-A';
    newRule(rule, callback);
}

exports.newRule = newRule;
exports.deleteRule = deleteRule;

function iptables(rule, callback) {
  log.debug("IP6TABLE: rule:",rule);
  running = true;

  let cmd = 'ip6tables';
  let args = iptablesArgs(rule);

  if (rule.sudo) {
    args = ['sudo', 'ip6tables', '-w'].concat(args);
    cmd = args.join(" ")
  }

  if (rule.checkBeforeAction) {
    let checkRule = JSON.parse(JSON.stringify(rule))
    checkRule.action = '-C'
    let checkArgs = iptablesArgs(checkRule)
    let checkCmd = ['sudo', 'ip6tables', '-w'].concat(checkArgs).join(" ")

    switch(rule.action) {
    case "-A":
      // check if exits before insertion
      cmd = `${checkCmd} || ${cmd}`
      break
    case "-D":
      cmd = `${checkCmd} && ${cmd}`
      break
    default:
      break
    }
  }

  log.debug("IPTABLE6:", cmd, workqueue.length);

  // for testing purpose only
  if(exports.test && typeof exports.test === 'function') {
    exports.test(cmd, args.join(" "))
    if (callback) {
      callback(null, null);
    }
    running = false;
    newRule(null, null);
    return
  }

  const proc = spawn(cmd, {shell: true});
  proc.stderr.on('data', function (buf) {
      log.error("IP6TABLE:IPTABLES:Failed to execute cmd ", cmd, buf.toString());
  });
  proc.on('exit', (code) => {
      if (callback) {
          callback(code, code);
      }
      running = false;
      newRule(null, null);
  });
  return proc;
}

function iptablesArgs(rule) {
    var args = [];

    if (!rule.chain) rule.chain = 'INPUT';
  if(rule.table) args = args.concat(["-t", rule.table])
    if (rule.chain) args = args.concat([rule.action, rule.chain]);
    if (rule.protocol) args = args.concat(["-p", rule.protocol]);
    if (rule.src) args = args.concat(["--source", rule.src]);
    if (rule.dst) args = args.concat(["--destination", rule.dst]);
    if (rule.sport) args = args.concat(["--sport", rule.sport]);
    if (rule.dport) args = args.concat(["--dport", rule.dport]);
    if (rule.in) args = args.concat(["-i", rule.in]);
    if (rule.out) args = args.concat(["-o", rule.out]);
    if (rule.target) args = args.concat(["-j", rule.target]);
    if (rule.list) args = args.concat(["-n", "-v"]);
  if (rule.mac) args = args.concat(["-m","mac","--mac-source",rule.mac]);
  if(rule.todest) args = args.concat(["--to-destination", rule.todest])

    return args;
}

function newRule(rule, callback) {
    // always make a copy
    if (rule) {
        rule = JSON.parse(JSON.stringify(rule));
        rule.callback = callback;
    }
    if (running == true) {
      if (rule) {
            workqueue.push(rule);
        }
        return;
    } else {
        if (rule) {
            workqueue.push(rule);
        }
        let nextRule = workqueue.splice(0, 1);
        if (nextRule && nextRule.length > 0) {
            iptables(nextRule[0], nextRule[0].callback);
        }
    }
}

function deleteRule(rule, callback) {
    rule.action = '-D';
    iptables(rule, callback);
}

function flush(callback) {
    this.process = require('child_process')
        .exec("sudo ip6tables -w -F && sudo ip6tables -w -F -t nat && sudo ip6tables -w -F -t raw", (err, out, code) => {
            if (err) {
                log.error("IP6TABLE:FLUSH:Unable to flush", err, out);
            }
            if (callback) {
                callback(err, null);
            }
        });
}

// run() is deleted as same functionality is provided in Iptables.run()

function dnsRedirectAsync(server, port) {
  return new Promise((resolve, reject) => {
    dnsRedirect(server, port, (err) => {
      if(err) {
        reject(err)
      } else {
        resolve()
      }
    })
  })
}

function dnsRedirect(server, port, cb) {
  let rule = {
    sudo: true,
    chain: 'PREROUTING',
    action: '-A',
    table: 'nat',
    protocol: 'udp',
    dport: '53',
    target: 'DNAT',
    todest: `[${server}]:${port}`,
    checkBeforeAction: true
  }

  newRule(rule, (err) => {
    if(err) {
      log.error("Failed to apply rule:", rule, {})
      cb(err)
    } else {
      rule.protocol = 'tcp'
      newRule(rule, cb)
    }
  })
}

function dnsUnredirectAsync(server, port) {
  return new Promise((resolve, reject) => {
    dnsUnredirect(server, port, (err) => {
      if(err) {
        reject(err)
      } else {
        resolve()
      }
    })
  })
}

function dnsUnredirect(server, port, cb) {
  let rule = {
    sudo: true,
    chain: 'PREROUTING',
    action: '-D',
    table: 'nat',
    protocol: 'udp',
    dport: '53',
    target: 'DNAT',
    todest: `[${server}]:${port}`,
    checkBeforeAction: true
  }

  newRule(rule, (err) => {
    if(err) {
      log.error("Failed to apply rule:", rule, {})
      cb(err)
    } else {
      rule.protocol = 'tcp'
      newRule(rule, cb)
    }
  })
}

exports.dnsRedirectAsync = dnsRedirectAsync
exports.dnsUnredirectAsync = dnsUnredirectAsync
exports.flush = flush
<|endoftext|>