<commit_before>exports.setup = function(Tests){

var channel = function(){
	return '/' + (+new Date);
};

Tests.describe('Planet API: Connection', function(it){

	it('should send an `initial_state` message after connect', function(expect){
		expect.perform(2);
		var socket = io.connect(null, {'force new connection': 1});
		socket.addListener('message', function(data){
			data = JSON.parse(data);
			//console.log(data);
			expect(data.type).toBe('initial_state');
			expect(data.payload).toBeType('object');
			this.disconnect();
		});

	});

});

Tests.describe('Planet API: Locks', function(it){

	it('should lock components', function(expect){
		expect.perform(1);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			console.log('connected!!');
			socket.send(JSON.stringify({
				type: 'state_update',
				payload: {
					component: 'component-x',
					payload: 999
				}
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type != 'lock_error') return;
			expect(data.payload).toBe('component-x');
			this.disconnect();
		});

	});

	it('should return a lock for unlocked components', function(expect){
		expect.perform(1);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			socket.send(JSON.stringify({
				type: 'acquire_lock',
				payload: 'component-y'
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type != 'lock_acquired') return;
			expect(data.payload).toBe('component-y');
			this.disconnect();
		});

	});

	it('should return an acquire_lock_error for locked components', function(expect){
		expect.perform(2);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'acquire_lock_error') return;
				expect(data.payload).toBeType('object');
				expect(data.payload.component).toBe('component-g');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-g'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_acquired') return;
				client.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-g'
				}));
			});

		});

	});

	it('should unlock components', function(expect){
		expect.perform(1);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_acquired') return;
				expect(data.payload).toBe('component-h');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-h'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type == 'lock_acquired'){
					socket.send(JSON.stringify({
						type: 'release_lock',
						payload: 'component-h'
					}));
				} else if (data.type == 'lock_released'){
					client.send(JSON.stringify({
						type: 'acquire_lock',
						payload: 'component-h'
					}));
				}
			});

		});

	});

	it('should broadcast locks', function(expect){
		expect.perform(1);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_component') return;
				expect(data.payload).toBe('component-z');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-z'
				}));
			});

		});

	});

	it('should broadcast unlocks', function(expect){
		expect.perform(1);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'release_component') return;
				expect(data.payload).toBe('component-i');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-i'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type == 'lock_acquired'){
					socket.send(JSON.stringify({
						type: 'release_lock',
						payload: 'component-i'
					}));
				}
			});

		});

	});

});

Tests.describe('Planet API: Updates', function(it){

	it('should echo a state_update message', function(expect){
		expect.perform(2);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			socket.send(JSON.stringify({
				type: 'acquire_lock',
				payload: 'component-x'
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type == 'lock_acquired' && data.payload == 'component-x'){
				socket.send(JSON.stringify({
					type: 'state_update',
					payload: {
						component: 'component-x',
						payload: 999
					}
				}));
			} else if (data.type == 'state_update'){
				expect(data.payload).toBeType('object');
				expect(data.payload['component-x']).toBe(999);
				this.disconnect();
			}
		});

	});

	it('it should broacast messages to all connected clients', function(expect){
		expect.perform(2);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type == 'state_update'){
					expect(data.payload).toBeType('object');
					expect(data.payload['component-x']).toBe(5050);
					this.disconnect();
					socket.disconnect();
				}
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-x'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type == 'lock_acquired' && data.payload == 'component-x'){
					socket.send(JSON.stringify({
						type: 'state_update',
						payload: {
							component: 'component-x',
							payload: 5050
						}
					}));
				}
			});

		});

	});

	it('should send back an `update_error` message for incorrect `state_update` requests', function(expect){
		expect.perform(1);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			socket.send(JSON.stringify({
				type: 'acquire_lock',
				payload: 'component-x'
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type == 'lock_acquired' && data.payload == 'component-x'){
				socket.send(JSON.stringify({
					type: 'state_update',
					payload: {
						name: 'component-x',
						payload: 999
					}
				}));
			} else if (data.type == 'update_error'){
				expect(data.payload).toBe(null);
				this.disconnect();
			}
		});

	});

});

Tests.describe('Planet API: Attempted Updates', function(it){

	it('should allow for attempted updates', function(expect){
		expect.perform(1);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			socket.send(JSON.stringify({
				type: 'attempt_update',
				payload: {
					component: 'component-u',
					payload: 999
				}
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type != 'state_update') return;
			expect(data.payload['component-u']).toBe(999);
			this.disconnect();
		});

	});

	it('should return a lock_error for locked components.', function(expect){
		expect.perform(1);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_error') return;
				expect(data.payload).toBe('component-y');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-y'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_acquired') return;
				client.send(JSON.stringify({
					type: 'attempt_update',
					payload: {
						component: 'component-y',
						payload: 123
					}
				}));
			});

		});

	});

});

};
<commit_msg>minor test changes<commit_after>exports.setup = function(Tests){

var channel = function(){
	return '/' + (+new Date);
};

Tests.describe('Planet API: Connection', function(it){

	it('should send an `initial_state` message after connect', function(expect){
		expect.perform(2);
		var socket = io.connect(null, {'force new connection': 1});
		socket.addListener('message', function(data){
			data = JSON.parse(data);
			expect(data.type).toBe('initial_state');
			expect(data.payload).toBeType('object');
			this.disconnect();
		});

	});

});

Tests.describe('Planet API: Locks', function(it){

	it('should lock components', function(expect){
		expect.perform(1);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			socket.send(JSON.stringify({
				type: 'state_update',
				payload: {
					component: 'component-x',
					payload: 999
				}
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type != 'lock_error') return;
			expect(data.payload).toBe('component-x');
			this.disconnect();
		});

	});

	it('should return `lock_acquired` for unlocked components', function(expect){
		expect.perform(1);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			socket.send(JSON.stringify({
				type: 'acquire_lock',
				payload: 'component-y'
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type != 'lock_acquired') return;
			expect(data.payload).toBe('component-y');
			this.disconnect();
		});

	});

	it('should return an `acquire_lock_error` for locked components', function(expect){
		expect.perform(2);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'acquire_lock_error') return;
				expect(data.payload).toBeType('object');
				expect(data.payload.component).toBe('component-g');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-g'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_acquired') return;
				client.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-g'
				}));
			});

		});

	});

	it('should unlock components', function(expect){
		expect.perform(1);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_acquired') return;
				expect(data.payload).toBe('component-h');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-h'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type == 'lock_acquired'){
					socket.send(JSON.stringify({
						type: 'release_lock',
						payload: 'component-h'
					}));
				} else if (data.type == 'lock_released'){
					client.send(JSON.stringify({
						type: 'acquire_lock',
						payload: 'component-h'
					}));
				}
			});

		});

	});

	it('should broadcast locks', function(expect){
		expect.perform(1);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_component') return;
				expect(data.payload).toBe('component-z');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-z'
				}));
			});

		});

	});

	it('should broadcast unlocks', function(expect){
		expect.perform(1);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'release_component') return;
				expect(data.payload).toBe('component-i');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-i'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type == 'lock_acquired'){
					socket.send(JSON.stringify({
						type: 'release_lock',
						payload: 'component-i'
					}));
				}
			});

		});

	});

});

Tests.describe('Planet API: Updates', function(it){

	it('should echo a `state_update` message', function(expect){
		expect.perform(2);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			socket.send(JSON.stringify({
				type: 'acquire_lock',
				payload: 'component-x'
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type == 'lock_acquired' && data.payload == 'component-x'){
				socket.send(JSON.stringify({
					type: 'state_update',
					payload: {
						component: 'component-x',
						payload: 999
					}
				}));
			} else if (data.type == 'state_update'){
				expect(data.payload).toBeType('object');
				expect(data.payload['component-x']).toBe(999);
				this.disconnect();
			}
		});

	});

	it('it should broacast `state_update` data to all connected clients', function(expect){
		expect.perform(4);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type == 'state_update'){
					expect(data.payload).toBeType('object');
					expect(data.payload['component-x']).toBe(5050);
					this.disconnect();
				}
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-x'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type == 'lock_acquired' && data.payload == 'component-x'){
					socket.send(JSON.stringify({
						type: 'state_update',
						payload: {
							component: 'component-x',
							payload: 5050
						}
					}));
				} else if (data.type == 'state_update'){
					expect(data.payload).toBeType('object');
					expect(data.payload['component-x']).toBe(5050);
					this.disconnect();
				}
			});

		});

	});

	it('should send back an `update_error` message for incorrect `state_update` requests', function(expect){
		expect.perform(1);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			socket.send(JSON.stringify({
				type: 'acquire_lock',
				payload: 'component-x'
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type == 'lock_acquired' && data.payload == 'component-x'){
				socket.send(JSON.stringify({
					type: 'state_update',
					payload: {
						//name: 'component-x', // wrong or no key
						payload: 999
					}
				}));
			} else if (data.type == 'update_error'){
				expect(data.payload).toBe(null);
				this.disconnect();
			}
		});

	});

});

Tests.describe('Planet API: Attempted Updates', function(it){

	it('should allow for attempted updates', function(expect){
		expect.perform(1);
		var socket = io.connect(null, {'force new connection': 1});

		socket.addListener('connect', function(){
			socket.send(JSON.stringify({
				type: 'attempt_update',
				payload: {
					component: 'component-u',
					payload: 999
				}
			}));
		});

		socket.addListener('message', function(data){
			data = JSON.parse(data);
			if (data.type != 'state_update') return;
			expect(data.payload['component-u']).toBe(999);
			this.disconnect();
		});

	});

	it('should return a `lock_error` for locked components.', function(expect){
		expect.perform(1);

		var socket, client = io.connect(null, {'force new connection': 1});
		client.addListener('connect', function(){

			client.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_error') return;
				expect(data.payload).toBe('component-y');
				this.disconnect();
				socket.disconnect();
			});

			socket = io.connect(null, {'force new connection': 1});
			socket.addListener('connect', function(){
				socket.send(JSON.stringify({
					type: 'acquire_lock',
					payload: 'component-y'
				}));
			});

			socket.addListener('message', function(data){
				data = JSON.parse(data);
				if (data.type != 'lock_acquired') return;
				client.send(JSON.stringify({
					type: 'attempt_update',
					payload: {
						component: 'component-y',
						payload: 123
					}
				}));
			});

		});

	});

});

};
<|endoftext|>


