<commit_before>/**
 * The browser-side counterpart to CesiumWidget
 *
 * @author Petrus Hyvonen
 * @copyright Petrus Hyvonen 2014
 * @version 0.1.0
 * @license Apache
 */

var cesium_root = IPython.notebook.base_url + 'nbextensions/CesiumWidget/cesium/Source';
var cesium_path = cesium_root + '/Cesium';

require.config({
    baseUrl: cesium_root,
    urlArgs: "",
    waitSeconds: 60,
    paths: {
        cesium: cesium_path
    },
    shim: {
        cesium: {
            exports: 'cesium'
        },
    }
});

define(
    ['jquery',
        'underscore',
        'widgets/js/widget',
        'widgets/js/manager',
        'cesium'], function ($, _, widget, manager, Cesium) {

        'use strict';

        // Add cesium CSS link
        var cssref = $('<link/>')
            .attr('rel', 'stylesheet')
            .attr('type', 'text/css')
            .attr('href', IPython.notebook.base_url + 'nbextensions/CesiumWidget/cesium/Source/Widgets/widgets.css')
            .appendTo($('head'));

        var CesiumView = widget.DOMWidgetView.extend({

            render: function () {
                CesiumView.__super__.render.apply(this, arguments);
                //console.log('Running Render');

                var WIDTH = this.model.get('width'),
                    HEIGHT = this.model.get('height');

                this.$frame = $('<div/>').height(HEIGHT).width(WIDTH).uniqueId().appendTo(this.$el);
                this.cesiumId = this.$frame[0].id;
                this.has_drawn = false;

                // Wait for element to be added to the DOM
                //this.once('displayed', this.myupdate, this);

                this.after_displayed(this.init_viewer, this);
            },

            // Update: Do things that are updated every time `this.model` is changed...
            // on the front-end or backend.

            init_viewer: function () {
                console.log('Running Update');

                // Create Cesiumjs Viewer if not already there
                if (!this.has_drawn) {
                    this.has_drawn = true;

                    var timeline = this.model.get('timeline');
                    var animation = this.model.get('animation');
                    var baseLayerPicker = this.model.get('base_layer_picker');
                    var geocoder = this.model.get('geocoder');
                    var homeButton = this.model.get('home_button');
                    var infoBox = this.model.get('infobox');
                    var sceneModePicker = this.model.get('scene_mode_picker');
                    var selectionIndicator = this.model.get('selection_indicator');
                    var navigationHelpButton = this.model.get('navigation_help_button');
                    var navigationInstructionsInitiallyVisible = this.model.get('navigation_instructions_initially_visible');
                    var scene3DOnly = this.model.get('scene_3D_only');
                    var sceneMode_name = this.model.get('scene_mode');

                    var sceneModes = {
                        'COLUMBUS_VIEW': Cesium.SceneMode.COLUMBUS_VIEW,
                        'SCENE2D': Cesium.SceneMode.SCENE2D,
                        'SCENE3D': Cesium.SceneMode.SCENE3D
                    };

                    if (sceneModes[sceneMode_name])
                        var sceneMode = sceneModes[sceneMode_name];
                    else {
                        var sceneMode = Cesium.SceneMode.SCENE3D;
                        console.log('Illegal scene_mode received')
                        }

                    this.viewer = new Cesium.Viewer(this.cesiumId,{
                        timeline: timeline,
                        animation: animation,
                        baseLayerPicker: baseLayerPicker,
                        geocoder: geocoder,
                        homeButton: homeButton,
                        infoBox: infoBox,
                        sceneModePicker: sceneModePicker,
                        selectionIndicator: selectionIndicator,
                        navigationHelpButton: navigationHelpButton,
                        navigationInstructionsInitiallyVisible: navigationInstructionsInitiallyVisible,
                        scene3DOnly: scene3DOnly,
                        sceneMode: sceneMode
                    });

                    this.viewer.fullscreenButton.viewModel.fullscreenElement = this.viewer.container.childNodes[0];
                }

                this.update_lightning();
                this.model.on('change:enable_lightning', this.update_lightning, this);

                this.update_czml();
                this.model.on('change:czml', this.update_czml, this);
                this.update_kml();
                this.model.on('change:kml', this.update_kml, this);
                this.update_geojson();
                this.model.on('change:geojson', this.update_geojson, this);

                this.fly_to();
                this.model.on('change:_flyto', this.fly_to, this);
                this.zoom_to();
                this.model.on('change:_zoomto', this.zoom_to, this);
                this.zoom_to_region();
                this.model.on('change:_zoomtoregion', this.zoom_to_region, this);
                // call __super__.update to handle housekeeping
                //return CesiumView.__super__.update.apply(this, arguments);
            },

            update_lightning: function() {
                var enableLighting = this.model.get('enable_lighting');
                this.viewer.scene.globe.enableLighting = enableLighting;
            },

            update_czml: function () {
                console.log('Update CZML!');
                // Add or update the CZML
                var czml_string = this.model.get('czml');
                if (!$.isEmptyObject(czml_string)) {
                    var data = $.parseJSON(czml_string);
                    var cz = new Cesium.CzmlDataSource();

                    cz.load(data, 'Python CZML');
                    if (!$.isEmptyObject(this.czml)) {
                        this.viewer.dataSources.remove(this.czml,true);
                    }
                    console.log(cz);

                    this.viewer.dataSources.add(cz);
                    this.czml = cz;
                }
            },

            update_geojson: function () {
                console.log('Update geojson!');
                // Add or update the CZML
                var geojson_string = this.model.get('geojson');
                if (!$.isEmptyObject(geojson_string)) {
                    var data = $.parseJSON(geojson_string);
                    var gjson = new Cesium.GeoJsonDataSource();

                    gjson.load(data, 'Python geojson');
                    if (!$.isEmptyObject(this.geojson)) {
                        this.viewer.dataSources.remove(this.geojson,true);
                    }
                    console.log(gjson);
                    this.viewer.dataSources.add(gjson);
                    this.geojson = gjson;
                }
            },

            update_kml: function () {
                console.log('Update KML!');
                // Add or update the KML
                var kml_string = this.model.get('kml_url');
                if (!$.isEmptyObject(kml_string)) {
                    //var data = $.parseJSON(kml_string);
                    var kml = new Cesium.KmlDataSource();

                    kml.load(kml_string, 'Python KML');
                    if (!$.isEmptyObject(this.kml)) {
                        this.viewer.dataSources.remove(this.kml,true);
                    }
                    console.log(kml);

                    this.viewer.dataSources.add(kml);
                    this.kml = kml;
                }
            },

            fly_to: function () {
            	console.log('fly to location!');
				// move the camera to a location
				var flyto = this.model.get('_flyto');
				if (!$.isEmptyObject(flyto)) {
					var pos = flyto; //flyto.split(",");
					this.viewer.camera.flyTo({
					        destination : Cesium.Cartesian3.fromDegrees(Number(pos[0]), Number(pos[1]), Number(pos[2])),
					        orientation : {
					            heading : Cesium.Math.toRadians(Number(pos[3])),
					            pitch : Cesium.Math.toRadians(Number(pos[4])),
					            roll : Cesium.Math.toRadians(Number(pos[5]))
					        }
					    });
					//this.model.set('_flyto', null);
					this.touch()
				}
				console.log(pos);
            },

            zoom_to: function () {
            	console.log('zoom to a location!');
				// move the camera to a location
				var zoomto = this.model.get('_zoomto');
				if (!$.isEmptyObject(zoomto)) {
					var pos = zoomto; //.split(",");
					this.viewer.camera.setView({
					        position : Cesium.Cartesian3.fromDegrees(Number(pos[0]), Number(pos[1]), Number(pos[2])),
					        heading : Cesium.Math.toRadians(Number(pos[3])),
					        pitch : Cesium.Math.toRadians(Number(pos[4])),
					        roll : Cesium.Math.toRadians(Number(pos[5]))
					    });
					    //this.model.set('_zoomto', null);
					    this.touch()
				}
				console.log(pos);
            },

            zoom_to_region: function () {
            	console.log('view region!');
				// move the camera to a location
				var region = this.model.get('_zoomtoregion');
				if (!$.isEmptyObject(region)) {
					var pos = region // .split(",");
					var rectangle = Cesium.Rectangle.fromDegrees(Number(pos[0]), Number(pos[1]), Number(pos[2]), Number(pos[3]));
					this.viewer.camera.viewRectangle(rectangle);
					this.model.set('_zoomtoregion', null);
					this.touch();
				}
				console.log(region);
            }

        });

        return { CesiumView: CesiumView }
    });

<commit_msg>Update cesium_widget.js<commit_after>/**
 * The browser-side counterpart to CesiumWidget
 *
 * @author Petrus Hyvonen
 * @copyright Petrus Hyvonen 2014
 * @version 0.1.0
 * @license Apache
 */

var cesium_root = IPython.notebook.base_url + 'nbextensions/CesiumWidget/cesium/Source';
var cesium_path = cesium_root + '/Cesium';

require.config({
    baseUrl: cesium_root,
    urlArgs: "",
    waitSeconds: 60,
    paths: {
        cesium: cesium_path
    },
    shim: {
        cesium: {
            exports: 'cesium'
        },
    }
});

