<commit_before>Ext.require([
    'Ext.container.Viewport',
    'Ext.layout.container.Border',
    'GeoExt.tree.Panel',
    'Ext.tree.plugin.TreeViewDragDrop',
    'GeoExt.panel.Map',
    'GeoExt.tree.OverlayLayerContainer',
    'GeoExt.tree.BaseLayerContainer',
    'GeoExt.data.LayerTreeModel',
    'GeoExt.tree.View',
    'GeoExt.container.WmsLegend',
    'GeoExt.tree.Column',
    // We need to require this class, even though it is used by Ext.EventObjectImpl
    // see: http://www.sencha.com/forum/showthread.php?262124-Missed-(-)-dependency-reference-to-a-Ext.util.Point-in-Ext.EventObjectImpl
    'Ext.util.Point'
]);

Ext.application({
    name: 'Tree Legend',
    launch: function() {
        var mapPanel = new GeoExt.MapPanel({
            region: "center",
            center: [146.1569825, -41.6109735],
            zoom: 6,
            layers: [
                new OpenLayers.Layer.WMS("Tasmania State Boundaries",
                    "http://demo.opengeo.org/geoserver/wms", {
                        layers: "topp:tasmania_state_boundaries"
                    }, {
                        buffer: 0,
                        // exclude this layer from layer container nodes
                        displayInLayerSwitcher: false
                   }),
                new OpenLayers.Layer.WMS("Water",
                    "http://demo.opengeo.org/geoserver/wms", {
                        layers: "topp:tasmania_water_bodies",
                        transparent: true,
                        format: "image/gif"
                    }, {
                        buffer: 0
                    }),
                new OpenLayers.Layer.WMS("Cities",
                    "http://demo.opengeo.org/geoserver/wms", {
                        layers: "topp:tasmania_cities",
                        transparent: true,
                        format: "image/gif"
                    }, {
                        buffer: 0
                    }),
                new OpenLayers.Layer.WMS("Tasmania Roads",
                    "http://demo.opengeo.org/geoserver/wms", {
                        layers: "topp:tasmania_roads",
                        transparent: true,
                        format: "image/gif"
                    }, {
                        buffer: 0
                    })
            ]
        });

        var store = Ext.create('Ext.data.TreeStore', {
            model: 'GeoExt.data.LayerTreeModel',
            root: {
                plugins: [{
                    ptype: "gx_layercontainer",
                    loader: {
                        createNode: function(attr) {
                            // add a WMS legend to each node created
                            attr.component = {
                                xtype: "gx_wmslegend",
                                layerRecord: mapPanel.layers.getByLayer(attr.layer),
                                showTitle: false,
                                // custom class for css positioning
                                // see tree-legend.html
                                cls: "legend"
                            };
                            return GeoExt.tree.LayerLoader.prototype.createNode.call(this, attr);
                        }
                    }
                }]
            }
        });

        var tree = new GeoExt.tree.Panel({
            region: "east",
            title: "Layers",
            width: 250,
            autoScroll: true,
            viewConfig: {
                plugins: [{
                    ptype: 'treeviewdragdrop',
                    appendOnly: false
                }]
            },
            store: store,
            rootVisible: false,
            lines: false
        });

        new Ext.Viewport({
            layout: "fit",
            hideBorders: true,
            items: {
                layout: "border",
                items: [
                    mapPanel, tree, {
                        contentEl: desc,
                        region: "west",
                        width: 250,
                        bodyStyle: {padding: "5px"}
                    }
                ]
            }
        });
    }
});
<commit_msg>Use Ext.create instead of new for Ext classes<commit_after>Ext.require([
    'Ext.container.Viewport',
    'Ext.layout.container.Border',
    'GeoExt.tree.Panel',
    'Ext.tree.plugin.TreeViewDragDrop',
    'GeoExt.panel.Map',
    'GeoExt.tree.OverlayLayerContainer',
    'GeoExt.tree.BaseLayerContainer',
    'GeoExt.data.LayerTreeModel',
    'GeoExt.tree.View',
    'GeoExt.container.WmsLegend',
    'GeoExt.tree.Column',
    // We need to require this class, even though it is used by Ext.EventObjectImpl
    // see: http://www.sencha.com/forum/showthread.php?262124-Missed-(-)-dependency-reference-to-a-Ext.util.Point-in-Ext.EventObjectImpl
    'Ext.util.Point'
]);

Ext.application({
    name: 'Tree Legend',
    launch: function() {
        var mapPanel = Ext.create('GeoExt.MapPanel', {
            region: "center",
            center: [146.1569825, -41.6109735],
            zoom: 6,
            layers: [
                new OpenLayers.Layer.WMS("Tasmania State Boundaries",
                    "http://demo.opengeo.org/geoserver/wms", {
                        layers: "topp:tasmania_state_boundaries"
                    }, {
                        buffer: 0,
                        // exclude this layer from layer container nodes
                        displayInLayerSwitcher: false
                   }),
                new OpenLayers.Layer.WMS("Water",
                    "http://demo.opengeo.org/geoserver/wms", {
                        layers: "topp:tasmania_water_bodies",
                        transparent: true,
                        format: "image/gif"
                    }, {
                        buffer: 0
                    }),
                new OpenLayers.Layer.WMS("Cities",
                    "http://demo.opengeo.org/geoserver/wms", {
                        layers: "topp:tasmania_cities",
                        transparent: true,
                        format: "image/gif"
                    }, {
                        buffer: 0
                    }),
                new OpenLayers.Layer.WMS("Tasmania Roads",
                    "http://demo.opengeo.org/geoserver/wms", {
                        layers: "topp:tasmania_roads",
                        transparent: true,
                        format: "image/gif"
                    }, {
                        buffer: 0
                    })
            ]
        });

        var store = Ext.create('Ext.data.TreeStore', {
            model: 'GeoExt.data.LayerTreeModel',
            root: {
                plugins: [{
                    ptype: "gx_layercontainer",
                    loader: {
                        createNode: function(attr) {
                            // add a WMS legend to each node created
                            attr.component = {
                                xtype: "gx_wmslegend",
                                layerRecord: mapPanel.layers.getByLayer(attr.layer),
                                showTitle: false,
                                // custom class for css positioning
                                // see tree-legend.html
                                cls: "legend"
                            };
                            return GeoExt.tree.LayerLoader.prototype.createNode.call(this, attr);
                        }
                    }
                }]
            }
        });

        var tree = Ext.create('GeoExt.tree.Panel', {
            region: "east",
            title: "Layers",
            width: 250,
            autoScroll: true,
            viewConfig: {
                plugins: [{
                    ptype: 'treeviewdragdrop',
                    appendOnly: false
                }]
            },
            store: store,
            rootVisible: false,
            lines: false
        });

        Ext.create('Ext.Viewport', {
            layout: "fit",
            hideBorders: true,
            items: {
                layout: "border",
                items: [
                    mapPanel, tree, {
                        contentEl: desc,
                        region: "west",
                        width: 250,
                        bodyStyle: {padding: "5px"}
                    }
                ]
            }
        });
    }
});
<|endoftext|>


<commit_before>import React from 'react';
import autobind from 'core-decorators/es/autobind';
import MediaQuery from 'react-responsive';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { graphql } from 'react-apollo';
import { Tab2, Tabs2, Intent } from '@blueprintjs/core';
import bp from '../../../../../../lib/react/components/utility/bp';
import UsersView from '../../views/UsersView';
import TeamsView from '../../views/TeamsView';
import GameStateView from '../../views/GameStateView';
import ServerSettingsView from '../../views/ServerSettingsView';
import InstructionArticlesView from '../../views/InstructionArticlesView';
import S3ExplorerView from '../../views/S3ExplorerView';
import ChallengesView from '../../views/ChallengesView';
import LogsView from '../../views/LogsView';
import ResponsesView from '../../views/ResponsesView';
import NotificationToaster from '../../../components/NotificationToaster';
import UncheckedResponseToaster from '../../../components/UncheckedResponseToaster';
import { getResponses } from '../../../../graphql/response';

const POLL_RESPONSE_INTERVAL = 60 * 1000;

const VIEWS = [
	'users',
	'teams',
	'challenges',
	'instructions',
	'uploads',
	'state',
	'server',
	'logs',
	'responses'
];

const QueryGetResponsesOptions = {
	name: 'QueryGetResponses',
	options: {
		fetchPolicy: 'network-only',
		variables: { uncheckedOnly: true }
	}
}

const mapStateToProps = (state, ownProps) => {
	return {
		showResponses: state.settings.showNotifications
	}
}

@graphql(getResponses('checked'), QueryGetResponsesOptions)
@withRouter
@connect(mapStateToProps)
@autobind
class AdminDashboard extends React.Component {
	state = {
		selectedTabId: 'users',
		uncheckedResponses: 0
	}

	componentWillMount() {
		this._clearPollingResponses();
		this._startPollingResponses();

		const { params } = this.props.match;
		if (params) {
			// Ensure view exists
			let viewExists = false;
			VIEWS.forEach((view) => {
				if (!viewExists) {
					if (view === params.view) viewExists = true;
				}
			})

			if (viewExists) {
				this.props.history.push(`/admin/dashboard/${params.view}${params.item?`/${params.item}`:''}`);
				this.setState({selectedTabId: params.view});
			}
			else {
				this.props.history.push(`/admin/dashboard/users`);
				this.setState({selectedTabId: 'users'});
				NotificationToaster.show({
					intent: Intent.WARNING,
					message: `The view '${params.view}' does not exist. You have been redirected to the 'users' view.`
				});
			}
		}
	}

	componentWillUnmount() {
		this._clearPollingResponses();
	}

	_startPollingResponses() {
		this.pollResponses = setInterval(this._handlePollResponses, POLL_RESPONSE_INTERVAL);
	}

	_clearPollingResponses() {
		clearInterval(this.pollResponses);
	}

	_handleResponseAction() {
		this.props.history.push(`/admin/dashboard/responses`);
		this.setState({selectedTabId: 'responses'});
	}

	async _handlePollResponses() {
		// Only request data if notifications are turned on
		if (!this.props.showResponses) return;

		try {
			const result = await this.props.QueryGetResponses.refetch();

			const { data: { error, getResponses } } = result;

			const difference = getResponses.length - this.state.uncheckedResponses;

			if (difference > 0) {
				UncheckedResponseToaster.show({
					timeout: 20000,
					intent: Intent.SUCCESS,
					message: `There ${difference>1?'are':'is'} ${difference} new unchecked ${difference>1?'responses':'response'} (${getResponses.length} total).`,
					action: {
						onClick: this._handleResponseAction,
						text: 'View'
					}
				});
			}
			else if (getResponses.length > 0) {
				UncheckedResponseToaster.show({
					timeout: 20000,
					intent: Intent.PRIMARY,
					message: `There ${getResponses.length===1?'is':'are'} ${getResponses.length} unchecked ${getResponses.length===1?'response':'responses'}.`,
					action: {
						onClick: this._handleResponseAction,
						text: 'View'
					}
				});
			}

			this.setState({ uncheckedResponses: getResponses.length });
		}
		catch (err) {
			NotificationToaster.show({
				intent: Intent.DANGER,
				message: error.toString()
			});
		}
	}