<commit_before>/*
* mvcApp
* author: ronglin
* create date: 2014.6.24
*/

'use strict';

var path = require('path'),
    utils = require('./utilities'),
	mvcAreas = require('./mvcAreas'),
    mvcController = require('./mvcController'),
    mvcAttributes = require('./attributes/$index'),
    mvcViewEngines = require('./mvcViewEngines'),
    mvcHandler = require('./mvcHandler'),
    mvcHandlerRouter = require('./mvcHandlerRouter');

var caching = require('./caching'),
    cachingStore = require('./cachingStore');

var midError = require('./middles/error'),
    midHeader = require('./middles/header'),
    midRequest = require('./middles/request'),
    midResponse = require('./middles/response');

var bodyParser = require('body-parser'),
    cookieParser = require('cookie-parser');

var mvcApp = function(set) {
    utils.extend(this, set);
    if (!this.appPath) { throw new Error('Parameter "appPath" is required'); }
    //
    this._handlers = new mvcHandlerRouter();
    this._setts = caching.region('mvc-runtime-settings');
    this._setts.set('env', process.env.NODE_ENV || 'development');
    //
    this.areas = new mvcAreas(this);
    this.engines = new mvcViewEngines();
    this.attributes = new mvcAttributes();
};

mvcApp.prototype = {

    _setts: null, _handlers: null, _inited: null,

    appPath: null, areas: null, engines: null, attributes: null,

    constructor: mvcApp, className: 'mvcApp',

    /*
    * get app setting
    */
    get: function(key) {
        return this._setts.get(key);
    },

    /*
    * set app setting
    */
    set: function(key, val) {
        return this._setts.set(key, val);
    },

    /*
    * use(handler)
    * use(routeExp, handler)
    * use(routeExp, name, handler)
    */
    use: function() {
        return this._handlers.register.apply(this._handlers, arguments);
    },

    /*
    * disuse(name)
    */
    disuse: function() {
        return this._handlers.unregister.apply(this._handlers, arguments);
    },

    /*
    * mapPath('~/xx')
    *
    * TODO:
    * mapPath('/xx')
    * mapPath('./xx')
    * mapPath('../xx')
    */
    mapPath: function(relPath) {
        if (!relPath) { return this.appPath; }
        if (relPath.charAt(0) === '~') { relPath = relPath.substr(1); }
        relPath = relPath.replace(/\/|\\/g, path.sep);
        return path.join(this.appPath, relPath);
    },

    /*
    * 1. initialize
    * 2. return the web server handler
    */
    handler: function () {
        //
        var handlers = this._handlers;
        if (this._inited !== true) {
            this._inited = true;
            //
            handlers.register(bodyParser.json());
            handlers.register(bodyParser.json({ type: 'application/hal+json' }));
            handlers.register(bodyParser.urlencoded({ extended: true }));
            handlers.register(cookieParser());
            //
            handlers.register('/', 'midHeader', midHeader());
            handlers.register('/', 'midRequest', midRequest());
            handlers.register('/', 'midResponse', midResponse());
            handlers.registerAtLast('/', 'midError', midError());
            //
            handlers.register(mvcHandler(this));
            //
            this.engines.register('.vash', require('./engines/vash'));
            this.attributes.registerAll();
            this.areas.registerAll(); // user code always focus on the controllers, so register at last
        }
        //
        return function(req, res) {
            handlers.execute(req, res);
        };
    }
};

// export
module.exports = {
    utils: utils,
    caching: caching,
    controller: mvcController.define,
    current: null,
    gainApp: function(set) {
        return this.current ? this.current : (this.current = new mvcApp(set));
    }
};
<commit_msg>export mvcActionResult<commit_after>/*
* mvcApp
* author: ronglin
* create date: 2014.6.24
*/

'use strict';

var path = require('path'),
    utils = require('./utilities'),
	mvcAreas = require('./mvcAreas'),
    mvcController = require('./mvcController'),
    mvcActionResult = require('./mvcActionResult'),
    mvcAttributes = require('./attributes/$index'),
    mvcViewEngines = require('./mvcViewEngines'),
    mvcHandler = require('./mvcHandler'),
    mvcHandlerRouter = require('./mvcHandlerRouter');

var caching = require('./caching'),
    cachingStore = require('./cachingStore');

var midError = require('./middles/error'),
    midHeader = require('./middles/header'),
    midRequest = require('./middles/request'),
    midResponse = require('./middles/response');

var bodyParser = require('body-parser'),
    cookieParser = require('cookie-parser');

var mvcApp = function(set) {
    utils.extend(this, set);
    if (!this.appPath) { throw new Error('Parameter "appPath" is required'); }
    //
    this._handlers = new mvcHandlerRouter();
    this._setts = caching.region('mvc-runtime-settings');
    this._setts.set('env', process.env.NODE_ENV || 'development');
    //
    this.areas = new mvcAreas(this);
    this.engines = new mvcViewEngines();
    this.attributes = new mvcAttributes();
};

mvcApp.prototype = {

    _setts: null, _handlers: null, _inited: null,

    appPath: null, areas: null, engines: null, attributes: null,

    constructor: mvcApp, className: 'mvcApp',

    /*
    * get app setting
    */
    get: function(key) {
        return this._setts.get(key);
    },

    /*
    * set app setting
    */
    set: function(key, val) {
        return this._setts.set(key, val);
    },

    /*
    * use(handler)
    * use(routeExp, handler)
    * use(routeExp, name, handler)
    */
    use: function() {
        return this._handlers.register.apply(this._handlers, arguments);
    },

    /*
    * disuse(name)
    */
    disuse: function() {
        return this._handlers.unregister.apply(this._handlers, arguments);
    },

    /*
    * mapPath('~/xx')
    *
    * TODO:
    * mapPath('/xx')
    * mapPath('./xx')
    * mapPath('../xx')
    */
    mapPath: function(relPath) {
        if (!relPath) { return this.appPath; }
        if (relPath.charAt(0) === '~') { relPath = relPath.substr(1); }
        relPath = relPath.replace(/\/|\\/g, path.sep);
        return path.join(this.appPath, relPath);
    },

    /*
    * 1. initialize
    * 2. return the web server handler
    */
    handler: function () {
        //
        var handlers = this._handlers;
        if (this._inited !== true) {
            this._inited = true;
            //
            handlers.register(bodyParser.json());
            handlers.register(bodyParser.json({ type: 'application/hal+json' }));
            handlers.register(bodyParser.urlencoded({ extended: true }));
            handlers.register(cookieParser());
            //
            handlers.register('/', 'midHeader', midHeader());
            handlers.register('/', 'midRequest', midRequest());
            handlers.register('/', 'midResponse', midResponse());
            handlers.registerAtLast('/', 'midError', midError());
            //
            handlers.register(mvcHandler(this));
            //
            this.engines.register('.vash', require('./engines/vash'));
            this.attributes.registerAll();
            this.areas.registerAll(); // user code always focus on the controllers, so register at last
        }
        //
        return function(req, res) {
            handlers.execute(req, res);
        };
    }
};

// export
module.exports = {
    utils: utils,
    caching: caching,
    controller: mvcController.define,
    actionResults: mvcActionResult,
    current: null,
    gainApp: function(set) {
        return this.current ? this.current : (this.current = new mvcApp(set));
    }
};
<|endoftext|>


<commit_before>// ======== DB-Model: ========
// "_id"           -> ID
// "name"          -> String
// "short"         -> String
// "claim"         -> String
// "description"   -> String
// "createdby"     -> userId
// "time_created"  -> Date
// "time_lastedit" -> Date
// "members"       -> List of userIds
// ===========================

Groups = new Meteor.Collection("Groups");
GroupLib = {};

/* Find groups for given filters
 *
 * filter: dictionary with filter options
 *   own: Limit to groups where logged-in user is a member
 *   user: Limit to groups where given user ID is a member (client only)
 *
 */
GroupLib.find = function(filter, limit) {
	var find = {};

	if (filter.own) {
		var me = Meteor.userId();
		if (!me) return []; // I don't exist? How could I be in a group?!

		find.members = me;
	}

	// If the property is set but falsy, we don't return anything
	if (filter.hasOwnProperty('user')) {
		if (!filter.user) return [];
		find.members = filter.user;
	}

	return Groups.find(find);
};

GroupLib.isMember = function(userId, groupId) {
	check(userId, String);
	check(groupId, String);
	return Groups.find({
		_id: groupId,
		members: userId
	}).count() > 0;
};