define(
    ['jquery',
        'underscore',
        'widgets/js/widget',
        'widgets/js/manager',
        'cesium'], function ($, _, widget, manager, Cesium) {

        'use strict';

        // Add cesium CSS link
        var cssref = $('<link/>')
            .attr('rel', 'stylesheet')
            .attr('type', 'text/css')
            .attr('href', IPython.notebook.base_url + 'nbextensions/CesiumWidget/cesium/Source/Widgets/widgets.css')
            .appendTo($('head'));

        var CesiumView = widget.DOMWidgetView.extend({

            render: function () {
                CesiumView.__super__.render.apply(this, arguments);
                //console.log('Running Render');

                var WIDTH = this.model.get('width'),
                    HEIGHT = this.model.get('height');

                this.$frame = $('<div/>').height(HEIGHT).width(WIDTH).uniqueId().appendTo(this.$el);
                this.cesiumId = this.$frame[0].id;
                this.has_drawn = false;

                // Wait for element to be added to the DOM
                //this.once('displayed', this.myupdate, this);

                this.after_displayed(this.init_viewer, this);
            },

            // Update: Do things that are updated every time `this.model` is changed...
            // on the front-end or backend.

            init_viewer: function () {
                console.log('Running Update');

                // Create Cesiumjs Viewer if not already there
                if (!this.has_drawn) {
                    this.has_drawn = true;

                    var timeline = this.model.get('timeline');
                    var animation = this.model.get('animation');
                    var baseLayerPicker = this.model.get('base_layer_picker');
                    var geocoder = this.model.get('geocoder');
                    var homeButton = this.model.get('home_button');
                    var infoBox = this.model.get('infobox');
                    var sceneModePicker = this.model.get('scene_mode_picker');
                    var selectionIndicator = this.model.get('selection_indicator');
                    var navigationHelpButton = this.model.get('navigation_help_button');
                    var navigationInstructionsInitiallyVisible = this.model.get('navigation_instructions_initially_visible');
                    var scene3DOnly = this.model.get('scene_3D_only');
                    var sceneMode_name = this.model.get('scene_mode');

                    var sceneModes = {
                        'COLUMBUS_VIEW': Cesium.SceneMode.COLUMBUS_VIEW,
                        'SCENE2D': Cesium.SceneMode.SCENE2D,
                        'SCENE3D': Cesium.SceneMode.SCENE3D
                    };

                    if (sceneModes[sceneMode_name])
                        var sceneMode = sceneModes[sceneMode_name];
                    else {
                        var sceneMode = Cesium.SceneMode.SCENE3D;
                        console.log('Illegal scene_mode received')
                        }

                    this.viewer = new Cesium.Viewer(this.cesiumId,{
                        timeline: timeline,
                        animation: animation,
                        baseLayerPicker: baseLayerPicker,
                        geocoder: geocoder,
                        homeButton: homeButton,
                        infoBox: infoBox,
                        sceneModePicker: sceneModePicker,
                        selectionIndicator: selectionIndicator,
                        navigationHelpButton: navigationHelpButton,
                        navigationInstructionsInitiallyVisible: navigationInstructionsInitiallyVisible,
                        scene3DOnly: scene3DOnly,
                        sceneMode: sceneMode
                    });

                    this.viewer.fullscreenButton.viewModel.fullscreenElement = this.viewer.container.childNodes[0];
                }

                this.update_lightning();
                this.model.on('change:enable_lightning', this.update_lightning, this);

                this.update_czml();
                this.model.on('change:czml', this.update_czml, this);
                this.update_kml();
                this.model.on('change:kml', this.update_kml, this);
                this.update_geojson();
                this.model.on('change:geojson', this.update_geojson, this);

                this.fly_to();
                this.model.on('change:_flyto', this.fly_to, this);
                this.zoom_to();
                this.model.on('change:_zoomto', this.zoom_to, this);
                this.zoom_to_region();
                this.model.on('change:_zoomtoregion', this.zoom_to_region, this);
                // call __super__.update to handle housekeeping
                //return CesiumView.__super__.update.apply(this, arguments);
            },

            update_lightning: function() {
                var enableLighting = this.model.get('enable_lighting');
                this.viewer.scene.globe.enableLighting = enableLighting;
            },

            update_czml: function () {
                console.log('Update CZML!');
                // Add or update the CZML
                var czml_string = this.model.get('czml');
                if (!$.isEmptyObject(czml_string)) {
                    var data = $.parseJSON(czml_string);
                    var cz = new Cesium.CzmlDataSource();

                    cz.load(data, 'Python CZML');
                    if (!$.isEmptyObject(this.czml)) {
                        this.viewer.dataSources.remove(this.czml,true);
                    }
                    console.log(cz);

                    this.viewer.dataSources.add(cz);
                    this.czml = cz;
                }
            },

            update_geojson: function () {
                console.log('Update geojson!');
                // Add or update the CZML
                var geojson_string = this.model.get('geojson');
                if (!$.isEmptyObject(geojson_string)) {
                    var data = $.parseJSON(geojson_string);
                    var gjson = new Cesium.GeoJsonDataSource();

                    gjson.load(data, 'Python geojson');
                    if (!$.isEmptyObject(this.geojson)) {
                        this.viewer.dataSources.remove(this.geojson,true);
                    }
                    console.log(gjson);
                    this.viewer.dataSources.add(gjson);
                    this.geojson = gjson;
                }
            },

            update_kml: function () {
                console.log('Update KML!');
                // Add or update the KML
                var kml_string = this.model.get('kml_url');
                if (!$.isEmptyObject(kml_string)) {
                    //var data = $.parseJSON(kml_string);
                    var kml = new Cesium.KmlDataSource();

                    kml.load(kml_string, 'Python KML');
                    if (!$.isEmptyObject(this.kml)) {
                        this.viewer.dataSources.remove(this.kml,true);
                    }
                    console.log(kml);

                    this.viewer.dataSources.add(kml);
                    this.kml = kml;
                }
            },

            fly_to: function () {
            	console.log('fly to location!');
				// move the camera to a location
				var flyto = this.model.get('_flyto');
				if (!$.isEmptyObject(flyto)) {
					var pos = flyto; //flyto.split(",");
					this.viewer.camera.flyTo({
					        destination : Cesium.Cartesian3.fromDegrees(Number(pos[0]), Number(pos[1]), Number(pos[2])),
					        orientation : {
					            heading : Cesium.Math.toRadians(Number(pos[3])),
					            pitch : Cesium.Math.toRadians(Number(pos[4])),
					            roll : Cesium.Math.toRadians(Number(pos[5]))
					        }
					    });
					//this.model.set('_flyto', null);
					this.touch()
				}
				console.log(pos);
            },

            zoom_to: function () {
            	console.log('zoom to a location!');
				// move the camera to a location
				var zoomto = this.model.get('_zoomto');
				if (!$.isEmptyObject(zoomto)) {
					var pos = zoomto; //.split(",");
					this.viewer.camera.setView({
					        position : Cesium.Cartesian3.fromDegrees(Number(pos[0]), Number(pos[1]), Number(pos[2])),
					        heading : Cesium.Math.toRadians(Number(pos[3])),
					        pitch : Cesium.Math.toRadians(Number(pos[4])),
					        roll : Cesium.Math.toRadians(Number(pos[5]))
					    });
					    //this.model.set('_zoomto', null);
					    this.touch()
				}
				console.log(pos);
            },

            zoom_to_region: function () {
            	console.log('view region!');
				// move the camera to a location
				var region = this.model.get('_zoomtoregion');
				if (!$.isEmptyObject(region)) {
					var pos = region // .split(",");
					var rectangle = Cesium.Rectangle.fromDegrees(Number(pos[0]), Number(pos[1]), Number(pos[2]), Number(pos[3]));
					this.viewer.camera.viewRectangle(rectangle);
					this.model.set('_zoomtoregion', null);
					this.touch();
				}
				console.log(region);
            },
            groundoverlay: function () {
            	console.log('add ground overlay');
            		var latitude = 40.0;
			var longitude = -100.0;
			var north = latitude + .35;
			var south = latitude - .35;
			var east = longitude + 1.55;
			var west = longitude - 1.55;
			var rectangle = Cesium.Rectangle.fromDegrees(west, south, east, north);

			var entity = viewer.entities.add({
    				rectangle: {
        				coordinates: rectangle,
        				material: './static/Cesium_Logo_Color.jpg'
    					}
				});
            }

        });

        return { CesiumView: CesiumView }
    });

<|endoftext|>


<commit_before>const shell = require('shelljs');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const lib = require('../lib');
const rimraf = require('rimraf');
const mkdirp = require('mkdirp');
const tools = require('../tools');
const atomar_config = require('../config');
const atomar_path = lib.lookup_module('atomar');

exports.command = 'deploy <deploy_path>';
exports.describe = 'Deploys an atomar application to run on an atomar instance';
exports.builder = {
    f: {
        alias: 'force',
        default: false,
        description: 'Overwrite an existing deployment'
    },
    app: {
        alias: 'app_path',
        default: './',
        description: 'The path to the application that will be deployed'
    },
    atomar: {
        alias: 'atomar_path',
        default: atomar_path,
        description: 'The path to the atomar installation.'
    }
};
exports.handler = function(argv) {
    let deploy_path = path.resolve(argv.deploy_path);
    let app_path = path.resolve(argv.app_path);
    let atomar_path = path.resolve(argv.atomar_path);

    let info = atomar_config.loadPackage();
    if(!info) throw new Error('Not an atomar module. Try running inside a module or use --app.');

    // validate atomar installation
    if(!atomar_path) {
        throw new Error('An installation of atomar could not be found. Please install atomar globally or specify a custom atomar installation path with --atomar_path');
    }

    let configPath = path.join(deploy_path, 'config.json');
    let htaccessPath = path.join(deploy_path, '.htaccess.json');
    let indexPath = path.join(deploy_path, 'index.php');

    // clean up existing deployment
    if(argv.force) {
        rimraf.sync(configPath);
        rimraf.sync(htaccessPath);
        rimraf.sync(indexPath);
    }

    if(tools.fileExists(configPath)) {
        throw new Error('A deployment already exists at ' + deploy_path + '. Use -f to overwrite');
    }

    console.log('Deploying "' + info.name + '" to ' + deploy_path);
    let templates = path.join(__dirname, 'deploy', 'templates');
    mkdirp(deploy_path);
    tools.injectTemplate(path.join(templates, 'index.php'), indexPath, {
        atomar_path: path.resolve(path.join(atomar_path, 'Atomar.php'))
    });
    tools.injectTemplate(path.join(templates, 'config.json'), configPath, {
        namespace: info.name,
        cron_token: crypto.randomBytes(20).toString('hex'),
        app_dir: app_path,

    });
    tools.injectTemplate(path.join(templates, '.htaccess'), htaccessPath);
    shell.exec('chmod 644 ' + htaccessPath);
};
<commit_msg>fixed bug in htaccess deploy path<commit_after>const shell = require('shelljs');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const lib = require('../lib');
const rimraf = require('rimraf');
const mkdirp = require('mkdirp');
const tools = require('../tools');
const atomar_config = require('../config');
const atomar_path = lib.lookup_module('atomar');

