<commit_before>"use strict";
// WrapUp base class

var isWindows = process.platform === "win32"

// core requires

var fs          = require("fs"),
    readFile    = fs.readFileSync,
    watchFile   = fs.watchFile,
    unwatchFile = fs.unwatchFile,
    path        = require("path"),
    exists      = fs.existsSync || path.existsSync,
    Stream      = require('stream').Stream

var pathsep = path.sep || (isWindows ? '\\' : '/')

//@* i love sebmarkbage
var Module = require("module")

// dependencies

var esprima = require("esprima"),
    prime   = require("prime/prime"),
    async   = require("async")

// Error objects

var errors                = require('./errors'),
    WrapUpNativeError     = errors.NativeError,
    WrapUpNamespaceError  = errors.NamespaceveError,
    WrapUpResolveError    = errors.ResolveError,
    WrapUpJavaScriptError = errors.JavaScriptError

// util methods

var util = require('./util')

var outputCallback = function(wrup, callback){
    return function(err, code){
        if (err) wrup.emit(wrup.watching ? "warn" : "error", err)
        else if (code != null) wrup.emit("data", code)
        if (!wrup.watching) wrup.emit("end")
        if (callback) callback(err, code)
    }
}

var handleGoError = function(wrup, err){
    wrup.emit("error", err)
    wrup.emit("end")
    return wrup
}

// WrapUp

var WrapUp = prime({

    inherits: Stream,

    // public API

    constructor: function(options){
        Stream.call(this)

        this.readable = true
        this.paused = false

        this.required = []
        this.options(options)
    },

    // stream methods

    pause: function(){
        this.paused = true
    },

    resume: function(){
        this.paused = false
        if (this.buffer) this.emit("data", this.buffer)
    },

    setEncoding: function(){},

    destroy: function(){
        this.readable = false
        this.emit("close")
    },

    // public API

    options: function(options){
        var _options = this._options || (this._options = {
            globalize: "window"
        })
        if (!options) options = {}
        if (options.globalize != null) _options.globalize = options.globalize
        if (options.globalizeVars != null) _options.globalizeVars = options.globalizeVars
        if (options.compress != null) _options.compress = options.compress
        if (options.output != null) _options.output = options.output
        if (options.sourcemap != null) _options.sourcemap = options.sourcemap
        if (options.sourcemapRoot != null) _options.sourcemapRoot = options.sourcemapRoot
        if (options.sourcemapURL != null) _options.sourcemapURL = options.sourcemapURL
        if (options.ast != null) _options.ast = options.ast
        return this
    },

    require: function(namespace, module){
        if (module == null){
            module = namespace
            namespace = null
        }
        this.required.push([namespace, module])
        return this
    },

    up: function(callback){
        return this.browser(callback)
    },

    browser: function(callback){
        var err = this.go()
        if (err) return handleGoError(this, err)
        require('./output/browser')(this, outputCallback(this, callback))
        return this
    },

    amd: function(callback){
        var err = this.go()
        if (err) return handleGoError(this, err)
        require('./output/amd')(this, outputCallback(this, callback))
        return this
    },

    graph: function(callback){
        var err = this.go()
        if (err) return handleGoError(this, err)
        require('./output/graph')(this, outputCallback(this, callback))
        return this
    },

    watch: function(method, callback){
        var self = this

        if (!this.watching){
            this.watching = true

            // make CTRL+C call the exit event
            process.on("SIGINT", function(){
                process.exit()
            })
            process.on("exit", function(){
                self.emit("end")
                ;(callback || util.noop)()
            })
        }

        // this flag prevents re-watching when building isn't ready yet.
        this._watchBuilding = true

        this[method](function(err){
            if (err) self.emit("warn", err)
            self._watchBuilding = false
            self._watch(function(err){
                if (err) self.emit("warn", err)
                else if (!self._watchBuilding) self.watch(method, callback)
            })
        })
        return this
    },

    // private API

    _watch: function(callback){
        var self = this, watchers = {}

        var changed = function(file){
            for (var p in watchers) watchers[p].close()
            self.emit("change", file)
            callback()
        }

        prime.each(this.modules, function(module, fullpath){
            fs.readFile(fullpath, "utf-8", function(err, src){
                if (err) return callback(err)
                // we need an throttle, because it can happen sometimes that the
                // watch callback is called multiple times for the same change.
                watchers[fullpath] = fs.watch(fullpath, util.throttle(function(event){
                    fs.readFile(fullpath, "utf-8", function(err, now){
                        // the file was removed
                        if (err && err.code == 'ENOENT') changed(fullpath)
                        // something else gone wrong
                        else if (err) callback(err)
                        // file has changed its content
                        else if (now != src) changed(fullpath)
                    })
                }))
            })
        })
    },

    // fill the modules, named and nameless objects, by processing each file.
    go: function(){

        this.packages = {}
        this.modules  = {}
        this.named    = {}
        this.nameless = []
        this.index    = 0
        var err

        this.required.some(function(m){
            var namespace = m[0], module = m[1]

            if (namespace && this.named[namespace]){
                err = new WrapUpNamespaceError(namespace, module)
                return true
            }

            var id = module && this.scan(module, null)
            if (id){
                if (namespace) this.named[namespace] = id
                else if (this.nameless.indexOf(id) === -1) this.nameless.push(id)
            }
        }, this)

        // check if there are any modules required
        if (!err && util.empty(this.modules)){
            err = new errors.EmptyError()
        }

        return err
    },

    // now we use esprima, the scan doesn't have to be sync actually, but it's
    // a lot simpler, and easier to read.
    scan: function(what, from, name){

        var modulefull = this.resolve(what, from)

        if (modulefull == null){
            this.emit("warn", new WrapUpResolveError(what, from))
            return
        }

        if (modulefull === true){
            this.emit("warn", new WrapUpNativeError(what, from))
            return
        }

        var module = this.modules[modulefull]
        if (module) return module.uid

        var src
        try {
            src = readFile(modulefull, "utf-8")
        } catch(e){
            // It is possible that .resolve still resolves the file correctly,
            // but that the file actually doesn't exist anymore. Then still
            // fire the "warn" event that the file cannot be resolved
            if (e.code == 'ENOENT'){
                this.emit("warn", new WrapUpResolveError(what, from))
                return
            }
            throw e
        }

        var ast
        try {
            // parse the code with esprima to see if there are any errors
            // and so we can walk through the AST to find require()s
            ast = esprima.parse(src, {
                source: util.relative(modulefull), // see https://github.com/ariya/esprima/pull/148
                loc: true
            })
        } catch (err){
            // add to the object so it will be watched for newer versions
            this.modules[modulefull] = {err: true}
            // ujs.parse already logs this error, but yes, twice doesn't hurt
            // for now
            this.emit("warn", new WrapUpJavaScriptError(modulefull, from, err.line, err.col))
            return
        }

        module = this.modules[modulefull] = {
            uid: (this.index++).toString(36),
            full: modulefull,
            deps: [], // dependencies
            requires: [], // require APT nodes
            ast: ast
        }

        this.walkASTForRequires(module)

        return module.uid
    },

    walkASTForRequires: function(module){
        var self = this
        var ast = module.ast
        var sourcemap = this._options.sourcemap && ast.loc && !ast.loc.source
        var source = sourcemap && util.relative(module.full)
        util.astWalker(module.ast, function(ast, parent, key){
            // temporary fix until https://github.com/ariya/esprima/pull/148
            // is pulled and released.
            if (sourcemap && key == 'loc'){
                ast.source = source
                return true
            }
            if (ast && (ast.type == "CallExpression" || ast.type == "NewExpression") && ast.callee.name == "require"){
                module.requires.push({require: ast, parent: parent, key: key})
                var dep = ast['arguments'].length == 1 && ast['arguments'][0].value
                var k = dep && self.scan(dep, module.full)
                // note that deps now also contains "null" values if the module
                // could not be resolved. This way an output prime can determine
                // to remove the require, or do something else with it.
                module.deps.push(k || null)
                return true
            }
        })
    },

    // this makes sure we always use the same directory for a specified package (the first it encounters)
    // this might not be ideal, but duplicating packages for the web is even worse
    resolve: function(what, from){

        var module = this.nodeResolve(what, from)

        if (!module) return null // cannot find module
        if (isWindows){
            if (!module.match(/^([\w]:)/)) return true
        } else {
            if (module.indexOf("/") !== 0) return true // native require
        }

        if (this.modules[module]) return module

        var jsonpath = this.findJSON(module)
        if (!jsonpath) return module // not part of any package

        var pkgpath = path.dirname(jsonpath) + pathsep
        var modulepath = module.replace(pkgpath, "")

        var json = require(jsonpath)
        var id = json.name + "@" + json.version
        var prevpkgpath = this.packages[id]
        pkgpath = prevpkgpath || (this.packages[id] = pkgpath)

        return prevpkgpath ? this.nodeResolve(path.join(pkgpath, modulepath), from) : module
    },

    //resolve module from cwd or relative to another module.
    nodeResolve: function(module, from){
        from = (from == null) ? path.join(process.cwd(), "wrup.js") : path.resolve(from)
        var m = new Module(from)
        m.filename = from
        m.paths = Module._nodeModulePaths(path.dirname(from))
        try {
            return Module._resolveFilename(module, m)
        } catch (err){}
        return null
    },

    findJSON: function(file){
        var dirname = file
        while (dirname = path.dirname(dirname)){
            var json = path.join(dirname, "package.json")
            if (exists(json)) return json
            if (dirname === "/" || isWindows && dirname.match(/^[\w]:\\$/)) break
        }
        return null
    }

})

module.exports = WrapUp
<commit_msg>Remove some unused variables<commit_after>"use strict";
// WrapUp base class

var isWindows = process.platform === "win32"

// core requires

var fs       = require("fs"),
    readFile = fs.readFileSync,
    path     = require("path"),
    exists   = fs.existsSync || path.existsSync,
    Stream   = require('stream').Stream

var pathsep = path.sep || (isWindows ? '\\' : '/')

//@* i love sebmarkbage
var Module = require("module")

// dependencies

var esprima = require("esprima"),
    prime   = require("prime/prime"),
    async   = require("async")

// Error objects

var errors                = require('./errors'),
    WrapUpNativeError     = errors.NativeError,
    WrapUpNamespaceError  = errors.NamespaceveError,
    WrapUpResolveError    = errors.ResolveError,
    WrapUpJavaScriptError = errors.JavaScriptError

// util methods

var util = require('./util')

var outputCallback = function(wrup, callback){
    return function(err, code){
        if (err) wrup.emit(wrup.watching ? "warn" : "error", err)
        else if (code != null) wrup.emit("data", code)
        if (!wrup.watching) wrup.emit("end")
        if (callback) callback(err, code)
    }
}

var handleGoError = function(wrup, err){
    wrup.emit("error", err)
    wrup.emit("end")
    return wrup
}

// WrapUp