	handleTabChange(newTabId) {
		this.props.history.push(`/admin/dashboard/${newTabId}`);
		this.setState({selectedTabId: newTabId});
	}

	renderTabs(vertical) {
		const { item } = this.props.match.params;
		return (
			<Tabs2 id='dashboard' className={vertical?'':'mobile-tabs'} onChange={this.handleTabChange}
				selectedTabId={this.state.selectedTabId} vertical={vertical}>
				<Tab2 id={VIEWS[0]} title='Users' panel={<UsersView shouldRefresh={this.state.selectedTabId===VIEWS[0]} item={item}/>}/>
				<Tab2 id={VIEWS[1]} title='Teams' panel={<TeamsView shouldRefresh={this.state.selectedTabId===VIEWS[1]} item={item}/>}/>
				<Tab2 id={VIEWS[8]} title='Responses' panel={<ResponsesView shouldRefresh={this.state.selectedTabId===VIEWS[8]} item={item}/>}/>
				<Tab2 id={VIEWS[2]} title='Challenges' panel={<ChallengesView shouldRefresh={this.state.selectedTabId===VIEWS[2]} item={item}/>}/>
				<Tab2 id={VIEWS[4]} title='Instructions' panel={<InstructionArticlesView shouldRefresh={this.state.selectedTabId===VIEWS[4]} item={item}/>}/>
				<Tab2 id={VIEWS[3]} title='Uploads (S3)' panel={<S3ExplorerView shouldRefresh={this.state.selectedTabId===VIEWS[3]} item={item}/>}/>
				<Tab2 id={VIEWS[5]} title='Game State' panel={<GameStateView shouldRefresh={this.state.selectedTabId===VIEWS[5]} item={item}/>}/>
				<Tab2 id={VIEWS[6]} title='Server' panel={<ServerSettingsView shouldRefresh={this.state.selectedTabId===VIEWS[6]} item={item}/>}/>
				<Tab2 id={VIEWS[7]} title='Logs' panel={<LogsView shouldRefresh={this.state.selectedTabId===VIEWS[7]} item={item}/>}/>
			</Tabs2>
		);
	}

	render() {
		return (

Administrator Dashboard

				<MediaQuery minWidth={bp.s+1}>
					{this.renderTabs(true)}
				</MediaQuery>
				<MediaQuery maxWidth={bp.s}>
					{this.renderTabs(false)}
				</MediaQuery>

		);
	}
}

export default AdminDashboard;
<commit_msg>[ADD] Rename dashboard pages<commit_after>import React from 'react';
import autobind from 'core-decorators/es/autobind';
import MediaQuery from 'react-responsive';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { graphql } from 'react-apollo';
import { Tab2, Tabs2, Intent } from '@blueprintjs/core';
import bp from '../../../../../../lib/react/components/utility/bp';
import UsersView from '../../views/UsersView';
import TeamsView from '../../views/TeamsView';
import GameStateView from '../../views/GameStateView';
import ServerSettingsView from '../../views/ServerSettingsView';
import InstructionArticlesView from '../../views/InstructionArticlesView';
import S3ExplorerView from '../../views/S3ExplorerView';
import ChallengesView from '../../views/ChallengesView';
import LogsView from '../../views/LogsView';
import ResponsesView from '../../views/ResponsesView';
import NotificationToaster from '../../../components/NotificationToaster';
import UncheckedResponseToaster from '../../../components/UncheckedResponseToaster';
import { getResponses } from '../../../../graphql/response';

const POLL_RESPONSE_INTERVAL = 60 * 1000;

const VIEWS = [
	'users',
	'teams',
	'challenges',
	'instructions',
	'uploads',
	'state',
	'server',
	'logs',
	'responses'
];

const QueryGetResponsesOptions = {
	name: 'QueryGetResponses',
	options: {
		fetchPolicy: 'network-only',
		variables: { uncheckedOnly: true }
	}
}

const mapStateToProps = (state, ownProps) => {
	return {
		showResponses: state.settings.showNotifications
	}
}

@graphql(getResponses('checked'), QueryGetResponsesOptions)
@withRouter
@connect(mapStateToProps)
@autobind
class AdminDashboard extends React.Component {
	state = {
		selectedTabId: 'users',
		uncheckedResponses: 0
	}

	componentWillMount() {
		this._clearPollingResponses();
		this._startPollingResponses();

		const { params } = this.props.match;
		if (params) {
			// Ensure view exists
			let viewExists = false;
			VIEWS.forEach((view) => {
				if (!viewExists) {
					if (view === params.view) viewExists = true;
				}
			})

			if (viewExists) {
				this.props.history.push(`/admin/dashboard/${params.view}${params.item?`/${params.item}`:''}`);
				this.setState({selectedTabId: params.view});
			}
			else {
				this.props.history.push(`/admin/dashboard/users`);
				this.setState({selectedTabId: 'users'});
				NotificationToaster.show({
					intent: Intent.WARNING,
					message: `The view '${params.view}' does not exist. You have been redirected to the 'users' view.`
				});
			}
		}
	}

	componentWillUnmount() {
		this._clearPollingResponses();
	}

	_startPollingResponses() {
		this.pollResponses = setInterval(this._handlePollResponses, POLL_RESPONSE_INTERVAL);
	}

	_clearPollingResponses() {
		clearInterval(this.pollResponses);
	}

	_handleResponseAction() {
		this.props.history.push(`/admin/dashboard/responses`);
		this.setState({selectedTabId: 'responses'});
	}

	async _handlePollResponses() {
		// Only request data if notifications are turned on
		if (!this.props.showResponses) return;

		try {
			const result = await this.props.QueryGetResponses.refetch();

			const { data: { error, getResponses } } = result;

			const difference = getResponses.length - this.state.uncheckedResponses;

			if (difference > 0) {
				UncheckedResponseToaster.show({
					timeout: 20000,
					intent: Intent.SUCCESS,
					message: `There ${difference>1?'are':'is'} ${difference} new unchecked ${difference>1?'responses':'response'} (${getResponses.length} total).`,
					action: {
						onClick: this._handleResponseAction,
						text: 'View'
					}
				});
			}
			else if (getResponses.length > 0) {
				UncheckedResponseToaster.show({
					timeout: 20000,
					intent: Intent.PRIMARY,
					message: `There ${getResponses.length===1?'is':'are'} ${getResponses.length} unchecked ${getResponses.length===1?'response':'responses'}.`,
					action: {
						onClick: this._handleResponseAction,
						text: 'View'
					}
				});
			}

			this.setState({ uncheckedResponses: getResponses.length });
		}
		catch (err) {
			NotificationToaster.show({
				intent: Intent.DANGER,
				message: error.toString()
			});
		}
	}

	handleTabChange(newTabId) {
		this.props.history.push(`/admin/dashboard/${newTabId}`);
		this.setState({selectedTabId: newTabId});
	}

	renderTabs(vertical) {
		const { item } = this.props.match.params;
		return (
			<Tabs2 id='dashboard' className={vertical?'':'mobile-tabs'} onChange={this.handleTabChange}
				selectedTabId={this.state.selectedTabId} vertical={vertical}>
				<Tab2 id={VIEWS[0]} title='Users' panel={<UsersView shouldRefresh={this.state.selectedTabId===VIEWS[0]} item={item}/>}/>
				<Tab2 id={VIEWS[1]} title='Teams' panel={<TeamsView shouldRefresh={this.state.selectedTabId===VIEWS[1]} item={item}/>}/>
				<Tab2 id={VIEWS[8]} title='Responses' panel={<ResponsesView shouldRefresh={this.state.selectedTabId===VIEWS[8]} item={item}/>}/>
				<Tab2 id={VIEWS[2]} title='Challenges' panel={<ChallengesView shouldRefresh={this.state.selectedTabId===VIEWS[2]} item={item}/>}/>
				<Tab2 id={VIEWS[4]} title='Instructions' panel={<InstructionArticlesView shouldRefresh={this.state.selectedTabId===VIEWS[4]} item={item}/>}/>
				<Tab2 id={VIEWS[3]} title='Uploads' panel={<S3ExplorerView shouldRefresh={this.state.selectedTabId===VIEWS[3]} item={item}/>}/>
				<Tab2 id={VIEWS[5]} title='Game State' panel={<GameStateView shouldRefresh={this.state.selectedTabId===VIEWS[5]} item={item}/>}/>
				<Tab2 id={VIEWS[6]} title='Settings' panel={<ServerSettingsView shouldRefresh={this.state.selectedTabId===VIEWS[6]} item={item}/>}/>
				<Tab2 id={VIEWS[7]} title='Logs' panel={<LogsView shouldRefresh={this.state.selectedTabId===VIEWS[7]} item={item}/>}/>
			</Tabs2>
		);
	}

	render() {
		return (

Administrator Dashboard

				<MediaQuery minWidth={bp.s+1}>
					{this.renderTabs(true)}
				</MediaQuery>
				<MediaQuery maxWidth={bp.s}>
					{this.renderTabs(false)}
				</MediaQuery>

		);
	}
}

export default AdminDashboard;
<|endoftext|>


<commit_before>require('mocha');
require('should');
var async = require('async');
var assert = require('assert');
var List = require('..').List;
var Views = require('..').Views;
var pages;