Meteor.methods({
	saveGroup: function(groupId, changes) {
		check(groupId, String);
		check(changes, {
			short:         Match.Optional(String),
			name:          Match.Optional(String),
			claim:         Match.Optional(String),
			description:   Match.Optional(String),
			logoUrl:       Match.Optional(String),
			backgroundUrl: Match.Optional(String),
		});

		var userId = Meteor.userId();
		if (!userId) throw new Meteor.Error(401, "please log-in");

		var isNew = groupId === 'create';

		// Load group from DB
		var group;
		if (isNew) {
			// Saving user is added as first member of the group
			group = {
				members: [userId]
			};
		} else {
			group = Groups.findOne(groupId);
			if (!group) throw new Meteor.Error(404, "Group not found");
		}

		// User must be member of group to edit it
		if (!isNew && !GroupLib.isMember(Meteor.userId(), group._id)) {
			throw new Meteor.Error(401, "Denied");
		}

		var updates = {};
		if (changes.short !== undefined) {
			var short = changes.short.trim();
			if (short.length === 0) {
				short = ''+(group.name || changes.name);
			}
			updates.short = short.substring(0, 7);
		}
		if (changes.hasOwnProperty('name')) {
			updates.name = changes.name.substring(0, 50);
		}
		if (changes.hasOwnProperty('claim')) {
			updates.claim = changes.claim.substring(0, 1000);
		}
		if (changes.hasOwnProperty('description')) {
			updates.description = changes.description.substring(0, 640*1024);
			if (Meteor.isServer) {
				updates.description = saneHtml(updates.description);
			}
		}

		if (changes.hasOwnProperty('logoUrl')) {
			updates.logoUrl = changes.logoUrl.substring(0, 1000);
		}
		if (changes.hasOwnProperty('backgroundUrl')) {
			updates.backgroundUrl = changes.backgroundUrl.substring(0, 1000);
		}

		// Don't update nothing
		if (Object.getOwnPropertyNames(updates).length === 0) return;

		if (isNew) {
			groupId = Groups.insert(_.extend(group, updates));
			Meteor.call('user.updateBadges', userId);
		} else {
			Groups.update(group._id, { $set: updates });
		}

		return groupId;
	},

	updateGroupMembership: function(userId, groupId, join) {
		check(userId, String);
		check(groupId, String);

		var senderId = Meteor.userId();
		if (!senderId) return;

		// Only current members of the group may draft other people into it
		var sel = {
			_id: groupId,
			members: senderId
		};

		var user = Meteor.users.findOne({_id: userId});
		if (!user) throw new Meteor.Error(404, "User not found");

		var update;
		if (join) {
			update = { $addToSet: { 'members': user._id } };
		} else {
			update = { $pull: { 'members': user._id } };
		}

		Groups.update(sel, update);
		if (Meteor.isServer) Meteor.call('user.updateBadges', user._id);
	},

	/* Update listing of a course or an event in a group. */
	updateGroupListing: function(thingId, groupId, join) {
		check(thingId, String);
		check(groupId, String);

		var senderId = Meteor.userId();
		if (!senderId) return;

		// Only current members of the group may list courses into groups
		if (!GroupLib.isMember(senderId, groupId)) {
			throw new Meteor.Error(401, "Denied");
		}

		var update;
		if (join) {
			update = { $addToSet: { 'groups': groupId } };
		} else {
			update = { $pull: { 'groups': groupId } };
		}

		// Welcome to my world of platypus-typing
		// Because thing may either be a group or an event, we just try both!
		var changed = Courses.update(thingId, update)
		            + Events.update(thingId, update);

		if (changed !== 1) throw new Meteor.Error(500, "Query affected "+changed+" documents, expected 1");
	}
});<commit_msg>improve error handling and explain weird permission logic<commit_after>// ======== DB-Model: ========
// "_id"           -> ID
// "name"          -> String
// "short"         -> String
// "claim"         -> String
// "description"   -> String
// "createdby"     -> userId
// "time_created"  -> Date
// "time_lastedit" -> Date
// "members"       -> List of userIds
// ===========================

Groups = new Meteor.Collection("Groups");
GroupLib = {};

/* Find groups for given filters
 *
 * filter: dictionary with filter options
 *   own: Limit to groups where logged-in user is a member
 *   user: Limit to groups where given user ID is a member (client only)
 *
 */
GroupLib.find = function(filter, limit) {
	var find = {};

	if (filter.own) {
		var me = Meteor.userId();
		if (!me) return []; // I don't exist? How could I be in a group?!

		find.members = me;
	}

	// If the property is set but falsy, we don't return anything
	if (filter.hasOwnProperty('user')) {
		if (!filter.user) return [];
		find.members = filter.user;
	}

	return Groups.find(find);
};

GroupLib.isMember = function(userId, groupId) {
	check(userId, String);
	check(groupId, String);
	return Groups.find({
		_id: groupId,
		members: userId
	}).count() > 0;
};

Meteor.methods({
	saveGroup: function(groupId, changes) {
		check(groupId, String);
		check(changes, {
			short:         Match.Optional(String),
			name:          Match.Optional(String),
			claim:         Match.Optional(String),
			description:   Match.Optional(String),
			logoUrl:       Match.Optional(String),
			backgroundUrl: Match.Optional(String),
		});

		var userId = Meteor.userId();
		if (!userId) throw new Meteor.Error(401, "please log-in");

		var isNew = groupId === 'create';

		// Load group from DB
		var group;
		if (isNew) {
			// Saving user is added as first member of the group
			group = {
				members: [userId]
			};
		} else {
			group = Groups.findOne(groupId);
			if (!group) throw new Meteor.Error(404, "Group not found");
		}

		// User must be member of group to edit it
		if (!isNew && !GroupLib.isMember(Meteor.userId(), group._id)) {
			throw new Meteor.Error(401, "Denied");
		}

		var updates = {};
		if (changes.short !== undefined) {
			var short = changes.short.trim();
			if (short.length === 0) {
				short = ''+(group.name || changes.name);
			}
			updates.short = short.substring(0, 7);
		}
		if (changes.hasOwnProperty('name')) {
			updates.name = changes.name.substring(0, 50);
		}
		if (changes.hasOwnProperty('claim')) {
			updates.claim = changes.claim.substring(0, 1000);
		}
		if (changes.hasOwnProperty('description')) {
			updates.description = changes.description.substring(0, 640*1024);
			if (Meteor.isServer) {
				updates.description = saneHtml(updates.description);
			}
		}

		if (changes.hasOwnProperty('logoUrl')) {
			updates.logoUrl = changes.logoUrl.substring(0, 1000);
		}
		if (changes.hasOwnProperty('backgroundUrl')) {
			updates.backgroundUrl = changes.backgroundUrl.substring(0, 1000);
		}

		// Don't update nothing
		if (Object.getOwnPropertyNames(updates).length === 0) return;

		if (isNew) {
			groupId = Groups.insert(_.extend(group, updates));
			Meteor.call('user.updateBadges', userId);
		} else {
			Groups.update(group._id, { $set: updates });
		}

		return groupId;
	},

	updateGroupMembership: function(userId, groupId, join) {
		check(userId, String);
		check(groupId, String);

		var senderId = Meteor.userId();
		if (!senderId) throw new Meteor.Error("Not permitted");

		// Only current members of the group may draft other people into it
		// We build a selector that only finds the group if the sender is a
		// member of it.
		var sel = {
			_id: groupId,
			members: senderId
		};

		// This check is not strictly necessary when the update uses the same
		// selector. It generates an error message though, whereas the update is
		// blind to that.
		if (!Groups.findOne(sel)) throw new Meteor.Error("No permitted");

		var user = Meteor.users.findOne({_id: userId});
		if (!user) throw new Meteor.Error(404, "User not found");

		var update;
		if (join) {
			update = { $addToSet: { 'members': user._id } };
		} else {
			update = { $pull: { 'members': user._id } };
		}

		// By using the restrictive selector that checks group membership we can
		// avoid the unlikely race condition where a user is not member anymore
		// but can still add somebody else to the group.
		Groups.update(sel, update);

		if (Meteor.isServer) Meteor.call('user.updateBadges', user._id);
	},

	/* Update listing of a course or an event in a group. */
	updateGroupListing: function(thingId, groupId, join) {
		check(thingId, String);
		check(groupId, String);

		var senderId = Meteor.userId();
		if (!senderId) return;

		// Only current members of the group may list courses into groups
		if (!GroupLib.isMember(senderId, groupId)) {
			throw new Meteor.Error(401, "Denied");
		}

		var update;
		if (join) {
			update = { $addToSet: { 'groups': groupId } };
		} else {
			update = { $pull: { 'groups': groupId } };
		}

		// Welcome to my world of platypus-typing
		// Because thing may either be a group or an event, we just try both!
		var changed = Courses.update(thingId, update)
		            + Events.update(thingId, update);

		if (changed !== 1) throw new Meteor.Error(500, "Query affected "+changed+" documents, expected 1");
	}
});<|endoftext|>


<commit_before>import chai from 'chai';
import chaiJsonSchema from 'chai-json-schema';
import schemas from 'jsfile-schemas';
import JsFile from 'JsFile';
import OdfEngine from './../../src/index';

chai.use(chaiJsonSchema);
const assert = chai.assert;

describe('jsFile-odf', () => {
    let files;
    const documentSchema = schemas.document;

    before(() => {
        files = window.files;
    });

    it('should exist', () => {
        assert.isFunction(OdfEngine);
    });

    it('should read the file', function () {
        this.timeout(50000);
        const queue = [];
        let name;
        for (name in files) {
            if (files.hasOwnProperty(name)) {
                (function (file, name) {
                    const jf = new JsFile(file, {
                        workerPath: '/base/dist/workers/'
                    });
                    const promise = jf.read().then(done, done);
                    queue.push(promise);

                    function done (result) {
                        assert.instanceOf(result, JsFile.Document, name);
                        const json = result.json();
                        const html = result.html();
                        const text = html.textContent || '';
                        assert.jsonSchema(json, documentSchema, name);
                        assert.notEqual(text.length, 0, `File ${name} shouldn't be empty`);
                        assert.notEqual(result.name.length, 0, `Engine should parse a name of file ${name}`);

                        if (/MetaData/.test(name)) {
                            assert.isTrue(/Metadata Examples, 22 Aug 2007/.test(text), 'should parse h1');
                        }
                    }
                }(files[name], name));
            }
        }

        return Promise.all(queue);
    });
});
<commit_msg>update tests<commit_after>import chai from 'chai';
import chaiJsonSchema from 'chai-json-schema';
import schemas from 'jsfile-schemas';
import JsFile from 'JsFile';
import OdfEngine from './../../src/index';

chai.use(chaiJsonSchema);
const assert = chai.assert;