var WrapUp = prime({

    inherits: Stream,

    // public API

    constructor: function(options){
        Stream.call(this)

        this.readable = true
        this.paused = false

        this.required = []
        this.options(options)
    },

    // stream methods

    pause: function(){
        this.paused = true
    },

    resume: function(){
        this.paused = false
        if (this.buffer) this.emit("data", this.buffer)
    },

    setEncoding: function(){},

    destroy: function(){
        this.readable = false
        this.emit("close")
    },

    // public API

    options: function(options){
        var _options = this._options || (this._options = {
            globalize: "window"
        })
        if (!options) options = {}
        if (options.globalize != null) _options.globalize = options.globalize
        if (options.globalizeVars != null) _options.globalizeVars = options.globalizeVars
        if (options.compress != null) _options.compress = options.compress
        if (options.output != null) _options.output = options.output
        if (options.sourcemap != null) _options.sourcemap = options.sourcemap
        if (options.sourcemapRoot != null) _options.sourcemapRoot = options.sourcemapRoot
        if (options.sourcemapURL != null) _options.sourcemapURL = options.sourcemapURL
        if (options.ast != null) _options.ast = options.ast
        return this
    },

    require: function(namespace, module){
        if (module == null){
            module = namespace
            namespace = null
        }
        this.required.push([namespace, module])
        return this
    },

    up: function(callback){
        return this.browser(callback)
    },

    browser: function(callback){
        var err = this.go()
        if (err) return handleGoError(this, err)
        require('./output/browser')(this, outputCallback(this, callback))
        return this
    },

    amd: function(callback){
        var err = this.go()
        if (err) return handleGoError(this, err)
        require('./output/amd')(this, outputCallback(this, callback))
        return this
    },

    graph: function(callback){
        var err = this.go()
        if (err) return handleGoError(this, err)
        require('./output/graph')(this, outputCallback(this, callback))
        return this
    },

    watch: function(method, callback){
        var self = this

        if (!this.watching){
            this.watching = true

            // make CTRL+C call the exit event
            process.on("SIGINT", function(){
                process.exit()
            })
            process.on("exit", function(){
                self.emit("end")
                ;(callback || util.noop)()
            })
        }

        // this flag prevents re-watching when building isn't ready yet.
        this._watchBuilding = true

        this[method](function(err){
            if (err) self.emit("warn", err)
            self._watchBuilding = false
            self._watch(function(err){
                if (err) self.emit("warn", err)
                else if (!self._watchBuilding) self.watch(method, callback)
            })
        })
        return this
    },

    // private API

    _watch: function(callback){
        var self = this, watchers = {}

        var changed = function(file){
            for (var p in watchers) watchers[p].close()
            self.emit("change", file)
            callback()
        }

        prime.each(this.modules, function(module, fullpath){
            fs.readFile(fullpath, "utf-8", function(err, src){
                if (err) return callback(err)
                // we need an throttle, because it can happen sometimes that the
                // watch callback is called multiple times for the same change.
                watchers[fullpath] = fs.watch(fullpath, util.throttle(function(event){
                    fs.readFile(fullpath, "utf-8", function(err, now){
                        // the file was removed
                        if (err && err.code == 'ENOENT') changed(fullpath)
                        // something else gone wrong
                        else if (err) callback(err)
                        // file has changed its content
                        else if (now != src) changed(fullpath)
                    })
                }))
            })
        })
    },

    // fill the modules, named and nameless objects, by processing each file.
    go: function(){

        this.packages = {}
        this.modules  = {}
        this.named    = {}
        this.nameless = []
        this.index    = 0
        var err

        this.required.some(function(m){
            var namespace = m[0], module = m[1]

            if (namespace && this.named[namespace]){
                err = new WrapUpNamespaceError(namespace, module)
                return true
            }

            var id = module && this.scan(module, null)
            if (id){
                if (namespace) this.named[namespace] = id
                else if (this.nameless.indexOf(id) === -1) this.nameless.push(id)
            }
        }, this)

        // check if there are any modules required
        if (!err && util.empty(this.modules)){
            err = new errors.EmptyError()
        }

        return err
    },

    // now we use esprima, the scan doesn't have to be sync actually, but it's
    // a lot simpler, and easier to read.
    scan: function(what, from, name){

        var modulefull = this.resolve(what, from)

        if (modulefull == null){
            this.emit("warn", new WrapUpResolveError(what, from))
            return
        }

        if (modulefull === true){
            this.emit("warn", new WrapUpNativeError(what, from))
            return
        }

        var module = this.modules[modulefull]
        if (module) return module.uid

        var src
        try {
            src = readFile(modulefull, "utf-8")
        } catch(e){
            // It is possible that .resolve still resolves the file correctly,
            // but that the file actually doesn't exist anymore. Then still
            // fire the "warn" event that the file cannot be resolved
            if (e.code == 'ENOENT'){
                this.emit("warn", new WrapUpResolveError(what, from))
                return
            }
            throw e
        }

        var ast
        try {
            // parse the code with esprima to see if there are any errors
            // and so we can walk through the AST to find require()s
            ast = esprima.parse(src, {
                source: util.relative(modulefull), // see https://github.com/ariya/esprima/pull/148
                loc: true
            })
        } catch (err){
            // add to the object so it will be watched for newer versions
            this.modules[modulefull] = {err: true}
            // ujs.parse already logs this error, but yes, twice doesn't hurt
            // for now
            this.emit("warn", new WrapUpJavaScriptError(modulefull, from, err.line, err.col))
            return
        }

        module = this.modules[modulefull] = {
            uid: (this.index++).toString(36),
            full: modulefull,
            deps: [], // dependencies
            requires: [], // require APT nodes
            ast: ast
        }

        this.walkASTForRequires(module)

        return module.uid
    },

    walkASTForRequires: function(module){
        var self = this
        var ast = module.ast
        var sourcemap = this._options.sourcemap && ast.loc && !ast.loc.source
        var source = sourcemap && util.relative(module.full)
        util.astWalker(module.ast, function(ast, parent, key){
            // temporary fix until https://github.com/ariya/esprima/pull/148
            // is pulled and released.
            if (sourcemap && key == 'loc'){
                ast.source = source
                return true
            }
            if (ast && (ast.type == "CallExpression" || ast.type == "NewExpression") && ast.callee.name == "require"){
                module.requires.push({require: ast, parent: parent, key: key})
                var dep = ast['arguments'].length == 1 && ast['arguments'][0].value
                var k = dep && self.scan(dep, module.full)
                // note that deps now also contains "null" values if the module
                // could not be resolved. This way an output prime can determine
                // to remove the require, or do something else with it.
                module.deps.push(k || null)
                return true
            }
        })
    },

    // this makes sure we always use the same directory for a specified package (the first it encounters)
    // this might not be ideal, but duplicating packages for the web is even worse
    resolve: function(what, from){

        var module = this.nodeResolve(what, from)

        if (!module) return null // cannot find module
        if (isWindows){
            if (!module.match(/^([\w]:)/)) return true
        } else {
            if (module.indexOf("/") !== 0) return true // native require
        }

        if (this.modules[module]) return module

        var jsonpath = this.findJSON(module)
        if (!jsonpath) return module // not part of any package

        var pkgpath = path.dirname(jsonpath) + pathsep
        var modulepath = module.replace(pkgpath, "")

        var json = require(jsonpath)
        var id = json.name + "@" + json.version
        var prevpkgpath = this.packages[id]
        pkgpath = prevpkgpath || (this.packages[id] = pkgpath)

        return prevpkgpath ? this.nodeResolve(path.join(pkgpath, modulepath), from) : module
    },

    //resolve module from cwd or relative to another module.
    nodeResolve: function(module, from){
        from = (from == null) ? path.join(process.cwd(), "wrup.js") : path.resolve(from)
        var m = new Module(from)
        m.filename = from
        m.paths = Module._nodeModulePaths(path.dirname(from))
        try {
            return Module._resolveFilename(module, m)
        } catch (err){}
        return null
    },

    findJSON: function(file){
        var dirname = file
        while (dirname = path.dirname(dirname)){
            var json = path.join(dirname, "package.json")
            if (exists(json)) return json
            if (dirname === "/" || isWindows && dirname.match(/^[\w]:\\$/)) break
        }
        return null
    }

})

module.exports = WrapUp
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const path = require('path');
const ipc = require('node-ipc');
const Managed = require('./managed.js');
const DBWriter = require('./dbwrite.js');

// Config
const appcfg = _.defaultsDeep(
	{},
	require('../cfg/user.json'),
	require('../cfg/config.json')
);

// IPC setup
const mgd = new Managed(
	{waitforgo: true},
	logfn.bind(null, 'log'),
	logfn.bind(null, 'err')
);
_.assign(ipc.config, {
	appspace: 'twarc',
	socketRoot: path.resolve(appcfg.sockpath) + path.sep,
	id: process.env.childname,
	retry: 250,
	silent: true
});

// DB
const dbw = new DBWriter({
	user_id_str: appcfg.user.id_str,
	path: appcfg.dbpath,
	// noSync: true
}, mgd.err.bind(mgd));
const dblog = true;

// Signal handlers
process.on('SIGINT', () => {});
process.on('SIGTERM', () => {
	mgd.log('Caught signal, exiting...')
	.then(() => {
		// Close IPC server & open sockets
		ipc.server.stop();
		ipc.server.sockets.forEach(s => s.end());

		// Close DBs
		dbw.close();

		return 0;
	}).catch(e => {
		// First catch in case of close errors
		return mgd.err(e);
	}).catch(e => {
		// Second catch in case of log error
		console.error(e);
		return 1;
	}).then(code => {
		process.exitCode = code;
		process.disconnect();
	});
});

// Start server
ipc.serve(() => {
	ipc.server.on('connect', socket => socket.on('end', () => socket.end()));
	ipc.server.on('queue', (data, socket) => writer('queue', data));
	ipc.server.on('status', (data, socket) => writer('status', data));
	ipc.server.on('following', (data, socket) => writer('following', data));
	ipc.server.on('user', (data, socket) => writer('user', data));
	ipc.server.on('user_tweet', (data, socket) => writer('user_tweet', data));
	ipc.server.on('other_tweet', (data, socket) => writer('other_tweet', data));
	ipc.server.on('delete', (data, socket) => writer('delete', data));
	ipc.server.on('favorite', (data, socket) => writer('favorite', data));
	ipc.server.on('unfavorite', (data, socket) => writer('unfavorite', data));
	mgd.go();
	// mgd.sendmsg('ready');
});
ipc.server.start();

// Misc funcs
function logfn (type, data) {
	if (data) {
		if (_.isError(data)) {
			data = _.toString(data.stack);
		}
		return mgd.sendmsg({type, data}).catch(e => console.log(e));
	}
	return Promise.resolve();
}

function writer (type, data) {
	try {
		let ret = writefn(type, data, !dblog);
		if (dblog) {
			mgd.log(ret);
		}
	}
	catch (e) {
		mgd.err(e);
	}
}