describe('render', function () {
  describe('rendering', function () {
    beforeEach(function () {
      pages = new Views();
      pages.engine('tmpl', require('engine-base'));
    });

    it('should throw an error when no callback is given:', function () {
      (function() {
        pages.render({});
      }).should.throw('Views#render is async and expects a callback function');
    });

    it('should throw an error when an engine is not defined:', function (done) {
      pages.addView('foo.bar', {content: '<%= name %>'});
      var page = pages.getView('foo.bar');

      pages.render(page, function(err) {
        assert(err.message === 'Views#render cannot find an engine for: .bar');
        done();
      });
    });

    it('should use helpers to render a view:', function (done) {
      var locals = {name: 'Halle'};

      pages.helper('upper', function (str) {
        return str.toUpperCase(str);
      });

      pages.addView('a.tmpl', {content: 'a <%= upper(name) %> b', locals: locals});
      var page = pages.getView('a.tmpl');

      pages.render(page, function (err, res) {
        if (err) return done(err);

        assert(res.contents.toString() === 'a HALLE b');
        done();
      });
    });

    it('should use helpers when rendering a view:', function (done) {
      var locals = {name: 'Halle'};
      pages.helper('upper', function (str) {
        return str.toUpperCase(str);
      });

      pages.addView('a.tmpl', {content: 'a <%= upper(name) %> b', locals: locals});
      var page = pages.getView('a.tmpl');

      pages.render(page, function (err, res) {
        if (err) return done(err);
        assert(res.contents.toString() === 'a HALLE b');
        done();
      });
    });

    it('should render a template when contents is a buffer:', function (done) {
      pages.addView('a.tmpl', {content: '<%= a %>', locals: {a: 'b'}});
      var view = pages.getView('a.tmpl');

      pages.render(view, function (err, view) {
        if (err) return done(err);
        assert(view.contents.toString() === 'b');
        done();
      });
    });

    it('should render a template when content is a string:', function (done) {
      pages.addView('a.tmpl', {content: '<%= a %>', locals: {a: 'b'}});
      var view = pages.getView('a.tmpl');

      pages.render(view, function (err, view) {
        if (err) return done(err);
        assert(view.contents.toString() === 'b');
        done();
      });
    });

    it('should render a view from its path:', function (done) {
      pages.addView('a.tmpl', {content: '<%= a %>', locals: {a: 'b'}});

      pages.render('a.tmpl', function (err, view) {
        if (err) return done(err);
        assert(view.content === 'b');
        done();
      });
    });

    it.skip('should use a plugin for rendering:', function (done) {
      pages.engine('tmpl', require('engine-base'));
      pages.preRender(/./, function (view, next) {
        view.engine = 'tmpl';
        // console.log(view)
        next();
      });

      pages.addViews({
        'a': {content: '<%= title %>', locals: {title: 'aaa'}},
        'b': {content: '<%= title %>', locals: {title: 'bbb'}},
        'c': {content: '<%= title %>', locals: {title: 'ccc'}},
        'd': {content: '<%= title %>', locals: {title: 'ddd'}},
        'e': {content: '<%= title %>', locals: {title: 'eee'}},
        'f': {content: '<%= title %>', locals: {title: 'fff'}},
        'g': {content: '<%= title %>', locals: {title: 'ggg'}},
        'h': {content: '<%= title %>', locals: {title: 'hhh'}},
        'i': {content: '<%= title %>', locals: {title: 'iii'}},
        'j': {content: '<%= title %>', locals: {title: 'jjj'}},
      });

      pages.use(function (collection) {
        var list = new List(collection);
        collection.renderEach = function (cb) {
          async.map(list.items, function (item, next) {
            try {
              collection.render(item, next);
            } catch(err) {
              return next(err);
            }
          }, cb);
        };
      })

      pages.renderEach(function (err, items) {
        if (err) return done(err);
        // console.log(err.stack)
        // assert(items[0].content === 'aaa');
        // assert(items[9].content === 'jjj');
        // assert(items.length === 10);
        done();
      });
    });
  });
});
<commit_msg>clean up<commit_after>require('mocha');
require('should');
var async = require('async');
var assert = require('assert');
var List = require('..').List;
var Views = require('..').Views;
var pages;

describe('render', function () {
  describe('rendering', function () {
    beforeEach(function () {
      pages = new Views();
      pages.engine('tmpl', require('engine-base'));
    });

    it('should throw an error when no callback is given:', function () {
      (function() {
        pages.render({});
      }).should.throw('Views#render is async and expects a callback function');
    });

    it('should throw an error when an engine is not defined:', function (done) {
      pages.addView('foo.bar', {content: '<%= name %>'});
      var page = pages.getView('foo.bar');

      pages.render(page, function(err) {
        assert(err.message === 'Views#render cannot find an engine for: .bar');
        done();
      });
    });

    it('should use helpers to render a view:', function (done) {
      var locals = {name: 'Halle'};

      pages.helper('upper', function (str) {
        return str.toUpperCase(str);
      });

      pages.addView('a.tmpl', {content: 'a <%= upper(name) %> b', locals: locals});
      var page = pages.getView('a.tmpl');

      pages.render(page, function (err, res) {
        if (err) return done(err);

        assert(res.contents.toString() === 'a HALLE b');
        done();
      });
    });

    it('should use helpers when rendering a view:', function (done) {
      var locals = {name: 'Halle'};
      pages.helper('upper', function (str) {
        return str.toUpperCase(str);
      });

      pages.addView('a.tmpl', {content: 'a <%= upper(name) %> b', locals: locals});
      var page = pages.getView('a.tmpl');

      pages.render(page, function (err, res) {
        if (err) return done(err);
        assert(res.contents.toString() === 'a HALLE b');
        done();
      });
    });

    it('should render a template when contents is a buffer:', function (done) {
      pages.addView('a.tmpl', {content: '<%= a %>', locals: {a: 'b'}});
      var view = pages.getView('a.tmpl');

      pages.render(view, function (err, view) {
        if (err) return done(err);
        assert(view.contents.toString() === 'b');
        done();
      });
    });

    it('should render a template when content is a string:', function (done) {
      pages.addView('a.tmpl', {content: '<%= a %>', locals: {a: 'b'}});
      var view = pages.getView('a.tmpl');

      pages.render(view, function (err, view) {
        if (err) return done(err);
        assert(view.contents.toString() === 'b');
        done();
      });
    });

    it('should render a view from its path:', function (done) {
      pages.addView('a.tmpl', {content: '<%= a %>', locals: {a: 'b'}});

      pages.render('a.tmpl', function (err, view) {
        if (err) return done(err);
        assert(view.content === 'b');
        done();
      });
    });

    it('should use a plugin for rendering:', function (done) {
      pages.preRender(/./, function (view, next) {
        view.engine = 'tmpl';
        next();
      });

      pages.addViews({
        'a': {content: '<%= title %>', locals: {title: 'aaa'}},
        'b': {content: '<%= title %>', locals: {title: 'bbb'}},
        'c': {content: '<%= title %>', locals: {title: 'ccc'}},
        'd': {content: '<%= title %>', locals: {title: 'ddd'}},
        'e': {content: '<%= title %>', locals: {title: 'eee'}},
        'f': {content: '<%= title %>', locals: {title: 'fff'}},
        'g': {content: '<%= title %>', locals: {title: 'ggg'}},
        'h': {content: '<%= title %>', locals: {title: 'hhh'}},
        'i': {content: '<%= title %>', locals: {title: 'iii'}},
        'j': {content: '<%= title %>', locals: {title: 'jjj'}},
      });

      pages.use(function (collection) {
        var list = new List(collection);

        collection.option('resolveEngine', function (ext) {
          if (ext.charAt(0) !== '.') ext = '.' + ext;
          return ext;
        });

        collection.renderEach = function (cb) {
          async.map(list.items, function (item, next) {
            collection.render(item, next);
          }, cb);
        };
      })

      pages.renderEach(function (err, items) {
        if (err) return done(err);
        assert(items[0].content === 'aaa');
        assert(items[9].content === 'jjj');
        assert(items.length === 10);
        done();
      });
    });
  });
});
<|endoftext|>


<commit_before>var fs = require('fs');
var env = process.env;
var keysDir = process.KEYS_DIR || __dirname + '/../../keys';

var defaults = {
      'env': env.NODE_ENV,
      'pgpPrivateKey': fs.readFileSync(keysDir + '/private.key', 'utf-8'),
      'pgpPublicKey': fs.readFileSync(keysDir + '/public.key', 'utf-8'),
      'pgpKeyPassphrase': env.PGP_PASSPHRASE,
      'hostDomain': env.HOST_DOMAIN || env.MAILGUN_DOMAIN || 'tipbox.dev',
      'hmacKey': env.HMAC_KEY || '',
      'groupId': env.OC_GROUPID,
      'apiKey': env.OC_API_KEY,
      'logLevel': 'warn'
};

var settings = {
    'development': {
      'mailgunApiKey': env.MAILGUN_API_KEY,
      'mailgunDomain': env.MAILGUN_DOMAIN || 'tipbox.in',
      'smtpHost': env.SMTP_HOST,
      'smtpPort': env.SMTP_PORT,
      'pgpKeyPassphrase': '1234',
      'hmacKey': '',
      'apiUrl': 'https://opencollective.herokuapp.com/',
      'logLevel': 'debug'
    }
  , 'staging': {
      'env': env.NODE_ENV,
      'mailgunApiKey': env.MAILGUN_API_KEY,
      'mailgunDomain': env.MAILGUN_DOMAIN,
      'logLevel': 'info'
  }
  , 'tipbox.in': {
      'mailgunApiKey': env.MAILGUN_API_KEY,
      'mailgunDomain': env.MAILGUN_DOMAIN
  }
  , 'tipbox.is': {
      'smtpHost': env.SMTP_HOST,
      'smtpPort': env.SMTP_PORT,
      'apiUrl': 'https://opencollective-prod.herokuapp.com/'
  }
};

module.exports = function(name) {
  var props = {};
  for (var key in defaults) { props[key] = defaults[key]; }
  for (var key in settings[name]) { props[key] = settings[name][key]; }
  return props;
}
<commit_msg>Default to error level<commit_after>var fs = require('fs');
var env = process.env;
var keysDir = process.KEYS_DIR || __dirname + '/../../keys';

var defaults = {
      'env': env.NODE_ENV,
      'pgpPrivateKey': fs.readFileSync(keysDir + '/private.key', 'utf-8'),
      'pgpPublicKey': fs.readFileSync(keysDir + '/public.key', 'utf-8'),
      'pgpKeyPassphrase': env.PGP_PASSPHRASE,
      'hostDomain': env.HOST_DOMAIN || env.MAILGUN_DOMAIN || 'tipbox.dev',
      'hmacKey': env.HMAC_KEY || '',
      'groupId': env.OC_GROUPID,
      'apiKey': env.OC_API_KEY,
      'logLevel': 'error'
};