describe('jsFile-odf', () => {
    let files;
    const documentSchema = schemas.document;

    before(() => {
        files = window.files;
    });

    it('should exist', () => {
        assert.isFunction(OdfEngine);
    });

    it('should have files for testing', () => {
        assert.notEqual(Object.keys(files || {}).length, 0);
    });

    it('should read the file', function () {
        this.timeout(50000);
        const queue = [];
        let name;
        for (name in files) {
            if (files.hasOwnProperty(name)) {
                (function (file, name) {
                    const jf = new JsFile(file, {
                        workerPath: '/base/dist/workers/'
                    });
                    const promise = jf.read().then(done, done);
                    queue.push(promise);

                    function done (result) {
                        assert.instanceOf(result, JsFile.Document, name);
                        const json = result.json();
                        const html = result.html();
                        const text = html.textContent || '';
                        assert.jsonSchema(json, documentSchema, name);
                        assert.notEqual(text.length, 0, `File ${name} shouldn't be empty`);
                        assert.notEqual(result.name.length, 0, `Engine should parse a name of file ${name}`);

                        if (/MetaData/.test(name)) {
                            assert.isTrue(/Metadata Examples, 22 Aug 2007/.test(text), 'should parse h1');
                        }
                    }
                }(files[name], name));
            }
        }

        return Promise.all(queue);
    });
});
<|endoftext|>


<commit_before>/* globals document, window, history, define */
"use strict";

!function (name, context, definition) {
  if (typeof define == "function") define(definition);
  else if (typeof module != "undefined") module.exports = definition();
  else context[name] = definition();
}("mandlebrot", this, () => {
  // INIT CANVAS
  const canvas = document.getElementById("canvas");
  const canvasOverlay = document.getElementById("canvasOverlay");

  canvas.width  = window.innerWidth;
  canvas.height = window.innerHeight;
  canvasOverlay.width  = window.innerWidth;
  canvasOverlay.height = window.innerHeight;

  const ratio = canvas.width / canvas.height;

  const yMax = 1.2;
  const width = yMax * (canvas.width / canvas.height); // -2 to 2

  const overlayCtx = canvasOverlay.getContext("2d");
  overlayCtx.lineWidth = 3;
  overlayCtx.strokeStyle = "#FF00FF";
  const ctx = canvas.getContext("2d");
  const imgData = ctx.createImageData(canvas.width, 1);

  const helpers = {
    getEl(id) {
      return document.getElementById(id);
    },

    getParams() {
      let params = window.location.search;
      const f = {};
      params.replace("?", "")
            .split("&")
            .map((p) => p.split("="))
            .forEach((p) => f[p[0]] = p[1]);
      return f;
    },

    getValue(param, value, fallback) {
      const params = helpers.getParams();
      return params[param] || value || fallback;
    },

    getBoolean(value) {
      if (typeof value === "string") return value == "true";
      return value;
    }
  };

  const paramMap = {
    maxIterations: "mi",
    escapeRadius: "er",
    color: "co",
    julia: "j",
    ci: "ci",
    cr: "cr",
    left: "l",
    top: "t",
    right: "r",
    bottom: "b"
  };

  const m = {
    y_interval() {
      return Math.abs(m.state.top - m.state.bottom) / canvasOverlay.height;
    },
    x_interval() {
      return Math.abs(m.state.left - m.state.right) / canvasOverlay.width;
    },
    state: {
      maxIterations: parseInt(helpers.getValue("mi", helpers.getEl("maxIterations").value, 50)),
      escapeRadius: parseInt(helpers.getValue("er", helpers.getEl("escapeRadius").value, 5)),
      color: helpers.getBoolean(helpers.getValue("co", helpers.getEl("color").checked, false)),
      julia: helpers.getBoolean(helpers.getValue("j", helpers.getEl("julia").checked, false)),
      ci: parseFloat(helpers.getValue("ci", 0.745)),
      cr: parseFloat(helpers.getValue("cr", -0.123)),
      left: parseFloat(helpers.getValue("l", -width)),
      top: parseFloat(helpers.getValue("t", yMax)),
      right: parseFloat(helpers.getValue("r", width)),
      bottom: parseFloat(helpers.getValue("b", -yMax))
    },
    ctx,
    overlayCtx,
    imgData,
    yPixel: 0, // the Y value of the canvas row we are on, used to track how close we are to being done
    numUpdates: 0, // used for batch updating to only update DOM once per tick
    y: parseFloat(helpers.getValue("t", yMax)), // the max y value of the complex plane
    lastUpdatedAt: 0, // for tracking render time
    totalTime: document.getElementById("totalTime"),

    // https://gist.github.com/mjackson/5311256#file-color-conversion-algorithms-js-L119
    hsvToRgb(h, s, v) {
      let r, g, b;

      const i = Math.floor(h * 6);
      const f = h * 6 - i;
      const p = v * (1 - s);
      const q = v * (1 - f * s);
      const 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;
      }

      return [ r * 255, g * 255, b * 255 ];
    },

    getColor(iterations) {
      // smooth color by adjusting iteration count
      const n = iterations.number - Math.log2(Math.log2(iterations.absoluteValue));

      // grayscale
      if (!m.state.color) {
        const value = 255 - (n / m.state.maxIterations * 255);
        return [value, value, value];
      }

      // color
      if (n >= m.state.maxIterations - 1) return [0, 0, 0]; // return black if in fractal

      const value = n / m.state.maxIterations;

      // adjusting hue and value to make colors look better (blue only)
      return m.hsvToRgb(.5 + value / 2, 1, 1 - value);
    },

    getIterations(real, imaginary) {
      let Zr = m.state.julia ? real : 0,
          Zi = m.state.julia ? imaginary : 0,
          tempR,
          tempI,
          n = 0,
          abs = 0,
          Cr = m.state.julia ? m.state.cr : real,
          Ci = m.state.julia ? m.state.ci : imaginary;

      for ( ; n < m.state.maxIterations && abs <= m.state.escapeRadius; n++) {
        tempR = Math.pow(Zr, 2) - Math.pow(Zi, 2) + Cr;
        tempI = 2 * Zr * Zi + Ci;

        Zr = tempR;
        Zi = tempI;
        abs = Math.sqrt(Math.pow(Zr, 2) + Math.pow(Zi, 2));
      }

      return { number: n, absoluteValue: abs };
    },

    updateProgressLine(yPixel) {
      m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);

      if (yPixel) {
        m.overlayCtx.beginPath();
        m.overlayCtx.moveTo(0, yPixel);
        m.overlayCtx.lineTo(canvasOverlay.width, yPixel);
        m.overlayCtx.stroke();
      }
    },

    drawSingleLine(x) {
      let offset = 0;
      const x_interval = m.x_interval();
      // build line of pixel data to render
      for(; x <= m.state.right; x += x_interval) {
        const iterations = m.getIterations(x, m.y);
        const color = m.getColor(iterations);

        m.imgData.data[offset++] = color[0];
        m.imgData.data[offset++] = color[1];
        m.imgData.data[offset++] = color[2];
        m.imgData.data[offset++] = 255;
      }
    },

    draw() {
      if (!m.startTime) m.startTime = Date.now();
      m.yPixel++; // update canvas row we are on for this iteration

      m.drawSingleLine(m.state.left);
      m.ctx.putImageData(imgData, 0, m.yPixel);
      const y_interval = m.y_interval();
      m.y -= y_interval;

      if (m.yPixel <= window.innerHeight) {
        // not done, keep drawing
        if (Date.now() - m.lastUpdatedAt > 200) {
          // throttle updating DOM
          m.lastUpdatedAt = Date.now();
          m.updateProgressLine(m.yPixel);
          // go to next tick so DOM can update
          setTimeout(m.draw, 0);
        } else {
          m.draw();
        }
      } else {
        // done drawing, reset
        m.y = m.state.top;
        m.lastUpdatedAt = 0;
        m.yPixel = 0;
        m.updateProgressLine();
        m.totalTime.textContent = `${(Date.now() - m.startTime) / 1000}s`; // TODO make this state change?
        m.startTime = null;
      }
    },

    getParams() {
      const params = [];
      for (let key in m.state) {
        params.push(`${paramMap[key]}=${m.state[key]}`);
      }

      return `?${params.join("&")}`;
    },

    pushState(replace) {
      if (replace) {
        history.replaceState(m.state, "Mandelbrot",  m.getParams());
      } else {
        history.pushState(m.state, "Mandelbrot", m.getParams());
      }
    },

    onPopState(e) {
      // TODO do I really need this as separate method?
      m.setState(e.state, null, true);
      m.y = e.state.top;
    },

    render(noPushState) {
      if (m.numUpdates !== 0) m.numUpdates--; // only reduce if we've qeued up some updates

      if (m.numUpdates === 0) { // wait till all updates are made
        // update DOM
        for (let prop in m.state) {
          const el = helpers.getEl(prop);
          if (el) {
            const value = m.state[prop];
            if (typeof value === "boolean") {
              el.checked = value;
            } else {
              el.value = value;
            }
          }
        }
        m.draw();
        if (!noPushState) m.pushState();
      }
    },

    setState(id, value, noPushState) {
      if (typeof id === "string") {
        m.numUpdates++;
        m.state[id] = value;

        setTimeout(m.render.bind(this, noPushState), 0);
      } else {
        // object
        for (let prop in id) {
          m.setState(prop, id[prop], noPushState);
        }
      }
    },

    bindListeners() {
      window.addEventListener("popstate", m.onPopState);

      // INPUT CONTROLS
      helpers.getEl("maxIterations").addEventListener("change", (e) => m.setState("maxIterations", parseInt(e.target.value)));
      helpers.getEl("escapeRadius").addEventListener("change", (e) => m.setState("escapeRadius", parseInt(e.target.value)));
      helpers.getEl("color").addEventListener("change", (e) => m.setState("color", e.target.checked));
      helpers.getEl("julia").addEventListener("change", (e) => m.setState("julia", e.target.checked));
      helpers.getEl("ci").addEventListener("change", (e) => m.setState("ci", parseFloat(e.target.value)));
      helpers.getEl("cr").addEventListener("change", (e) => m.setState("cr", parseFloat(e.target.value)));

      // DRAG ZOOMING
      let zoomBox = null;

      ["mousedown", "touchstart"].forEach((downEvent) => {
        canvasOverlay.addEventListener(downEvent, (e) => {
          zoomBox = [e.clientX, e.clientY, 0, 0];
        });
      });

      ["mousemove", "touchmove"].forEach((moveEvent) => {
        canvasOverlay.addEventListener(moveEvent, (e) => {
          if (zoomBox) {
            // clear out old box first
            m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);

            // draw new box keeping aspect ratio
            zoomBox[2] = e.clientX;
            zoomBox[3] = zoomBox[1] + ((e.clientX - zoomBox[0]) / ratio);

            m.overlayCtx.strokeRect(zoomBox[0], zoomBox[1], zoomBox[2] - zoomBox[0], zoomBox[3] - zoomBox[1]);
          }
        });
      });

      ["mouseup", "touchend"].forEach((upEvent) => {
        canvasOverlay.addEventListener(upEvent, () => {
          m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);
          const x_interval = m.x_interval();
          const y_interval = m.y_interval();
          const top = m.state.top - y_interval * zoomBox[1];

          m.y = top;

          m.setState({
            right: m.state.left + x_interval * zoomBox[2],
            left: m.state.left + x_interval * zoomBox[0],
            bottom: m.state.top - y_interval * zoomBox[3],
            top
          });

          zoomBox = null;
        });
      });
    },

    init() {
      m.bindListeners();
      m.render(true);
      m.pushState(true);
    }
  };

  return {
    helpers,
    m
  };
});
<commit_msg>change coloring<commit_after>/* globals document, window, history, define */
"use strict";