function writefn (type, data, silent, txn) {
	const types = ['user', 'user_tweet', 'other_tweet', 'delete', 'favorite', 'unfavorite'];
	let ret = false;
	let time;

	switch (type) {
		case 'queue':
			ret = writeq(data, txn);
			break;
		case 'status_raw':
			ret = dbw.setstatus('', data, false, txn);
			break;
		case 'status':
			time = data.time;
			delete data.time;
			ret = dbw.setstatus('', data, time, txn);
			break;
		case 'user':
			ret = dbw.writeuser(data, txn);
			break;
		case 'user_tweet':
			ret = dbw.writetweet(data, txn);
			break;
		case 'other_tweet':
			ret = dbw.writetweet(data, txn);
			break;
		case 'delete':
			ret = dbw.deletetweet(data, txn);
			break;
		case 'favorite':
			ret = dbw.writefav(data, txn);
			break;
		case 'unfavorite':
			ret = dbw.deletefav(data, txn);
			break;
	}

	// Convert result to string description of updates
	// TODO: move to writer() instead so we can pull the rest into DBWriter
	if (!silent) {
		if (ret) {
			if (_.isBoolean(ret)) {
				ret = `Updated ${type}`;
			}
			else if (_.isArray(ret)) {
				// For now we can assume only status/status_raw return arrays
				ret = 'Updated status items:\n    ' + ret.join('\n    ');
			}
			else if (_.isObject(ret)) {
				// For now we can assume only queue returns objects
				let total = 0;
				let counts = [];
				let retstr = '';
				if (ret.status.size > 0) {
					// Convert to array since we'll join it later anyways
					// TODO: don't
					let statuses = Array.from(ret.status);
					let num = statuses.length;
					total += num;
					// TODO: change to for..of so we don't double-iterate
					retstr = '\nUpdated status items:\n    ' + statuses.join('\n    ');
					counts.push(`${num} status item${num > 1 ? 's' : ''}`);
				}
				for (let name of types) {
					let num = ret[name];
					if (num > 0) {
						total += num;
						counts.push(`${num} ${name}${num == 1 ? '' : name.endsWith('s') ? 'es' : 's'}`);
					}
				}
				ret = `Updated ${total} items (${counts.join(', ')})` + retstr;
			}
			// Any other cases we want to handle?
		}
		else if (type === 'queue') {
			ret = 'All items up-to-date';
		}
	}

	return ret;

	function writeq (queue, qtxn) {
		let retq = false;
		let closetxn = false;
		let count = {
			'status': new Set(),
			'user': 0,
			'user_tweet': 0,
			'other_tweet': 0,
			'delete': 0,
			'favorite': 0,
			'unfavorite': 0
		};

		// Open transaction if req'd
		if (!qtxn) {
			qtxn = dbw.begin();
			closetxn = true;
		}

		try {
			// Recursively call
			for (let i = 0; i < queue.length; i++) {
				let item = queue[i];
				if (_.has(item, 'type') && _.has(item, 'data')) {
					// Leave return value to end of queue, but return something if any write succeeds
					let retw = writefn(item.type, item.data, true, qtxn);
					if (retw) {
						if (_.isArray(retw)) {
							_.forEach(retw, k => count.status.add(k));
						}
						else if (_.isObject(retw)) {
							// Assume returned object is from a sub-queue
							// Merge counts
							for (let st of retw.status) {
								count.status.add(st);
							}
							for (let t of types) {
								count[t] += retw[t];
							}
						}
						else {
							count[item.type]++;
						}
						retq = count;
					}
				}
			}

			if (closetxn) {
				qtxn.commit();
			}
		}
		catch (e) {
			if (closetxn) {
				qtxn.abort();
			}
			throw e;
		}

		return retq;
	}

}
<commit_msg>Moved update string construction to writer()<commit_after>'use strict';

const _ = require('lodash');
const path = require('path');
const ipc = require('node-ipc');
const Managed = require('./managed.js');
const DBWriter = require('./dbwrite.js');

// Config
const appcfg = _.defaultsDeep(
	{},
	require('../cfg/user.json'),
	require('../cfg/config.json')
);

// IPC setup
const mgd = new Managed(
	{waitforgo: true},
	logfn.bind(null, 'log'),
	logfn.bind(null, 'err')
);
_.assign(ipc.config, {
	appspace: 'twarc',
	socketRoot: path.resolve(appcfg.sockpath) + path.sep,
	id: process.env.childname,
	retry: 250,
	silent: true
});

// DB
const dbw = new DBWriter({
	user_id_str: appcfg.user.id_str,
	path: appcfg.dbpath,
	// noSync: true
}, mgd.err.bind(mgd));
const dblog = true;

// Signal handlers
process.on('SIGINT', () => {});
process.on('SIGTERM', () => {
	mgd.log('Caught signal, exiting...')
	.then(() => {
		// Close IPC server & open sockets
		ipc.server.stop();
		ipc.server.sockets.forEach(s => s.end());

		// Close DBs
		dbw.close();

		return 0;
	}).catch(e => {
		// First catch in case of close errors
		return mgd.err(e);
	}).catch(e => {
		// Second catch in case of log error
		console.error(e);
		return 1;
	}).then(code => {
		process.exitCode = code;
		process.disconnect();
	});
});

// Start server
ipc.serve(() => {
	ipc.server.on('connect', socket => socket.on('end', () => socket.end()));
	ipc.server.on('queue', (data, socket) => writer('queue', data));
	ipc.server.on('status', (data, socket) => writer('status', data));
	ipc.server.on('following', (data, socket) => writer('following', data));
	ipc.server.on('user', (data, socket) => writer('user', data));
	ipc.server.on('user_tweet', (data, socket) => writer('user_tweet', data));
	ipc.server.on('other_tweet', (data, socket) => writer('other_tweet', data));
	ipc.server.on('delete', (data, socket) => writer('delete', data));
	ipc.server.on('favorite', (data, socket) => writer('favorite', data));
	ipc.server.on('unfavorite', (data, socket) => writer('unfavorite', data));
	mgd.go();
	// mgd.sendmsg('ready');
});
ipc.server.start();

// Misc funcs
function logfn (type, data) {
	if (data) {
		if (_.isError(data)) {
			data = _.toString(data.stack);
		}
		return mgd.sendmsg({type, data}).catch(e => console.log(e));
	}
	return Promise.resolve();
}

function writer (type, data) {
	const types = ['user', 'user_tweet', 'other_tweet', 'delete', 'favorite', 'unfavorite'];

	try {
		let ret = writefn(type, data, !dblog);
		if (dblog) {
			let updstr;

			// Convert result to string description of updates
			if (ret) {
				if (_.isBoolean(ret)) {
					updstr = `Updated ${type}`;
				}
				else if (_.isArray(ret)) {
					// For now we can assume only status/status_raw return arrays
					updstr = 'Updated status items:\n    ' + ret.join('\n    ');
				}
				else if (_.isObject(ret)) {
					// For now we can assume only queue returns objects
					let total = 0;
					let counts = [];
					let stastr = '';
					if (ret.status.size > 0) {
						// Convert to array since we'll join it later anyways
						// TODO: don't
						let statuses = Array.from(ret.status);
						let num = statuses.length;
						total += num;
						// TODO: change to for..of so we don't double-iterate
						stastr = '\nUpdated status items:\n    ' + statuses.join('\n    ');
						counts.push(`${num} status item${num > 1 ? 's' : ''}`);
					}
					for (let name of types) {
						let num = ret[name];
						if (num > 0) {
							total += num;
							counts.push(`${num} ${name}${num == 1 ? '' : name.endsWith('s') ? 'es' : 's'}`);
						}
					}
					updstr = `Updated ${total} items (${counts.join(', ')})` + stastr;
				}
				// Any other cases we want to handle?
			}
			else if (type === 'queue') {
				updstr = 'All items up-to-date';
			}

			if (updstr) {
				mgd.log(updstr);
			}
		}
	}
	catch (e) {
		mgd.err(e);
	}
}

function writefn (type, data, txn) {
	let ret = false;
	let time;

	switch (type) {
		case 'queue':
			ret = writeq(data, txn);
			break;
		case 'status_raw':
			ret = dbw.setstatus('', data, false, txn);
			break;
		case 'status':
			time = data.time;
			delete data.time;
			ret = dbw.setstatus('', data, time, txn);
			break;
		case 'user':
			ret = dbw.writeuser(data, txn);
			break;
		case 'user_tweet':
			ret = dbw.writetweet(data, txn);
			break;
		case 'other_tweet':
			ret = dbw.writetweet(data, txn);
			break;
		case 'delete':
			ret = dbw.deletetweet(data, txn);
			break;
		case 'favorite':
			ret = dbw.writefav(data, txn);
			break;
		case 'unfavorite':
			ret = dbw.deletefav(data, txn);
			break;
	}

	return ret;

	function writeq (queue, qtxn) {
		let retq = false;
		let closetxn = false;
		let count = {
			'status': new Set(),
			'user': 0,
			'user_tweet': 0,
			'other_tweet': 0,
			'delete': 0,
			'favorite': 0,
			'unfavorite': 0
		};

		// Open transaction if req'd
		if (!qtxn) {
			qtxn = dbw.begin();
			closetxn = true;
		}

		try {
			// Recursively call
			for (let i = 0; i < queue.length; i++) {
				let item = queue[i];
				if (_.has(item, 'type') && _.has(item, 'data')) {
					// Leave return value to end of queue, but return something if any write succeeds
					let retw = writefn(item.type, item.data, qtxn);
					if (retw) {
						if (_.isArray(retw)) {
							_.forEach(retw, k => count.status.add(k));
						}
						else if (_.isObject(retw)) {
							// Assume returned object is from a sub-queue
							// Merge counts
							for (let st of retw.status) {
								count.status.add(st);
							}
							for (let t of types) {
								count[t] += retw[t];
							}
						}
						else {
							count[item.type]++;
						}
						retq = count;
					}
				}
			}

			if (closetxn) {
				qtxn.commit();
			}
		}
		catch (e) {
			if (closetxn) {
				qtxn.abort();
			}
			throw e;
		}

		return retq;
	}

}
<|endoftext|>