var settings = {
    'development': {
      'mailgunApiKey': env.MAILGUN_API_KEY,
      'mailgunDomain': env.MAILGUN_DOMAIN || 'tipbox.in',
      'smtpHost': env.SMTP_HOST,
      'smtpPort': env.SMTP_PORT,
      'pgpKeyPassphrase': '1234',
      'hmacKey': '',
      'apiUrl': 'https://opencollective.herokuapp.com/',
      'logLevel': 'debug'
    }
  , 'staging': {
      'env': env.NODE_ENV,
      'mailgunApiKey': env.MAILGUN_API_KEY,
      'mailgunDomain': env.MAILGUN_DOMAIN,
      'logLevel': 'info'
  }
  , 'tipbox.in': {
      'mailgunApiKey': env.MAILGUN_API_KEY,
      'mailgunDomain': env.MAILGUN_DOMAIN
  }
  , 'tipbox.is': {
      'smtpHost': env.SMTP_HOST,
      'smtpPort': env.SMTP_PORT,
      'apiUrl': 'https://opencollective-prod.herokuapp.com/'
  }
};

module.exports = function(name) {
  var props = {};
  for (var key in defaults) { props[key] = defaults[key]; }
  for (var key in settings[name]) { props[key] = settings[name][key]; }
  return props;
}
<|endoftext|>


<commit_before>import React from 'react'
import { StyledPageTop, StyledPageContent, StyledPageContainer } from './styled'
import {
  TriangleDotsHalf,
  TriangleDotsFull,
  TriangleDotsLarge
} from '@components/svgs'

import { Meta } from '@components/meta'

const getDisplayName = (WrappedComponent) =>
  WrappedComponent.displayName || WrappedComponent.name || 'Component'

const Title = ({ children }) => (

)

const divider =

const Subtitle = ({ children }) =>
  children ? (

      {Array.isArray(children) ?
        children.reduce((prev, item, index) => {
          const itemEl =
{item}

          if (index === children.length - 1) {
            return prev.concat([itemEl])
          }
          return prev.concat([itemEl, divider])
        }, []) :
        children
      }

  ) : null

const TopArea = ({ title, subtitle, button }) => (

    </>
  </StyledPageTop>
)

const Button = ({ button }) => {
  if (!button) {
    return null
  }
  const { label, href } = button
  return label && href ? (

  ) : null
}
const PageTemplate = (Component, meta) => {
  class PageTemplateWrapper extends React.PureComponent {

    render() {
      return (
        <>
          <TopArea {...meta} />
          <Meta {...meta} />

            <TriangleDotsLarge
              style={{
                position: 'absolute',
                top: 0
              }}
            />
          </StyledPageContainer>
        </>
      )
    }
  }

  PageTemplateWrapper.displayName = `PageTemplateWrapper(${getDisplayName(
    Component
  )})`

  return PageTemplateWrapper
}

export default PageTemplate
<commit_msg>Add keys to subtitle array.<commit_after>import React from 'react'
import { StyledPageTop, StyledPageContent, StyledPageContainer } from './styled'
import {
  TriangleDotsHalf,
  TriangleDotsFull,
  TriangleDotsLarge
} from '@components/svgs'

import { Meta } from '@components/meta'

const getDisplayName = (WrappedComponent) =>
  WrappedComponent.displayName || WrappedComponent.name || 'Component'

const Title = ({ children }) => (

)

const SubtitleDivider = () => (

)
const Subtitle = ({ children }) =>
  children ? (

      {Array.isArray(children) ?
        children.reduce((prev, item, index) => {
          const itemEl =
{item}

          if (index === children.length - 1) {
            return prev.concat([itemEl])
          }
          return prev.concat([itemEl, <SubtitleDivider key={`divider-${index}`}/>])
        }, []) :
        children
      }

  ) : null

const TopArea = ({ title, subtitle, button }) => (

    </>
  </StyledPageTop>
)

const Button = ({ button }) => {
  if (!button) {
    return null
  }
  const { label, href } = button
  return label && href ? (

  ) : null
}
const PageTemplate = (Component, meta) => {
  class PageTemplateWrapper extends React.PureComponent {

    render() {
      return (
        <>
          <TopArea {...meta} />
          <Meta {...meta} />

            <TriangleDotsLarge
              style={{
                position: 'absolute',
                top: 0
              }}
            />
          </StyledPageContainer>
        </>
      )
    }
  }

  PageTemplateWrapper.displayName = `PageTemplateWrapper(${getDisplayName(
    Component
  )})`

  return PageTemplateWrapper
}

export default PageTemplate
<|endoftext|>


<commit_before>
const RG = require('./rg.js');
RG.System = require('./system.js');
RG.Map = require('./map.js');
RG.Time = require('./time.js');

/* Game engine which handles turn scheduling, systems updates and in-game
 * messaging between objects. */