!function (name, context, definition) {
  if (typeof define == "function") define(definition);
  else if (typeof module != "undefined") module.exports = definition();
  else context[name] = definition();
}("mandlebrot", this, () => {
  // INIT CANVAS
  const canvas = document.getElementById("canvas");
  const canvasOverlay = document.getElementById("canvasOverlay");

  canvas.width  = window.innerWidth;
  canvas.height = window.innerHeight;
  canvasOverlay.width  = window.innerWidth;
  canvasOverlay.height = window.innerHeight;

  const ratio = canvas.width / canvas.height;

  const yMax = 1.2;
  const width = yMax * (canvas.width / canvas.height); // -2 to 2

  const overlayCtx = canvasOverlay.getContext("2d");
  overlayCtx.lineWidth = 3;
  overlayCtx.strokeStyle = "#FF00FF";
  const ctx = canvas.getContext("2d");
  const imgData = ctx.createImageData(canvas.width, 1);

  const helpers = {
    getEl(id) {
      return document.getElementById(id);
    },

    getParams() {
      let params = window.location.search;
      const f = {};
      params.replace("?", "")
            .split("&")
            .map((p) => p.split("="))
            .forEach((p) => f[p[0]] = p[1]);
      return f;
    },

    getValue(param, value, fallback) {
      const params = helpers.getParams();
      return params[param] || value || fallback;
    },

    getBoolean(value) {
      if (typeof value === "string") return value == "true";
      return value;
    }
  };

  const paramMap = {
    maxIterations: "mi",
    escapeRadius: "er",
    color: "co",
    julia: "j",
    ci: "ci",
    cr: "cr",
    left: "l",
    top: "t",
    right: "r",
    bottom: "b"
  };

  const m = {
    y_interval() {
      return Math.abs(m.state.top - m.state.bottom) / canvasOverlay.height;
    },
    x_interval() {
      return Math.abs(m.state.left - m.state.right) / canvasOverlay.width;
    },
    state: {
      maxIterations: parseInt(helpers.getValue("mi", helpers.getEl("maxIterations").value, 50)),
      escapeRadius: parseInt(helpers.getValue("er", helpers.getEl("escapeRadius").value, 5)),
      color: helpers.getBoolean(helpers.getValue("co", helpers.getEl("color").checked, false)),
      julia: helpers.getBoolean(helpers.getValue("j", helpers.getEl("julia").checked, false)),
      ci: parseFloat(helpers.getValue("ci", 0.745)),
      cr: parseFloat(helpers.getValue("cr", -0.123)),
      left: parseFloat(helpers.getValue("l", -width)),
      top: parseFloat(helpers.getValue("t", yMax)),
      right: parseFloat(helpers.getValue("r", width)),
      bottom: parseFloat(helpers.getValue("b", -yMax))
    },
    ctx,
    overlayCtx,
    imgData,
    yPixel: 0, // the Y value of the canvas row we are on, used to track how close we are to being done
    numUpdates: 0, // used for batch updating to only update DOM once per tick
    y: parseFloat(helpers.getValue("t", yMax)), // the max y value of the complex plane
    lastUpdatedAt: 0, // for tracking render time
    totalTime: document.getElementById("totalTime"),

    // https://gist.github.com/mjackson/5311256#file-color-conversion-algorithms-js-L119
    hsvToRgb(h, s, v) {
      let r, g, b;

      const i = Math.floor(h * 6);
      const f = h * 6 - i;
      const p = v * (1 - s);
      const q = v * (1 - f * s);
      const 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;
      }

      return [ r * 255, g * 255, b * 255 ];
    },

    getColor(iterations) {
      // smooth color by adjusting iteration count
      const n = iterations.number - Math.log2(Math.log2(iterations.absoluteValue));

      // grayscale
      if (!m.state.color) {
        const value = 255 - (n / m.state.maxIterations * 255);
        return [value, value, value];
      }

      // color
      const value = n / m.state.maxIterations;

      // adjusting hue and value to make colors look better (blue only)
      // return m.hsvToRgb(.5 + value / 2, 1, 1 - value);
      return m.hsvToRgb(Math.abs(value), 1, 1 - value);
    },

    getIterations(real, imaginary) {
      let Zr = m.state.julia ? real : 0,
          Zi = m.state.julia ? imaginary : 0,
          tempR,
          tempI,
          n = 0,
          abs = 0,
          Cr = m.state.julia ? m.state.cr : real,
          Ci = m.state.julia ? m.state.ci : imaginary;

      for ( ; n < m.state.maxIterations && abs <= m.state.escapeRadius; n++) {
        tempR = Math.pow(Zr, 2) - Math.pow(Zi, 2) + Cr;
        tempI = 2 * Zr * Zi + Ci;

        Zr = tempR;
        Zi = tempI;
        abs = Math.sqrt(Math.pow(Zr, 2) + Math.pow(Zi, 2));
      }

      return { number: n, absoluteValue: abs };
    },

    updateProgressLine(yPixel) {
      m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);

      if (yPixel) {
        m.overlayCtx.beginPath();
        m.overlayCtx.moveTo(0, yPixel);
        m.overlayCtx.lineTo(canvasOverlay.width, yPixel);
        m.overlayCtx.stroke();
      }
    },

    drawSingleLine(x) {
      let offset = 0;
      const x_interval = m.x_interval();
      // build line of pixel data to render
      for(; x <= m.state.right; x += x_interval) {
        const iterations = m.getIterations(x, m.y);
        const color = m.getColor(iterations);

        m.imgData.data[offset++] = color[0];
        m.imgData.data[offset++] = color[1];
        m.imgData.data[offset++] = color[2];
        m.imgData.data[offset++] = 255;
      }
    },

    draw() {
      if (!m.startTime) m.startTime = Date.now();
      m.yPixel++; // update canvas row we are on for this iteration

      m.drawSingleLine(m.state.left);
      m.ctx.putImageData(imgData, 0, m.yPixel);
      const y_interval = m.y_interval();
      m.y -= y_interval;

      if (m.yPixel <= window.innerHeight) {
        // not done, keep drawing
        if (Date.now() - m.lastUpdatedAt > 200) {
          // throttle updating DOM
          m.lastUpdatedAt = Date.now();
          m.updateProgressLine(m.yPixel);
          // go to next tick so DOM can update
          setTimeout(m.draw, 0);
        } else {
          m.draw();
        }
      } else {
        // done drawing, reset
        m.y = m.state.top;
        m.lastUpdatedAt = 0;
        m.yPixel = 0;
        m.updateProgressLine();
        m.totalTime.textContent = `${(Date.now() - m.startTime) / 1000}s`; // TODO make this state change?
        m.startTime = null;
      }
    },

    getParams() {
      const params = [];
      for (let key in m.state) {
        params.push(`${paramMap[key]}=${m.state[key]}`);
      }

      return `?${params.join("&")}`;
    },

    pushState(replace) {
      if (replace) {
        history.replaceState(m.state, "Mandelbrot",  m.getParams());
      } else {
        history.pushState(m.state, "Mandelbrot", m.getParams());
      }
    },

    onPopState(e) {
      // TODO do I really need this as separate method?
      m.setState(e.state, null, true);
      m.y = e.state.top;
    },

    render(noPushState) {
      if (m.numUpdates !== 0) m.numUpdates--; // only reduce if we've qeued up some updates

      if (m.numUpdates === 0) { // wait till all updates are made
        // update DOM
        for (let prop in m.state) {
          const el = helpers.getEl(prop);
          if (el) {
            const value = m.state[prop];
            if (typeof value === "boolean") {
              el.checked = value;
            } else {
              el.value = value;
            }
          }
        }
        m.draw();
        if (!noPushState) m.pushState();
      }
    },

    setState(id, value, noPushState) {
      if (typeof id === "string") {
        m.numUpdates++;
        m.state[id] = value;

        setTimeout(m.render.bind(this, noPushState), 0);
      } else {
        // object
        for (let prop in id) {
          m.setState(prop, id[prop], noPushState);
        }
      }
    },

    bindListeners() {
      window.addEventListener("popstate", m.onPopState);

      // INPUT CONTROLS
      helpers.getEl("maxIterations").addEventListener("change", (e) => m.setState("maxIterations", parseInt(e.target.value)));
      helpers.getEl("escapeRadius").addEventListener("change", (e) => m.setState("escapeRadius", parseInt(e.target.value)));
      helpers.getEl("color").addEventListener("change", (e) => m.setState("color", e.target.checked));
      helpers.getEl("julia").addEventListener("change", (e) => m.setState("julia", e.target.checked));
      helpers.getEl("ci").addEventListener("change", (e) => m.setState("ci", parseFloat(e.target.value)));
      helpers.getEl("cr").addEventListener("change", (e) => m.setState("cr", parseFloat(e.target.value)));

      // DRAG ZOOMING
      let zoomBox = null;

      ["mousedown", "touchstart"].forEach((downEvent) => {
        canvasOverlay.addEventListener(downEvent, (e) => {
          zoomBox = [e.clientX, e.clientY, 0, 0];
        });
      });

      ["mousemove", "touchmove"].forEach((moveEvent) => {
        canvasOverlay.addEventListener(moveEvent, (e) => {
          if (zoomBox) {
            // clear out old box first
            m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);

            // draw new box keeping aspect ratio
            zoomBox[2] = e.clientX;
            zoomBox[3] = zoomBox[1] + ((e.clientX - zoomBox[0]) / ratio);

            m.overlayCtx.strokeRect(zoomBox[0], zoomBox[1], zoomBox[2] - zoomBox[0], zoomBox[3] - zoomBox[1]);
          }
        });
      });

      ["mouseup", "touchend"].forEach((upEvent) => {
        canvasOverlay.addEventListener(upEvent, () => {
          m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);
          const x_interval = m.x_interval();
          const y_interval = m.y_interval();
          const top = m.state.top - y_interval * zoomBox[1];

          m.y = top;

          m.setState({
            right: m.state.left + x_interval * zoomBox[2],
            left: m.state.left + x_interval * zoomBox[0],
            bottom: m.state.top - y_interval * zoomBox[3],
            top
          });

          zoomBox = null;
        });
      });
    },

    init() {
      m.bindListeners();
      m.render(true);
      m.pushState(true);
    }
  };

  return {
    helpers,
    m
  };
});
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
//  Copyright (C) 2013  The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// WidgetModel, WidgetView, and WidgetManager
//============================================================================
/**
 * Base Widget classes
 * @module IPython
 * @namespace IPython
 * @submodule widget
 */