exports.command = 'deploy <deploy_path>';
exports.describe = 'Deploys an atomar application to run on an atomar instance';
exports.builder = {
    f: {
        alias: 'force',
        default: false,
        description: 'Overwrite an existing deployment'
    },
    app: {
        alias: 'app_path',
        default: './',
        description: 'The path to the application that will be deployed'
    },
    atomar: {
        alias: 'atomar_path',
        default: atomar_path,
        description: 'The path to the atomar installation.'
    }
};
exports.handler = function(argv) {
    let deploy_path = path.resolve(argv.deploy_path);
    let app_path = path.resolve(argv.app_path);
    let atomar_path = path.resolve(argv.atomar_path);

    let info = atomar_config.loadPackage();
    if(!info) throw new Error('Not an atomar module. Try running inside a module or use --app.');

    // validate atomar installation
    if(!atomar_path) {
        throw new Error('An installation of atomar could not be found. Please install atomar globally or specify a custom atomar installation path with --atomar_path');
    }

    let configPath = path.join(deploy_path, 'config.json');
    let htaccessPath = path.join(deploy_path, '.htaccess');
    let indexPath = path.join(deploy_path, 'index.php');

    // clean up existing deployment
    if(argv.force) {
        rimraf.sync(configPath);
        rimraf.sync(htaccessPath);
        rimraf.sync(indexPath);
    }

    if(tools.fileExists(configPath)) {
        throw new Error('A deployment already exists at ' + deploy_path + '. Use -f to overwrite');
    }

    console.log('Deploying "' + info.name + '" to ' + deploy_path);
    let templates = path.join(__dirname, 'deploy', 'templates');
    mkdirp(deploy_path);
    tools.injectTemplate(path.join(templates, 'index.php'), indexPath, {
        atomar_path: path.resolve(path.join(atomar_path, 'Atomar.php'))
    });
    tools.injectTemplate(path.join(templates, 'config.json'), configPath, {
        namespace: info.name,
        cron_token: crypto.randomBytes(20).toString('hex'),
        app_dir: app_path,

    });
    tools.injectTemplate(path.join(templates, '.htaccess'), htaccessPath);
    shell.exec('chmod 644 ' + htaccessPath);
};
<|endoftext|>


<commit_before>
/* This file contains Battle-related goals used by NPC actors. */

const Goal = require('./goals');
const Evaluator = require('./evaluators');

const {GOAL_ACTIVE, GOAL_COMPLETED} = Goal;

const GoalsBattle = {};

//---------------------------------------------------------------------------
// COMPOSITE GOALS
//---------------------------------------------------------------------------

class GoalWinBattle extends Goal.Base {

    constructor(actor) {
        super(actor);
        this.setType('GoalWinBattle');
    }

    activate() {
        this.addSubGoal(new GoalFindEnemyArmy(this.actor));
        this.status = GOAL_ACTIVE;
        this.dbg('Activated goal. Added FindEnemyArmy');
    }

    process() {
        this.dbg('process() begin');
        this.activateIfInactive();
        this.status = this.processSubGoals();
        return this.status;
    }

}
GoalsBattle.WinBattle = GoalWinBattle;

//---------------------------------------------------------------------------
// ATOMIC GOALS
//---------------------------------------------------------------------------

/* Commander will use this goal to follow its army. */
class GoalFollowArmy extends Goal.Base {

    constructor(actor) {
        super(actor);
        this.setType('GoalFollowArmy');
    }

    activate() {
        // 1. Calculate center of mass of army
        // 2. Check distance to the army
        // 3. Move into army's direction if not too close
        //    - Depends on the style/FOV of commander
    }

    process() {
        this.activateIfInactive();
        this.status = GOAL_COMPLETED;
        return this.status;
    }
}
GoalsBattle.FollowArmy = GoalFollowArmy;

/* Goal to find the enemy army. Commander will choose a direction, and the whole
 * army will march into that direction. */
class GoalFindEnemyArmy extends Goal.Base {

    constructor(actor) {
        super(actor);
        this.setType('GoalFindEnemyArmy');
    }

    activate() {
        const brain = this.actor.getBrain();

        const cmdDir = [1, 0];
        const level = this.actor.getLevel();
        const [x, y] = this.actor.getXY();

        if (x < level.getMap().cols / 2) {cmdDir[0] = 1;}
        else {cmdDir[0] = -1;}
        if (y < level.getMap().rows / 2 ) {cmdDir[1] = 1;}
        else {cmdDir[1] = -1;}

        this.dbg(`Cmd army to move to dir ${cmdDir}`);
        // If enemy not seen, order move until found
        const actors = brain.getMemory().getFriends();
        this.dbg(`${actors.length} friends found for command`);
        actors.forEach(actor => {
            const orderBias = 1.0;
            const orderEval = new Evaluator.Orders(orderBias);
            const ordersGoal = new Goal.MoveUntilEnemy(actor, cmdDir);
            orderEval.setArgs({srcActor: this.actor, goal: ordersGoal});

            const topGoal = actor.getBrain().getGoal();
            topGoal.giveOrders(orderEval);
        });
        this.status = GOAL_ACTIVE;
    }

    process() {
        this.activateIfInactive();

        const enemyFound = false;
        if (enemyFound) {
            this.status = GOAL_COMPLETED;
        }

        // Set to GOAL_COMPLETE when enemy found
        // Otherwise keep this active

        return this.status;
    }

}
GoalsBattle.FindEnemyArmy = GoalFindEnemyArmy;

/* Tells to own army actors to attack the most suitable enemy. */
class GoalEngageEnemy extends Goal.Base {

    constructor(actor) {
        super(actor);
    }

    activate() {

    }

    process() {
        this.activateIfInactive();

    }

}
GoalsBattle.EngageEnemy = GoalEngageEnemy;

class GoalRetreat extends Goal.Base {

    constructor(actor) {
        super(actor);
    }

}
GoalsBattle.Retreat = GoalRetreat;

module.exports = GoalsBattle;
<commit_msg>Added proper computation of army movement direction.<commit_after>
/* This file contains Battle-related goals used by NPC actors. */

const Goal = require('./goals');
const Evaluator = require('./evaluators');

const {GOAL_ACTIVE, GOAL_COMPLETED} = Goal;

const GoalsBattle = {};

//---------------------------------------------------------------------------
// COMPOSITE GOALS
//---------------------------------------------------------------------------

class GoalWinBattle extends Goal.Base {

    constructor(actor) {
        super(actor);
        this.setType('GoalWinBattle');
    }

    activate() {
        this.addSubGoal(new GoalFindEnemyArmy(this.actor));
        this.status = GOAL_ACTIVE;
        this.dbg('Activated goal. Added FindEnemyArmy');
    }

    process() {
        this.dbg('process() begin');
        this.activateIfInactive();
        this.status = this.processSubGoals();
        return this.status;
    }

}
GoalsBattle.WinBattle = GoalWinBattle;

//---------------------------------------------------------------------------
// ATOMIC GOALS
//---------------------------------------------------------------------------

/* Commander will use this goal to follow its army. */
class GoalFollowArmy extends Goal.Base {

    constructor(actor) {
        super(actor);
        this.setType('GoalFollowArmy');
    }

    activate() {
        // 1. Calculate center of mass of army
        // 2. Check distance to the army
        // 3. Move into army's direction if not too close
        //    - Depends on the style/FOV of commander
    }

    process() {
        this.activateIfInactive();
        this.status = GOAL_COMPLETED;
        return this.status;
    }
}
GoalsBattle.FollowArmy = GoalFollowArmy;

/* Goal to find the enemy army. Commander will choose a direction, and the whole
 * army will march into that direction. */
class GoalFindEnemyArmy extends Goal.Base {

    constructor(actor) {
        super(actor);
        this.setType('GoalFindEnemyArmy');
    }

    activate() {
        const brain = this.actor.getBrain();

        const cmdDir = [0, 0];
        const level = this.actor.getLevel();
        const [x, y] = this.actor.getXY();

        // Choose the army movement direction based on 3x3 grid of the level
        // Always move towards center
        const xLowLimit = level.getMap().cols / 3;
        const xHiLimit = 2 * level.getMap().cols / 3;
        const yLowLimit = level.getMap().rows / 3;
        const yHiLimit = 2 * level.getMap().rows / 3;

        if (x < xLowLimit) {cmdDir[0] = 1;}
        else if (x > xHiLimit) {cmdDir[0] = -1;}
        if (y < yLowLimit) {cmdDir[1] = 1;}
        else if (y > yHiLimit) {cmdDir[1] = -1;}

        this.dbg(`Cmd army to move to dir ${cmdDir}`);
        // If enemy not seen, order move until found
        const actors = brain.getMemory().getFriends();
        this.dbg(`${actors.length} friends found for command`);
        actors.forEach(actor => {
            const orderBias = 1.0;
            const orderEval = new Evaluator.Orders(orderBias);
            const ordersGoal = new Goal.MoveUntilEnemy(actor, cmdDir);
            orderEval.setArgs({srcActor: this.actor, goal: ordersGoal});

            const topGoal = actor.getBrain().getGoal();
            topGoal.giveOrders(orderEval);
        });
        this.status = GOAL_ACTIVE;
    }