const Engine = function(eventPool) {

    // Ignore GUI commands by default
    this.isGUICommand = () => false;
    this.doGUICommand = null;

    this.nextActor = null;
    this.animation = null;
    this.animationCallback = null;

    const _levelMap = {}; // All levels, ID -> level
    const _activeLevels = []; // Only these levels are simulated
    const _scheduler = new RG.Time.Scheduler();
    const _msg = new RG.MessageHandler();
    const _eventPool = eventPool;

    this.visibleCells = [];

    this.getMessages = () => _msg.getMessages();
    this.hasNewMessages = () => _msg.hasNew();
    this.clearMessages = () => { _msg.clear();};

    //--------------------------------------------------------------
    // ECS SYSTEMS
    //--------------------------------------------------------------

    // These systems updated after each action. Order is important, for example,
    // animations should be seen before actors are killed
    this.systemOrder = ['Disability', 'SpiritBind', 'BaseAction',
        'Attack', 'Chat',
        'Shop', 'SpellCast',
        'SpellEffect', 'Missile', 'Movement', 'Animation', 'Damage',
        'Battle', 'Skills', 'ExpPoints', 'Communication',
        'Events'];

    this.systems = {};
    this.systems.Disability = new RG.System.Disability(
        ['Stun', 'Paralysis']);
    this.systems.SpiritBind = new RG.System.SpiritBind(['SpiritBind']);
    this.systems.BaseAction = new RG.System.BaseAction(['Pickup', 'UseStairs']);
    this.systems.Chat = new RG.System.Chat(['Chat']);
    this.systems.Shop = new RG.System.Shop(['Transaction']);
    this.systems.Attack = new RG.System.Attack(['Attack']);
    this.systems.Missile = new RG.System.Missile(['Missile']);
    this.systems.Movement = new RG.System.Movement(['Movement']);
    this.systems.SpellCast = new RG.System.SpellCast(['SpellCast',
        'PowerDrain']);
    this.systems.SpellEffect = new RG.System.SpellEffect(
        ['SpellRay', 'SpellCell', 'SpellMissile', 'SpellArea']);
    this.systems.Animation = new RG.System.Animation(
        ['Animation']);
    this.systems.Damage = new RG.System.Damage(['Damage', 'Health']);
    this.systems.Battle = new RG.System.Battle(['BattleOver']);
    this.systems.Skills = new RG.System.Skills(['SkillsExp']);
    this.systems.ExpPoints = new RG.System.ExpPoints(
        ['ExpPoints', 'Experience']);
    this.systems.Communication = new RG.System.Communication(
        ['Communication']);
    this.systems.Events = new RG.System.Events(['Event']);

    // Systems updated once each game loop (once for each player action)
    this.loopSystemOrder = ['Hunger'];
    this.loopSystems = {};
    this.loopSystems.Hunger = new RG.System.Hunger(['Action', 'Hunger']);

    // Time-based systems are added to the scheduler directly
    this.timeSystems = {};

    const effects = new RG.System.TimeEffects(['Expiration', 'Poison']);

    this.updateSystems = function() {
        for (let i = 0; i < this.systemOrder.length; i++) {
            const sysName = this.systemOrder[i];
            this.systems[sysName].update();
        }
    };

    this.updateLoopSystems = function() {
        for (let i = 0; i < this.loopSystemOrder.length; i++) {
            const sysName = this.loopSystemOrder[i];
            this.loopSystems[sysName].update();
        }
    };

    //--------------------------------------------------------------
    // SCHEDULING/ACTIONS
    //--------------------------------------------------------------

    /* Returns next actor from the scheduling queue.*/
    this.getNextActor = () => _scheduler.next();

    /* Adds an actor to the scheduler. */
    this.addActor = actor => {
        _scheduler.add(actor, true, 0);
    };

    /* Removes an actor from a scheduler.*/
    this.removeActor = actor => {
        _scheduler.remove(actor);
    };

    /* Adds an event to the scheduler.*/
    this.addEvent = gameEvent => {
        const repeat = gameEvent.getRepeat();
        const offset = gameEvent.getOffset();
        _scheduler.add(gameEvent, repeat, offset);
    };

    /* Performs one game action.*/
    this.doAction = action => {
        _scheduler.setAction(action);
        action.doAction();
        if (action.hasOwnProperty('energy')) {
            if (action.hasOwnProperty('actor')) {
                const actor = action.actor;
                if (actor.has('Action')) {
                    actor.get('Action').addEnergy(action.energy);
                }
            }
        }
    };

    //--------------------------------------------------------------
    // GAME LOOPS
    //--------------------------------------------------------------

    /* Main update command. Call this either with cmd to perform, or object
     * containing the pressed keycode. */
    this.update = function(obj) {
        if (!this.isGameOver()) {
            this.clearMessages();

            if (this.nextActor !== null) {
                if (obj.hasOwnProperty('code')) {
                    const code = obj.code;
                    if (this.isGUICommand(code)) {
                        this.doGUICommand(code);
                    }
                    else {
                        this.updateGameLoop({code});
                    }
                }
                else {
                    this.updateGameLoop(obj);
                }
            }

        }
        else {
            this.clearMessages();
            _eventPool.emitEvent(RG.EVT_MSG, {msg: 'GAME OVER!'});
            this.simulateGame(100);
        }
    };

    /* Updates the loop by executing one player command, then looping until
     * next player command.*/
    this.updateGameLoop = function(obj) {
        this.playerCommand(obj);
        this.currPlayer = this.nextActor;
        this.nextActor = this.getNextActor();

        // Next/act until player found, then go back waiting for key...
        while (!this.nextActor.isPlayer() && !this.isGameOver()) {
            const action = this.nextActor.nextAction();
            this.doAction(action);

            this.updateSystems(); // All systems for each actor

            // TODO check any animations that should be shown

            this.nextActor = this.getNextActor();
            if (RG.isNullOrUndef([this.nextActor])) {
                RG.err('Game.Engine', 'updateGameLoop',
                    'Game loop out of events! Fatal!');
                break; // if errors suppressed (testing), breaks the loop
            }
        }

        this.updateLoopSystems(); // Loop systems once per player action

    };

    /* Simulates the game without a player.*/
    this.simulateGame = function(nTurns = 1) {
        for (let i = 0; i < nTurns; i++) {
            this.nextActor = this.getNextActor();

            if (!this.nextActor.isPlayer()) {
                const action = this.nextActor.nextAction();
                this.doAction(action);
                this.updateSystems();
            }
            else {
                RG.err('Engine', 'simulateGame',
                    "Doesn't work with player.");
            }
        }
    };

    this.playerCommand = function(obj) {
        if (this.nextActor.isPlayer() === false) {
            let msg = '';
            if (this.nextActor.hasOwnProperty('isEvent')) {
                msg = 'Expected player, got an event: ';
            }
            else {
                msg = 'Expected player, got: ' + this.nextActor.getName();
            }
            msg += '\n' + JSON.stringify(this.nextActor);
            RG.err('Engine', 'playerCommand', msg);
        }
        const action = this.nextActor.nextAction(obj);
        this.doAction(action);
        this.updateSystems();
        this.playerCommandCallback(this.nextActor);
    };

    //--------------------------------------------------------------
    // MANAGING ACTIVE LEVELS
    //--------------------------------------------------------------

    this.numActiveLevels = () => _activeLevels.length;

    this.hasLevel = level => _levelMap.hasOwnProperty(level.getID());

    /* Adds one level to the game database.*/
    this.addLevel = level => {
        const id = level.getID();
        if (!_levelMap.hasOwnProperty(id)) {
            _levelMap[level.getID()] = level;
        }
        else {
            RG.err('Game.Engine', 'addLevel',
                'Level ID ' + id + ' already exists!');
        }
    };

    /* Adds an active level. Only these levels are simulated.*/
    this.addActiveLevel = function(level) {
        const levelID = level.getID();
        const index = _activeLevels.indexOf(levelID);

        // Check if a level must be removed
        if (_activeLevels.length === (RG.MAX_ACTIVE_LEVELS)) {
            if (index === -1) { // No room for new level, pop one
                const removedLevelID = _activeLevels.pop();
                const removedLevel = _levelMap[removedLevelID];
                if (removedLevel) {
                    const rmvActors = removedLevel.getActors();
                    for (let i = 0; i < rmvActors.length; i++) {
                        rmvActors[i].get('Action').disable();
                    }
                    RG.debug(this, 'Removed active level to make space...');
                }
                else {
                    const levelIDs = Object.keys(_levelMap).join(', ');
                    RG.err('Game.Engine', 'addActiveLevel',
                        `Failed to remove level ID ${removedLevelID}.
                        IDs: ${levelIDs}`);
                }
            }
            else { // Level already in actives, move to the front only
                _activeLevels.splice(index, 1);
                _activeLevels.unshift(levelID);
                RG.debug(this, 'Moved level to the front of active levels.');
            }
        }

        // This is a new level, enable all actors by enabling Action comp
        if (index === -1) {
            _activeLevels.unshift(levelID);
            const actActors = level.getActors();
            for (let j = 0; j < actActors.length; j++) {
                actActors[j].get('Action').enable();
            }
        }
    };

    this.isGameOver = () => false;

    this.isActiveLevel = level => {
        const index = _activeLevels.indexOf(level.getID());
        return index >= 0;
    };

    /* Adds a TimeSystem into the engine. Each system can be updated with given
     * intervals instead of every turn or loop.*/
    this.addTimeSystem = function(name, obj) {
        this.timeSystems[name] = obj;
        // Must schedule the system to activate it
        const updateEvent = new RG.Time.GameEvent(100,
            obj.update.bind(obj), true, 0);
        this.addEvent(updateEvent);
    };
    this.addTimeSystem('TimeEffects', effects);

    //--------------------------------------------------------------
    // EVENT LISTENING
    //--------------------------------------------------------------

    this.hasNotify = true;
    this.notify = function(evtName, args) {
        if (evtName === RG.EVT_DESTROY_ITEM) {
            const item = args.item;

            // chaining due to inventory container
            const owner = item.getOwner().getOwner();
            if (!owner.getInvEq().removeItem(item)) {
                RG.err('Game.Engine', 'notify - DESTROY_ITEM',
                    'Failed to remove item from inventory.');
            }
        }
        else if (evtName === RG.EVT_ACT_COMP_ADDED) {
            if (args.hasOwnProperty('actor')) {
                this.addActor(args.actor);
            }
            else {
                RG.err('Game.Engine', 'notify - ACT_COMP_ADDED',
                    'No actor specified for the event.');
            }
        }
        else if (evtName === RG.EVT_ACT_COMP_REMOVED) {
            if (args.hasOwnProperty('actor')) {
                this.removeActor(args.actor);
            }
            else {
                RG.err('Game.Engine', 'notify - ACT_COMP_REMOVED',
                    'No actor specified for the event.');
            }
        }
        else if (evtName === RG.EVT_ACT_COMP_ENABLED) {
            if (args.hasOwnProperty('actor')) {
                this.addActor(args.actor);
            }
            else {
                RG.err('Game.Engine', 'notify - ACT_COMP_ENABLED',
                    'No actor specified for the event.');
            }
        }
        else if (evtName === RG.EVT_ACT_COMP_DISABLED) {
            if (args.hasOwnProperty('actor')) {
                this.removeActor(args.actor);
            }
            else {
                RG.err('Game', 'notify - ACT_COMP_DISABLED',
                    'No actor specified for the event.');
            }
        }
        else if (evtName === RG.EVT_LEVEL_PROP_ADDED) {
            if (args.propType === 'actors') {
                if (this.isActiveLevel(args.level)) {
                    // args.obj is actor
                    args.obj.get('Action').enable();
                }
            }
        }
        else if (evtName === RG.EVT_LEVEL_CHANGED) {
            const actor = args.actor;
            if (actor.isPlayer()) {
                this.addActiveLevel(actor.getLevel());
                args.src.onExit();
                args.src.onFirstExit();
                args.target.onEnter();
                args.target.onFirstEnter();
            }
        }
        else if (evtName === RG.EVT_ANIMATION) {
            if (this.canPlayerSeeAnimation(args.animation)) {
                if (this.animationCallback) {
                    this.animation = args.animation;
                    this.animationCallback(this.animation);
                }
            }
        }
    };
    _eventPool.listenEvent(RG.EVT_DESTROY_ITEM, this);
    _eventPool.listenEvent(RG.EVT_ACT_COMP_ADDED, this);
    _eventPool.listenEvent(RG.EVT_ACT_COMP_REMOVED, this);
    _eventPool.listenEvent(RG.EVT_ACT_COMP_ENABLED, this);
    _eventPool.listenEvent(RG.EVT_ACT_COMP_DISABLED, this);
    _eventPool.listenEvent(RG.EVT_LEVEL_PROP_ADDED, this);
    _eventPool.listenEvent(RG.EVT_LEVEL_CHANGED, this);
    _eventPool.listenEvent(RG.EVT_ANIMATION, this);

    this.hasAnimation = function() {
        return this.animation !== null &&
            this.animation.hasFrames();
    };

    this.setVisibleCells = cells => {
        this.visibleCells = cells;
    };

    /* Returns true if player can see the given animation. In general, true
     * whenever animation contains at least one cell visible to the player. */
    this.canPlayerSeeAnimation = animation => {
        const coordList = this.visibleCells.map(cell => (
            [cell.getX(), cell.getY()]
        ));
        return animation.hasCoord(coordList);
    };

};

module.exports = Engine;
<commit_msg>Added caching of visible cell coordinates.<commit_after>
const RG = require('./rg.js');
RG.System = require('./system.js');
RG.Map = require('./map.js');
RG.Time = require('./time.js');

/* Game engine which handles turn scheduling, systems updates and in-game
 * messaging between objects. */