// require(['components/underscore/underscore-min.js',
//          'components/backbone/backbone-min.js'],

"use strict";

// Only run once on a notebook.
if (IPython.notebook.widget_manager == undefined) {

    //-----------------------------------------------------------------------
    // WidgetModel class
    //-----------------------------------------------------------------------
    var WidgetModel = Backbone.Model.extend({
        apply: function(sender) {
            this.save();

            for (var index in this.views) {
                var view = this.views[index];
                if (view !== sender) {
                    view.refresh();
                }
            }
        }
    });

    //-----------------------------------------------------------------------
    // WidgetView class
    //-----------------------------------------------------------------------
    var WidgetView = Backbone.View.extend({

        initialize: function() {
            this.model.on('change',this.refresh,this);
        },

        refresh: function() {
            this.update();

            if (this.model.css != undefined) {
                for (var selector in this.model.css) {
                    if (this.model.css.hasOwnProperty(selector)) {

                        // Get the elements via the css selector.  If the selector is
                        // blank, assume the current element is the target.
                        var elements = this.$el.find(selector);
                        if (selector=='') {
                            elements = this.$el;
                        }

                        // Apply the css traits to all elements that match the selector.
                        if (elements.length>0){
                            var css_traits = this.model.css[selector];
                            for (var css_key in css_traits) {
                                if (css_traits.hasOwnProperty(css_key)) {
                                    elements.css(css_key, css_traits[css_key]);
                                }
                            }
                        }
                    }
                }
            }
        },
    });

    //-----------------------------------------------------------------------
    // WidgetManager class
    //-----------------------------------------------------------------------
    // Public constructor
    var WidgetManager = function(comm_manager){
        this.comm_manager = comm_manager;
        this.widget_model_types = {};
        this.widget_view_types = {};
        this.model_widget_views = {};

        var that = this;
        Backbone.sync = function(method, model, options, error) {
            var result = that.send_sync(method, model);
            if (options.success) {
              options.success(result);
            }
        };
    }

    // Register a widget model type.
    WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {

        // Register the widget with the comm manager.  Make sure to pass this object's context
        // in so `this` works in the call back.
        this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this));

        // Register the types of the model and view correspong to this widget type.  Later
        // the widget manager will initialize these when the comm is opened.
        this.widget_model_types[widget_model_name] = widget_model_type;
    }

    // Register a widget view type.
    WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
        this.widget_view_types[widget_view_name] = widget_view_type;
    }

    // Handle when a comm is opened.
    WidgetManager.prototype.handle_com_open = function (comm, msg) {
        var widget_type_name = msg.content.target_name;

        // Create the corresponding widget model.
        var widget_model = new this.widget_model_types[widget_type_name];

        // Remember comm associated with the model.
        widget_model.comm = comm;
        comm.model = widget_model;

        // Create an array to remember the views associated with the model.
        widget_model.views = [];

        // Add a handle to delete the control when the comm is closed.
        var that = this;
        var handle_close = function(msg) {
            that.handle_comm_closed(comm, msg);
        }
        comm.on_close(handle_close);

        // Handle incomming messages.
        var handle_msg = function(msg) {
            that.handle_comm_msg(comm, msg);
        }
        comm.on_msg(handle_msg);
    }

    // Create view that represents the model.
    WidgetManager.prototype.show_view = function (widget_area, widget_model, widget_view_name) {
        var widget_view = new this.widget_view_types[widget_view_name]({model: widget_model});
        widget_view.render();
        widget_model.views.push(widget_view);

        // Handle when the view element is remove from the page.
        widget_view.$el.on("remove", function(){
            var index = widget_model.views.indexOf(widget_view);
            if (index > -1) {
                widget_model.views.splice(index, 1);
            }
            widget_view.remove(); // Clean-up view

            // Close the comm if there are no views left.
            if (widget_model.views.length()==0) {
                widget_model.comm.close();
            }
        });

        // Add the view's element to cell's widget div.
        widget_area
            .append($("<div />").append(widget_view.$el))
            .parent().show(); // Show the widget_area (parent of widget_subarea)

        // Update the view based on the model contents.
        widget_view.refresh();
    }

    // Handle incomming comm msg.
    WidgetManager.prototype.handle_comm_msg = function (comm, msg) {
        // Different logic for different methods.
        var method = msg.content.data.method;
        switch (method){
            case 'show':

                // TODO: Get cell from registered output handler.
                var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1);
                var widget_subarea = cell.element.find('.widget_area').find('.widget_subarea');

                if (msg.content.data.parent != undefined) {
                    var find_results = widget_subarea.find("." + msg.content.data.parent);
                    if (find_results.length > 0) {
                        widget_subarea = find_results;
                    }
                }

                this.show_view(widget_subarea, comm.model, msg.content.data.view_name);
                break;
            case 'update':
                this.handle_update(comm, msg.content.data.state);
                break;
        }
    }

    // Handle when a widget is updated via the python side.
    WidgetManager.prototype.handle_update = function (comm, state) {
        for (var key in state) {
            if (state.hasOwnProperty(key)) {
                if (key=="_css"){
                    comm.model.css = state[key];
                } else {
                    comm.model.set(key, state[key]);
                }
            }
        }
        comm.model.save();
    }

    // Handle when a widget is closed.
    WidgetManager.prototype.handle_comm_closed = function (comm, msg) {
        for (var view_index in comm.model.views) {
            var view = comm.model.views[view_index];
            view.remove();
        }
    }

    // Get the cell output area corresponding to the comm.
    WidgetManager.prototype._get_comm_outputarea = function (comm) {
        // TODO: get element from comm instead of guessing
        var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index())
        return cell.output_area;
    }

    // Send widget state to python backend.
    WidgetManager.prototype.send_sync = function (method, model) {

        // Create a callback for the output if the widget has an output area associate with it.
        var callbacks = {};
        var comm = model.comm;
        var outputarea = this._get_comm_outputarea(comm);
        if (outputarea != null) {
            callbacks = {
                iopub : {
                output : $.proxy(outputarea.handle_output, outputarea),
                clear_output : $.proxy(outputarea.handle_clear_output, outputarea)}
            };
        };
        var model_json = model.toJSON();
        var data = {sync_method: method, sync_data: model_json};
        comm.send(data, callbacks);
        return model_json;
    }

    IPython.WidgetManager = WidgetManager;
    IPython.WidgetModel = WidgetModel;
    IPython.WidgetView = WidgetView;

    IPython.notebook.widget_manager = new WidgetManager(IPython.notebook.kernel.comm_manager);

}
<commit_msg>Use require.js where possible.<commit_after>//----------------------------------------------------------------------------
//  Copyright (C) 2013  The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// WidgetModel, WidgetView, and WidgetManager
//============================================================================
/**
 * Base Widget classes
 * @module IPython
 * @namespace IPython
 * @submodule widget
 */

"use strict";