    process() {
        this.activateIfInactive();

        const enemyFound = false;
        if (enemyFound) {
            this.status = GOAL_COMPLETED;
        }

        // Set to GOAL_COMPLETE when enemy found
        // Otherwise keep this active

        return this.status;
    }

}
GoalsBattle.FindEnemyArmy = GoalFindEnemyArmy;

/* Tells to own army actors to attack the most suitable enemy. */
class GoalEngageEnemy extends Goal.Base {

    constructor(actor) {
        super(actor);
    }

    activate() {

    }

    process() {
        this.activateIfInactive();

    }

}
GoalsBattle.EngageEnemy = GoalEngageEnemy;

class GoalRetreat extends Goal.Base {

    constructor(actor) {
        super(actor);
    }

}
GoalsBattle.Retreat = GoalRetreat;

module.exports = GoalsBattle;
<|endoftext|>


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

/* Copyright 2016 Myles Borins
 *
 * 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.
 */

/* eslint no-console: 0 */

var fs = require('fs');
var path = require('path');

var argv = require('yargs')
  .alias('o', 'output')
  .alias('h', 'help')
  .describe('o', 'The output file path')
  .string('o')
  .usage('Usage: $0 <input-file> -o [output-file]')
  .help()
  .argv;

// var path = require('path');

var esmall = require('../');
var {success, error} = require('./logger');

if (argv._.length === 0) {
  error('You must provide an input file!');
  process.exit(1);
}

function resolve(pathName) {
  try {
    var resolved = path.resolve(pathName);
  }
  catch (err) {
    error('Resolving the path has failed', err);
    process.exit(1);
  }
  return resolved;
}

function convertFile(err, data) {
  if (err) {
    error('Reading the file failed', err);
  }
  esmall(data.toString(), handleMinified);
}

function handleMinified(err, minified) {
  if (!argv.o) {
    console.log(minified);
    process.exit(0);
  }
  fs.writeFile(resolve(argv.o), minified, cleanup);
}

function cleanup(err) {
  if (err) {
    error('Writing to file failed', err);
    process.exit(1);
  }
  success('It worked 🎉');
  process.exit(0);
}

fs.open(resolve(argv._[0]), 'r', function(err, fd) {
  if (err) {
    if (err.code === 'ENOENT') {
      error(`${argv._[0]} does not exist`);
      process.exit(1);
    } else {
      throw err;
    }
  }
  fs.readFile(fd, convertFile);
});
<commit_msg>s/console.log/process.stdout.write<commit_after>#!/usr/bin/env node

/* Copyright 2016 Myles Borins
 *
 * 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.
 */

/* eslint no-console: 0 */

var fs = require('fs');
var path = require('path');

var argv = require('yargs')
  .alias('o', 'output')
  .alias('h', 'help')
  .describe('o', 'The output file path')
  .string('o')
  .usage('Usage: $0 <input-file> -o [output-file]')
  .help()
  .argv;

var path = require('path');

var esmall = require('../');
var {success, error} = require('./logger');

if (argv._.length === 0) {
  error('You must provide an input file!');
  process.exit(1);
}

function resolve(pathName) {
  try {
    var resolved = path.resolve(pathName);
  }
  catch (err) {
    error('Resolving the path has failed', err);
    process.exit(1);
  }
  return resolved;
}

function convertFile(err, data) {
  if (err) {
    error('Reading the file failed', err);
  }
  esmall(data.toString(), handleMinified);
}

function handleMinified(err, minified) {
  if (!argv.o) {
    process.stdout.write(minified);
    process.exit(0);
  }
  fs.writeFile(resolve(argv.o), minified, cleanup);
}

function cleanup(err) {
  if (err) {
    error('Writing to file failed', err);
    process.exit(1);
  }
  success('It worked 🎉');
  process.exit(0);
}

fs.open(resolve(argv._[0]), 'r', function(err, fd) {
  if (err) {
    if (err.code === 'ENOENT') {
      error(`${argv._[0]} does not exist`);
      process.exit(1);
    } else {
      throw err;
    }
  }
  fs.readFile(fd, convertFile);
});
<|endoftext|>


<commit_before>module.exports = function() {
    return {
        defaultRoute: '/workspace',

        workspace: {
            ingest: 1,
            content: 1,
            tasks: 0
        },

        editor: {
            toolbar: false,
            embeds: false,
            paste: {
                forcePlainText: true,
                cleanPastedHTML: false
            }
        },

        features: {
            elasticHighlight: 1
        },

        view: {
            timeformat: 'HH:mm',
            dateformat: 'DD/MM/YYYY'
        },

        search: {
            slugline: 1, headline: 1, unique_name: 1, story_text: 1,
            byline: 1, keywords: 1, creator: 1, from_desk: 1,
            to_desk: 1, spike: 1, scheduled: 1, company_codes: 1,
            useDefaultTimezone: 1, ingest_provider: 1
        },

        previewFormats: [{
            name: 'AAPIpNewsFormatter',
            outputType: 'json',
            outputField: 'article_text'
        }],

        feedParsers: [
            {value: 'zczc', name: 'AAP ZCZC Parser'},
            {value: 'BOB_zczc', name: 'AAP ZCZC (BOB) Parser'},
            {value: 'PMF_zczc', name: 'AAP ZCZC (PMF) Parser'},
            {value: 'Meadinet_zczc', name: 'AAP ZCZC (Medianet) Parser'},
            {value: 'Racing_zczc', name: 'AAP ZCZC (BRA) Parser'},
            {value: 'Sportsresults_zczc', name: 'AAP ZCZC (Sports Results) Parser'},
            {value: 'text_file', name: 'AAP Text File'},
            {value: 'News Bites', name: 'AAP News Bites'}
        ],

        defaultTimezone: 'Australia/Sydney',
        shortDateFormat: 'DD/MM',
        ArchivedDateFormat: 'D/MM/YYYY',

        list: {
            'priority': [
                'priority',
                'urgency'
            ],
            'firstLine': [
                'wordcount',
                'slugline',
                'highlights',
                'headline',
                'versioncreated'
            ],
            'secondLine': [
                'profile',
                'state',
                'embargo',
                'takekey',
                'takepackage',
                'signal',
                'broadcast',
                'flags',
                'updated',
                'category',
                'provider',
                'expiry',
                'desk'
            ]
        },

        langOverride: {
            'en': {
                "URGENCY": "NEWS VALUE",
                "Urgency": "News Value",
                "urgency": "news value",
                "Urgency stats": "News Value stats",
                "SERVICE": "CATEGORY",
                "SERVICES": "CATEGORIES",
                "Services": "Categories",
                "Service": "Category",
                "Mar": "March",
                "Apr": "April",
                "Jun": "June",
                "Jul": "July",
                "Sep": "Sept"
            },

            'en_GB': {
                "URGENCY": "NEWS VALUE",
                "Urgency": "News Value",
                "urgency": "news value",
                "Urgency stats": "News Value stats",
                "SERVICE": "CATEGORY",
                "SERVICES": "CATEGORIES",
                "Services": "Categories",
                "Service": "Category",
                "Mar": "March",
                "Apr": "April",
                "Jun": "June",
                "Jul": "July",
                "Sep": "Sept"
            },

            'en_US': {
                "URGENCY": "NEWS VALUE",
                "Urgency": "News Value",
                "urgency": "news value",
                "Urgency stats": "News Value stats",
                "SERVICE": "CATEGORY",
                "SERVICES": "CATEGORIES",
                "Services": "Categories",
                "Service": "Category",
                "Mar": "March",
                "Apr": "April",
                "Jun": "June",
                "Jul": "July",
                "Sep": "Sept"
            },

            'en_AU': {
                "URGENCY": "NEWS VALUE",
                "Urgency": "News Value",
                "urgency": "news value",
                "Urgency stats": "News Value stats",
                "SERVICE": "CATEGORY",
                "SERVICES": "CATEGORIES",
                "Services": "Categories",
                "Service": "Category",
                "Mar": "March",
                "Apr": "April",
                "Jun": "June",
                "Jul": "July",
                "Sep": "Sept"
            }
        }
    };
};
<commit_msg>[SDESK-268] Allow complex boolean queries in search<commit_after>module.exports = function() {
    return {
        defaultRoute: '/workspace',

        workspace: {
            ingest: 1,
            content: 1,
            tasks: 0
        },

        editor: {
            toolbar: false,
            embeds: false,
            paste: {
                forcePlainText: true,
                cleanPastedHTML: false
            }
        },

        features: {
            elasticHighlight: 1
        },

        view: {
            timeformat: 'HH:mm',
            dateformat: 'DD/MM/YYYY'
        },

        search: {
            slugline: 1, headline: 1, unique_name: 1, story_text: 1,
            byline: 1, keywords: 1, creator: 1, from_desk: 1,
            to_desk: 1, spike: 1, scheduled: 1, company_codes: 1,
            useDefaultTimezone: 1, ingest_provider: 1, raw_search: 1
        },

        previewFormats: [{
            name: 'AAPIpNewsFormatter',
            outputType: 'json',
            outputField: 'article_text'
        }],

        feedParsers: [
            {value: 'zczc', name: 'AAP ZCZC Parser'},
            {value: 'BOB_zczc', name: 'AAP ZCZC (BOB) Parser'},
            {value: 'PMF_zczc', name: 'AAP ZCZC (PMF) Parser'},
            {value: 'Meadinet_zczc', name: 'AAP ZCZC (Medianet) Parser'},
            {value: 'Racing_zczc', name: 'AAP ZCZC (BRA) Parser'},
            {value: 'Sportsresults_zczc', name: 'AAP ZCZC (Sports Results) Parser'},
            {value: 'text_file', name: 'AAP Text File'},
            {value: 'News Bites', name: 'AAP News Bites'}
        ],

        defaultTimezone: 'Australia/Sydney',
        shortDateFormat: 'DD/MM',
        ArchivedDateFormat: 'D/MM/YYYY',

        list: {
            'priority': [
                'priority',
                'urgency'
            ],
            'firstLine': [
                'wordcount',
                'slugline',
                'highlights',
                'headline',
                'versioncreated'
            ],
            'secondLine': [
                'profile',
                'state',
                'embargo',
                'takekey',
                'takepackage',
                'signal',
                'broadcast',
                'flags',
                'updated',
                'category',
                'provider',
                'expiry',
                'desk'
            ]
        },

        langOverride: {
            'en': {
                "Advanced Search": "Advanced",
                "URGENCY": "NEWS VALUE",
                "Urgency": "News Value",
                "urgency": "news value",
                "Urgency stats": "News Value stats",
                "SERVICE": "CATEGORY",
                "SERVICES": "CATEGORIES",
                "Services": "Categories",
                "Service": "Category",
                "Mar": "March",
                "Apr": "April",
                "Jun": "June",
                "Jul": "July",
                "Sep": "Sept"
            },

            'en_GB': {
                "Advanced Search": "Advanced",
                "URGENCY": "NEWS VALUE",
                "Urgency": "News Value",
                "urgency": "news value",
                "Urgency stats": "News Value stats",
                "SERVICE": "CATEGORY",
                "SERVICES": "CATEGORIES",
                "Services": "Categories",
                "Service": "Category",
                "Mar": "March",
                "Apr": "April",
                "Jun": "June",
                "Jul": "July",
                "Sep": "Sept"
            },

            'en_US': {
                "Advanced Search": "Advanced",
                "URGENCY": "NEWS VALUE",
                "Urgency": "News Value",
                "urgency": "news value",
                "Urgency stats": "News Value stats",
                "SERVICE": "CATEGORY",
                "SERVICES": "CATEGORIES",
                "Services": "Categories",
                "Service": "Category",
                "Mar": "March",
                "Apr": "April",
                "Jun": "June",
                "Jul": "July",
                "Sep": "Sept"
            },

            'en_AU': {
                "Advanced Search": "Advanced",
                "URGENCY": "NEWS VALUE",
                "Urgency": "News Value",
                "urgency": "news value",
                "Urgency stats": "News Value stats",
                "SERVICE": "CATEGORY",
                "SERVICES": "CATEGORIES",
                "Services": "Categories",
                "Service": "Category",
                "Mar": "March",
                "Apr": "April",
                "Jun": "June",
                "Jul": "July",
                "Sep": "Sept"
            }
        }
    };
};
<|endoftext|>