const Engine = function(eventPool) {

    // Ignore GUI commands by default
    this.isGUICommand = () => false;
    this.doGUICommand = null;

    this.nextActor = null;
    this.animation = null;
    this.animationCallback = null;

    const _levelMap = {}; // All levels, ID -> level
    const _activeLevels = []; // Only these levels are simulated
    const _scheduler = new RG.Time.Scheduler();
    const _msg = new RG.MessageHandler();
    const _eventPool = eventPool;

    this.visibleCells = [];

    this._cache = {};

    this.getMessages = () => _msg.getMessages();
    this.hasNewMessages = () => _msg.hasNew();
    this.clearMessages = () => { _msg.clear();};

    //--------------------------------------------------------------
    // ECS SYSTEMS
    //--------------------------------------------------------------

    // These systems updated after each action. Order is important, for example,
    // animations should be seen before actors are killed
    this.systemOrder = ['Disability', 'SpiritBind', 'BaseAction',
        'Attack', 'Chat',
        'Shop', 'SpellCast',
        'SpellEffect', 'Missile', 'Movement', 'Animation', 'Damage',
        'Battle', 'Skills', 'ExpPoints', 'Communication',
        'Events'];

    this.systems = {};
    this.systems.Disability = new RG.System.Disability(
        ['Stun', 'Paralysis']);
    this.systems.SpiritBind = new RG.System.SpiritBind(['SpiritBind']);
    this.systems.BaseAction = new RG.System.BaseAction(['Pickup', 'UseStairs']);
    this.systems.Chat = new RG.System.Chat(['Chat']);
    this.systems.Shop = new RG.System.Shop(['Transaction']);
    this.systems.Attack = new RG.System.Attack(['Attack']);
    this.systems.Missile = new RG.System.Missile(['Missile']);
    this.systems.Movement = new RG.System.Movement(['Movement']);
    this.systems.SpellCast = new RG.System.SpellCast(['SpellCast',
        'PowerDrain']);
    this.systems.SpellEffect = new RG.System.SpellEffect(
        ['SpellRay', 'SpellCell', 'SpellMissile', 'SpellArea']);
    this.systems.Animation = new RG.System.Animation(
        ['Animation']);
    this.systems.Damage = new RG.System.Damage(['Damage', 'Health']);
    this.systems.Battle = new RG.System.Battle(['BattleOver']);
    this.systems.Skills = new RG.System.Skills(['SkillsExp']);
    this.systems.ExpPoints = new RG.System.ExpPoints(
        ['ExpPoints', 'Experience']);
    this.systems.Communication = new RG.System.Communication(
        ['Communication']);
    this.systems.Events = new RG.System.Events(['Event']);

    // Systems updated once each game loop (once for each player action)
    this.loopSystemOrder = ['Hunger'];
    this.loopSystems = {};
    this.loopSystems.Hunger = new RG.System.Hunger(['Action', 'Hunger']);

    // Time-based systems are added to the scheduler directly
    this.timeSystems = {};

    const effects = new RG.System.TimeEffects(['Expiration', 'Poison']);

    this.updateSystems = function() {
        for (let i = 0; i < this.systemOrder.length; i++) {
            const sysName = this.systemOrder[i];
            this.systems[sysName].update();
        }
    };

    this.updateLoopSystems = function() {
        for (let i = 0; i < this.loopSystemOrder.length; i++) {
            const sysName = this.loopSystemOrder[i];
            this.loopSystems[sysName].update();
        }
    };

    //--------------------------------------------------------------
    // SCHEDULING/ACTIONS
    //--------------------------------------------------------------

    /* Returns next actor from the scheduling queue.*/
    this.getNextActor = () => _scheduler.next();

    /* Adds an actor to the scheduler. */
    this.addActor = actor => {
        _scheduler.add(actor, true, 0);
    };

    /* Removes an actor from a scheduler.*/
    this.removeActor = actor => {
        _scheduler.remove(actor);
    };

    /* Adds an event to the scheduler.*/
    this.addEvent = gameEvent => {
        const repeat = gameEvent.getRepeat();
        const offset = gameEvent.getOffset();
        _scheduler.add(gameEvent, repeat, offset);
    };

    /* Performs one game action.*/
    this.doAction = action => {
        _scheduler.setAction(action);
        action.doAction();
        if (action.hasOwnProperty('energy')) {
            if (action.hasOwnProperty('actor')) {
                const actor = action.actor;
                if (actor.has('Action')) {
                    actor.get('Action').addEnergy(action.energy);
                }
            }
        }
    };

    //--------------------------------------------------------------
    // GAME LOOPS
    //--------------------------------------------------------------

    /* Main update command. Call this either with cmd to perform, or object
     * containing the pressed keycode. */
    this.update = function(obj) {
        if (!this.isGameOver()) {
            this.clearMessages();

            if (this.nextActor !== null) {
                if (obj.hasOwnProperty('code')) {
                    const code = obj.code;
                    if (this.isGUICommand(code)) {
                        this.doGUICommand(code);
                    }
                    else {
                        this.updateGameLoop({code});
                    }
                }
                else {
                    this.updateGameLoop(obj);
                }
            }

        }
        else {
            this.clearMessages();
            _eventPool.emitEvent(RG.EVT_MSG, {msg: 'GAME OVER!'});
            this.simulateGame(100);
        }
    };

    /* Updates the loop by executing one player command, then looping until
     * next player command.*/
    this.updateGameLoop = function(obj) {
        this.playerCommand(obj);
        this.currPlayer = this.nextActor;
        this.nextActor = this.getNextActor();

        // Next/act until player found, then go back waiting for key...
        while (!this.nextActor.isPlayer() && !this.isGameOver()) {
            const action = this.nextActor.nextAction();
            this.doAction(action);

            this.updateSystems(); // All systems for each actor

            this.nextActor = this.getNextActor();
            if (RG.isNullOrUndef([this.nextActor])) {
                RG.err('Game.Engine', 'updateGameLoop',
                    'Game loop out of events! Fatal!');
                break; // if errors suppressed (testing), breaks the loop
            }
        }

        this.updateLoopSystems(); // Loop systems once per player action

    };

    /* Simulates the game without a player.*/
    this.simulateGame = function(nTurns = 1) {
        for (let i = 0; i < nTurns; i++) {
            this.nextActor = this.getNextActor();

            if (!this.nextActor.isPlayer()) {
                const action = this.nextActor.nextAction();
                this.doAction(action);
                this.updateSystems();
            }
            else {
                RG.err('Engine', 'simulateGame',
                    "Doesn't work with player.");
            }
        }
    };

    this.playerCommand = function(obj) {
        if (this.nextActor.isPlayer() === false) {
            let msg = '';
            if (this.nextActor.hasOwnProperty('isEvent')) {
                msg = 'Expected player, got an event: ';
            }
            else {
                msg = 'Expected player, got: ' + this.nextActor.getName();
            }
            msg += '\n' + JSON.stringify(this.nextActor);
            RG.err('Engine', 'playerCommand', msg);
        }
        const action = this.nextActor.nextAction(obj);
        this.doAction(action);
        this.updateSystems();
        this.playerCommandCallback(this.nextActor);
    };

    //--------------------------------------------------------------
    // MANAGING ACTIVE LEVELS
    //--------------------------------------------------------------

    this.numActiveLevels = () => _activeLevels.length;

    this.hasLevel = level => _levelMap.hasOwnProperty(level.getID());

    /* Adds one level to the game database.*/
    this.addLevel = level => {
        const id = level.getID();
        if (!_levelMap.hasOwnProperty(id)) {
            _levelMap[level.getID()] = level;
        }
        else {
            RG.err('Game.Engine', 'addLevel',
                'Level ID ' + id + ' already exists!');
        }
    };

    /* Adds an active level. Only these levels are simulated.*/
    this.addActiveLevel = function(level) {
        const levelID = level.getID();
        const index = _activeLevels.indexOf(levelID);

        // Check if a level must be removed
        if (_activeLevels.length === (RG.MAX_ACTIVE_LEVELS)) {
            if (index === -1) { // No room for new level, pop one
                const removedLevelID = _activeLevels.pop();
                const removedLevel = _levelMap[removedLevelID];
                if (removedLevel) {
                    const rmvActors = removedLevel.getActors();
                    for (let i = 0; i < rmvActors.length; i++) {
                        rmvActors[i].get('Action').disable();
                    }
                    RG.debug(this, 'Removed active level to make space...');
                }
                else {
                    const levelIDs = Object.keys(_levelMap).join(', ');
                    RG.err('Game.Engine', 'addActiveLevel',
                        `Failed to remove level ID ${removedLevelID}.
                        IDs: ${levelIDs}`);
                }
            }
            else { // Level already in actives, move to the front only
                _activeLevels.splice(index, 1);
                _activeLevels.unshift(levelID);
                RG.debug(this, 'Moved level to the front of active levels.');
            }
        }

        // This is a new level, enable all actors by enabling Action comp
        if (index === -1) {
            _activeLevels.unshift(levelID);
            const actActors = level.getActors();
            for (let j = 0; j < actActors.length; j++) {
                actActors[j].get('Action').enable();
            }
        }
    };

    this.isGameOver = () => false;

    this.isActiveLevel = level => {
        const index = _activeLevels.indexOf(level.getID());
        return index >= 0;
    };

    /* Adds a TimeSystem into the engine. Each system can be updated with given
     * intervals instead of every turn or loop.*/
    this.addTimeSystem = function(name, obj) {
        this.timeSystems[name] = obj;
        // Must schedule the system to activate it
        const updateEvent = new RG.Time.GameEvent(100,
            obj.update.bind(obj), true, 0);
        this.addEvent(updateEvent);
    };
    this.addTimeSystem('TimeEffects', effects);

    //--------------------------------------------------------------
    // EVENT LISTENING
    //--------------------------------------------------------------

    this.hasNotify = true;
    this.notify = function(evtName, args) {
        if (evtName === RG.EVT_DESTROY_ITEM) {
            const item = args.item;

            // chaining due to inventory container
            const owner = item.getOwner().getOwner();
            if (!owner.getInvEq().removeItem(item)) {
                RG.err('Game.Engine', 'notify - DESTROY_ITEM',
                    'Failed to remove item from inventory.');
            }
        }
        else if (evtName === RG.EVT_ACT_COMP_ADDED) {
            if (args.hasOwnProperty('actor')) {
                this.addActor(args.actor);
            }
            else {
                RG.err('Game.Engine', 'notify - ACT_COMP_ADDED',
                    'No actor specified for the event.');
            }
        }
        else if (evtName === RG.EVT_ACT_COMP_REMOVED) {
            if (args.hasOwnProperty('actor')) {
                this.removeActor(args.actor);
            }
            else {
                RG.err('Game.Engine', 'notify - ACT_COMP_REMOVED',
                    'No actor specified for the event.');
            }
        }
        else if (evtName === RG.EVT_ACT_COMP_ENABLED) {
            if (args.hasOwnProperty('actor')) {
                this.addActor(args.actor);
            }
            else {
                RG.err('Game.Engine', 'notify - ACT_COMP_ENABLED',
                    'No actor specified for the event.');
            }
        }
        else if (evtName === RG.EVT_ACT_COMP_DISABLED) {
            if (args.hasOwnProperty('actor')) {
                this.removeActor(args.actor);
            }
            else {
                RG.err('Game', 'notify - ACT_COMP_DISABLED',
                    'No actor specified for the event.');
            }
        }
        else if (evtName === RG.EVT_LEVEL_PROP_ADDED) {
            if (args.propType === 'actors') {
                if (this.isActiveLevel(args.level)) {
                    // args.obj is actor
                    args.obj.get('Action').enable();
                }
            }
        }
        else if (evtName === RG.EVT_LEVEL_CHANGED) {
            const actor = args.actor;
            if (actor.isPlayer()) {
                this.addActiveLevel(actor.getLevel());
                args.src.onExit();
                args.src.onFirstExit();
                args.target.onEnter();
                args.target.onFirstEnter();
            }
        }
        else if (evtName === RG.EVT_ANIMATION) {
            if (this.canPlayerSeeAnimation(args.animation)) {
                if (this.animationCallback) {
                    this.animation = args.animation;
                    this.animationCallback(this.animation);
                }
            }
        }
    };
    _eventPool.listenEvent(RG.EVT_DESTROY_ITEM, this);
    _eventPool.listenEvent(RG.EVT_ACT_COMP_ADDED, this);
    _eventPool.listenEvent(RG.EVT_ACT_COMP_REMOVED, this);
    _eventPool.listenEvent(RG.EVT_ACT_COMP_ENABLED, this);
    _eventPool.listenEvent(RG.EVT_ACT_COMP_DISABLED, this);
    _eventPool.listenEvent(RG.EVT_LEVEL_PROP_ADDED, this);
    _eventPool.listenEvent(RG.EVT_LEVEL_CHANGED, this);
    _eventPool.listenEvent(RG.EVT_ANIMATION, this);

    this.hasAnimation = function() {
        return this.animation !== null &&
            this.animation.hasFrames();
    };

    this.setVisibleArea = (level, cells) => {
        this.visibleLevelID = level.getID();
        this.visibleCells = cells;
        this._cache.visibleCoord = {};
    };

    /* Returns true if player can see the given animation. In general, true
     * whenever animation contains at least one cell visible to the player. */
    this.canPlayerSeeAnimation = animation => {
        if (animation.levelID === this.visibleLevelID) {
            if (Object.keys(this._cache.visibleCoord).length === 0) {
                this.visibleCells.forEach(cell => {
                    const [x, y] = [cell.getX(), cell.getY()];
                    this._cache.visibleCoord[x + ',' + y] = true;
                });
            }
            return animation.hasCoord(this._cache.visibleCoord);
        }
        return false;
    };

};