// Only run once on a notebook.
require(["components/underscore/underscore-min",
         "components/backbone/backbone-min"], function () {
    if (IPython.notebook.widget_manager == undefined) {

        //-----------------------------------------------------------------------
        // WidgetModel class
        //-----------------------------------------------------------------------
        var WidgetModel = Backbone.Model.extend({
            apply: function(sender) {
                this.save();

                for (var index in this.views) {
                    var view = this.views[index];
                    if (view !== sender) {
                        view.refresh();
                    }
                }
            }
        });

        //-----------------------------------------------------------------------
        // WidgetView class
        //-----------------------------------------------------------------------
        var WidgetView = Backbone.View.extend({

            initialize: function() {
                this.model.on('change',this.refresh,this);
            },

            refresh: function() {
                this.update();

                if (this.model.css != undefined) {
                    for (var selector in this.model.css) {
                        if (this.model.css.hasOwnProperty(selector)) {

                            // Get the elements via the css selector.  If the selector is
                            // blank, assume the current element is the target.
                            var elements = this.$el.find(selector);
                            if (selector=='') {
                                elements = this.$el;
                            }

                            // Apply the css traits to all elements that match the selector.
                            if (elements.length>0){
                                var css_traits = this.model.css[selector];
                                for (var css_key in css_traits) {
                                    if (css_traits.hasOwnProperty(css_key)) {
                                        elements.css(css_key, css_traits[css_key]);
                                    }
                                }
                            }
                        }
                    }
                }
            },
        });

        //-----------------------------------------------------------------------
        // WidgetManager class
        //-----------------------------------------------------------------------
        // Public constructor
        var WidgetManager = function(comm_manager){
            this.comm_manager = comm_manager;
            this.widget_model_types = {};
            this.widget_view_types = {};
            this.model_widget_views = {};

            var that = this;
            Backbone.sync = function(method, model, options, error) {
                var result = that.send_sync(method, model);
                if (options.success) {
                  options.success(result);
                }
            };
        }

        // Register a widget model type.
        WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {

            // Register the widget with the comm manager.  Make sure to pass this object's context
            // in so `this` works in the call back.
            this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this));

            // Register the types of the model and view correspong to this widget type.  Later
            // the widget manager will initialize these when the comm is opened.
            this.widget_model_types[widget_model_name] = widget_model_type;
        }

        // Register a widget view type.
        WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
            this.widget_view_types[widget_view_name] = widget_view_type;
        }

        // Handle when a comm is opened.
        WidgetManager.prototype.handle_com_open = function (comm, msg) {
            var widget_type_name = msg.content.target_name;

            // Create the corresponding widget model.
            var widget_model = new this.widget_model_types[widget_type_name];

            // Remember comm associated with the model.
            widget_model.comm = comm;
            comm.model = widget_model;

            // Create an array to remember the views associated with the model.
            widget_model.views = [];

            // Add a handle to delete the control when the comm is closed.
            var that = this;
            var handle_close = function(msg) {
                that.handle_comm_closed(comm, msg);
            }
            comm.on_close(handle_close);

            // Handle incomming messages.
            var handle_msg = function(msg) {
                that.handle_comm_msg(comm, msg);
            }
            comm.on_msg(handle_msg);
        }

        // Create view that represents the model.
        WidgetManager.prototype.show_view = function (widget_area, widget_model, widget_view_name) {
            var widget_view = new this.widget_view_types[widget_view_name]({model: widget_model});
            widget_view.render();
            widget_model.views.push(widget_view);

            // Handle when the view element is remove from the page.
            widget_view.$el.on("remove", function(){
                var index = widget_model.views.indexOf(widget_view);
                if (index > -1) {
                    widget_model.views.splice(index, 1);
                }
                widget_view.remove(); // Clean-up view

                // Close the comm if there are no views left.
                if (widget_model.views.length()==0) {
                    widget_model.comm.close();
                }
            });

            // Add the view's element to cell's widget div.
            widget_area
                .append($("<div />").append(widget_view.$el))
                .parent().show(); // Show the widget_area (parent of widget_subarea)

            // Update the view based on the model contents.
            widget_view.refresh();
        }

        // Handle incomming comm msg.
        WidgetManager.prototype.handle_comm_msg = function (comm, msg) {
            // Different logic for different methods.
            var method = msg.content.data.method;
            switch (method){
                case 'show':

                    // TODO: Get cell from registered output handler.
                    var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1);
                    var widget_subarea = cell.element.find('.widget_area').find('.widget_subarea');

                    if (msg.content.data.parent != undefined) {
                        var find_results = widget_subarea.find("." + msg.content.data.parent);
                        if (find_results.length > 0) {
                            widget_subarea = find_results;
                        }
                    }

                    this.show_view(widget_subarea, comm.model, msg.content.data.view_name);
                    break;
                case 'update':
                    this.handle_update(comm, msg.content.data.state);
                    break;
            }
        }

        // Handle when a widget is updated via the python side.
        WidgetManager.prototype.handle_update = function (comm, state) {
            for (var key in state) {
                if (state.hasOwnProperty(key)) {
                    if (key=="_css"){
                        comm.model.css = state[key];
                    } else {
                        comm.model.set(key, state[key]);
                    }
                }
            }
            comm.model.save();
        }

        // Handle when a widget is closed.
        WidgetManager.prototype.handle_comm_closed = function (comm, msg) {
            for (var view_index in comm.model.views) {
                var view = comm.model.views[view_index];
                view.remove();
            }
        }

        // Get the cell output area corresponding to the comm.
        WidgetManager.prototype._get_comm_outputarea = function (comm) {
            // TODO: get element from comm instead of guessing
            var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index())
            return cell.output_area;
        }

        // Send widget state to python backend.
        WidgetManager.prototype.send_sync = function (method, model) {

            // Create a callback for the output if the widget has an output area associate with it.
            var callbacks = {};
            var comm = model.comm;
            var outputarea = this._get_comm_outputarea(comm);
            if (outputarea != null) {
                callbacks = {
                    iopub : {
                    output : $.proxy(outputarea.handle_output, outputarea),
                    clear_output : $.proxy(outputarea.handle_clear_output, outputarea)}
                };
            };
            var model_json = model.toJSON();
            var data = {sync_method: method, sync_data: model_json};
            comm.send(data, callbacks);
            return model_json;
        }

        IPython.WidgetManager = WidgetManager;
        IPython.WidgetModel = WidgetModel;
        IPython.WidgetView = WidgetView;

        IPython.notebook.widget_manager = new WidgetManager(IPython.notebook.kernel.comm_manager);

    }
});
<|endoftext|>


<commit_before>import React from 'react'
import {
  StyleSheet,
  View,
  ListView,
  Text,
  ScrollView,
  TouchableOpacity,
  Image,
} from 'react-native'

import NavigatorScreen from '../components/navigator-screen'
import LoadingView from './loading'
import * as c from '../components/colors'
import tabs from './tabs'

let Entities = require('html-entities').AllHtmlEntities;
entities = new Entities()

export default class PoliticoleView extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
      dataSource: null,
      loaded : false,
      error: false,
    }
  }

    componentWillMount() {
        this.fetchData()
    }

    _rowHasChanged(r1, r2) {
      return r1.title != r2.title
    }

    async fetchData() {
        try {
          let response = await fetch(tabs[1].url)
          let responseJson = await response.json()
          this.setState({dataSource: responseJson})
        } catch (error) {
          this.setState({error: true})
          console.error(error)
        }
        this.setState({loaded: true})
    }

     _renderRow(story){
        return(
            <TouchableOpacity onPress={this._onPressNews.bind(this)}>
                <View style={styles.pageContainer}>
                    <View style={styles.rightContainer}>
                        <Text style={styles.newsTitle}>{entities.decode(story.title)}</Text>
                        <Text style={styles.newsSummary}>{entities.decode(story.contentSnippet)}</Text>
                    </View>
                </View>
            </TouchableOpacity>
        )
    }

    _onPressNews(view) {
        // Figure out how to call this
        // most likely from the parent

        // this.props.navigator.push({
        //   title: viewTitle,
        //   component: NewsDetail,
        //   passProps: {news},
        // })

        console.log("show the news story...")
    }

  render() {
    if (this.state.dataSource != null) {
        let ds = new ListView.DataSource({
          rowHasChanged: this._rowHasChanged,
    })
    return (
      <View style={[styles.container, styles.newsItemContainer]}>
       <ListView
          {...this.props}
          dataSource={ds.cloneWithRows(this.state.dataSource.responseData.feed.entries)}
          renderRow={this._renderRow.bind(this)}
          style={styles.listView} />
       </View>
      )
    } else {
      return (
        <LoadingView />
      )
    }
  }
}

var styles = StyleSheet.create({
    pageContainer: {
        marginLeft : 10,
        marginRight : 10,
        borderBottomWidth: 1,
        borderBottomColor: '#ebebeb',
    },
    container: {
        flex: 1,
        flexDirection : 'row',
        justifyContent: 'center',
    },
    rightContainer: {
        flex: 1,
    },
    newsItemContainer: {
        paddingBottom: 50,
    },
    listView: {
        backgroundColor: '#ffffff',
    },
    newsPic: {
        width: 90,
        height: 60,
        margin: 10,
        marginLeft: 0,
    },
    newsTitle: {
        color: c.black,
        paddingLeft: 10,
        paddingRight: 10,
        paddingTop: 10,
        paddingBottom: 3,
        fontSize: 16,
        textAlign: 'left',
    },
    newsSummary: {
        color: c.iosText,
        paddingLeft: 10,
        paddingRight: 10,
        paddingBottom: 6,
        fontSize: 13,
        textAlign: 'left',
    },
})

<commit_msg>use NewsContainer for PoliticOle<commit_after>import React from 'react'
import NewsContainer from './news-container'

export default function PoliticOleNewsView(props) {
  return <NewsContainer {...props} />
}
<|endoftext|>


<commit_before>/* Helpers */
Array.matrix = function (m, initial) {
    var a, i, j, mat = [];
    for (i = 0; i < m; i += 1) {
        a = [];
        for (j = 0; j < m; j += 1) {
            a[j] = initial;
        }
        mat[i] = a;
    }
    return mat;
};

Number.prototype.toArray = function () {
	var arr = [];

	for( var i = 0;i < this;i++ ) {
		arr.push(false);
	}

	return arr;
};

Object.prototype.extend = function (newObj) {
	var obj = {};

	// wholesale copy from existing object
	for (var prop in this) {
		if (this.hasOwnProperty(prop)) {
			obj[prop] = this[prop];
		}
	}

	// overlap props from new object
	for (var prop in newObj) {
		if (newObj.hasOwnProperty(prop)) {
			obj[prop] = newObj[prop];
		}
	}

	return obj;
}