<commit_before>module.exports = function() {
    return {
        apps: ['superdesk-planning', 'superdesk.analytics', 'aap.apps'],
        importApps: ['superdesk-planning', 'superdesk-analytics', '../aap'],
        defaultRoute: '/workspace',
        workspace: {
            ingest: 1,
            content: 1,
            tasks: 0,
            planning: 1,
            assignments: 1
        },

        profile: {
            jid: false
        },

        item_profile: {
            change_profile: 1
        },

        editor: {
            toolbar: false,
            embeds: false,
            paste: {
                forcePlainText: true,
                cleanPastedHTML: false
            }
        },

        features: {
            elasticHighlight: 1,
            swimlane: {defaultNumberOfColumns: 4},
            editFeaturedImage: 1,
            confirmMediaOnUpdate: 1,
            hideLiveSuggestions: 1,
            preview: 1,
            previewFormats: 1,
            noTakes: 1,
            searchShortcut: 1,
            slackNotifications: 1,
            editor3: 1,
            analytics: 1,
            editorAttachments: false,
            editorInlineComments: false,
            editorSuggestions: false,
            validatePointOfInterestForImages: true,
        },

        activity: {
            'edit.item.popup': 0,
            'view.item.popup': 0
        },
        confirm_spike: false,

        view: {
            timeformat: 'HH:mm',
            dateformat: 'DD/MM/YYYY'
        },

        search: {
            slugline: 1, headline: 1, unique_name: 1, story_text: 1,
            byline: 1, keywords: 1, creator: 1, from_desk: 1,
            to_desk: 1, spike: 1, scheduled: 1, company_codes: 1,
            useDefaultTimezone: 1, ingest_provider: 1, raw_search: 1,
            featuremedia: 1, marked_desks: 1
        },

        infoRemovedFields: {
            keywords: true
        },

        defaultTimezone: 'Australia/Sydney',
        shortDateFormat: 'DD/MM',
        ArchivedDateFormat: 'D/MM/YYYY',
        ArchivedDateOnCalendarYear: 1,

        list: {
            'priority': [
                'urgency',
                'priority'
            ],
            'firstLine': [
                'wordcount',
                'slugline',
                'highlights',
                'associations',
                'queueError',
                'headline',
                'markedDesks',
                'assignment',
                'versioncreated'
            ],
            'secondLine': [
                'profile',
                'state',
                'embargo',
                'takekey',
                'signal',
                'broadcast',
                'flags',
                'updated',
                'category',
                'provider',
                'expiry',
                'desk'
            ],
            'singleLine': [
                'slugline',
                'highlights',
                'associations',
                'queueError',
                'takekey',
                'state',
                'update',
                'embargo',
                'flags',
                'updated',
                'headline',
                'markedDesks',
                'assignment',
                'wordcount',
                'provider',
                'versioncreator',
                'versioncreated'
            ],
            'narrowView': [
                'slugline',
                'takekey',
                'state',
                'markedDesks',
                'provider',
                'versioncreated'
            ],
            'singleLineView': true
        },
        langOverride: {
            'en': {
                'Advanced Search': 'Advanced',
                'URGENCY': 'NEWS VALUE',
                'Urgency': 'News Value',
                'urgency': 'news value',
                'Urgency stats': 'News Value stats',
                'SERVICE': 'CATEGORY',
                'SERVICES': 'CATEGORIES',
                'Services': 'Categories',
                'Service': 'Category',
                'Mar': 'March',
                'Apr': 'April',
                'Jun': 'June',
                'Jul': 'July',
                'Sep': 'Sept',
                'ANPA Category': 'Category',
                'ANPA CATEGORY': 'CATEGORY'
            },

            'en_GB': {
                'Advanced Search': 'Advanced',
                'URGENCY': 'NEWS VALUE',
                'Urgency': 'News Value',
                'urgency': 'news value',
                'Urgency stats': 'News Value stats',
                'SERVICE': 'CATEGORY',
                'SERVICES': 'CATEGORIES',
                'Services': 'Categories',
                'Service': 'Category',
                'Mar': 'March',
                'Apr': 'April',
                'Jun': 'June',
                'Jul': 'July',
                'Sep': 'Sept',
                'ANPA Category': 'Category',
                'ANPA CATEGORY': 'CATEGORY'
            },

            'en_US': {
                'Advanced Search': 'Advanced',
                'URGENCY': 'NEWS VALUE',
                'Urgency': 'News Value',
                'urgency': 'news value',
                'Urgency stats': 'News Value stats',
                'SERVICE': 'CATEGORY',
                'SERVICES': 'CATEGORIES',
                'Services': 'Categories',
                'Service': 'Category',
                'Mar': 'March',
                'Apr': 'April',
                'Jun': 'June',
                'Jul': 'July',
                'Sep': 'Sept',
                'ANPA Category': 'Category',
                'ANPA CATEGORY': 'CATEGORY'
            },

            'en_AU': {
                'Advanced Search': 'Advanced',
                'URGENCY': 'NEWS VALUE',
                'Urgency': 'News Value',
                'urgency': 'news value',
                'Urgency stats': 'News Value stats',
                'SERVICE': 'CATEGORY',
                'SERVICES': 'CATEGORIES',
                'Services': 'Categories',
                'Service': 'Category',
                'Mar': 'March',
                'Apr': 'April',
                'Jun': 'June',
                'Jul': 'July',
                'Sep': 'Sept',
                'ANPA Category': 'Category',
                'ANPA CATEGORY': 'CATEGORY'
            }
        }
    };
};
<commit_msg>(fix): editFeaturedImage setting should use boolean not int<commit_after>module.exports = function() {
    return {
        apps: ['superdesk-planning', 'superdesk.analytics', 'aap.apps'],
        importApps: ['superdesk-planning', 'superdesk-analytics', '../aap'],
        defaultRoute: '/workspace',
        workspace: {
            ingest: 1,
            content: 1,
            tasks: 0,
            planning: 1,
            assignments: 1
        },

        profile: {
            jid: false
        },

        item_profile: {
            change_profile: 1
        },

        editor: {
            toolbar: false,
            embeds: false,
            paste: {
                forcePlainText: true,
                cleanPastedHTML: false
            }
        },

        features: {
            elasticHighlight: 1,
            swimlane: {defaultNumberOfColumns: 4},
            editFeaturedImage: true,
            confirmMediaOnUpdate: 1,
            hideLiveSuggestions: 1,
            preview: 1,
            previewFormats: 1,
            noTakes: 1,
            searchShortcut: 1,
            slackNotifications: 1,
            editor3: 1,
            analytics: 1,
            editorAttachments: false,
            editorInlineComments: false,
            editorSuggestions: false,
            validatePointOfInterestForImages: true,
        },

        activity: {
            'edit.item.popup': 0,
            'view.item.popup': 0
        },
        confirm_spike: false,

        view: {
            timeformat: 'HH:mm',
            dateformat: 'DD/MM/YYYY'
        },

        search: {
            slugline: 1, headline: 1, unique_name: 1, story_text: 1,
            byline: 1, keywords: 1, creator: 1, from_desk: 1,
            to_desk: 1, spike: 1, scheduled: 1, company_codes: 1,
            useDefaultTimezone: 1, ingest_provider: 1, raw_search: 1,
            featuremedia: 1, marked_desks: 1
        },

        infoRemovedFields: {
            keywords: true
        },

        defaultTimezone: 'Australia/Sydney',
        shortDateFormat: 'DD/MM',
        ArchivedDateFormat: 'D/MM/YYYY',
        ArchivedDateOnCalendarYear: 1,

        list: {
            'priority': [
                'urgency',
                'priority'
            ],
            'firstLine': [
                'wordcount',
                'slugline',
                'highlights',
                'associations',
                'queueError',
                'headline',
                'markedDesks',
                'assignment',
                'versioncreated'
            ],
            'secondLine': [
                'profile',
                'state',
                'embargo',
                'takekey',
                'signal',
                'broadcast',
                'flags',
                'updated',
                'category',
                'provider',
                'expiry',
                'desk'
            ],
            'singleLine': [
                'slugline',
                'highlights',
                'associations',
                'queueError',
                'takekey',
                'state',
                'update',
                'embargo',
                'flags',
                'updated',
                'headline',
                'markedDesks',
                'assignment',
                'wordcount',
                'provider',
                'versioncreator',
                'versioncreated'
            ],
            'narrowView': [
                'slugline',
                'takekey',
                'state',
                'markedDesks',
                'provider',
                'versioncreated'
            ],
            'singleLineView': true
        },
        langOverride: {
            'en': {
                'Advanced Search': 'Advanced',
                'URGENCY': 'NEWS VALUE',
                'Urgency': 'News Value',
                'urgency': 'news value',
                'Urgency stats': 'News Value stats',
                'SERVICE': 'CATEGORY',
                'SERVICES': 'CATEGORIES',
                'Services': 'Categories',
                'Service': 'Category',
                'Mar': 'March',
                'Apr': 'April',
                'Jun': 'June',
                'Jul': 'July',
                'Sep': 'Sept',
                'ANPA Category': 'Category',
                'ANPA CATEGORY': 'CATEGORY'
            },

            'en_GB': {
                'Advanced Search': 'Advanced',
                'URGENCY': 'NEWS VALUE',
                'Urgency': 'News Value',
                'urgency': 'news value',
                'Urgency stats': 'News Value stats',
                'SERVICE': 'CATEGORY',
                'SERVICES': 'CATEGORIES',
                'Services': 'Categories',
                'Service': 'Category',
                'Mar': 'March',
                'Apr': 'April',
                'Jun': 'June',
                'Jul': 'July',
                'Sep': 'Sept',
                'ANPA Category': 'Category',
                'ANPA CATEGORY': 'CATEGORY'
            },

            'en_US': {
                'Advanced Search': 'Advanced',
                'URGENCY': 'NEWS VALUE',
                'Urgency': 'News Value',
                'urgency': 'news value',
                'Urgency stats': 'News Value stats',
                'SERVICE': 'CATEGORY',
                'SERVICES': 'CATEGORIES',
                'Services': 'Categories',
                'Service': 'Category',
                'Mar': 'March',
                'Apr': 'April',
                'Jun': 'June',
                'Jul': 'July',
                'Sep': 'Sept',
                'ANPA Category': 'Category',
                'ANPA CATEGORY': 'CATEGORY'
            },

            'en_AU': {
                'Advanced Search': 'Advanced',
                'URGENCY': 'NEWS VALUE',
                'Urgency': 'News Value',
                'urgency': 'news value',
                'Urgency stats': 'News Value stats',
                'SERVICE': 'CATEGORY',
                'SERVICES': 'CATEGORIES',
                'Services': 'Categories',
                'Service': 'Category',
                'Mar': 'March',
                'Apr': 'April',
                'Jun': 'June',
                'Jul': 'July',
                'Sep': 'Sept',
                'ANPA Category': 'Category',
                'ANPA CATEGORY': 'CATEGORY'
            }
        }
    };
};
<|endoftext|>