module.exports = Engine;
<|endoftext|>


<commit_before>var proxy = require("http-proxy-middleware");

module.exports = {
    server: {
        baseDir: "src/main/resources/static",
        middleware: [
            proxy("/api", {target: "http://localhost:8400/"}),
            proxy("/proxy", {target: "http://localhost:8400/"})
        ]
    }
};
<commit_msg>KYLO-762 Added login and logout paths to Browser Sync.<commit_after>var proxy = require("http-proxy-middleware");
var proxyFilter = function (pathName, req) {
    return pathName.match(/^\/api|^\/login$|^\/logout$|^\/proxy/);
};

module.exports = {
    server: {
        baseDir: "src/main/resources/static",
        middleware: [
            proxy(proxyFilter, {target: "http://localhost:8400/"})
        ]
    }
};
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length<commit_msg>Fixing punctuation<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)<|endoftext|>


<commit_before>/**
 * Copyright 2014 Confluent Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
"use strict";

/**
 * A simple consumer of tweets that periodically reports trending topics.
 */

var KafkaRest = require("../.."),
    argv = require('minimist')(process.argv.slice(2));

var api_url = argv.url || "http://localhost:8082";
var topicName = argv.topic;
var consumerGroup = argv.group;
var fromBeginning = argv['from-beginning'];
var help = (argv.help || argv.h);

if (help || topicName === undefined) {
    console.log("Compute and report trending topics in tweets.");
    console.log();
    console.log("Usage: node trending.js [--url <api-base-url>] --topic <topic> [--group <consumer-group-name>] [--from-beginning]");
    process.exit(help ? 0 : 1);
}

if (consumerGroup === undefined)
    consumerGroup = "tweet-trending-consumer-" + Math.round(Math.random() * 100000);

var kafka = new KafkaRest({"url": api_url});
var consumer_instance;
// How often to report the top 10
var report_period = 10000;
// How much to discount the current weights for each report_period
var period_discount_rate = .99;

var consumerConfig = {};
if (fromBeginning) {
    consumerConfig['auto.offset.reset'] = 'smallest';
}
kafka.consumer(consumerGroup).join(consumerConfig, function(err, ci) {
    if (err) return console.log("Failed to create instance in consumer group: " + err);
    consumer_instance = ci;
    var stream = consumer_instance.subscribe(topicName);
    stream.on('read', function(msgs) {
        for(var i = 0; i < msgs.length; i++) {
            var tweet = JSON.parse(msgs[i].value.toString('utf8'));
            processTweet(tweet);
        }
    });
    stream.on('error', function(err) {
        console.log("Consumer instance reported an error: " + err);
        shutdown();
    });

    process.on('SIGINT', shutdown);
});

// Implements a simple EWA scheme on lower-cased ngrams.
var topics = {};
function processTweet(tweet) {
    var words = tweet.text.toLowerCase().split(/\s/);

    // Filter blanks, common words
    var filtered_words = [];
    for(var i = 0; i < words.length; i++) {
        if (words[i].length > 0 && !stopwords[words[i]])
            filtered_words.push(words[i]);
    }

    // Generate ngrams and increment weights
    for(var i = 0; i < filtered_words.length; i++) {
        var ngram = filtered_words[i];
        for(var n = 1; n < 3; n++) {
            if (i + n < filtered_words.length) {
                ngram += " " + filtered_words[i + n];
                if (topics[ngram] === undefined)
                    topics[ngram] = {'topic': ngram, 'weight': 0};
                topics[ngram].weight += 1;
            }
        }
    }
}

// Setup period reporting, discounting of topic weights, and cleanup of small
var reportInterval = setInterval(function() {
    var sorted_terms = [];
    for(var topicKey in topics) {
        var topic = topics[topicKey];
        // Discounting won't affect sorting, so we can do this in the same pass
        topic.weight *= period_discount_rate;
        sorted_terms.push(topic);
    }
    sorted_terms.sort(function(a,b) { return (a.weight > b.weight ? -1 : (a.weight == b.weight ? 0 : 1)); });

    for(var i = 0; i < Math.min(10, sorted_terms.length); i++) {
        console.log("" + i + ". " + sorted_terms[i].topic + " \t(" + sorted_terms[i].weight + ")");
    }
    console.log();
}, report_period);

function shutdown() {
    consumer_instance.shutdown(function(err) {
        if (err) console.log("Error shutting down consumer instance: " + err);
    });
    clearInterval(reportInterval);
}

var stopwords = {};
(function() {
    var stopwords_str = "a about above after again against all am an and any are aren't as at be because been before being " +
        "below between both but by can't cannot could couldn't did didn't do does doesn't doing don't down during each few " +
        "for from further had hadn't has hasn't have haven't having he he'd he'll he's her here here's hers herself him " +
        "himself his how how's i i'd i'll i'm i've if in into is isn't it it's its itself let's me more most mustn't my " +
        "myself no nor not of off on once only or other ought our ours ourselves out over own same shan't she she'd she'll " +
        "she's should shouldn't so some such than that that's the their theirs them themselves then there there's these they " +
        "they'd they'll they're they've this those through to too under until up very was wasn't we we'd we'll we're we've " +
        "were weren't what what's when when's where where's which while who who's whom why why's with won't would wouldn't " +
        "you you'd you'll you're you've your yours yourself yourselves rt";
    var stopwords_list = stopwords_str.split(' ');
    for(var i = 0; i < stopwords_list.length; i++)
        stopwords[stopwords_list[i]] = true;
})();
<commit_msg>Make Twitter example get trending hashtags instead of ngrams.<commit_after>/**
 * Copyright 2014 Confluent Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
"use strict";

/**
 * A simple consumer of tweets that periodically reports trending hashtags.
 */

var KafkaRest = require("../.."),
    argv = require('minimist')(process.argv.slice(2));

var api_url = argv.url || "http://localhost:8082";
var topicName = argv.topic;
var consumerGroup = argv.group;
var fromBeginning = argv['from-beginning'];
var help = (argv.help || argv.h);

if (help || topicName === undefined) {
    console.log("Compute and report trending hashtags in tweets.");
    console.log();
    console.log("Usage: node trending.js [--url <api-base-url>] --topic <topic> [--group <consumer-group-name>] [--from-beginning]");
    process.exit(help ? 0 : 1);
}

if (consumerGroup === undefined)
    consumerGroup = "tweet-trending-consumer-" + Math.round(Math.random() * 100000);

var kafka = new KafkaRest({"url": api_url});
var consumer_instance;
// How often to report the top 10
var report_period = 10000;
// How much to discount the current weights for each report_period
var period_discount_rate = .99;

var consumerConfig = {};
if (fromBeginning) {
    consumerConfig['auto.offset.reset'] = 'smallest';
}
kafka.consumer(consumerGroup).join(consumerConfig, function(err, ci) {
    if (err) return console.log("Failed to create instance in consumer group: " + err);
    consumer_instance = ci;
    var stream = consumer_instance.subscribe(topicName);
    stream.on('read', function(msgs) {
        for(var i = 0; i < msgs.length; i++) {
            var tweet = JSON.parse(msgs[i].value.toString('utf8'));
            processTweet(tweet);
        }
    });
    stream.on('error', function(err) {
        console.log("Consumer instance reported an error: " + err);
        shutdown();
    });

    process.on('SIGINT', shutdown);
});

// Implements a simple EWA scheme on lower-cased hashtags.
var hashtags = {};
function processTweet(tweet) {
    var words = tweet.text.toLowerCase().split(/\s/);

    // Filter to hash tags, increment weights
    for(var i = 0; i < words.length; i++) {
        var word = words[i];
        if (word.length > 0 && word[0] == '#') {
            if (hashtags[word] === undefined)
                hashtags[word] = {'name': word, 'weight': 0};
            hashtags[word].weight += 1;
        }
    }
}

// Setup period reporting, discounting of hashtag weights, and cleanup of small
var reportInterval = setInterval(function() {
    var sorted_terms = [];
    for(var hashtagKey in hashtags) {
        var hashtag = hashtags[hashtagKey];
        // Discounting won't affect sorting, so we can do this in the same pass
        hashtag.weight *= period_discount_rate;
        sorted_terms.push(hashtag);
    }
    sorted_terms.sort(function(a,b) { return (a.weight > b.weight ? -1 : (a.weight == b.weight ? 0 : 1)); });

    for(var i = 0; i < Math.min(10, sorted_terms.length); i++) {
        console.log("" + i + ". " + sorted_terms[i].name + " \t(" + sorted_terms[i].weight + ")");
    }
    console.log();
}, report_period);

function shutdown() {
    consumer_instance.shutdown(function(err) {
        if (err) console.log("Error shutting down consumer instance: " + err);
    });
    clearInterval(reportInterval);
}
<|endoftext|>


<commit_before>fs = require('fs');
csv = require('csv');

// Functions needed ...

// To instantiate admin authentication data
//   * just bundle the object to JS

// To instantiate student authentication data
// To instantiate course membership rosters
// To call a requested admin page (default is top)
// To perform various admin operations after key validation
// To call the quiz page on a student and course
// To perform the final save and marking of a quiz after key validation

// To get a random key or random student ID, when needed in initializing
// student data
function getRandomKey(len, base) {
    // Modified from http://jsperf.com/random-md5-hash-implementations
    len = len ? len : 16;
    base = base ? base : 16;
    var _results;
    _results = [];
    for (var i=0;i<len;i+=1) {
        _results.push((Math.random() * base | 0).toString(base));
    }
    return _results.join("");
}

o = {};
o.one = 1;
o.two = "2";
o.three = "THREE";
myo = JSON.stringify(o);
fs.writeFile("/tmp/test", myo, function(err) {
    if(err) {
        console.log(err);
    } else {
        console.log("The file was saved! "+ myo);
    }
});
<commit_msg>Basic initialisation framework, I think<commit_after>fs = require('fs');
csv = require('csv');

var dirs = ['answer', 'ids', 'quiz'];

// make data dirs as required
for (var i=0,ilen=dirs.length;i<ilen;i+=1) {
    var dir = dirs[i];
    try {
        fs.mkdirSync(dir);
    } catch (e) {}
}

// To get a random key or random student ID, when needed in initializing data files
function getRandomKey(len, base) {
    // Modified from http://jsperf.com/random-md5-hash-implementations
    len = len ? len : 16;
    base = base ? base : 16;
    var _results;
    _results = [];
    for (var i=0;i<len;i+=1) {
        _results.push((Math.random() * base | 0).toString(base));
    }
    return _results.join("");
}