<commit_before>(function (that, environment) {
    'use strict';

    var ExcelHeatMap = (function () {

        /*
         * private variables and functions
         */

        var tableData, //holds the table data. Each cell value should be only numbers, if not we will consider that value as null

        // hold the library default options
        defaultOptions = {
            max : 0,
            min : 0,
            // colors pattern
            defaultColors : [
                '#63BE7B',
                '#FBE983',
                '#F8696B',
                '#ffff00'
            ],
            defaultTextColor : '#FFFFFF',
            NaNcolor : '#808080' //grey color
        };

        /*
         * Common Utils
         */
        var Utils = {
            findMaxMin : function (selector) {
                var cells = document.querySelectorAll(selector);
                var max = defaultOptions.max;
                var min = defaultOptions.min;
                for( var i=0, l=cells.length; i < l; i++ ) {
                   var val = this.getCellValue(cells[i].innerText);

                   if( val !== null && val !== '' && !isNaN(val) ) {
                       max = this.getMax(max,val);
                       min = this.getMin(min,val);
                   }
                }
                defaultOptions.max = max;
                defaultOptions.min = min;

                return cells;
            },
            getCellValue : function (val) {
                if(this.isNumber(val)) {
                   return parseFloat(val);
                }
                return '';
            },
            computeColor : function (percent) {
                if( percent === null && isNaN(percent) ) {
                    return defaultOptions.NaNcolor;
                }

                var colors = defaultOptions.defaultColors;
                var nColors = colors.length;

                var colorPosition = percent * (nColors - 1);

                var sIndex = Math.floor(colorPosition);
                sIndex = Math.min(nColors -2, sIndex);

                var start = colors[sIndex];
                var end = colors[sIndex+1];

                var hsvStart = this.rgb2hsv(this.hex2num(start));
                var hsvEnd = this.rgb2hsv(this.hex2num(end));

                var interiorPercent = (percent * (nColors - 1)) - sIndex;

                var hsvResult = this.transition3(interiorPercent, 1, hsvStart, hsvEnd);

                var dispRGB = this.hsv2rgb(hsvResult);

                var color = this.num2hex(dispRGB);

                return color;

            },
            getMax : function (a,b) {
                return Math.max(a,b);
            },
            getMin : function (a,b) {
                return Math.min(a,b);
            },
            isNumber : function (number) {
               return !isNaN(parseFloat(number)) && isFinite(number);
            },
            hex2num : function (val) {
                if(val.charAt(0) === '#') {
                    val = val.slice(1); //remove the # character
               }

               if (val.length !== 6) {
                    throw new Error('Exception color to be in format of "#FFFFFF"');
               }

               var rgb = [];

               for(var i=0; i < 6; i+=2) {
                   var part = val.charAt(i) + val.charAt(i+1);

                   rgb.push(parseInt(part,16));
               }

               return rgb;
            },
            num2hex : function (rgb) {
               var res = '#';
               for (var i= 0,l = rgb.length; i<l; i++) {
                    var hex = Math.round(rgb[i]).toString(16);
                    while (hex.length < 2) {
                        hex = '0' + hex;
                    }
                    res +=hex;
               }

               return res;
            },
            rgb2hsv : function( rgb ) {
                var r, g, b;
                r = rgb[0];
                g = rgb[1];
                b = rgb[2];

                r = r/255;
                g = g/255;
                b = b/255;

                var max = Math.max(r,g,b);
                var min = Math.min(r,g,b);

                var h,s,v = max;

                var diff = max - min;
                s = (max === 0) ? 0 : diff / max;
                if (max === min) {
                    h = 0;
                } else {
                    switch (max) {
                        case r : h = (g - b) / diff + (g < b ? 6 : 0);
                        break;
                        case g : h = (b - r) / diff + 2;
                        break;
                        case h : h = (r - g) / diff + 4;
                        break;
                    }
                    h = h / 6;
                }
                h = Math.max(0,Math.min(h,1));
                s = Math.max(0,Math.min(s,1));
                v = Math.max(0,Math.min(v,1));

                return [h,s,v];

            },
            hsv2rgb : function ( hsv ) {
                var h = hsv[0];
                var s = hsv[1];
                var v = hsv[2];

                var r,g,b;

                var i = Math.floor(h * 6);
                var f = h * 6 - i;
                var p = v * (1 - s);
                var q = v * (1 - f * s);
                var t = v * (1 - (1 - f) * s);

                switch (i % 6) {
                    case 0 : r = v; g = t; b = p;
                    break;
                    case 1 : r = q; g = v; b = p;
                    break;
                    case 2 : r = p; g = v; b = t;
                    break;
                    case 3 : r = p; g = q; b = v;
                    break;
                    case 4 : r = t; g = p; b = v;
                    break;
                    case 5 : r = v; g = p; b = q;
                    break;
                }

                r = (Math.min(r,1)) * 255;
                g = (Math.min(g,1)) * 255;
                b = (Math.min(b,1)) * 255;

                return [r,g,b];

            },
            transition : function(value, max, start, end) {
                return start + (end - start) * value / max;
            },
            transition3 : function (val, max, start, end) {
                //handle situation where grey scale colors have red hue
                if (start[1] === 0) { start[0] = end[0]; }
                if (end[1] === 0) { end[0] = start[0]; }

                //handle black saturation issue
                if (start[2] === 0) { start[1] = end[1]; }
                if (end[2] === 0) { end[1] = start[1]; }

                var p = val / max;
                //hue has to wrap correctly around zero

                var distCCW = (start[0] >= end[0]) ? start[0] - end[0] : 1 + start[0] - end[0];
                var distCW = (start[0] >= end[0]) ? 1 + end[0] - start[0] : end[0] - start[0];

                var hue = (distCW <= distCCW) ? start[0] + (distCW * p) : start[0] - (distCCW * p);
                if(hue<0) { hue += 1; }

                var saturation = this.transition(val,max,start[1],end[1]);

                var value = this.transition(val, max, start[1], end[1]);

                return [hue, saturation, value];
            }
        };

        /*
         * Public Api to expose to the user
         */

        var init = function (id, data, func) {
            tableData = Utils.findMaxMin(id);

            if (!tableData) {
                throw new Error('Error : Couldn\'t find the specified id');
            }
        },

        renderHtml = function () {

            var range = defaultOptions.max - defaultOptions.min;
            for( var i = 0, l = tableData.length; i < l; i++ ) {
                var val = Utils.getCellValue(tableData[i].innerText);
                var color = defaultOptions.NaNcolor;
                if ( val !== undefined && val !== '' && !isNaN(val) && range !== 0 ) {

                   var adj = val - defaultOptions.min;

                   var percent = ( 1.0 * adj ) / range;

                   color = Utils.computeColor(percent);

                }

                tableData[i].style.backgroundColor = color;
                tableData[i].style.color = defaultOptions.defaultTextColor;

            }
        };

        return {
            init : init,
            render : renderHtml
        };
    }());

    environment.ExcelHeatMap = environment.ExcelHeatMap || ExcelHeatMap;

})(this,window,undefined);
<commit_msg>Accept custom options<commit_after>(function (that, environment) {
    'use strict';

    var ExcelHeatMap = (function () {

        /*
         * private variables and functions
         */

        var tableData, //holds the table data. Each cell value should be only numbers, if not we will consider that value as null

        // hold the library default options
        defaultOptions = {};

        /*
         * Common Utils
         */
        var Utils = {
            extend : function (options) {
                defaultOptions.max = options.max || defaultOptions.max;
                defaultOptions.min = options.min || defaultOptions.min;
                defaultOptions.defaultTextColor = options.defaultTextColor || defaultOptions.defaultTextColor;
                defaultOptions.NaNcolor = options.NaNcolor || defaultOptions.Nancolor;
                defaultOptions.defaultColors =
                    (options.defaultColors && this.isArray(options.defaultColors))?
                    options.defaultColors : defaultOptions.defaultColors;

            },
            isArray : function (obj) {
                return Object.prototype.toString.call (obj) === '[object Array]';
            },
            findMaxMin : function (selector) {
                var cells = document.querySelectorAll(selector);
                var max = defaultOptions.max;
                var min = defaultOptions.min;
                for( var i=0, l=cells.length; i < l; i++ ) {
                   var val = this.getCellValue(cells[i].innerText);

                   if( val !== null && val !== '' && !isNaN(val) ) {
                       max = this.getMax(max,val);
                       min = this.getMin(min,val);
                   }
                }
                defaultOptions.max = max;
                defaultOptions.min = min;

                return cells;
            },
            getCellValue : function (val) {
                if(this.isNumber(val)) {
                   return parseFloat(val);
                }
                return '';
            },
            computeColor : function (percent) {
                if( percent === null && isNaN(percent) ) {
                    return defaultOptions.NaNcolor;
                }

                var colors = defaultOptions.defaultColors;
                var nColors = colors.length;

                var colorPosition = percent * (nColors - 1);

                var sIndex = Math.floor(colorPosition);
                sIndex = Math.min(nColors -2, sIndex);

                var start = colors[sIndex];
                var end = colors[sIndex+1];

                var hsvStart = this.rgb2hsv(this.hex2num(start));
                var hsvEnd = this.rgb2hsv(this.hex2num(end));

                var interiorPercent = (percent * (nColors - 1)) - sIndex;

                var hsvResult = this.transition3(interiorPercent, 1, hsvStart, hsvEnd);

                var dispRGB = this.hsv2rgb(hsvResult);

                var color = this.num2hex(dispRGB);

                return color;

            },
            getMax : function (a,b) {
                return Math.max(a,b);
            },
            getMin : function (a,b) {
                return Math.min(a,b);
            },
            isNumber : function (number) {
               return !isNaN(parseFloat(number)) && isFinite(number);
            },
            hex2num : function (val) {
                if(val.charAt(0) === '#') {
                    val = val.slice(1); //remove the # character
               }

               if (val.length !== 6) {
                    throw new Error('Exception color to be in format of "#FFFFFF"');
               }

               var rgb = [];

               for(var i=0; i < 6; i+=2) {
                   var part = val.charAt(i) + val.charAt(i+1);

                   rgb.push(parseInt(part,16));
               }

               return rgb;
            },
            num2hex : function (rgb) {
               var res = '#';
               for (var i= 0,l = rgb.length; i<l; i++) {
                    var hex = Math.round(rgb[i]).toString(16);
                    while (hex.length < 2) {
                        hex = '0' + hex;
                    }
                    res +=hex;
               }

               return res;
            },
            rgb2hsv : function( rgb ) {
                var r, g, b;
                r = rgb[0];
                g = rgb[1];
                b = rgb[2];

                r = r/255;
                g = g/255;
                b = b/255;

                var max = Math.max(r,g,b);
                var min = Math.min(r,g,b);

                var h,s,v = max;

                var diff = max - min;
                s = (max === 0) ? 0 : diff / max;
                if (max === min) {
                    h = 0;
                } else {
                    switch (max) {
                        case r : h = (g - b) / diff + (g < b ? 6 : 0);
                        break;
                        case g : h = (b - r) / diff + 2;
                        break;
                        case h : h = (r - g) / diff + 4;
                        break;
                    }
                    h = h / 6;
                }
                h = Math.max(0,Math.min(h,1));
                s = Math.max(0,Math.min(s,1));
                v = Math.max(0,Math.min(v,1));

                return [h,s,v];

            },
            hsv2rgb : function ( hsv ) {
                var h = hsv[0];
                var s = hsv[1];
                var v = hsv[2];

                var r,g,b;

                var i = Math.floor(h * 6);
                var f = h * 6 - i;
                var p = v * (1 - s);
                var q = v * (1 - f * s);
                var t = v * (1 - (1 - f) * s);

                switch (i % 6) {
                    case 0 : r = v; g = t; b = p;
                    break;
                    case 1 : r = q; g = v; b = p;
                    break;
                    case 2 : r = p; g = v; b = t;
                    break;
                    case 3 : r = p; g = q; b = v;
                    break;
                    case 4 : r = t; g = p; b = v;
                    break;
                    case 5 : r = v; g = p; b = q;
                    break;
                }

                r = (Math.min(r,1)) * 255;
                g = (Math.min(g,1)) * 255;
                b = (Math.min(b,1)) * 255;

                return [r,g,b];

            },
            transition : function(value, max, start, end) {
                return start + (end - start) * value / max;
            },
            transition3 : function (val, max, start, end) {
                //handle situation where grey scale colors have red hue
                if (start[1] === 0) { start[0] = end[0]; }
                if (end[1] === 0) { end[0] = start[0]; }

                //handle black saturation issue
                if (start[2] === 0) { start[1] = end[1]; }
                if (end[2] === 0) { end[1] = start[1]; }

                var p = val / max;
                //hue has to wrap correctly around zero

                var distCCW = (start[0] >= end[0]) ? start[0] - end[0] : 1 + start[0] - end[0];
                var distCW = (start[0] >= end[0]) ? 1 + end[0] - start[0] : end[0] - start[0];

                var hue = (distCW <= distCCW) ? start[0] + (distCW * p) : start[0] - (distCCW * p);
                if(hue<0) { hue += 1; }

                var saturation = this.transition(val,max,start[1],end[1]);

                var value = this.transition(val, max, start[1], end[1]);

                return [hue, saturation, value];
            }
        };

        /*
         * Public Api to expose to the user
         */

        var init = function (id, data, func) {

            defaultOptions = {
                max : 0,
                min : 0,
                // colors pattern
                defaultColors : [
                    '#63BE7B',
                    '#FBE983',
                    '#F8696B',
                    '#ffff00'
                ],
                defaultTextColor : '#FFFFFF',
                NaNcolor : '#808080' //grey color
            };

            if (data) {
                Utils.extend(data);
            }

            console.log (defaultOptions);
            tableData = Utils.findMaxMin(id);

            if (!tableData) {
                throw new Error('Error : Couldn\'t find the specified id');
            }
        },

        renderHtml = function () {

            var range = defaultOptions.max - defaultOptions.min;
            for( var i = 0, l = tableData.length; i < l; i++ ) {
                var val = Utils.getCellValue(tableData[i].innerText);
                var color = defaultOptions.NaNcolor;
                if ( val !== undefined && val !== '' && !isNaN(val) && range !== 0 ) {

                   var adj = val - defaultOptions.min;

                   var percent = ( 1.0 * adj ) / range;

                   color = Utils.computeColor(percent);

                }

                tableData[i].style.backgroundColor = color;
                tableData[i].style.color = defaultOptions.defaultTextColor;

            }
        };

        return {
            init : init,
            render : renderHtml
        };
    }());

    environment.ExcelHeatMap = environment.ExcelHeatMap || ExcelHeatMap;

})(this,window,undefined);
<|endoftext|>