<commit_before>let test = require('../util/test'),
    moment = require('moment'),
    _includes = require('lodash.includes')

test('Draft and submit a report', async t => {
    t.plan(16)

    let {pageHelpers, $, $$, assertElementText, By, until, shortWaitMs} = t.context

    await pageHelpers.goHomeAndThenToReportsPage()
    await pageHelpers.writeInForm('#intent', 'meeting goal')

    let $engagementDate = await $('#engagementDate')
    await $engagementDate.click()

    await pageHelpers.clickTodayButton()

    let $locationAutocomplete = await pageHelpers.chooseAutocompleteOption('#location', 'general hospita')

    t.is(
        await $locationAutocomplete.getAttribute('value'),
        'General Hospital',
        'Clicking a location autocomplete suggestion populates the autocomplete field.'
    )

    let $positiveAtmosphereButton = await $('#positiveAtmos')
    await $positiveAtmosphereButton.click()

    let $attendeesAutocomplete = await pageHelpers.chooseAutocompleteOption('#attendees', 'christopf topferness')

    t.is(
        await $attendeesAutocomplete.getAttribute('value'),
        '',
        'Clicking an attendee autocomplete suggestion empties the autocomplete field.'
    )

    let [$principalPrimaryCheckbox, $principalName, $principalPosition, $principalOrg] =
        await $$('#attendeesTable tbody tr:last-child td')

    t.is(
        await $principalPrimaryCheckbox.findElement(By.css('input')).getAttribute('value'),
        'on',
        'Principal primary attendee checkbox should be checked'
    )
    await assertElementText(t, $principalName, 'TOPFERNESS, Christopf')
    await assertElementText(t, $principalPosition, 'Planning Captain')
    await assertElementText(t, $principalOrg, 'MoD')

    let $poamsAutocomplete = await pageHelpers.chooseAutocompleteOption('#poams', '1.1.B')

    t.is(
        await $poamsAutocomplete.getAttribute('value'),
        '',
        'Clicking a PoAM autocomplete suggestion empties the autocomplete field.'
    )

    let $newPoamRow = await $('.poams-selector table tbody tr td')
    await assertElementText(t, $newPoamRow, '1.1.B - Milestone the Second in EF 1.1')

    await pageHelpers.writeInForm('#keyOutcomes', 'key outcomes')
    await pageHelpers.writeInForm('#nextSteps', 'next steps')

    let $reportTextField = await $('.reportTextField')
    t.false(await $reportTextField.isDisplayed(), 'Add details field should not be present before "add details" button is clicked"')

    let $addDetailsButton = await $('#toggleReportDetails')
    await $addDetailsButton.click()

    await pageHelpers.writeInForm('.reportTextField .text-editor', 'report details')

    let $formButtonSubmit = await $('#formBottomSubmit')
    await $formButtonSubmit.click()
    await pageHelpers.assertReportShowStatusText(t, "This is a DRAFT report and hasn't been submitted.")

    let currentPathname = await t.context.getCurrentPathname()
    t.regex(currentPathname, /reports\/\d+/, 'URL is updated to reports/show page')

    let $submitReportButton = await $('#submitReportButton')
    await $submitReportButton.click()
    // This assertion bombs out with a StaleElementReferenceError and I'm not sure why.
    // await pageHelpers.assertReportShowStatusText(t, "This report is PENDING approvals.")

    let $approveButton = await $('.approve-button')
    await $approveButton.click()

    await assertElementText(
        t,
        await $('.alert'),
        'Successfully approved report.',
        'Clicking the approve button displays a message telling the user that the action was successful.'
    )

    await t.context.get('/', 'rebecca')
    let $homeTile = await $('.home-tile')
    await t.context.driver.wait(until.elementIsVisible($homeTile))
    await $homeTile.click()

    let $firstReadReportButton = await $('.read-report-button')
    let reportHref = await $firstReadReportButton.getAttribute('href')
    await $firstReadReportButton.click()

    await pageHelpers.assertReportShowStatusText(t, "This report is PENDING approvals.")
    let $rebeccaApproveButton = await $('.approve-button')
    await $rebeccaApproveButton.click()

    await assertElementText(
        t,
        await $('.alert'),
        'Successfully approved report. It has been added to the daily rollup',
        'When a report is approved, the user sees a message indicating that it has been added to the daily rollup'
    )

    let $dailyRollupLink = await t.context.driver.findElement(By.linkText('Daily rollup'))
    await $dailyRollupLink.click()

    currentPathname = await t.context.getCurrentPathname()
    t.is(currentPathname, '/rollup', 'Clicking the "daily rollup" link takes the user to the rollup page')

    async function getReportHrefsForPage() {
        let $readReportButtons = await $$('.read-report-button')

        // Normally, we would do a Promise.all here to read all button href values in parallel.
        // However, hilariously, that causes webdriver to fail with EPIPE errors. So we will
        // issue the commands synchronously to avoid overloading it.
        let hrefs = []
        for (let $button of $readReportButtons) {
            hrefs.push(await $button.getAttribute('href'))
        }
        return hrefs
    }

    async function getAllReportHrefs() {
        let reportsHrefs = await getReportHrefsForPage()
        let pageCount
        try {
            pageCount = (await $$('.pagination li:not(:first-child):not(:last-child) a', shortWaitMs)).length
        } catch (e) {
            if (e.name === 'TimeoutError') {
                // If there are no pagination controls, then we do not need to look at multiple pages
                return reportsHrefs
            }
            throw e
        }

        for (let pageIndex = 1; pageIndex < pageCount; pageIndex++) {
            // +1 because nth-child is 1-indexed,
            // and +1 because the first pagination button will be the "previous" button.
            let $pageButton = await $(`.pagination li:nth-child(${pageIndex + 2}) a`)
            await t.context.driver.wait(until.elementIsVisible($pageButton))

            await $pageButton.click()
            // After we click the button, we need to give React time to load the new results
            await t.context.driver.wait(until.elementLocated(By.css(`.pagination li:nth-child(${pageIndex + 2}).active a`)))

            let reportHrefsForPage = await getReportHrefsForPage()
            reportsHrefs.push(...reportHrefsForPage)
        }

        return reportsHrefs
    }

    let allReportRefs = await getAllReportHrefs()
    t.true(_includes(allReportRefs, reportHref), 'Daily rollup report list includes the recently approved report')
})