try {
    fs.openSync('./ids/admin.csv', 'r')
} catch (e) {
    if (e.code === 'ENOENT') {
        if (process.argv.length === 3) {
            var lst = [process.argv[2], getRandomKey()];
            csv().to('./ids/admin.csv').write(lst);
        } else {
            throw "ERROR: Must provide admin name as a single argument at first startup";
        }
    } else {
        throw e;
    }
}

function loadStudents() {
    console.log("XXX Next, load students, if any ...");
}

function loadClasses() {
    console.log("XXX And next, load classes, if any ...");
}

function runServer() {
    console.log("XXX And finally, spin up the server in all its glory ...");
}

var admin = {};
function loadAdmin() {
    csv()
        .from.stream(fs.createReadStream('./ids/admin.csv'))
        .on ('record', function (row,index) {
            admin[row[1]] = row[0];
            console.log("Admin URL for "+row[0]+": http://localhost:7943?admin="+row[1]);
        })
        .on('end', function(count){
            loadStudents();
        })
        .on('error', function (e) {
            throw e;
        });
}

// Setup
loadAdmin();

// Functions needed ...

// To instantiate admin authentication data
//   * just bundle the object to JS

// To instantiate student authentication data
// To instantiate course membership rosters
// To call a requested admin page (default is top)
// To perform various admin operations after key validation
// To call the quiz page on a student and course
// To perform the final save and marking of a quiz after key validation

<|endoftext|>


<commit_before>
var createClass = require('../functions/createClass');
var convertValueType = require('../functions/convertValueType');
var Binder = require('../Binder');
var View = require('../View');
var Cursor = require('../Cursor');

var createClassBinder = function(negate)
{
	var ClassBinder = createClass(
	{
		extend: Binder
	},
	/** @lends ClassBinder.prototype */
	{
		/**
		 * One-way data binder (model to DOM) for CSS class.
		 * Sets/Unsets the class of the element to some predefined value when model atrribute changes.
		 *
		 * @constructs
		 * @augments Binder
		 * @param {Object} options Options objectt
		 */
		constructor: function(options)
		{
			Binder.call(this, options);

			this.className = undefined;
			this.equalsTo = undefined;
			this.valueCursor = undefined;
		},

		init: function()
		{
			this.className = this.options.params[0] || null;
			this.equalsTo = true;
			this.valueCursor = undefined;

			if(this.options.params[1])
			{
				this.equalsTo = this.convertBindingValue(this.options.params[1]);
				if(this.equalsTo instanceof Cursor)
				{
					this.valueCursor = this.equalsTo;
					this.equalsTo = this.valueCursor.get();
				}
				if(this.equalsTo == null) this.equalsTo = null;
			}

			this.negate = this.options.params[2] === 'ne' || negate;

			ClassBinder._super.init.call(this);
		},

		refresh: function()
		{
			if(this.className)
			{
				if(this.matchValue())
				{
					this.element.classList.add(this.className);
				}
				else
				{
					this.element.classList.remove(this.className);
				}
			}
		},

		matchValue: function()
		{
			if(this.options.params.length > 1)
			{
				if(this.valueCursor)
				{
					this.equalsTo = this.valueCursor.get();
					if(this.equalsTo == null) this.equalsTo = null;
				}
				var value = this.value;
				if(value == null) value = null;
				if(this.negate) return value !== this.equalsTo;
				else return value === this.equalsTo;
			}
			else return this.value;
		}
	});

	if(typeof document === 'object' && document !== null)
	{
		if(!('classList' in document.documentElement))
		{
			ClassBinder.prototype.refresh = function(value)
			{
				if(this.className)
				{
					this.$element[this.matchValue() ? 'addClass' : 'removeClass'](this.className);
				}
			};
		}
	}

	return ClassBinder;

};

var ClassBinder = createClassBinder(false);
var ClassNotBinder = createClassBinder(true);

View.registerBinder('class', ClassBinder);
View.registerBinder('classnot', ClassNotBinder);

module.exports = {
	ClassBinder: ClassBinder,
	ClassNotBinder: ClassNotBinder
};
<commit_msg>fix(ClassBinder): wrong behavior when equalsTo is not specified<commit_after>
var createClass = require('../functions/createClass');
var convertValueType = require('../functions/convertValueType');
var Binder = require('../Binder');
var View = require('../View');
var Cursor = require('../Cursor');

var createClassBinder = function(negate)
{
	var ClassBinder = createClass(
	{
		extend: Binder
	},
	/** @lends ClassBinder.prototype */
	{
		/**
		 * One-way data binder (model to DOM) for CSS class.
		 * Sets/Unsets the class of the element to some predefined value when model atrribute changes.
		 *
		 * @constructs
		 * @augments Binder
		 * @param {Object} options Options objectt
		 */
		constructor: function(options)
		{
			Binder.call(this, options);

			this.className = undefined;
			this.equalsTo = undefined;
			this.valueCursor = undefined;
		},

		init: function()
		{
			this.className = this.options.params[0] || null;
			this.equalsTo = true;
			this.valueCursor = undefined;

			if(this.options.params[1])
			{
				this.equalsTo = this.convertBindingValue(this.options.params[1]);
				if(this.equalsTo instanceof Cursor)
				{
					this.valueCursor = this.equalsTo;
					this.equalsTo = this.valueCursor.get();
				}
				if(this.equalsTo == null) this.equalsTo = null;
			}

			this.negate = this.options.params[2] === 'ne' || negate;

			ClassBinder._super.init.call(this);
		},

		refresh: function()
		{
			if(this.className)
			{
				if(this.matchValue())
				{
					this.element.classList.add(this.className);
				}
				else
				{
					this.element.classList.remove(this.className);
				}
			}
		},

		matchValue: function()
		{
			var value = this.value;
			if(value == null) value = null;
			if(this.options.params.length > 1)
			{
				if(this.valueCursor)
				{
					this.equalsTo = this.valueCursor.get();
					if(this.equalsTo == null) this.equalsTo = null;
				}
			}
			if(negate) return value !== this.equalsTo;
			else return value === this.equalsTo;
		}
	});

	if(typeof document === 'object' && document !== null)
	{
		if(!('classList' in document.documentElement))
		{
			ClassBinder.prototype.refresh = function(value)
			{
				if(this.className)
				{
					this.$element[this.matchValue() ? 'addClass' : 'removeClass'](this.className);
				}
			};
		}
	}

	return ClassBinder;

};

var ClassBinder = createClassBinder(false);
var ClassNotBinder = createClassBinder(true);

View.registerBinder('class', ClassBinder);
View.registerBinder('classnot', ClassNotBinder);

module.exports = {
	ClassBinder: ClassBinder,
	ClassNotBinder: ClassNotBinder
};
<|endoftext|>


<commit_before>const fs = require('fs-extra');
const _ = require('lodash');

const settings = require('../../config/settings');
const build = require('./build');
const buildOptionsGenerator = require('./build_options');

// -----------------------------------------------------------------------------
// Iterate through all applications calling the callback with the buildOptions
// -----------------------------------------------------------------------------
function allAppBuildOptions(options) {
  let port = parseInt(settings.hotPort, 10);
  return _.map(settings.apps, (app, appName) => {
    const buildOptions = buildOptionsGenerator(appName, app, port, options);
    port += 1;
    return buildOptions;
  });
}

// -----------------------------------------------------------------------------
// Build a single app
// -----------------------------------------------------------------------------
function buildAppParts(buildOptions, onlyPack) {
  if (onlyPack) {
    return build.buildWebpackEntries(buildOptions).then(() => {
      console.log(`Finished Javascript for ${buildOptions.appName}`);
    });
  }
  return build.build(buildOptions).then((result) => {
    console.log(`Finished Javascript for ${buildOptions.appName}.`);
    console.log(`Built ${result.pages.length} pages.`);
  });
}

// -----------------------------------------------------------------------------
// Build a single app
// -----------------------------------------------------------------------------
function buildApp(appName, options) {
  const app = _.find(settings.apps, (e, name) => appName === name);
  const buildOptions = buildOptionsGenerator(appName, app, settings.hotPort, options);
  return {
    buildOptions,
    buildPromise: buildAppParts(buildOptions, options.onlyPack)
  };
}

// -----------------------------------------------------------------------------
// Build all apps
// -----------------------------------------------------------------------------
function buildApps(options) {
  return _.map(allAppBuildOptions(options), (buildOptions) => {
    fs.emptyDirSync(buildOptions.outputPath);
    return {
      buildOptions,
      buildPromise: buildAppParts(buildOptions, options.onlyPack)
    };
  });
}

module.exports = {
  buildApp,
  buildApps
};
<commit_msg>Fixes promises returned when building apps.<commit_after>const fs = require('fs-extra');
const _ = require('lodash');

const settings = require('../../config/settings');
const build = require('./build');
const buildOptionsGenerator = require('./build_options');

// -----------------------------------------------------------------------------
// Iterate through all applications calling the callback with the buildOptions
// -----------------------------------------------------------------------------
function allAppBuildOptions(options) {
  let port = parseInt(settings.hotPort, 10);
  return _.map(settings.apps, (app, appName) => {
    const buildOptions = buildOptionsGenerator(appName, app, port, options);
    port += 1;
    return buildOptions;
  });
}

// -----------------------------------------------------------------------------
// Build a single app
// -----------------------------------------------------------------------------
function buildAppParts(buildOptions, onlyPack) {
  if (onlyPack) {
    const buildPromise = build.buildWebpackEntries(buildOptions);
    buildPromise.then(() => {
      console.log(`Finished Javascript for ${buildOptions.appName}`);
    });
    return buildPromise;
  }
  const buildPromise = build.build(buildOptions);
  buildPromise.then((result) => {
    console.log(`Finished Javascript for ${buildOptions.appName}.`);
    console.log(`Built ${result.pages.length} pages.`);
  });
  return buildPromise;
}

// -----------------------------------------------------------------------------
// Build a single app
// -----------------------------------------------------------------------------
function buildApp(appName, options) {
  const app = _.find(settings.apps, (e, name) => appName === name);
  const buildOptions = buildOptionsGenerator(appName, app, settings.hotPort, options);
  return {
    buildOptions,
    buildPromise: buildAppParts(buildOptions, options.onlyPack)
  };
}

// -----------------------------------------------------------------------------
// Build all apps
// -----------------------------------------------------------------------------
function buildApps(options) {
  return _.map(allAppBuildOptions(options), (buildOptions) => {
    fs.emptyDirSync(buildOptions.outputPath);
    return {
      buildOptions,
      buildPromise: buildAppParts(buildOptions, options.onlyPack)
    };
  });
}

module.exports = {
  buildApp,
  buildApps
};
<|endoftext|>