var MATRIX_GAMES = (function () {
	/* baseBoard -- Game generator. Builds games and executes gameplay. */
	var baseBoard = function (spec) {
		var playerIndex, board, lastMove = null;

		initGame();

		// private baseBoard methods
		function initGame() {
			board = Array.matrix(spec.size, false);
			lastMove = null;
			playerIndex = 0;
		}

		function getCurrentPlayer() {
			return spec.players[playerIndex];
		}

		function makeMove(move) {
			lastMove = spec.placement(board, move.x, move.y);
		}

		function generateRandomMove() {
			var x = 0, y = 0;

			do {
				x = Math.floor(Math.random()*spec.size),
				y = Math.floor(Math.random()*spec.size);
			} while (board[x][y] !== false);

			return { x: x, y: y };
		}

		function iterateOverBoard(fn) {
			for(var i = 0;i < spec.size;i++) {
				for(var j = 0; j < spec.size;j++) {
					if (fn(board[j][i], j, i) === false) {
						break;
					}
				}
			}
		}

		function advancePlayer() {
			playerIndex = (playerIndex + 1) % spec.players.length;
			return getCurrentPlayer();
		}

		function numberInLine(origin, direction) {
			var count = 0;
			var comparer = board[origin.x][origin.y];

			// direction.x and direction.y are either:
			// -1, 0, or 1.
			var current = {
				x: origin.x + direction.x,
				y: origin.y + direction.y
			};

			while (
				board[current.x] !== undefined &&
				board[current.x][current.y] === comparer) {
					current.x += direction.x;
					current.y += direction.y;
					count++;
			}

			return count;
		}

		function contiguousElements(direction) {
			if (lastMove != null) {
				var lastPlayer = board[lastMove.x][lastMove.y];
				var origin = { x: lastMove.x, y: lastMove.y };

				return 1 + numberInLine(origin, direction) + numberInLine(origin, { x: -1*direction.x, y: -1*direction.y });
			} else {
				return 0;
			}
		}

		// protected baseBoard methods
		return {
			outputStatus: function () {
				console.log("******************");

				var outputStr = "";

				iterateOverBoard(function (val, x, y) {
					outputStr += val === false ? "-" : val;

					if (x === spec.size-1) {
						console.log(outputStr);
						outputStr = "";
					}
				});

				console.log("\n");

				var winner = this.isGameOver();

				console.log("GAMEOVER? " +
					(winner ?
						winner === true ? "True" : "True (winner is: " + winner + ")" :
						"False"
					)
				);
			},

			isGameOver: function() {
				if (spec.completion.apply(this) === true) {
					return getCurrentPlayer();
				}

				var fullBoard = true;

				iterateOverBoard(function (val, x, y) {
					if (val === false) {
						return fullBoard = false;
					}
				});

				return fullBoard;
			},
			makeMove: function (move) {
				lastMove = spec.placement.call(this, board, move.x, move.y);
			},

			player: function () {
				return getCurrentPlayer();
			},

			connectionVertical: function () {
				return contiguousElements({ x: 0, y: 1 }) >= spec.connectionLength;
			},

			connectionHorizontal: function () {
				return contiguousElements({ x: 1, y: 0 }) >= spec.connectionLength;
			},

			connectionDiagonalRight: function () {
				return contiguousElements({ x: 1, y: -1 }) >= spec.connectionLength;
			},

			connectionDiagonalLeft: function () {
				return contiguousElements({ x: -1, y: -1 }) >= spec.connectionLength;
			},

			play: function (){
				while (this.isGameOver() === false) {
					this.makeMove(generateRandomMove());
					this.outputStatus();
					advancePlayer();
				}

				initGame();
			}
		};
	};

	var defaults = {
		players: ['A', 'B'],
		completion: function () {
			return this.connectionHorizontal() || this.connectionVertical() || this.connectionDiagonalRight() || this.connectionDiagonalLeft();
		},

		placement: function (board, x, y) {
			board[x][y] = this.player();

			return { x: x, y: y };
		}
	};

	return {
		ticTacToe: baseBoard(defaults.extend({
			size: 3,
			connectionLength: 3
		})),

		connectFour: baseBoard(defaults.extend({
			size: 6,
			connectionLength: 4,

			placement: function (board, x, y) {
				// in connect four, the play drops
				// all the way down.
				while (board[x][y+1] === false) {
					y++;
				}

				board[x][y] = this.player();

				return { x: x, y: y };
			}
		})),

		megaTicTacToe: baseBoard(defaults.extend({
			size: 8,
			connectionLength: 3,
			completion: function () {
				return this.connectionHorizontal() || this.connectionVertical();
			}
		}))
	}
}());<commit_msg>Minor cleanup:<commit_after>/* Helpers */
Array.matrix = function (m, initial) {
    var a, i, j, mat = [];
    for (i = 0; i < m; i += 1) {
        a = [];
        for (j = 0; j < m; j += 1) {
            a[j] = initial;
        }
        mat[i] = a;
    }
    return mat;
};

Number.prototype.toArray = function () {
	var arr = [];

	for( var i = 0;i < this;i++ ) {
		arr.push(false);
	}

	return arr;
};

Object.prototype.extend = function (newObj) {
	var obj = {};

	// wholesale copy from existing object
	for (var prop in this) {
		if (this.hasOwnProperty(prop)) {
			obj[prop] = this[prop];
		}
	}

	// overlap props from new object
	for (var prop in newObj) {
		if (newObj.hasOwnProperty(prop)) {
			obj[prop] = newObj[prop];
		}
	}

	return obj;
}

var MATRIX_GAMES = (function () {
	/* baseBoard -- Game generator. Builds games and executes gameplay. */
	var baseBoard = function (spec) {
		var playerIndex, board, lastMove = null;

		initGame();

		// private baseBoard methods
		function initGame() {
			board = Array.matrix(spec.size, false);
			lastMove = null;
			playerIndex = 0;
		}

		function getCurrentPlayer() {
			return spec.players[playerIndex];
		}

		function makeMove(move) {
			lastMove = spec.placement(board, move.x, move.y);
		}

		function generateRandomMove() {
			var x = 0, y = 0;

			do {
				x = Math.floor(Math.random()*spec.size),
				y = Math.floor(Math.random()*spec.size);
			} while (board[x][y] !== false);

			return { x: x, y: y };
		}

		function iterateOverBoard(fn) {
			for(var i = 0;i < spec.size;i++) {
				for(var j = 0; j < spec.size;j++) {
					if (fn(board[j][i], j, i) === false) {
						break;
					}
				}
			}
		}

		function advancePlayer() {
			playerIndex = (playerIndex + 1) % spec.players.length;
			return getCurrentPlayer();
		}

		function numberInLine(origin, direction) {
			var count = 0;
			var comparer = board[origin.x][origin.y];

			// direction.x and direction.y are either:
			// -1, 0, or 1.
			var current = {
				x: origin.x + direction.x,
				y: origin.y + direction.y
			};

			while (
				board[current.x] !== undefined &&
				board[current.x][current.y] === comparer) {
					current.x += direction.x;
					current.y += direction.y;
					count++;
			}

			return count;
		}

		function contiguousElements(direction) {
			if (lastMove === null) {
				return 0;
			}

			var lastPlayer = board[lastMove.x][lastMove.y];
			var origin = { x: lastMove.x, y: lastMove.y };

			return 1 + numberInLine(origin, direction) + numberInLine(origin, { x: -1*direction.x, y: -1*direction.y });
		}

		// protected baseBoard methods
		return {
			outputStatus: function () {
				console.log("******************");

				var outputStr = "";

				iterateOverBoard(function (val, x, y) {
					outputStr += val === false ? "-" : val;

					if (x === spec.size-1) {
						console.log(outputStr);
						outputStr = "";
					}
				});

				console.log("\n");

				var winner = this.isGameOver();

				console.log("GAMEOVER? " +
					(winner ?
						winner === true ? "True" : "True (winner is: " + winner + ")" :
						"False"
					)
				);
			},

			isGameOver: function() {
				if (spec.completion.apply(this) === true) {
					return getCurrentPlayer();
				}

				var fullBoard = true;

				iterateOverBoard(function (val, x, y) {
					if (val === false) {
						return fullBoard = false;
					}
				});

				return fullBoard;
			},

			makeMove: function (move) {
				lastMove = spec.placement.call(this, board, move.x, move.y);
			},

			player: function () {
				return getCurrentPlayer();
			},

			connectionVertical: function () {
				return contiguousElements({ x: 0, y: 1 }) >= spec.connectionLength;
			},

			connectionHorizontal: function () {
				return contiguousElements({ x: 1, y: 0 }) >= spec.connectionLength;
			},

			connectionDiagonalRight: function () {
				return contiguousElements({ x: 1, y: -1 }) >= spec.connectionLength;
			},

			connectionDiagonalLeft: function () {
				return contiguousElements({ x: -1, y: -1 }) >= spec.connectionLength;
			},

			play: function () {
				while (this.isGameOver() === false) {
					this.makeMove(generateRandomMove());
					this.outputStatus();
					advancePlayer();
				}

				initGame();
			}
		};
	};

	var defaults = {
		players: ['A', 'B'],
		completion: function () {
			return this.connectionHorizontal() || this.connectionVertical() || this.connectionDiagonalRight() || this.connectionDiagonalLeft();
		},

		placement: function (board, x, y) {
			board[x][y] = this.player();

			return { x: x, y: y };
		}
	};

	return {
		ticTacToe: baseBoard(defaults.extend({
			size: 3,
			connectionLength: 3
		})),

		connectFour: baseBoard(defaults.extend({
			size: 6,
			connectionLength: 4,

			placement: function (board, x, y) {
				// in connect four, the play drops
				// all the way down.
				while (board[x][y+1] === false) {
					y++;
				}

				board[x][y] = this.player();

				return { x: x, y: y };
			}
		})),

		megaTicTacToe: baseBoard(defaults.extend({
			size: 8,
			connectionLength: 3,
			completion: function () {
				return this.connectionHorizontal() || this.connectionVertical();
			}
		}))
	}
}());<|endoftext|>