test('Verify that validation and other reports/new interactions work', async t => {
    t.plan(28)

    let {assertElementText, $, $$, assertElementNotPresent, pageHelpers, shortWaitMs, By} = t.context

    await pageHelpers.goHomeAndThenToReportsPage()
    await assertElementText(t, await $('.legend .title-text'), 'Create a new Report')

    let $searchBarInput = await $('#searchBarInput')

    async function verifyFieldIsRequired($fieldGroup, $input, warningClass, fieldName) {
        await $input.click()
        await $input.clear()
        await $searchBarInput.click()

        t.true(
            _includes(await $fieldGroup.getAttribute('class'), warningClass),
            `${fieldName} enters invalid state when the user leaves the field without entering anything`
        )

        await $input.sendKeys('user input')
        await $input.sendKeys(t.context.Key.TAB) // fire blur event
        t.false(
            _includes(await $fieldGroup.getAttribute('class'), warningClass),
            `After typing in ${fieldName} field, warning state goes away`
        )
    }

    let $meetingGoal = await $('.meeting-goal')
    let $meetingGoalInput = await $('#intent')

    t.false(
        _includes(await $meetingGoal.getAttribute('class'), 'has-warning'),
        `Meeting goal does not start in an invalid state`
    )
    t.is(await $meetingGoalInput.getAttribute('value'), '', `Meeting goal field starts blank`)

    await verifyFieldIsRequired($meetingGoal, $meetingGoalInput, 'has-warning', 'Meeting goal')

    let $engagementDate = await $('#engagementDate')
    t.is(await $engagementDate.getAttribute('value'), '', 'Engagement date field starts blank')
    await $engagementDate.click()

    await pageHelpers.clickTodayButton()

    t.is(
        await $engagementDate.getAttribute('value'),
        moment().format('DD/MM/YYYY'),
        'Clicking the "today" button puts the current date in the engagement field'
    )

    let $locationInput = await $('#location')
    t.is(await $locationInput.getAttribute('value'), '', 'Location field starts blank')

    let $locationShortcutButton = await $('.location-form-group .shortcut-list button')
    await $locationShortcutButton.click()
    t.is(await $locationInput.getAttribute('value'), 'General Hospital', 'Clicking the shortcut adds a location')

    await assertElementNotPresent(t, '#cancelledReason', 'Cancelled reason should not be present initially', shortWaitMs)
    let $atmosphereFormGroup = await $('.atmosphere-form-group')
    t.true(await $atmosphereFormGroup.isDisplayed(), 'Atmosphere form group should be shown by default')

    await assertElementNotPresent(
        t, '#atmosphere-details', 'Atmosphere details should not be displayed before choosing an atmosphere', shortWaitMs
    )

    let $positiveAtmosphereButton = await $('#positiveAtmos')
    await $positiveAtmosphereButton.click()

    let $atmosphereDetails = await $('#atmosphereDetails')
    t.is(await $atmosphereDetails.getAttribute('placeholder'), 'Why was this engagement positive? (optional)')

    let $neutralAtmosphereButton = await $('#neutralAtmos')
    await $neutralAtmosphereButton.click()
    t.is((await $atmosphereDetails.getAttribute('placeholder')).trim(), 'Why was this engagement neutral?')

    let $negativeAtmosphereButton = await $('#negativeAtmos')
    await $negativeAtmosphereButton.click()
    t.is((await $atmosphereDetails.getAttribute('placeholder')).trim(), 'Why was this engagement negative?')

    let $atmosphereDetailsGroup = await $('.atmosphere-details')

    await $neutralAtmosphereButton.click()
    await verifyFieldIsRequired($atmosphereDetailsGroup, $atmosphereDetails, 'has-error', 'Neutral atmosphere details')

    let $attendanceFieldsetTitle = await $('#attendance-fieldset .title-text')
    await assertElementText(
        t,
        $attendanceFieldsetTitle,
        'Meeting attendance',
        'Meeting attendance fieldset should have correct title for an uncancelled enagement'
    )

    let $cancelledCheckbox = await $('.cancelled-checkbox')
    await $cancelledCheckbox.click()

    await assertElementNotPresent(
        t, '.atmosphere-form-group', 'After cancelling the enagement, the atmospherics should be hidden', shortWaitMs
    )
    let $cancelledReason = await $('.cancelled-reason-form-group')
    t.true(await $cancelledReason.isDisplayed(), 'After cancelling the engagement, the cancellation reason should appear')
    await assertElementText(
        t,
        $attendanceFieldsetTitle,
        'Planned attendance',
        'Meeting attendance fieldset should have correct title for a cancelled enagement'
    )

    let $attendeesRows = await $$('#attendeesTable tbody tr')
    t.is($attendeesRows.length, 2, 'Attendees table starts with 2 body rows')

    let [$advisorPrimaryCheckbox, $advisorName, $advisorPosition, $advisorOrg] =
        await $$('#attendeesTable tbody tr:first-child td')

    t.is(
        await $advisorPrimaryCheckbox.findElement(By.css('input')).getAttribute('value'),
        'on',
        'Advisor primary attendee checkbox should be checked'
    )
    await assertElementText(t, $advisorName, 'ERINSON, Erin CIV')
    await assertElementText(t, $advisorPosition, 'EF 2.2 Advisor D')
    await assertElementText(t, $advisorOrg, 'EF 2.2')

    // We expect to see two shortcut buttons. One will be the current user's name.
    // Clicking on that button will have no effect, because the current user is already an attendee. The other will
    // be a principal's name. That's the button we want. Most of the time, that button appears to be last, but sometimes
    // it is not. To work around this, we'll click ALL the buttons.
    // If we fixed https://github.com/deptofdefense/anet/issues/527, we would not have this problem.
    let $addAttendeeShortcutButtons = await $$('#attendance-fieldset .shortcut-list button')
    await Promise.all($addAttendeeShortcutButtons.map($button => $button.click()))

    t.is((await $$('#attendeesTable tbody tr')).length, 3, 'Clicking the shortcut button adds a row to the table')

    let $submitButton = await $('#formBottomSubmit')
    await $submitButton.click()
    await pageHelpers.assertReportShowStatusText(t, "This is a DRAFT report and hasn't been submitted.")
})
<commit_msg>Fix test for adding recent attendees<commit_after>let test = require('../util/test'),
    moment = require('moment'),
    _includes = require('lodash.includes')