<commit_before>var Q = require('q');
var request = require("request");
var cheerio = require('cheerio');

module.exports = {
  search: function(query, zooqle_url, cat, page, limit) {
    var count = 1;
    var deferred = Q.defer();
    var data_content = {};
    var torrent_content = [];
    var torrent_verified;
    var search_url = zooqle_url + '/search?q=' + encodeURIComponent(query) + '&sd=d';

    var options = {
      url: search_url,
      headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36'
      }
    };

    request(options, function(err, response, body){

      if(!err && response.statusCode === 200){

        $ = cheerio.load(body);

        // console.log(body);
        if($('table.table-torrents tr').length > 2){
          $('table.table-torrents tr').each(function(index, torrents){
              var torrent_link;

              find_torrent_title = $(torrents).find('a.small');
              find_torrent_size = $(torrents).find('div.prog-blue');
              find_torrent_seeders = $(torrents).find('div.prog-green');
              find_torrent_leechers = $(torrents).find('div.prog-yellow');
              find_date_added = $(torrents).find('td.text-nowrap.text-muted.smaller');

              links = $(torrents).find('a');
              $(links).each(function(i, link){

                if($(link).attr('href').indexOf("magnet:?xt=urn:") > -1 && $(link).attr('href') !== null) {
                  torrent_link = $(link).attr('href');
                }

              });

              torrent_title = find_torrent_title.text();
              torrent_size = find_torrent_size.text();
              torrent_seed = find_torrent_seeders.text();
              torrent_leech = find_torrent_leechers.text();
              date_added = find_date_added.text();

            data_content = {
              torrent_num: count,
              title: torrent_title,
              category: '',
              seeds: torrent_seed,
              leechs: torrent_leech,
              size: torrent_size,
              torrent_link:  torrent_link,
              date_added: date_added
            };

            torrent_content.push(data_content);

            deferred.resolve(torrent_content);
            // like break
            if (++count > limit) { return false; }
        });
        } else {
          deferred.reject("No torrents found");
        }
      } else {
        deferred.reject("There was a problem loading Zooqle");
      }

    });

    return deferred.promise;

  }
};
<commit_msg>Zooqle: fix for blank torrents<commit_after>var Q = require('q');
var request = require("request");
var cheerio = require('cheerio');

module.exports = {
  search: function(query, zooqle_url, cat, page, limit) {
    var count = 1;
    var deferred = Q.defer();
    var data_content = {};
    var torrent_content = [];
    var torrent_verified;
    var search_url = zooqle_url + '/search?q=' + encodeURIComponent(query) + '&s=ns&v=t&sd=d';

    var options = {
      url: search_url,
      headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36'
      }
    };

    request(options, function(err, response, body){

      if(!err && response.statusCode === 200){

        $ = cheerio.load(body);

        // console.log(body);
        if($('table.table-torrents tr').length > 2){
          $('table.table-torrents tr').each(function(index, torrents){
              var torrent_link;

              find_torrent_title = $(torrents).find('a.small');
              find_torrent_size = $(torrents).find('div.prog-blue');
              find_torrent_seeders = $(torrents).find('div.prog-green');
              find_torrent_leechers = $(torrents).find('div.prog-yellow');
              find_date_added = $(torrents).find('td.text-nowrap.text-muted.smaller');

              links = $(torrents).find('a');
              $(links).each(function(i, link){

                if($(link).attr('href').indexOf("magnet:?xt=urn:") > -1 && $(link).attr('href') !== null) {
                  torrent_link = $(link).attr('href');
                }

              });

              torrent_title = find_torrent_title.text();
              torrent_size = find_torrent_size.text();
              torrent_seed = find_torrent_seeders.text();
              torrent_leech = find_torrent_leechers.text();
              date_added = find_date_added.text();

            data_content = {
              torrent_num: count,
              title: torrent_title,
              category: '',
              seeds: torrent_seed,
              leechs: torrent_leech,
              size: torrent_size,
              torrent_link:  torrent_link,
              date_added: date_added
            };

            if(torrent_title){
              torrent_content.push(data_content);
            }

            deferred.resolve(torrent_content);
            // like break
            if (++count > limit) { return false; }
        });
        } else {
          deferred.reject("No torrents found");
        }
      } else {
        deferred.reject("There was a problem loading Zooqle");
      }

    });

    return deferred.promise;

  }
};
<|endoftext|>


<commit_before>(function($, document) {
	// ie 6, 7 and 8 can not change the type of an input once it's created
	$.support.useHTMLForInputType = (function() {
		try {
			var field = document.createElement( "INPUT" );
			document.body.appendChild( field );
			field.setAttribute( "type", "checkbox" );
		} catch(e) {
			return true;
		} finally {
			field.parentNode && document.body.removeChild( field );
		}
		return false;
	})();

	var create = $.create = (function() {

		function addAttrs( el, obj, context ) {
			for( var attr in obj ){
				switch( attr ) {
				case 'tag' :
					break;
				case 'html' :
					el.innerHTML = obj[ attr ];
					break;
				case 'css' :
					for( var style in obj.css ) {
						$.attr( el.style, style, obj.css[ style ] );
					}
					break;
				case 'text' : case 'child' : case 'children' :
					createNode( obj[attr], el, context );
					break;
				case 'cls' :
					el.className = obj[attr];
					break;
				case 'data' :
					for( var data in obj.data ) {
						$.data( el, data, obj.data[data] );
					}
					break;
				default :
					if( attr.indexOf("on") === 0 && $.isFunction(obj[attr]) ) {
						$.event.add( el, attr.substr(2).replace(/^[A-Z]/, function(a) { return a.toLowerCase(); }), obj[attr] );
					} else {
						$.attr( el, attr, obj[attr] );
					}
				}
			}
		}

		function createNode(obj, parent, context) {
			if(obj && ($.isArray(obj) || obj instanceof $)) {
				for(var ret = [], i = 0; i < obj.length; i++) {
					var newNode = createNode(obj[i], parent, context);
					if(newNode) {
						ret.push(newNode);
					}
				}
				return ret;
			}
			var el;
			if(typeof(obj) === 'string') {
			  el = context.createTextNode(obj);
			} else if(!obj) {
				return undefined;
			} else if(obj.nodeType === 1) {
				el = obj;
			} else {
				if($.support.useHTMLForInputType && obj.tag && obj.tag.match(/input|button/i)) {
					el = context.createElement("<"+obj.tag+" type='"+obj.type+"' name='"+obj.name+"' " + (obj.checked ? " checked" : "") + ">");
					delete obj.type;
					delete obj.name;
				} else {
					el = context.createElement(obj.tag||'DIV');
				}
				addAttrs(el, obj, context);
			}
			if(parent){ parent.appendChild(el); }
			return el;
		};

		return function(elementDef, parentNode) {
			return createNode(elementDef, parentNode, (parentNode && parentNode.ownerDocument) || document);
		};

	})();

	// inject create into jquery internals so object definitions are treated as first class constructors (overrides non-public methods)
	var clean = $.clean,
		init = $.fn.init;

	$.clean = function( elems, context, fragment ) {
		for(var i = 0; i < elems.length; i++) {
			if( elems[i].tag )
				elems[i] = create( elems[i], null, context );
		}
		return clean( elems, context, fragment );
	};

	$.fn.init = function( selector, context, rootjQuery ) {
		if ( selector && selector.tag ) {
			selector = create( selector, null, context );
		}
		return init.call( this, selector, context, rootjQuery );
	};

	$.fn.init.prototype = $.fn;

})(jQuery, window.document);

<commit_msg>update for jquery 1.6<commit_after>(function($, document) {
	// ie 6, 7 and 8 can not change the type of an input once it's created
	$.support.useHTMLForInputType = (function() {
		try {
			var field = document.createElement( "INPUT" );
			document.body.appendChild( field );
			field.setAttribute( "type", "checkbox" );
		} catch(e) {
			return true;
		} finally {
			field.parentNode && document.body.removeChild( field );
		}
		return false;
	})();

	var create = $.create = (function() {

		function addAttrs( el, obj, context ) {
			for( var attr in obj ){
				switch( attr ) {
				case 'tag' :
					break;
				case 'html' :
					el.innerHTML = obj[ attr ];
					break;
				case 'css' :
					for( var style in obj.css ) {
						$.attr( el.style, style, obj.css[ style ] );
					}
					break;
				case 'text' : case 'child' : case 'children' :
					createNode( obj[attr], el, context );
					break;
				case 'cls' :
					el.className = obj[attr];
					break;
				case 'data' :
					for( var data in obj.data ) {
						$.data( el, data, obj.data[data] );
					}
					break;
				default :
					if( attr.indexOf("on") === 0 && $.isFunction(obj[attr]) ) {
						$.event.add( el, attr.substr(2).replace(/^[A-Z]/, function(a) { return a.toLowerCase(); }), obj[attr] );
					} else {
						$.attr( el, attr, obj[attr] );
					}
				}
			}
		}

		function createNode(obj, parent, context) {
			if(obj && ($.isArray(obj) || obj instanceof $)) {
				for(var ret = [], i = 0; i < obj.length; i++) {
					var newNode = createNode(obj[i], parent, context);
					if(newNode) {
						ret.push(newNode);
					}
				}
				return ret;
			}
			var el;
			if(typeof(obj) === 'string') {
			  el = context.createTextNode(obj);
			} else if(!obj) {
				return undefined;
			} else if(obj.nodeType === 1) {
				el = obj;
			} else {
				if($.support.useHTMLForInputType && obj.tag && obj.tag.match(/input|button/i)) {
					el = context.createElement("<"+obj.tag+" type='"+obj.type+"' name='"+obj.name+"' " + (obj.checked ? " checked" : "") + ">");
					delete obj.type;
					delete obj.name;
				} else {
					el = context.createElement(obj.tag||'DIV');
				}
				addAttrs(el, obj, context);
			}
			if(parent){ parent.appendChild(el); }
			return el;
		};

		return function(elementDef, parentNode) {
			return createNode(elementDef, parentNode, (parentNode && parentNode.ownerDocument) || document);
		};

	})();

	// inject create into jquery internals so object definitions are treated as first class constructors (overrides non-public methods)
	var clean = $.clean,
		init = $.fn.init;

	$.clean = function( elems, context, fragment, scripts ) {
		for(var i = 0; i < elems.length; i++) {
			if( elems[i].tag )
				elems[i] = create( elems[i], null, context );
		}
		return clean( elems, context, fragment, scripts );
	};

	$.fn.init = function( selector, context, rootjQuery ) {
		if ( selector && selector.tag ) {
			selector = create( selector, null, context );
		}
		return init.call( this, selector, context, rootjQuery );
	};

	$.fn.init.prototype = $.fn;

})(jQuery, window.document);

<|endoftext|>


<commit_before>/*
 * jquery.finger
 * https://github.com/ngryman/jquery.finger
 *
 * Copyright (c) 2013 ngryman
 * Licensed under the MIT license.
 */