test('Draft and submit a report', async t => {
    t.plan(16)

    let {pageHelpers, $, $$, assertElementText, By, until, shortWaitMs} = t.context

    await pageHelpers.goHomeAndThenToReportsPage()
    await pageHelpers.writeInForm('#intent', 'meeting goal')

    let $engagementDate = await $('#engagementDate')
    await $engagementDate.click()

    await pageHelpers.clickTodayButton()

    let $locationAutocomplete = await pageHelpers.chooseAutocompleteOption('#location', 'general hospita')

    t.is(
        await $locationAutocomplete.getAttribute('value'),
        'General Hospital',
        'Clicking a location autocomplete suggestion populates the autocomplete field.'
    )

    let $positiveAtmosphereButton = await $('#positiveAtmos')
    await $positiveAtmosphereButton.click()

    let $attendeesAutocomplete = await pageHelpers.chooseAutocompleteOption('#attendees', 'christopf topferness')

    t.is(
        await $attendeesAutocomplete.getAttribute('value'),
        '',
        'Clicking an attendee autocomplete suggestion empties the autocomplete field.'
    )

    let [$principalPrimaryCheckbox, $principalName, $principalPosition, $principalOrg] =
        await $$('#attendeesTable tbody tr:last-child td')

    t.is(
        await $principalPrimaryCheckbox.findElement(By.css('input')).getAttribute('value'),
        'on',
        'Principal primary attendee checkbox should be checked'
    )
    await assertElementText(t, $principalName, 'TOPFERNESS, Christopf')
    await assertElementText(t, $principalPosition, 'Planning Captain')
    await assertElementText(t, $principalOrg, 'MoD')

    let $poamsAutocomplete = await pageHelpers.chooseAutocompleteOption('#poams', '1.1.B')

    t.is(
        await $poamsAutocomplete.getAttribute('value'),
        '',
        'Clicking a PoAM autocomplete suggestion empties the autocomplete field.'
    )

    let $newPoamRow = await $('.poams-selector table tbody tr td')
    await assertElementText(t, $newPoamRow, '1.1.B - Milestone the Second in EF 1.1')

    await pageHelpers.writeInForm('#keyOutcomes', 'key outcomes')
    await pageHelpers.writeInForm('#nextSteps', 'next steps')

    let $reportTextField = await $('.reportTextField')
    t.false(await $reportTextField.isDisplayed(), 'Add details field should not be present before "add details" button is clicked"')

    let $addDetailsButton = await $('#toggleReportDetails')
    await $addDetailsButton.click()

    await pageHelpers.writeInForm('.reportTextField .text-editor', 'report details')

    let $formButtonSubmit = await $('#formBottomSubmit')
    await $formButtonSubmit.click()
    await pageHelpers.assertReportShowStatusText(t, "This is a DRAFT report and hasn't been submitted.")

    let currentPathname = await t.context.getCurrentPathname()
    t.regex(currentPathname, /reports\/\d+/, 'URL is updated to reports/show page')

    let $submitReportButton = await $('#submitReportButton')
    await $submitReportButton.click()
    // This assertion bombs out with a StaleElementReferenceError and I'm not sure why.
    // await pageHelpers.assertReportShowStatusText(t, "This report is PENDING approvals.")

    let $approveButton = await $('.approve-button')
    await $approveButton.click()

    await assertElementText(
        t,
        await $('.alert'),
        'Successfully approved report.',
        'Clicking the approve button displays a message telling the user that the action was successful.'
    )

    await t.context.get('/', 'rebecca')
    let $homeTile = await $('.home-tile')
    await t.context.driver.wait(until.elementIsVisible($homeTile))
    await $homeTile.click()

    let $firstReadReportButton = await $('.read-report-button')
    let reportHref = await $firstReadReportButton.getAttribute('href')
    await $firstReadReportButton.click()

    await pageHelpers.assertReportShowStatusText(t, "This report is PENDING approvals.")
    let $rebeccaApproveButton = await $('.approve-button')
    await $rebeccaApproveButton.click()

    await assertElementText(
        t,
        await $('.alert'),
        'Successfully approved report. It has been added to the daily rollup',
        'When a report is approved, the user sees a message indicating that it has been added to the daily rollup'
    )

    let $dailyRollupLink = await t.context.driver.findElement(By.linkText('Daily rollup'))
    await $dailyRollupLink.click()

    currentPathname = await t.context.getCurrentPathname()
    t.is(currentPathname, '/rollup', 'Clicking the "daily rollup" link takes the user to the rollup page')

    async function getReportHrefsForPage() {
        let $readReportButtons = await $$('.read-report-button')

        // Normally, we would do a Promise.all here to read all button href values in parallel.
        // However, hilariously, that causes webdriver to fail with EPIPE errors. So we will
        // issue the commands synchronously to avoid overloading it.
        let hrefs = []
        for (let $button of $readReportButtons) {
            hrefs.push(await $button.getAttribute('href'))
        }
        return hrefs
    }

    async function getAllReportHrefs() {
        let reportsHrefs = await getReportHrefsForPage()
        let pageCount
        try {
            pageCount = (await $$('.pagination li:not(:first-child):not(:last-child) a', shortWaitMs)).length
        } catch (e) {
            if (e.name === 'TimeoutError') {
                // If there are no pagination controls, then we do not need to look at multiple pages
                return reportsHrefs
            }
            throw e
        }

        for (let pageIndex = 1; pageIndex < pageCount; pageIndex++) {
            // +1 because nth-child is 1-indexed,
            // and +1 because the first pagination button will be the "previous" button.
            let $pageButton = await $(`.pagination li:nth-child(${pageIndex + 2}) a`)
            await t.context.driver.wait(until.elementIsVisible($pageButton))

            await $pageButton.click()
            // After we click the button, we need to give React time to load the new results
            await t.context.driver.wait(until.elementLocated(By.css(`.pagination li:nth-child(${pageIndex + 2}).active a`)))

            let reportHrefsForPage = await getReportHrefsForPage()
            reportsHrefs.push(...reportHrefsForPage)
        }

        return reportsHrefs
    }

    let allReportRefs = await getAllReportHrefs()
    t.true(_includes(allReportRefs, reportHref), 'Daily rollup report list includes the recently approved report')
})

test('Verify that validation and other reports/new interactions work', async t => {
    t.plan(28)

    let {assertElementText, $, $$, assertElementNotPresent, pageHelpers, shortWaitMs, By} = t.context

    await pageHelpers.goHomeAndThenToReportsPage()
    await assertElementText(t, await $('.legend .title-text'), 'Create a new Report')

    let $searchBarInput = await $('#searchBarInput')

    async function verifyFieldIsRequired($fieldGroup, $input, warningClass, fieldName) {
        await $input.click()
        await $input.clear()
        await $searchBarInput.click()

        t.true(
            _includes(await $fieldGroup.getAttribute('class'), warningClass),
            `${fieldName} enters invalid state when the user leaves the field without entering anything`
        )

        await $input.sendKeys('user input')
        await $input.sendKeys(t.context.Key.TAB) // fire blur event
        t.false(
            _includes(await $fieldGroup.getAttribute('class'), warningClass),
            `After typing in ${fieldName} field, warning state goes away`
        )
    }

    let $meetingGoal = await $('.meeting-goal')
    let $meetingGoalInput = await $('#intent')

    t.false(
        _includes(await $meetingGoal.getAttribute('class'), 'has-warning'),
        `Meeting goal does not start in an invalid state`
    )
    t.is(await $meetingGoalInput.getAttribute('value'), '', `Meeting goal field starts blank`)

    await verifyFieldIsRequired($meetingGoal, $meetingGoalInput, 'has-warning', 'Meeting goal')

    let $engagementDate = await $('#engagementDate')
    t.is(await $engagementDate.getAttribute('value'), '', 'Engagement date field starts blank')
    await $engagementDate.click()

    await pageHelpers.clickTodayButton()

    t.is(
        await $engagementDate.getAttribute('value'),
        moment().format('DD/MM/YYYY'),
        'Clicking the "today" button puts the current date in the engagement field'
    )

    let $locationInput = await $('#location')
    t.is(await $locationInput.getAttribute('value'), '', 'Location field starts blank')

    let $locationShortcutButton = await $('.location-form-group .shortcut-list button')
    await $locationShortcutButton.click()
    t.is(await $locationInput.getAttribute('value'), 'General Hospital', 'Clicking the shortcut adds a location')

    await assertElementNotPresent(t, '#cancelledReason', 'Cancelled reason should not be present initially', shortWaitMs)
    let $atmosphereFormGroup = await $('.atmosphere-form-group')
    t.true(await $atmosphereFormGroup.isDisplayed(), 'Atmosphere form group should be shown by default')

    await assertElementNotPresent(
        t, '#atmosphere-details', 'Atmosphere details should not be displayed before choosing an atmosphere', shortWaitMs
    )

    let $positiveAtmosphereButton = await $('#positiveAtmos')
    await $positiveAtmosphereButton.click()

    let $atmosphereDetails = await $('#atmosphereDetails')
    t.is(await $atmosphereDetails.getAttribute('placeholder'), 'Why was this engagement positive? (optional)')

    let $neutralAtmosphereButton = await $('#neutralAtmos')
    await $neutralAtmosphereButton.click()
    t.is((await $atmosphereDetails.getAttribute('placeholder')).trim(), 'Why was this engagement neutral?')

    let $negativeAtmosphereButton = await $('#negativeAtmos')
    await $negativeAtmosphereButton.click()
    t.is((await $atmosphereDetails.getAttribute('placeholder')).trim(), 'Why was this engagement negative?')

    let $atmosphereDetailsGroup = await $('.atmosphere-details')

    await $neutralAtmosphereButton.click()
    await verifyFieldIsRequired($atmosphereDetailsGroup, $atmosphereDetails, 'has-error', 'Neutral atmosphere details')

    let $attendanceFieldsetTitle = await $('#attendance-fieldset .title-text')
    await assertElementText(
        t,
        $attendanceFieldsetTitle,
        'Meeting attendance',
        'Meeting attendance fieldset should have correct title for an uncancelled enagement'
    )

    let $cancelledCheckbox = await $('.cancelled-checkbox')
    await $cancelledCheckbox.click()

    await assertElementNotPresent(
        t, '.atmosphere-form-group', 'After cancelling the enagement, the atmospherics should be hidden', shortWaitMs
    )
    let $cancelledReason = await $('.cancelled-reason-form-group')
    t.true(await $cancelledReason.isDisplayed(), 'After cancelling the engagement, the cancellation reason should appear')
    await assertElementText(
        t,
        $attendanceFieldsetTitle,
        'Planned attendance',
        'Meeting attendance fieldset should have correct title for a cancelled enagement'
    )

    let $attendeesRows = await $$('#attendeesTable tbody tr')
    t.is($attendeesRows.length, 2, 'Attendees table starts with 2 body rows')

    let [$advisorPrimaryCheckbox, $advisorName, $advisorPosition, $advisorOrg] =
        await $$('#attendeesTable tbody tr:first-child td')

    t.is(
        await $advisorPrimaryCheckbox.findElement(By.css('input')).getAttribute('value'),
        'on',
        'Advisor primary attendee checkbox should be checked'
    )
    await assertElementText(t, $advisorName, 'ERINSON, Erin CIV')
    await assertElementText(t, $advisorPosition, 'EF 2.2 Advisor D')
    await assertElementText(t, $advisorOrg, 'EF 2.2')

    $attendeesRows = await $$('#attendeesTable tbody tr')
    let $addAttendeeShortcutButtons = await $$('#attendance-fieldset .shortcut-list button')
    // Add all recent attendees
    await Promise.all($addAttendeeShortcutButtons.map($button => $button.click()))

    t.is((await $$('#attendeesTable tbody tr')).length, $attendeesRows.length + $addAttendeeShortcutButtons.length, 'Clicking the shortcut buttons adds rows to the table')

    let $submitButton = await $('#formBottomSubmit')
    await $submitButton.click()
    await pageHelpers.assertReportShowStatusText(t, "This is a DRAFT report and hasn't been submitted.")
})
<|endoftext|>