(function (factory) {
	if (typeof define === 'function' && define.amd)
		define(['jquery'], factory);
	else if (typeof exports === 'object')
		factory(require('jquery'));
	else
		factory(jQuery);
}(function ($) {

	var ua = navigator.userAgent,
		isChrome = /chrome/i.exec(ua),
		isAndroid = /android/i.exec(ua),
		hasTouch = 'ontouchstart' in window && !(isChrome && !isAndroid),
		startEvent = hasTouch ? 'touchstart' : 'mousedown',
		stopEvent = hasTouch ? 'touchend touchcancel' : 'mouseup mouseleave',
		moveEvent = hasTouch ? 'touchmove' : 'mousemove',

		namespace = 'finger',
		rootEl = $('html')[0],

		start = {},
		move = {},
		motion,
		cancel,
		safeguard,
		timeout,
		prevEl,
		prevTime,

		Finger = $.Finger = {
			pressDuration: 300,
			doubleTapInterval: 300,
			flickDuration: 150,
			motionThreshold: 5
		};

	function preventDefault(event) {
		event.preventDefault();
		$.event.remove(rootEl, 'click', preventDefault);
	}

	function page(coord, event) {
		return (hasTouch ? event.originalEvent.touches[0] : event)['page' + coord.toUpperCase()];
	}

	function trigger(event, evtName, remove) {
		var fingerEvent = $.Event(evtName, move);
		$.event.trigger(fingerEvent, { originalEvent: event }, event.target);

		if (fingerEvent.isDefaultPrevented()) {
			if (~evtName.indexOf('tap') && !hasTouch)
				$.event.add(rootEl, 'click', preventDefault);
			else
				event.preventDefault();
		}

		if (remove) {
			$.event.remove(rootEl, moveEvent + '.' + namespace, moveHandler);
			$.event.remove(rootEl, stopEvent + '.' + namespace, stopHandler);
		}
	}

	function startHandler(event) {
		var timeStamp = event.timeStamp || +new Date();

		if (safeguard == timeStamp) return;
		safeguard = timeStamp;

		// initializes data
		start.x = move.x = page('x', event);
		start.y = move.y = page('y', event);
		start.time = timeStamp;
		start.target = event.target;
		move.orientation = null;
		move.end = false;
		motion = false;
		cancel = false;
		timeout = setTimeout(function() {
			cancel = true;
			trigger(event, 'press');
		}, Finger.pressDuration);

		$.event.add(rootEl, moveEvent + '.' + namespace, moveHandler);
		$.event.add(rootEl, stopEvent + '.' + namespace, stopHandler);

		// global prevent default
		if (Finger.preventDefault) {
			event.preventDefault();
			$.event.add(rootEl, 'click', preventDefault);
		}
	}

	function moveHandler(event) {
		// motion data
		move.x = page('x', event);
		move.y = page('y', event);
		move.dx = move.x - start.x;
		move.dy = move.y - start.y;
		move.adx = Math.abs(move.dx);
		move.ady = Math.abs(move.dy);

		// security
		motion = move.adx > Finger.motionThreshold || move.ady > Finger.motionThreshold;
		if (!motion) return;

		// moves cancel press events
		clearTimeout(timeout);

		// orientation
		if (!move.orientation) {
			if (move.adx > move.ady) {
				move.orientation = 'horizontal';
				move.direction = move.dx > 0 ? +1 : -1;
			}
			else {
				move.orientation = 'vertical';
				move.direction = move.dy > 0 ? +1 : -1;
			}
		}

		// for delegated events, the target may change over time
		// this ensures we notify the right target and simulates the mouseleave behavior
		while (event.target && event.target !== start.target)
			event.target = event.target.parentNode;
		if (event.target !== start.target) {
			event.target = start.target;
			stopHandler.call(this, $.Event(stopEvent + '.' + namespace, event));
			return;
		}

		// fire drag event
		trigger(event, 'drag');
	}

	function stopHandler(event) {
		var timeStamp = event.timeStamp || +new Date(),
			dt = timeStamp - start.time,
			evtName;

		// always clears press timeout
		clearTimeout(timeout);

		// tap-like events
		// triggered only if targets match
		if (!motion && !cancel && event.target === start.target) {
			var doubleTap = prevEl === event.target && timeStamp - prevTime < Finger.doubleTapInterval;
			evtName = doubleTap ? 'doubletap' : 'tap';
			prevEl = doubleTap ? null : start.target;
			prevTime = timeStamp;
		}
		// motion events
		else {
			// ensure last target is set the initial one
			event.target = start.target;
			if (dt < Finger.flickDuration) trigger(event, 'flick');
			move.end = true;
			evtName = 'drag';
		}

		trigger(event, evtName, true);
	}

	// initial binding
	$.event.add(rootEl, startEvent + '.' + namespace, startHandler);

	// expose events as methods
	$.each('tap doubletap press drag flick'.split(' '), function(i, name) {
		$.fn[name] = function(fn) {
			return fn ? this.on(name, fn) : this.trigger(name);
		};
	});

	return Finger;

}));
<commit_msg>ignore non-left mouse clicks (#48)<commit_after>/*
 * jquery.finger
 * https://github.com/ngryman/jquery.finger
 *
 * Copyright (c) 2013 ngryman
 * Licensed under the MIT license.
 */

(function (factory) {
	if (typeof define === 'function' && define.amd)
		define(['jquery'], factory);
	else if (typeof exports === 'object')
		factory(require('jquery'));
	else
		factory(jQuery);
}(function ($) {

	var ua = navigator.userAgent,
		isChrome = /chrome/i.exec(ua),
		isAndroid = /android/i.exec(ua),
		hasTouch = 'ontouchstart' in window && !(isChrome && !isAndroid),
		startEvent = hasTouch ? 'touchstart' : 'mousedown',
		stopEvent = hasTouch ? 'touchend touchcancel' : 'mouseup mouseleave',
		moveEvent = hasTouch ? 'touchmove' : 'mousemove',

		namespace = 'finger',
		rootEl = $('html')[0],

		start = {},
		move = {},
		motion,
		cancel,
		safeguard,
		timeout,
		prevEl,
		prevTime,

		Finger = $.Finger = {
			pressDuration: 300,
			doubleTapInterval: 300,
			flickDuration: 150,
			motionThreshold: 5
		};

	function preventDefault(event) {
		event.preventDefault();
		$.event.remove(rootEl, 'click', preventDefault);
	}

	function page(coord, event) {
		return (hasTouch ? event.originalEvent.touches[0] : event)['page' + coord.toUpperCase()];
	}

	function trigger(event, evtName, remove) {
		var fingerEvent = $.Event(evtName, move);
		$.event.trigger(fingerEvent, { originalEvent: event }, event.target);

		if (fingerEvent.isDefaultPrevented()) {
			if (~evtName.indexOf('tap') && !hasTouch)
				$.event.add(rootEl, 'click', preventDefault);
			else
				event.preventDefault();
		}

		if (remove) {
			$.event.remove(rootEl, moveEvent + '.' + namespace, moveHandler);
			$.event.remove(rootEl, stopEvent + '.' + namespace, stopHandler);
		}
	}

	function startHandler(event) {
		if (event.which > 1)
			return;

		var timeStamp = event.timeStamp || +new Date();

		if (safeguard == timeStamp) return;
		safeguard = timeStamp;

		// initializes data
		start.x = move.x = page('x', event);
		start.y = move.y = page('y', event);
		start.time = timeStamp;
		start.target = event.target;
		move.orientation = null;
		move.end = false;
		motion = false;
		cancel = false;
		timeout = setTimeout(function() {
			cancel = true;
			trigger(event, 'press');
		}, Finger.pressDuration);

		$.event.add(rootEl, moveEvent + '.' + namespace, moveHandler);
		$.event.add(rootEl, stopEvent + '.' + namespace, stopHandler);

		// global prevent default
		if (Finger.preventDefault) {
			event.preventDefault();
			$.event.add(rootEl, 'click', preventDefault);
		}
	}

	function moveHandler(event) {
		// motion data
		move.x = page('x', event);
		move.y = page('y', event);
		move.dx = move.x - start.x;
		move.dy = move.y - start.y;
		move.adx = Math.abs(move.dx);
		move.ady = Math.abs(move.dy);

		// security
		motion = move.adx > Finger.motionThreshold || move.ady > Finger.motionThreshold;
		if (!motion) return;

		// moves cancel press events
		clearTimeout(timeout);

		// orientation
		if (!move.orientation) {
			if (move.adx > move.ady) {
				move.orientation = 'horizontal';
				move.direction = move.dx > 0 ? +1 : -1;
			}
			else {
				move.orientation = 'vertical';
				move.direction = move.dy > 0 ? +1 : -1;
			}
		}

		// for delegated events, the target may change over time
		// this ensures we notify the right target and simulates the mouseleave behavior
		while (event.target && event.target !== start.target)
			event.target = event.target.parentNode;
		if (event.target !== start.target) {
			event.target = start.target;
			stopHandler.call(this, $.Event(stopEvent + '.' + namespace, event));
			return;
		}

		// fire drag event
		trigger(event, 'drag');
	}

	function stopHandler(event) {
		var timeStamp = event.timeStamp || +new Date(),
			dt = timeStamp - start.time,
			evtName;

		// always clears press timeout
		clearTimeout(timeout);

		// tap-like events
		// triggered only if targets match
		if (!motion && !cancel && event.target === start.target) {
			var doubleTap = prevEl === event.target && timeStamp - prevTime < Finger.doubleTapInterval;
			evtName = doubleTap ? 'doubletap' : 'tap';
			prevEl = doubleTap ? null : start.target;
			prevTime = timeStamp;
		}
		// motion events
		else {
			// ensure last target is set the initial one
			event.target = start.target;
			if (dt < Finger.flickDuration) trigger(event, 'flick');
			move.end = true;
			evtName = 'drag';
		}

		trigger(event, evtName, true);
	}

	// initial binding
	$.event.add(rootEl, startEvent + '.' + namespace, startHandler);

	// expose events as methods
	$.each('tap doubletap press drag flick'.split(' '), function(i, name) {
		$.fn[name] = function(fn) {
			return fn ? this.on(name, fn) : this.trigger(name);
		};
	});

	return Finger;

}));
<|endoftext|>


<commit_before>'use strict';

window.Darwinator.GeneticAlgorithm = window.Darwinator.GeneticAlgorithm || {

  // GA parameter constants
  POPULATION_SIZE:          10,
  CROSSOVER_PROBABILITY:    0.8,
  MUTATION_PROBABILITY:     0.025,
  TOURNAMENT_PARAMETER:     0.75,
  NUMBER_OF_GENERATIONS:    100,
  NUMBER_OF_VARIABLES:      3,
  NUMBER_OF_GENES:          3,
  TOURNAMENT_SIZE:          4,
  ELITISM_DEGREE:           2,

  // GA parameter variables
  variableRange:           undefined,
  mutationRate:            undefined,

  // Other constants
  PLAYER_ADVANTAGE:         10,
  POOR_MAX_FITNESS:         0.1,

  /**
  * Generates a population of individuals from a given population. The new population is likely to be
  * more adapted to find a solution to the enemyScore() function.
  *
  * @method Darwinator.GeneticAlgorithm#generatePopulation
  * @param {Phaser.Game} [game] - The game that uses the algorithm.
  * @param {Phaser.Sprite} [target] - The sprite to be attacked by the enemies.
  * @param {Phaser.Group} [enemyGroup] - Optional. If not provided, a group with default values will be set.
  * @param {Boolean} [singleGeneration] - If true, only one iteration will be run, else, this.NUMBER_OF_GENERATIONS is used.
  * @param {Array} [spawnPositions] - The positions on which the enemies are allowed to spawn.
  * @return {Phaser.Group} The new wave of enemies
  */
  generatePopulation: function(population, options, targetFunction) {
    var singleGeneration = options.singleGeneration;
    var fitnessLevels = [];
    spawnPositions = Phaser.Math.shuffleArray(spawnPositions.slice(0));

    if(!population.length){
      population = this.initPopulation(options.varRange);
      console.log('GA: Enemy group not provided. Initializing with default values.');
      if (singleGeneration) {
        return population;
      }
    }
    console.log('GA: Starting GA run..');

    if (options.preEvaluated) {
      for (var i = 0; i < population.length; i++) {
        fitnessLevels.push(population[i].fitness);
      }
    } else {
      fitnessLevels = evaluatePopulation();
    }

    // weak population => more mutation
    if (options.preEvaluated)
    this.mutationRate = fitnessLevels[bestIndex] <= this.POOR_MAX_FITNESS ? 20 : 1;

    // algorithm main loop
    for (var i = 0; i < (singleGeneration ? 1 : this.NUMBER_OF_GENERATIONS); i++) {

      var maxFit = 0.0;
      var bestIndividual = population[0];

      for(var l = 0; l < population.length; l++) {
        var ind = population[l];
        fitnessLevels[l] = this.evaluateInd(decodedInd);
        if(fitnessLevels[l] > maxFit) {
          maxFit = fitnessLevels[l];
          bestIndividual = population[l];
          if (maxFit > totalMaxFit) {
            totalMaxFit = maxFit;
          }
        }
      }

      // clone population
      var tmpPopulation = population.slice(0);

      // selection
      for(var l = 0; l < population.length; l += 2) {
        var ind1 = this.selection(fitnessLevels);
        var ind2 = this.selection(fitnessLevels);
        // crossover
        if (Math.random() < this.CROSSOVER_PROBABILITY) {
          var chromePair        = this.cross(population[ind1], population[ind2]);
          tmpPopulation[l]      = chromePair[0];
          tmpPopulation[l + 1]  = chromePair[1];
        } else {
          tmpPopulation[l]      = population[ind1];
          tmpPopulation[l + 1]  = population[ind2];
        }
        // mutation
        tmpPopulation[l]    = this.mutate(tmpPopulation[l]);
        tmpPopulation[l+1]  = this.mutate(tmpPopulation[l+1]);
      }

      if(fitnessLevels[bestIndex] > this.POOR_MAX_FITNESS){
        // elitism
        for(l = 0; l < this.ELITISM_DEGREE; l++) {
          tmpPopulation[l] = bestIndividual;
        }
      }

      // replace old population
      population = tmpPopulation;
    }

    var nextGeneration = this.translatePopulation(population, enemyGroup, game, target, spawnPositions);
    console.log('GA: Returning the new generation!');
    return nextGeneration;
  },

  /**
  * Generates a group of enemy sprites with some default values.
  *
  * @method Darwinator.GeneticAlgorithm#initPopulation
  * @param {Phaser.Group} [enemyGroup] - The enemy group to fill with enemies.
  * @param {Phaser.Game} [game] - The game that uses the algorithm.
  * @param {Phaser.Sprite} [target] - The sprite to be attacked by the enemies.
  * @param {Array} [spawnPositions] - The positions on which the enemies are allowed to spawn.
  * @return {Array} An enemy population with default attribute values.
  */
  initPopulation: function(enemyGroup, game, target, spawnPositions) {
    // 4 different enemy initial set of attributes - just an example, not permanent!
    var enemiesPerType  = this.POPULATION_SIZE / 5;
    var pos;
    var strength, agility, intellect;
    for(var i = 0; i < this.POPULATION_SIZE; i++){
      pos = spawnPositions[i % spawnPositions.length];
      if(i < enemiesPerType){
        // smart but slow and weak
        strength  = 0;
        agility   = 0;
        intellect = this.variableRange;
      }else if(i < enemiesPerType*2){
        // strong but slow and stupid
        strength  = this.variableRange;
        agility   = 0;
        intellect = 0;
      }else if(i < enemiesPerType*3){
        // fast but weak and stupid
        strength  = 0;
        agility   = this.variableRange;
        intellect = 0;
      }else{
        // hybrid
        strength  = agility = intellect = Math.round(this.variableRange / 3);
      }
      enemyGroup.add(new Darwinator.Enemy(game, target, pos.x, pos.y, undefined, strength, agility, intellect));
    }
    return enemyGroup;
  },

  /**
  * Cross two individuals to create two new ones by performing a tradeoff between
  * two randomly selected genes in each individual.
  *
  * Example: Select index of x and y.
  * First individual: decrease x and increase y
  * Second individual: decrease y and increase x
  *
  * @method Darwinator.GeneticAlgorithm#cross
  * @param {Array} [firstInd] - The first individual to be crossed
  * @param {Array} [secondInd] - The second individual to be crossed
  * @return {Array} - A tuple containing the two new individuals.
  */
  cross: function(firstInd, secondInd) {
    var crossPoint1 = Math.round(Math.random()*(this.NUMBER_OF_GENES - 1));
    var crossPoint2 = Math.round(Math.random()*(this.NUMBER_OF_GENES - 1));

    var tradeOff        = Math.random();
    var tradeOffAmount1 = Math.round(tradeOff * firstInd[crossPoint1]);
    var tradeOffAmount2 = Math.round(tradeOff * secondInd[crossPoint2]);

    var newInd1 = firstInd.slice(0);
    var newInd2 = secondInd.slice(0);

    newInd1[crossPoint1] -= tradeOffAmount1;
    newInd1[crossPoint2] += tradeOffAmount1;

    newInd2[crossPoint2] -= tradeOffAmount2;
    newInd2[crossPoint1] += tradeOffAmount2;

    return [newInd1, newInd2];
  },

  /**
  * Select a individual based on the fitness levels of the entire population.
  * this.TOURNAMENT_SIZE many individuals will be selected at random, and one of them will
  * be returned. The tournament works in such a way that a individual with a high fitness level
  * is more likely to be returned from the tournament, but is not more likely to participate.
  *
  * @method Darwinator.GeneticAlgorithm#selection
  * @param {Array} - The fitness levels of the entire population
  * @return {Number} - The index of the selected individual.
  */
  selection: function(fitnessLevels) {
    var tournamentParticipants = new Array(this.TOURNAMENT_SIZE);

    /* Select individuals at random, and represent them as a touple containing their indexes and their
    * fitness levels. */
    for (var i = 0; i < this.TOURNAMENT_SIZE; i++) {
      tournamentParticipants[i]    = new Array(2);
      tournamentParticipants[i][0] = Math.round(Math.random() * (this.POPULATION_SIZE - 1));
      tournamentParticipants[i][1] = fitnessLevels[tournamentParticipants[i][0]];
    }

    /* Sort by fitness levels */
    tournamentParticipants.sort(
      function(a,b) {return b[1]-a[1];}
    );

    for(i = 0; i < this.TOURNAMENT_SIZE; i++) {
      if (Math.random() < this.TOURNAMENT_PARAMETER) {
        return tournamentParticipants[i][0];
      }
    }

    return tournamentParticipants[i - 1][0];
  },

  /**
  * Mutate a given individual by performing a tradeoff between two randomly selected genes.
  *
  * @method Darwinator.GeneticAlgorithm#mutate
  * @param {Array} - The individual to be mutated
  * @return {Array} - The mutated individual.
  */
  mutate: function(individual) {
    if (Math.random() < this.MUTATION_PROBABILITY * this.mutationRate) {
      var gene1 = Math.round(Math.random()*(this.NUMBER_OF_GENES - 1));
      var gene2 = Math.round(Math.random()*(this.NUMBER_OF_GENES - 1));
      var tradeOffAmount = Math.round(Math.random() * individual[gene1]);

      individual[gene1] -= tradeOffAmount;
      individual[gene2] += tradeOffAmount;
    }
    return individual;
  },

  /**
  * Evaluates an enemy sprite based on its score.
  *
  * @method Darwinator.GeneticAlgorithm#evaluateInd
  * @param {Phaser.Sprite} - The individual to be evaluated
  * @return {Number} - The fitness level of the individual
  */
  evaluateInd: function(enemy, targetFunction) {
    var fitness = 1 - (1 / targetFunction(enemy));
    return fitness == -Infinity ? 0 : fitness;// maximize fitness based on enemy score
  }

};
<commit_msg>generelized evaluation<commit_after>'use strict';

window.Darwinator.GeneticAlgorithm = window.Darwinator.GeneticAlgorithm || {

  // GA parameter constants
  POPULATION_SIZE:          10,
  CROSSOVER_PROBABILITY:    0.8,
  MUTATION_PROBABILITY:     0.025,
  TOURNAMENT_PARAMETER:     0.75,
  NUMBER_OF_GENERATIONS:    100,
  NUMBER_OF_VARIABLES:      3,
  NUMBER_OF_GENES:          3,
  TOURNAMENT_SIZE:          4,
  ELITISM_DEGREE:           2,

  // GA parameter variables
  variableRange:           undefined,
  mutationRate:            undefined,

  // Other constants
  PLAYER_ADVANTAGE:         10,
  POOR_MAX_FITNESS:         0.1,

  /**
  * Generates a population of individuals from a given population. The new population is likely to be
  * more adapted to find a solution to the enemyScore() function.
  *
  * @method Darwinator.GeneticAlgorithm#generatePopulation
  * @param {Phaser.Game} [game] - The game that uses the algorithm.
  * @param {Phaser.Sprite} [target] - The sprite to be attacked by the enemies.
  * @param {Phaser.Group} [enemyGroup] - Optional. If not provided, a group with default values will be set.
  * @param {Boolean} [singleGeneration] - If true, only one iteration will be run, else, this.NUMBER_OF_GENERATIONS is used.
  * @param {Array} [spawnPositions] - The positions on which the enemies are allowed to spawn.
  * @return {Phaser.Group} The new wave of enemies
  */
  generatePopulation: function(population, options, targetFunction) {
    var singleGeneration = options.singleGeneration;
    var fitnessLevels = [];
    spawnPositions = Phaser.Math.shuffleArray(spawnPositions.slice(0));

    if(!population.length){
      population = this.initPopulation(options.varRange);
      console.log('GA: Enemy group not provided. Initializing with default values.');
      if (singleGeneration) {
        return population;
      }
    }
    console.log('GA: Starting GA run..');

    if (options.preEvaluated) {
      for (var i = 0; i < population.length; i++) {
        fitnessLevels.push(population[i].fitness);
      }
    } else {
      fitnessLevels = evaluatePopulation();
    }

    // weak population => more mutation
    if (options.preEvaluated)
    this.mutationRate = fitnessLevels[bestIndex] <= this.POOR_MAX_FITNESS ? 20 : 1;

    // algorithm main loop
    for (var i = 0; i < (singleGeneration ? 1 : this.NUMBER_OF_GENERATIONS); i++) {

      var maxFit = 0.0;
      var bestIndividual = population[0];

      for(var l = 0; l < population.length; l++) {
        var ind = population[l];
        fitnessLevels[l] = this.evaluateInd(decodedInd);
        if(fitnessLevels[l] > maxFit) {
          maxFit = fitnessLevels[l];
          bestIndividual = population[l];
          if (maxFit > totalMaxFit) {
            totalMaxFit = maxFit;
          }
        }
      }

      // clone population
      var tmpPopulation = population.slice(0);

      // selection
      for(var l = 0; l < population.length; l += 2) {
        var ind1 = this.selection(fitnessLevels);
        var ind2 = this.selection(fitnessLevels);
        // crossover
        if (Math.random() < this.CROSSOVER_PROBABILITY) {
          var chromePair        = this.cross(population[ind1], population[ind2]);
          tmpPopulation[l]      = chromePair[0];
          tmpPopulation[l + 1]  = chromePair[1];
        } else {
          tmpPopulation[l]      = population[ind1];
          tmpPopulation[l + 1]  = population[ind2];
        }
        // mutation
        tmpPopulation[l]    = this.mutate(tmpPopulation[l]);
        tmpPopulation[l+1]  = this.mutate(tmpPopulation[l+1]);
      }

      if(fitnessLevels[bestIndex] > this.POOR_MAX_FITNESS){
        // elitism
        for(l = 0; l < this.ELITISM_DEGREE; l++) {
          tmpPopulation[l] = bestIndividual;
        }
      }

      // replace old population
      population = tmpPopulation;
    }

    var nextGeneration = this.translatePopulation(population, enemyGroup, game, target, spawnPositions);
    console.log('GA: Returning the new generation!');
    return nextGeneration;
  },

  /**
  * Generates a group of enemy sprites with some default values.
  *
  * @method Darwinator.GeneticAlgorithm#initPopulation
  * @param {Phaser.Group} [enemyGroup] - The enemy group to fill with enemies.
  * @param {Phaser.Game} [game] - The game that uses the algorithm.
  * @param {Phaser.Sprite} [target] - The sprite to be attacked by the enemies.
  * @param {Array} [spawnPositions] - The positions on which the enemies are allowed to spawn.
  * @return {Array} An enemy population with default attribute values.
  */
  initPopulation: function(enemyGroup, game, target, spawnPositions) {
    // 4 different enemy initial set of attributes - just an example, not permanent!
    var enemiesPerType  = this.POPULATION_SIZE / 5;
    var pos;
    var strength, agility, intellect;
    for(var i = 0; i < this.POPULATION_SIZE; i++){
      pos = spawnPositions[i % spawnPositions.length];
      if(i < enemiesPerType){
        // smart but slow and weak
        strength  = 0;
        agility   = 0;
        intellect = this.variableRange;
      }else if(i < enemiesPerType*2){
        // strong but slow and stupid
        strength  = this.variableRange;
        agility   = 0;
        intellect = 0;
      }else if(i < enemiesPerType*3){
        // fast but weak and stupid
        strength  = 0;
        agility   = this.variableRange;
        intellect = 0;
      }else{
        // hybrid
        strength  = agility = intellect = Math.round(this.variableRange / 3);
      }
      enemyGroup.add(new Darwinator.Enemy(game, target, pos.x, pos.y, undefined, strength, agility, intellect));
    }
    return enemyGroup;
  },

  /**
  * Cross two individuals to create two new ones by performing a tradeoff between
  * two randomly selected genes in each individual.
  *
  * Example: Select index of x and y.
  * First individual: decrease x and increase y
  * Second individual: decrease y and increase x
  *
  * @method Darwinator.GeneticAlgorithm#cross
  * @param {Array} [firstInd] - The first individual to be crossed
  * @param {Array} [secondInd] - The second individual to be crossed
  * @return {Array} - A tuple containing the two new individuals.
  */
  cross: function(firstInd, secondInd) {
    var crossPoint1 = Math.round(Math.random()*(this.NUMBER_OF_GENES - 1));
    var crossPoint2 = Math.round(Math.random()*(this.NUMBER_OF_GENES - 1));

    var tradeOff        = Math.random();
    var tradeOffAmount1 = Math.round(tradeOff * firstInd[crossPoint1]);
    var tradeOffAmount2 = Math.round(tradeOff * secondInd[crossPoint2]);

    var newInd1 = firstInd.slice(0);
    var newInd2 = secondInd.slice(0);

    newInd1[crossPoint1] -= tradeOffAmount1;
    newInd1[crossPoint2] += tradeOffAmount1;

    newInd2[crossPoint2] -= tradeOffAmount2;
    newInd2[crossPoint1] += tradeOffAmount2;

    return [newInd1, newInd2];
  },

  /**
  * Select a individual based on the fitness levels of the entire population.
  * this.TOURNAMENT_SIZE many individuals will be selected at random, and one of them will
  * be returned. The tournament works in such a way that a individual with a high fitness level
  * is more likely to be returned from the tournament, but is not more likely to participate.
  *
  * @method Darwinator.GeneticAlgorithm#selection
  * @param {Array} - The fitness levels of the entire population
  * @return {Number} - The index of the selected individual.
  */
  selection: function(fitnessLevels) {
    var tournamentParticipants = new Array(this.TOURNAMENT_SIZE);

    /* Select individuals at random, and represent them as a touple containing their indexes and their
    * fitness levels. */
    for (var i = 0; i < this.TOURNAMENT_SIZE; i++) {
      tournamentParticipants[i]    = new Array(2);
      tournamentParticipants[i][0] = Math.round(Math.random() * (this.POPULATION_SIZE - 1));
      tournamentParticipants[i][1] = fitnessLevels[tournamentParticipants[i][0]];
    }

    /* Sort by fitness levels */
    tournamentParticipants.sort(
      function(a,b) {return b[1]-a[1];}
    );

    for(i = 0; i < this.TOURNAMENT_SIZE; i++) {
      if (Math.random() < this.TOURNAMENT_PARAMETER) {
        return tournamentParticipants[i][0];
      }
    }

    return tournamentParticipants[i - 1][0];
  },

  /**
  * Mutate a given individual by performing a tradeoff between two randomly selected genes.
  *
  * @method Darwinator.GeneticAlgorithm#mutate
  * @param {Array} - The individual to be mutated
  * @return {Array} - The mutated individual.
  */
  mutate: function(individual) {
    if (Math.random() < this.MUTATION_PROBABILITY * this.mutationRate) {
      var gene1 = Math.round(Math.random()*(this.NUMBER_OF_GENES - 1));
      var gene2 = Math.round(Math.random()*(this.NUMBER_OF_GENES - 1));
      var tradeOffAmount = Math.round(Math.random() * individual[gene1]);

      individual[gene1] -= tradeOffAmount;
      individual[gene2] += tradeOffAmount;
    }
    return individual;
  },

  /**
  * Evaluates an individual based on the given target function.
  * A higher target function value will give a higher fitness.
  *
  * @method Darwinator.GeneticAlgorithm#evaluateInd
  * @param {Array} - The individual to be evaluated
  * @return {Number} - The fitness level of the individual
  */
  evaluateInd: function(individual, targetFunction) {
    var fitness = 1 - (1 / targetFunction(individual));
    return fitness == -Infinity ? 0 : fitness;
  }

};
<|endoftext|>