<commit_before>module.exports = function(grunt) {
    var bannerContent = '/*!\n' +
                        ' * Uppercut JavaScript library v<%= pkg.version %>\n' +
                        ' * (c) Matthew M. Osborn - <%= pkg.homepage %>\n' +
                        ' * License: <%= pkg.licenses[0].type %> (<%= pkg.licenses[0].url %>)\n' +
                        ' */\n\n';

   var name = '<%= pkg.name %>';

   grunt.initConfig({
    // pkg is used from templates and therefore
    // MUST be defined inside initConfig object
    pkg : grunt.file.readJSON('package.json'),
    uglify: {
      options: {
        banner: bannerContent,
        sourceMapRoot: '../',
        sourceMap: 'dist/'+name+'.min.js.map',
        sourceMapUrl: name+'.min.js.map'
      },
      target : {
        src : ['dist/' + name + '.js'],
        dest : 'dist/' + name + '.min.js'
      }
    },
    // concat configuration
    concat: {
      options: {
        banner: bannerContent
      },
      target : {
        src : ['build/before.js', 'src/**/*.js', 'build/after.js'],
        dest : 'dist/' + name + '.js'
      }
    },
    jshint: {
      options: {
        trailing: true,
        eqeqeq: true
      },
      target: {
        src : ['src/**/*.js']
      }
    },
    jasmine: {
      src: 'dist/uppercut.js',
      options: {
        specs: 'spec/*Spec.js',
        keepRunner: false, // Handy for debuging
        vendor: [
            'bower_components/knockoutjs/dist/knockout.js',
        ]
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jasmine');
  grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
  grunt.registerTask('test', ['default','jasmine']);

  grunt.registerTask('dist', function() {
      // Update the version in bower.json
      var bowerConfig = grunt.file.readJSON('bower.json'),
          version = grunt.config('pkg.version');
      bowerConfig.version = version;
      grunt.file.write('bower.json', JSON.stringify(bowerConfig, true, 2));

      console.log('To publish, run:');
      console.log('    git add bower.json');
      console.log('    git add -f ./dist/uppercut.js');
      console.log('    git add -f ./dist/uppercut.min.js');
      console.log('    git add -f ./dist/uppercut.min.js.map');
      console.log('    git checkout head');
      console.log('    git commit -m \'Version ' + version + ' for distribution\'');
      console.log('    git tag -a v' + version + ' -m \'Add tag v' + version + '\'');
      console.log('    git checkout master');
      console.log('    git push origin --tags');
  });

};
<commit_msg>Create a push task that does the build and dist task<commit_after>module.exports = function(grunt) {
    var bannerContent = '/*!\n' +
                        ' * Uppercut JavaScript library v<%= pkg.version %>\n' +
                        ' * (c) Matthew M. Osborn - <%= pkg.homepage %>\n' +
                        ' * License: <%= pkg.licenses[0].type %> (<%= pkg.licenses[0].url %>)\n' +
                        ' */\n\n';

   var name = '<%= pkg.name %>';

   grunt.initConfig({
    // pkg is used from templates and therefore
    // MUST be defined inside initConfig object
    pkg : grunt.file.readJSON('package.json'),
    uglify: {
      options: {
        banner: bannerContent,
        sourceMapRoot: '../',
        sourceMap: 'dist/'+name+'.min.js.map',
        sourceMapUrl: name+'.min.js.map'
      },
      target : {
        src : ['dist/' + name + '.js'],
        dest : 'dist/' + name + '.min.js'
      }
    },
    // concat configuration
    concat: {
      options: {
        banner: bannerContent
      },
      target : {
        src : ['build/before.js', 'src/**/*.js', 'build/after.js'],
        dest : 'dist/' + name + '.js'
      }
    },
    jshint: {
      options: {
        trailing: true,
        eqeqeq: true
      },
      target: {
        src : ['src/**/*.js']
      }
    },
    jasmine: {
      src: 'dist/uppercut.js',
      options: {
        specs: 'spec/*Spec.js',
        keepRunner: false, // Handy for debuging
        vendor: [
            'bower_components/knockoutjs/dist/knockout.js',
        ]
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jasmine');
  grunt.registerTask('dist', function() {
      // Update the version in bower.json
      var bowerConfig = grunt.file.readJSON('bower.json'),
          version = grunt.config('pkg.version');
      bowerConfig.version = version;
      grunt.file.write('bower.json', JSON.stringify(bowerConfig, true, 2));

      console.log('To publish, run:');
      console.log('    git add bower.json');
      console.log('    git add -f ./dist/uppercut.js');
      console.log('    git add -f ./dist/uppercut.min.js');
      console.log('    git add -f ./dist/uppercut.min.js.map');
      console.log('    git checkout head');
      console.log('    git commit -m \'Version ' + version + ' for distribution\'');
      console.log('    git tag -a v' + version + ' -m \'Add tag v' + version + '\'');
      console.log('    git checkout master');
      console.log('    git push origin --tags');
  });
  grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
  grunt.registerTask('test', ['default','jasmine']);
  grunt.registerTask('push', ['test', 'dist'])

};
<|endoftext|>


<commit_before>import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('add-preprint-box', 'Integration | Component | add preprint box', {
  integration: true
});

test('it renders', function(assert) {

  // Set any properties with this.set('myProperty', 'value');
  // Handle any actions with this.on('myAction', function(val) { ... });

  this.render(hbs`{{add-preprint-box}}`);

  assert.ok(this.$().text().trim().includes, 'Do you want to add your own research as a preprint?');
});
<commit_msg>Use assert.strictEqual in test.<commit_after>import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('add-preprint-box', 'Integration | Component | add preprint box', {
  integration: true
});

test('it renders', function(assert) {

  // Set any properties with this.set('myProperty', 'value');
  // Handle any actions with this.on('myAction', function(val) { ... });

  this.render(hbs`{{add-preprint-box}}`);

  assert.strictEqual(this.$('p')[0].textContent, 'Do you want to add your own research as a preprint?');
});
<|endoftext|>


<commit_before>import {dispatch, matcher} from 'common/functional';

import gameKeyboardController from 'game/keyboard-controller';
import {BrickCollection} from 'game/entities/brick';
import {default as Ball, BallCollection} from 'game/entities/ball';
import {BulletCollection} from 'game/entities/bullet';
import {default as Pill, PillCollection} from 'game/entities/pill';
import Vaus from 'game/entities/vaus';
import CreateWalls from 'game/entities/wall';
import GameModel from 'game/model';

import Coordinates from 'graphics/coordinates';
import Scene from 'graphics/scene';

import {bounce, overlap} from 'physics/collisions';

import Vector from 'maths/vector';

import soundController from 'sound/arkanoid/sound-controller';

import cond from 'lodash.cond';
import flow from 'lodash.flow';
import is_nil from 'lodash.isnil';

const PILL_BONUS_POINT = 1000;

const BALL_SPEED_MIN = .2;
const BALL_SPEED_MAX = .6;
const BALL_SPEED_STEP = .025;
const BALL_SPEED_INITIAL = .3;

export default function GameController({model, view, keyboard}) {
	const scene = view.scene();
	const screen = view.screen();
	const gameScene = Scene(Coordinates({
		width:  scene.width()  - 2,
		height: scene.height() - 1
	}, {x: 1, y: 1}));
	const gameZone = gameScene.localRect();
	const brickScene = Scene(Coordinates(gameZone.size));
	const bricks = BrickCollection();
	const balls = BallCollection();
	const bullets = BulletCollection();
	const pills = PillCollection();
	const vaus = Vaus({x: 1, y: gameScene.height() - 2});

	let ball_stuck_x = .5;

	//////////////////////////////////////////////////////////////////////////
	// Ball speed helpers

	function throw_ball(ball, speed = BALL_SPEED_INITIAL) {
		if (ball.velocity().isNull()) {
			const ball_x = ball.rect().center.x;
			const vaus_box = vaus.rect();
			const teta = Math.PI/2*(ball_x - vaus_box.center.x)/vaus_box.width;
			ball.setVelocity(
				Vector({x: Math.sin(teta), y: -Math.cos(teta)}).mul(speed)
			);
		}
	}

	function slow_down(speed, min, step = BALL_SPEED_STEP) {
		return speed > min
			? Math.max(speed - step, min)
			: speed;
	}

	function speed_up(speed, max, step = BALL_SPEED_STEP) {
		return speed > 0 && speed < max
			? Math.min(speed + step, max)
			: speed;
	}

	//////////////////////////////////////////////////////////////////////////
	// Collision helpers

	function ball_collides_with_bricks(ball_box, velocity) {
		const epsilon = 1/screen.absoluteScale();
		for (let brick of bricks.neighborhood(ball_box.topLeft)) {
			const v = bounce(ball_box, velocity, brick.rect(), epsilon);
			if (!is_nil(v)) {
				return [v, brick];
			}
		}
	}

	function ball_collides_with_vaus(ball_box, velocity) {
		const epsilon = 1/screen.absoluteScale();
		const vaus_box = vaus.rect();
		if (overlap(ball_box, vaus_box, epsilon) !== overlap.NONE) {
			const ball_x = ball_box.center.x;
			const vaus_x = vaus_box.center.x;
			const offset_x = ball_x - vaus_x;
			if (vaus.mode() === Vaus.Mode.Catch) {
				ball_stuck_x = offset_x;
				return [Vector.Null, vaus];
			} else {
				const teta = Math.PI/2*(offset_x)/vaus_box.width;
				return [
					Vector({x: Math.sin(teta), y: -Math.cos(teta)}).mul(slow_down(velocity.norm, BALL_SPEED_INITIAL)),
					vaus
				];
			}
		}
	}

	function ball_collides_with_walls(ball_box, velocity) {
		if (ball_box.leftX <= gameZone.leftX) {
			// collide with left wall
			return [Vector({x: -velocity.x, y: velocity.y})];
		} else if (ball_box.rightX >= gameZone.rightX) {
			// collide with right wall
			return [Vector({x: -velocity.x, y: velocity.y})];
		} else if (ball_box.topY <= gameZone.topY) {
			// collide with roof
			const speed = velocity.norm;
			const v = speed_up(speed, BALL_SPEED_MAX)/speed;
			return [Vector({x: v*velocity.x, y: -v*velocity.y})];
		}
	}

	function ball_goes_out(ball_box, velocity) {
		if (ball_box.bottomY >= gameZone.bottomY) {
			if(model.cheatMode()) {
				return [Vector({x: velocity.x, y: -velocity.y})];
			}
			return [];
		}
	}

	const ball_collides = dispatch(
		ball_collides_with_bricks,
		ball_collides_with_vaus,
		ball_collides_with_walls,
		ball_goes_out,
		(ball_box, velocity) => [velocity]
	);

	function pill_collides(pill) {
		const pill_box = pill.rect();
		const o = overlap(pill_box, vaus.rect(), pill.velocity().y);
		if (o !== overlap.NONE || pill_box.topY >= gameZone.bottomY) {
			if (o !== overlap.NONE) {
				vaus.emit('powerUp', pill.type());
			}
			pill.destroy();
		}
	}

	function bullet_collides(bullet) {
		const epsilon = 1/screen.absoluteScale();
		const bullet_box = bullet.rect();
		if (bullet_box.bottomY > 0) {
			for (let brick of bricks.neighborhood(bullet_box.topLeft)) {
				if (overlap(bullet_box, brick.rect(), epsilon) !== overlap.NONE) {
					brick.hit();
					bullet.destroy();
				}
			}
		} else bullet.destroy();
	}

	//////////////////////////////////////////////////////////////////////////
	// Position helpers

	function reset_ball_position(ball) {
		const vaus_box = vaus.rect();
		ball.setPosition({
			x: vaus_box.center.x + ball_stuck_x,
			y: vaus_box.topLeft.y - 2*Ball.Radius
		});
	}

	function update_ball(ball) {
		if (!ball.velocity().isNull()) {
			const ball_box = ball.rect().translate(ball.velocity());
			const [speed, entity] = ball_collides(ball_box, ball.velocity());
			if (!is_nil(speed)) {
				ball.setVelocity(speed);
				if (!is_nil(entity)) {
					entity.hit();
				}
			} else {
				ball.destroy();
			}
		} else {
			reset_ball_position(ball);
		}
		ball.update();
	}

	function update_bullet(bullet) {
		bullet_collides(bullet);
		bullet.update();
	}

	function update_pill(pill) {
		pill_collides(pill);
		pill.update();
	}

	function update_vaus() {
		const {leftX: vaus_left_x, rightX: vaus_right_x} = vaus.rect();
		const {leftX: zone_left_x, rightX: zone_right_x} = gameScene.localRect();

		if (!vaus.velocity().isNull() && vaus_left_x <= zone_left_x) {
			vaus.move(Vector.Null);
			vaus.setPosition(vaus.position().add({x: zone_left_x - vaus_left_x, y: 0}));
		}
		if (!vaus.velocity().isNull() && vaus_right_x >= zone_right_x) {
			vaus.move(Vector.Null);
			vaus.setPosition(vaus.position().add({x: zone_right_x - vaus_right_x, y: 0}));
		}
		vaus.update();
	}

	function update() {
		if (model.isRunning()) {
			update_vaus();
			for (let bullet of bullets) {
				update_bullet(bullet);
			}
			for (let ball of balls) {
				update_ball(ball);
			}
			for (let pill of pills) {
				update_pill(pill);
			}
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Game state helpers

	function loop() {
		update();
		screen.render();
		requestAnimationFrame(loop);
	}

	bricks
		.on('itemAdded', brick => brickScene.add(brick))
		.on('itemChanged', brick => {
			model.updateScore(brick.points());
			soundController.ballCollidesWithBricks();
		})
		.on('itemDestroyed', brick => {
			brickScene.remove(brick);
			if (model.isRunning()) {
				pills.random(brick.position());
			}
		})
		.on('completed', () => {
			if (model.isRunning()) {
				balls.hide();
				vaus.hide();
				model.gainLife();
				model.nextStage();
				model.setState(GameModel.State.Ready);
			}
		});
	bullets
		.on('itemAdded', bullet => gameScene.add(bullet))
		.on('itemDestroyed', bullet => gameScene.remove(bullet));
	balls
		.on('itemAdded', ball => gameScene.add(ball))
		.on('itemDestroyed', ball => gameScene.remove(ball))
		.on('empty', () => {
			if (model.isRunning()) {
				soundController.ballGoesOut();
				model.setState(model.lifeCount() > 0
					? GameModel.State.Ready
					: GameModel.State.GameOver
				);
			}
		});
	pills
		.on('itemAdded', pill => gameScene.add(pill))
		.on('itemDestroyed', pill => gameScene.remove(pill));
	vaus
		.on('powerUp', flow(
			power_up => {
				model.updateScore(PILL_BONUS_POINT);
				vaus.setMode(Vaus.Mode.Small);
				balls
					.forEach(throw_ball)
					.unsplit().setSpeed(BALL_SPEED_INITIAL);
				return power_up;
			},
			cond([
				[matcher(Pill.ExtraLife), () => model.gainLife()],
				[matcher(Pill.Catch),     () => vaus.setMode(Vaus.Mode.Catch)],
				[matcher(Pill.Expand),    () => vaus.setMode(Vaus.Mode.Large)],
				[matcher(Pill.Laser),     () => vaus.setMode(Vaus.Mode.Armed)],
				[matcher(Pill.Split),     () => balls.split()],
				[matcher(Pill.Slow),      () => balls.setSpeed(BALL_SPEED_MIN)]
			])
		))
		.on('hit', () => soundController.ballCollidesWithVaus());
	model
		.on('reset', () => {
			bricks.reset();
			brickScene.reset();
			balls.hide();
			vaus.hide();
		})
		.on('changed', cond([
			[matcher('stage'), () => {
				bricks.reset(model.bricks());
			}],
			[matcher('state', GameModel.State.Paused), () => {
				balls.hide();
				vaus.hide();
			}],
			[matcher('state', GameModel.State.Ready), () => {
				keyboard.use(null);
				model.takeLife();
				vaus
					.setMode(Vaus.Mode.Small)
					.reset({x: 1, y: gameZone.height - 2})
					.show();
				balls
					.reset()
					.create(Vector.Null)
					.forEach(reset_ball_position);
				bullets.reset();
				pills.reset();
			}],
			[matcher('state', GameModel.State.Running), () => {
				keyboard.use(gameKeyboardController);
				balls.show();
				vaus.show();
				balls.forEach(throw_ball);
			}]
		]));
	keyboard
		.on('direction-changed', direction => {
			vaus.move(direction)
		})
		.on('pause', () => {
			model.setState(GameModel.State.Paused);
		})
		.on('fire', () => {
			if (vaus.mode() === Vaus.Mode.Armed) {
				const vaus_box = vaus.rect();
				bullets.create(vaus_box.topLeft.add({x: 1, y: 0}));
				bullets.create(vaus_box.topRight.sub({x: 1 + 8/16, y: 0}));
			}
			balls.forEach(throw_ball);
		});

	vaus.hide();
	balls.hide();
	gameScene.add(brickScene, vaus);
	scene.add(...CreateWalls(scene.width() - 1, scene.height()), gameScene);

	return {
		run() {
			loop();
			return this;
		}
	};
}
<commit_msg>Refactoring<commit_after>import {dispatch, matcher} from 'common/functional';

import gameKeyboardController from 'game/keyboard-controller';
import {BrickCollection} from 'game/entities/brick';
import {default as Ball, BallCollection} from 'game/entities/ball';
import {BulletCollection} from 'game/entities/bullet';
import {default as Pill, PillCollection} from 'game/entities/pill';
import Vaus from 'game/entities/vaus';
import CreateWalls from 'game/entities/wall';
import GameModel from 'game/model';

import Coordinates from 'graphics/coordinates';
import Scene from 'graphics/scene';

import {bounce, overlap} from 'physics/collisions';

import Vector from 'maths/vector';

import soundController from 'sound/arkanoid/sound-controller';

import cond from 'lodash.cond';
import flow from 'lodash.flow';
import is_nil from 'lodash.isnil';

const PILL_BONUS_POINT = 1000;

const BALL_SPEED_MIN = .2;
const BALL_SPEED_MAX = .6;
const BALL_SPEED_STEP = .025;
const BALL_SPEED_INITIAL = .3;

export default function GameController({model, view, keyboard}) {
	const scene = view.scene();
	const screen = view.screen();
	const gameScene = Scene(Coordinates({
		width:  scene.width()  - 2,
		height: scene.height() - 1
	}, {x: 1, y: 1}));
	const gameZone = gameScene.localRect();
	const brickScene = Scene(Coordinates(gameZone.size));
	const bricks = BrickCollection();
	const balls = BallCollection();
	const bullets = BulletCollection();
	const pills = PillCollection();
	const vaus = Vaus({x: 1, y: gameScene.height() - 2});

	let ballXOffset = .5;

	//////////////////////////////////////////////////////////////////////////
	// Ball speed helpers

	function ball_bounce_angle(x_offset, vaus_width) {
		return Math.PI/2*(x_offset)/vaus_width;
	}

	function throw_ball(ball, speed = BALL_SPEED_INITIAL) {
		if (ball.velocity().isNull()) {
			const teta = ball_bounce_angle(ballXOffset, vaus.rect().width);
			ball.setVelocity(
				Vector({x: Math.sin(teta), y: -Math.cos(teta)}).mul(speed)
			);
		}
	}

	function slow_down(speed, min, step = BALL_SPEED_STEP) {
		return speed > min
			? Math.max(speed - step, min)
			: speed;
	}

	function speed_up(speed, max, step = BALL_SPEED_STEP) {
		return speed > 0 && speed < max
			? Math.min(speed + step, max)
			: speed;
	}

	//////////////////////////////////////////////////////////////////////////
	// Collision helpers

	function ball_collides_with_bricks(ball_box, velocity) {
		const epsilon = 1/screen.absoluteScale();
		for (let brick of bricks.neighborhood(ball_box.topLeft)) {
			const v = bounce(ball_box, velocity, brick.rect(), epsilon);
			if (!is_nil(v)) {
				return [v, brick];
			}
		}
	}

	function ball_collides_with_vaus(ball_box, velocity) {
		const epsilon = 1/screen.absoluteScale();
		const vaus_box = vaus.rect();
		if (overlap(ball_box, vaus_box, epsilon) !== overlap.NONE) {
			const ball_x = ball_box.center.x;
			const vaus_x = vaus_box.center.x;
			ballXOffset = ball_x - vaus_x;
			if (vaus.mode() === Vaus.Mode.Catch) {
				return [Vector.Null, vaus];
			} else {
				const teta = ball_bounce_angle(ballXOffset, vaus_box.width);
				return [
					Vector({x: Math.sin(teta), y: -Math.cos(teta)}).mul(slow_down(velocity.norm, BALL_SPEED_INITIAL)),
					vaus
				];
			}
		}
	}

	function ball_collides_with_walls(ball_box, velocity) {
		if (ball_box.leftX <= gameZone.leftX) {
			// collide with left wall
			return [Vector({x: -velocity.x, y: velocity.y})];
		} else if (ball_box.rightX >= gameZone.rightX) {
			// collide with right wall
			return [Vector({x: -velocity.x, y: velocity.y})];
		} else if (ball_box.topY <= gameZone.topY) {
			// collide with roof
			const speed = velocity.norm;
			const v = speed_up(speed, BALL_SPEED_MAX)/speed;
			return [Vector({x: v*velocity.x, y: -v*velocity.y})];
		}
	}

	function ball_goes_out(ball_box, velocity) {
		if (ball_box.bottomY >= gameZone.bottomY) {
			if(model.cheatMode()) {
				return [Vector({x: velocity.x, y: -velocity.y})];
			}
			return [];
		}
	}

	const ball_collides = dispatch(
		ball_collides_with_bricks,
		ball_collides_with_vaus,
		ball_collides_with_walls,
		ball_goes_out,
		(ball_box, velocity) => [velocity]
	);

	function pill_collides(pill) {
		const pill_box = pill.rect();
		const o = overlap(pill_box, vaus.rect(), pill.velocity().y);
		if (o !== overlap.NONE || pill_box.topY >= gameZone.bottomY) {
			if (o !== overlap.NONE) {
				vaus.emit('powerUp', pill.type());
			}
			pill.destroy();
		}
	}

	function bullet_collides(bullet) {
		const epsilon = 1/screen.absoluteScale();
		const bullet_box = bullet.rect();
		if (bullet_box.bottomY > 0) {
			for (let brick of bricks.neighborhood(bullet_box.topLeft)) {
				if (overlap(bullet_box, brick.rect(), epsilon) !== overlap.NONE) {
					brick.hit();
					bullet.destroy();
				}
			}
		} else bullet.destroy();
	}

	//////////////////////////////////////////////////////////////////////////
	// Position helpers

	function reset_ball_position(ball) {
		const vaus_box = vaus.rect();
		ball.setPosition({
			x: vaus_box.center.x + ballXOffset,
			y: vaus_box.topLeft.y - 2*Ball.Radius
		});
	}

	function update_ball(ball) {
		if (!ball.velocity().isNull()) {
			const ball_box = ball.rect().translate(ball.velocity());
			const [speed, entity] = ball_collides(ball_box, ball.velocity());
			if (!is_nil(speed)) {
				ball.setVelocity(speed);
				if (!is_nil(entity)) {
					entity.hit();
				}
			} else {
				ball.destroy();
			}
		} else {
			reset_ball_position(ball);
		}
		ball.update();
	}

	function update_bullet(bullet) {
		bullet_collides(bullet);
		bullet.update();
	}

	function update_pill(pill) {
		pill_collides(pill);
		pill.update();
	}

	function update_vaus() {
		const {leftX: vaus_left_x, rightX: vaus_right_x} = vaus.rect();
		const {leftX: zone_left_x, rightX: zone_right_x} = gameScene.localRect();

		if (!vaus.velocity().isNull() && vaus_left_x <= zone_left_x) {
			vaus.move(Vector.Null);
			vaus.setPosition(vaus.position().add({x: zone_left_x - vaus_left_x, y: 0}));
		}
		if (!vaus.velocity().isNull() && vaus_right_x >= zone_right_x) {
			vaus.move(Vector.Null);
			vaus.setPosition(vaus.position().add({x: zone_right_x - vaus_right_x, y: 0}));
		}
		vaus.update();
	}

	function update() {
		if (model.isRunning()) {
			update_vaus();
			for (let bullet of bullets) {
				update_bullet(bullet);
			}
			for (let ball of balls) {
				update_ball(ball);
			}
			for (let pill of pills) {
				update_pill(pill);
			}
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Game state helpers

	function loop() {
		update();
		screen.render();
		requestAnimationFrame(loop);
	}

	bricks
		.on('itemAdded', brick => brickScene.add(brick))
		.on('itemChanged', brick => {
			model.updateScore(brick.points());
			soundController.ballCollidesWithBricks();
		})
		.on('itemDestroyed', brick => {
			brickScene.remove(brick);
			if (model.isRunning()) {
				pills.random(brick.position());
			}
		})
		.on('completed', () => {
			if (model.isRunning()) {
				balls.hide();
				vaus.hide();
				model.gainLife();
				model.nextStage();
				model.setState(GameModel.State.Ready);
			}
		});
	bullets
		.on('itemAdded', bullet => gameScene.add(bullet))
		.on('itemDestroyed', bullet => gameScene.remove(bullet));
	balls
		.on('itemAdded', ball => gameScene.add(ball))
		.on('itemDestroyed', ball => gameScene.remove(ball))
		.on('empty', () => {
			if (model.isRunning()) {
				soundController.ballGoesOut();
				model.setState(model.lifeCount() > 0
					? GameModel.State.Ready
					: GameModel.State.GameOver
				);
			}
		});
	pills
		.on('itemAdded', pill => gameScene.add(pill))
		.on('itemDestroyed', pill => gameScene.remove(pill));
	vaus
		.on('powerUp', flow(
			power_up => {
				model.updateScore(PILL_BONUS_POINT);
				vaus.setMode(Vaus.Mode.Small);
				balls
					.forEach(throw_ball)
					.unsplit().setSpeed(BALL_SPEED_INITIAL);
				return power_up;
			},
			cond([
				[matcher(Pill.ExtraLife), () => model.gainLife()],
				[matcher(Pill.Catch),     () => vaus.setMode(Vaus.Mode.Catch)],
				[matcher(Pill.Expand),    () => vaus.setMode(Vaus.Mode.Large)],
				[matcher(Pill.Laser),     () => vaus.setMode(Vaus.Mode.Armed)],
				[matcher(Pill.Split),     () => balls.split()],
				[matcher(Pill.Slow),      () => balls.setSpeed(BALL_SPEED_MIN)]
			])
		))
		.on('hit', () => soundController.ballCollidesWithVaus());
	model
		.on('reset', () => {
			bricks.reset();
			brickScene.reset();
			balls.hide();
			vaus.hide();
		})
		.on('changed', cond([
			[matcher('stage'), () => {
				bricks.reset(model.bricks());
			}],
			[matcher('state', GameModel.State.Paused), () => {
				balls.hide();
				vaus.hide();
			}],
			[matcher('state', GameModel.State.Ready), () => {
				ballXOffset = .5;
				keyboard.use(null);
				model.takeLife();
				vaus
					.setMode(Vaus.Mode.Small)
					.reset({x: 1, y: gameZone.height - 2})
					.show();
				balls
					.reset()
					.create(Vector.Null)
					.forEach(reset_ball_position);
				bullets.reset();
				pills.reset();
			}],
			[matcher('state', GameModel.State.Running), () => {
				keyboard.use(gameKeyboardController);
				balls.show();
				vaus.show();
				balls.forEach(throw_ball);
			}]
		]));
	keyboard
		.on('direction-changed', direction => {
			vaus.move(direction)
		})
		.on('pause', () => {
			model.setState(GameModel.State.Paused);
		})
		.on('fire', () => {
			if (vaus.mode() === Vaus.Mode.Armed) {
				const vaus_box = vaus.rect();
				bullets.create(vaus_box.topLeft.add({x: 1, y: 0}));
				bullets.create(vaus_box.topRight.sub({x: 1 + 8/16, y: 0}));
			}
			balls.forEach(throw_ball);
		});

	vaus.hide();
	balls.hide();
	gameScene.add(brickScene, vaus);
	scene.add(...CreateWalls(scene.width() - 1, scene.height()), gameScene);

	return {
		run() {
			loop();
			return this;
		}
	};
}
<|endoftext|>


<commit_before>'use strict';

define(['Three', 'Scene', 'FirstPersonControls', 'PointerLock', 'Tween', 'loaders/ScriptsLoader', 'Editor'], function(THREE, scene, controls, pointerLock, tween, scripts, editor) {
    var mouse = new THREE.Vector2();
    var isIntersecting = false;
    var lastIntersected = null;

    // TODO take this from a serious place (e.g. excluded objects could have a flag in scene.json?)
    var excludedObjects = ['Floor', 'Skybox'];

    // Based on the example in http://threejs.org/docs/#Reference/Core/Raycaster
    var onMouseMove = function(event) {
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    };

    var onMouseDown = function(event) {
        if (isIntersecting && pointerLock.enabled()) {
            switch (event.button) {
                case 0:
                    onSelect(lastIntersected);
                    break;
                case 2:
                    editor.rightClick(lastIntersected);
                    break;
            }
        }
    };

    // TODO perhaps we could pass time hovered as the event payload
    var onIntersect = function(obj) {
        lastIntersected = obj;
        scripts.dispatchEvent(scripts.events.starthover, null, obj.uuid);
    };

    var onStopIntersect = function(obj) {
        scripts.dispatchEvent(scripts.events.starthover, null, obj.uuid);
    };

    var onSelect = function(obj) {
        scripts.dispatchEvent(scripts.events.select, null, obj.uuid);
    };

    var loop = function() {
        /* This would use the mouse position, not the reticle position. Might be useful in the future (e.g. for KeyVR)
        var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
        vector.unproject(controls.camera);
        var raycaster = new THREE.Raycaster(controls.getPosition(), vector.sub(controls.getPosition()).normalize());
        */

        if (!pointerLock.enabled()) {
            return;
        }

        // FIXME This magic vector was taken from https://github.com/neuman/vreticle
        // It probably represents the position of the reticle.
        var vector = new THREE.Vector3(-0.0012499999999999734, -0.0053859964093356805, 0.5);
        vector.unproject(controls.camera);
        var raycaster = new THREE.Raycaster(controls.getPosition(), vector.sub(controls.getPosition()).normalize());

        var intersects = raycaster.intersectObjects(scene.getScene().children);
        isIntersecting = false;
        if (intersects.length) {
            var obj = intersects[0].object;
            if (!excludedObjects.some(function(exc) {
                return exc == obj.name;
            })) {

                if (lastIntersected != null && lastIntersected != obj) {
                    onStopIntersect(lastIntersected);
                }

                if (obj != lastIntersected) {
                    onIntersect(obj);
                }

                lastIntersected = obj;
                isIntersecting = true;
            }
        }

        if (!isIntersecting) {
            if (lastIntersected != null) {
                onStopIntersect(lastIntersected);
            }

            lastIntersected = null;
        }
    };

    var createReticle = function() {
        var geometry = new THREE.CircleGeometry(0.05, 16);
        geometry.vertices.shift();
        var material = new THREE.LineBasicMaterial();
        material.color.set(0x000000);

        var mesh = new THREE.Line(geometry, material);
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = -10;

        return mesh;
    };

    var init = function() {
        window.addEventListener('mousemove', onMouseMove, false);
        window.addEventListener('mousedown', onMouseDown, false);

        var reticleContainer = new THREE.Object3D();
        reticleContainer.add(reticle);
        controls.camera.add(reticleContainer);
    };

    var reticle = createReticle();

    return {
        loop: loop,
        init: init
    };
});
<commit_msg>Hide/show reticle on PointerLock<commit_after>'use strict';

define(['Three', 'Scene', 'FirstPersonControls', 'PointerLock', 'Tween', 'loaders/ScriptsLoader', 'Editor'], function(THREE, scene, controls, pointerLock, tween, scripts, editor) {
    var mouse = new THREE.Vector2();
    var isIntersecting = false;
    var lastIntersected = null;

    // TODO take this from a serious place (e.g. excluded objects could have a flag in scene.json?)
    var excludedObjects = ['Floor', 'Skybox'];

    // Based on the example in http://threejs.org/docs/#Reference/Core/Raycaster
    var onMouseMove = function(event) {
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    };

    var onMouseDown = function(event) {
        if (isIntersecting && pointerLock.enabled()) {
            switch (event.button) {
                case 0:
                    onSelect(lastIntersected);
                    break;
                case 2:
                    editor.rightClick(lastIntersected);
                    break;
            }
        }
    };

    // TODO perhaps we could pass time hovered as the event payload
    var onIntersect = function(obj) {
        lastIntersected = obj;
        scripts.dispatchEvent(scripts.events.starthover, null, obj.uuid);
    };

    var onStopIntersect = function(obj) {
        scripts.dispatchEvent(scripts.events.starthover, null, obj.uuid);
    };

    var onSelect = function(obj) {
        scripts.dispatchEvent(scripts.events.select, null, obj.uuid);
    };

    var loop = function() {
        /* This would use the mouse position, not the reticle position. Might be useful in the future (e.g. for KeyVR)
        var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
        vector.unproject(controls.camera);
        var raycaster = new THREE.Raycaster(controls.getPosition(), vector.sub(controls.getPosition()).normalize());
        */

        if (!pointerLock.enabled()) {
			hideReticle();
            return;
        }

		showReticle();

        // FIXME This magic vector was taken from https://github.com/neuman/vreticle
        // It probably represents the position of the reticle.
        var vector = new THREE.Vector3(-0.0012499999999999734, -0.0053859964093356805, 0.5);
        vector.unproject(controls.camera);
        var raycaster = new THREE.Raycaster(controls.getPosition(), vector.sub(controls.getPosition()).normalize());

        var intersects = raycaster.intersectObjects(scene.getScene().children);
        isIntersecting = false;
        if (intersects.length) {
            var obj = intersects[0].object;
            if (!excludedObjects.some(function(exc) {
                return exc == obj.name;
            })) {

                if (lastIntersected != null && lastIntersected != obj) {
                    onStopIntersect(lastIntersected);
                }

                if (obj != lastIntersected) {
                    onIntersect(obj);
                }

                lastIntersected = obj;
                isIntersecting = true;
            }
        }

        if (!isIntersecting) {
            if (lastIntersected != null) {
                onStopIntersect(lastIntersected);
            }

            lastIntersected = null;
        }
    };

    var createReticle = function() {
        var geometry = new THREE.CircleGeometry(0.05, 16);
        geometry.vertices.shift();
        var material = new THREE.LineBasicMaterial();
        material.color.set(0x000000);

        var mesh = new THREE.Line(geometry, material);
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = -10;

        return mesh;
    };

	var hideReticle = function() {
		reticle.visible = false;
	};

	var showReticle = function() {
		reticle.visible = true;
	};

    var init = function() {
        window.addEventListener('mousemove', onMouseMove, false);
        window.addEventListener('mousedown', onMouseDown, false);

        var reticleContainer = new THREE.Object3D();
        reticleContainer.add(reticle);
        controls.camera.add(reticleContainer);
    };

    var reticle = createReticle();

    return {
        loop: loop,
        init: init
    };
});
<|endoftext|>


<commit_before>// @flow
import React from 'react';
import Relay from 'react-relay/classic';
import { compose } from 'recompose';
import JSURL from 'jsurl';

import LocationSubscriber from '@ncigdc/components/LocationSubscriber';
import PieChart from '@ncigdc/components/Charts/PieChart';
import { Row, Column } from '@ncigdc/uikit/Flex';
import styled from '@ncigdc/theme/styled';
import type { TRawQuery } from '@ncigdc/utils/uri/types';
import type { TBucket } from '@ncigdc/components/Aggregations/types';
import withRouter from '@ncigdc/utils/withRouter';
import { mergeQuery, makeFilter, inCurrentFilters } from '@ncigdc/utils/filters';
import { removeEmptyKeys, parseFilterParam } from '@ncigdc/utils/uri';

export type TProps = {
  push: Function,
  aggregations: {
    demographic__ethnicity: { buckets: [TBucket] },
    demographic__gender: { buckets: [TBucket] },
    demographic__race: { buckets: [TBucket] },
    diagnoses__vital_status: { buckets: [TBucket] },
    project__disease_type: { buckets: [TBucket] },
    project__primary_site: { buckets: [TBucket] },
    project__program__name: { buckets: [TBucket] },
    project__project_id: { buckets: [TBucket] },
  },
};

const toPieData = clickHandler => bucket => ({
  id: bucket.key,
  doc_count: bucket.doc_count,
  clickHandler,
  tooltip: (

      {bucket.key}

      {bucket.doc_count.toLocaleString()} case{bucket.doc_count > 1 ? 's' : 0}

  ),
});

const ColumnCenter = styled(Column, {
  justifyContent: 'center',
  alignItems: 'center',
});

const RowCenter = styled(Row, {
  justifyContent: 'space-around',
  alignItems: 'center',
});

const PieTitle = styled.h4({
  color: ({ theme }) => theme.primary || 'inherit',
});

function addFilter(query: Object, push: Function): Function {
  return (field, values) => {
    const newQuery = mergeQuery({
      filters: makeFilter([{ field, value: Array.isArray(values) ? values : [values] }], false),
    }, query, 'toggle');

    push({
      query: removeEmptyKeys({ ...newQuery, filters: newQuery.filters && JSURL.stringify(newQuery.filters) }),
    });
  };
}

const enhance = compose(withRouter);

const ExploreCasesChartsComponent = ({ aggregations, push }: TProps) => (
  <LocationSubscriber>{(ctx: {| pathname: string, query: TRawQuery |}) => {
    const clickHandler = addFilter(ctx.query, push);
    const currentFilters = ctx.query && parseFilterParam((ctx.query || {}).filters, {}).content || [];
    const currentFieldNames = currentFilters.map(f => f.content.field);
    return (
      <RowCenter>
        <ColumnCenter>
          <PieTitle>Primary Sites</PieTitle>
          <PieChart
            data={
              aggregations.project__primary_site.buckets
                .filter(bucket =>
                  (currentFieldNames.includes('cases.primary_site') ?
                      inCurrentFilters({ key: bucket.key, dotField: 'cases.primary_site', currentFilters }) : true
                  )
                )
                .map(toPieData(({ data }) => clickHandler('cases.primary_site', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
        <ColumnCenter>
          <PieTitle>Projects</PieTitle>
          <PieChart
            data={
              aggregations.project__project_id.buckets
              .filter(bucket =>
                (currentFieldNames.includes('cases.project.project_id') ?
                    inCurrentFilters({ key: bucket.key, dotField: 'cases.project.project_id', currentFilters }) : true
                )
              )
              .map(toPieData(({ data }) => clickHandler('cases.project.project_id', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
        <ColumnCenter>
          <PieTitle>Disease Type</PieTitle>
          <PieChart
            data={
              aggregations.project__disease_type.buckets
                .filter(bucket =>
                  (currentFieldNames.includes('cases.disease_type') ?
                      inCurrentFilters({ key: bucket.key, dotField: 'cases.disease_type', currentFilters }) : true
                  )
                )
                .map(toPieData(({ data }) => clickHandler('cases.disease_type', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
        <ColumnCenter>
          <PieTitle>Gender</PieTitle>
          <PieChart
            data={
              aggregations.demographic__gender.buckets
                .filter(bucket =>
                  (currentFieldNames.includes('cases.demographic.gender') ?
                      inCurrentFilters({ key: bucket.key, dotField: 'cases.demographic.gender', currentFilters }) : true
                  )
                )
                .map(toPieData(({ data }) => clickHandler('cases.demographic.gender', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
        <ColumnCenter>
          <PieTitle>Vital Status</PieTitle>
          <PieChart
            data={
              aggregations.diagnoses__vital_status.buckets
                .filter(bucket =>
                  (currentFieldNames.includes('cases.diagnoses.vital_status') ?
                      inCurrentFilters({ key: bucket.key, dotField: 'cases.diagnoses.vital_status', currentFilters }) :
                      true
                  )
                )
                .map(toPieData(({ data }) => clickHandler('cases.diagnoses.vital_status', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
      </RowCenter>
    );
  }}</LocationSubscriber>
);

export const ExploreCasesChartsQuery = {
  fragments: {
    aggregations: () => Relay.QL`
      fragment on CaseAggregations {
        demographic__ethnicity {
          buckets {
            doc_count
            key
          }
        }
        demographic__gender {
          buckets {
            doc_count
            key
          }
        }
        demographic__race {
          buckets {
            doc_count
            key
          }
        }
        diagnoses__vital_status {
          buckets {
            doc_count
            key
          }
        }
        project__disease_type {
          buckets {
            doc_count
            key
          }
        }
        project__primary_site {
          buckets {
            doc_count
            key
          }
        }
        project__project_id {
          buckets {
            doc_count
            key
          }
        }
        project__program__name {
          buckets {
            doc_count
            key
          }
        }
      }
    `,
  },
};

const ExploreCasesCharts = Relay.createContainer(
  enhance(ExploreCasesChartsComponent),
  ExploreCasesChartsQuery
);

export default ExploreCasesCharts;
<commit_msg>[minor] PRTL-1139 update primary site & disease type explore pies (#1698)<commit_after>// @flow
import React from 'react';
import Relay from 'react-relay/classic';
import { compose } from 'recompose';
import JSURL from 'jsurl';

import LocationSubscriber from '@ncigdc/components/LocationSubscriber';
import PieChart from '@ncigdc/components/Charts/PieChart';
import { Row, Column } from '@ncigdc/uikit/Flex';
import styled from '@ncigdc/theme/styled';
import type { TRawQuery } from '@ncigdc/utils/uri/types';
import type { TBucket } from '@ncigdc/components/Aggregations/types';
import withRouter from '@ncigdc/utils/withRouter';
import { mergeQuery, makeFilter, inCurrentFilters } from '@ncigdc/utils/filters';
import { removeEmptyKeys, parseFilterParam } from '@ncigdc/utils/uri';

export type TProps = {
  push: Function,
  aggregations: {
    demographic__ethnicity: { buckets: [TBucket] },
    demographic__gender: { buckets: [TBucket] },
    demographic__race: { buckets: [TBucket] },
    diagnoses__vital_status: { buckets: [TBucket] },
    project__disease_type: { buckets: [TBucket] },
    project__primary_site: { buckets: [TBucket] },
    project__program__name: { buckets: [TBucket] },
    project__project_id: { buckets: [TBucket] },
  },
};

const toPieData = clickHandler => bucket => ({
  id: bucket.key,
  doc_count: bucket.doc_count,
  clickHandler,
  tooltip: (

      {bucket.key}

      {bucket.doc_count.toLocaleString()} case{bucket.doc_count > 1 ? 's' : 0}

  ),
});

const ColumnCenter = styled(Column, {
  justifyContent: 'center',
  alignItems: 'center',
});

const RowCenter = styled(Row, {
  justifyContent: 'space-around',
  alignItems: 'center',
});

const PieTitle = styled.h4({
  color: ({ theme }) => theme.primary || 'inherit',
});

function addFilter(query: Object, push: Function): Function {
  return (field, values) => {
    const newQuery = mergeQuery({
      filters: makeFilter([{ field, value: Array.isArray(values) ? values : [values] }], false),
    }, query, 'toggle');

    push({
      query: removeEmptyKeys({ ...newQuery, filters: newQuery.filters && JSURL.stringify(newQuery.filters) }),
    });
  };
}

const enhance = compose(withRouter);

const ExploreCasesChartsComponent = ({ aggregations, push }: TProps) => (
  <LocationSubscriber>{(ctx: {| pathname: string, query: TRawQuery |}) => {
    const clickHandler = addFilter(ctx.query, push);
    const currentFilters = ctx.query && parseFilterParam((ctx.query || {}).filters, {}).content || [];
    const currentFieldNames = currentFilters.map(f => f.content.field);
    return (
      <RowCenter>
        <ColumnCenter>
          <PieTitle>Primary Sites</PieTitle>
          <PieChart
            data={
              aggregations.primary_site.buckets
                .filter(bucket =>
                  (currentFieldNames.includes('cases.primary_site') ?
                      inCurrentFilters({ key: bucket.key, dotField: 'cases.primary_site', currentFilters }) : true
                  )
                )
                .map(toPieData(({ data }) => clickHandler('cases.primary_site', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
        <ColumnCenter>
          <PieTitle>Projects</PieTitle>
          <PieChart
            data={
              aggregations.project__project_id.buckets
              .filter(bucket =>
                (currentFieldNames.includes('cases.project.project_id') ?
                    inCurrentFilters({ key: bucket.key, dotField: 'cases.project.project_id', currentFilters }) : true
                )
              )
              .map(toPieData(({ data }) => clickHandler('cases.project.project_id', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
        <ColumnCenter>
          <PieTitle>Disease Type</PieTitle>
          <PieChart
            data={
              aggregations.disease_type.buckets
                .filter(bucket =>
                  (currentFieldNames.includes('cases.disease_type') ?
                      inCurrentFilters({ key: bucket.key, dotField: 'cases.disease_type', currentFilters }) : true
                  )
                )
                .map(toPieData(({ data }) => clickHandler('cases.disease_type', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
        <ColumnCenter>
          <PieTitle>Gender</PieTitle>
          <PieChart
            data={
              aggregations.demographic__gender.buckets
                .filter(bucket =>
                  (currentFieldNames.includes('cases.demographic.gender') ?
                      inCurrentFilters({ key: bucket.key, dotField: 'cases.demographic.gender', currentFilters }) : true
                  )
                )
                .map(toPieData(({ data }) => clickHandler('cases.demographic.gender', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
        <ColumnCenter>
          <PieTitle>Vital Status</PieTitle>
          <PieChart
            data={
              aggregations.diagnoses__vital_status.buckets
                .filter(bucket =>
                  (currentFieldNames.includes('cases.diagnoses.vital_status') ?
                      inCurrentFilters({ key: bucket.key, dotField: 'cases.diagnoses.vital_status', currentFilters }) :
                      true
                  )
                )
                .map(toPieData(({ data }) => clickHandler('cases.diagnoses.vital_status', data.id)))
            }
            path="doc_count"
            height={125}
            width={125}
          />
        </ColumnCenter>
      </RowCenter>
    );
  }}</LocationSubscriber>
);

export const ExploreCasesChartsQuery = {
  fragments: {
    aggregations: () => Relay.QL`
      fragment on CaseAggregations {
        demographic__ethnicity {
          buckets {
            doc_count
            key
          }
        }
        demographic__gender {
          buckets {
            doc_count
            key
          }
        }
        demographic__race {
          buckets {
            doc_count
            key
          }
        }
        diagnoses__vital_status {
          buckets {
            doc_count
            key
          }
        }
        disease_type {
          buckets {
            doc_count
            key
          }
        }
        primary_site {
          buckets {
            doc_count
            key
          }
        }
        project__project_id {
          buckets {
            doc_count
            key
          }
        }
        project__program__name {
          buckets {
            doc_count
            key
          }
        }
      }
    `,
  },
};

const ExploreCasesCharts = Relay.createContainer(
  enhance(ExploreCasesChartsComponent),
  ExploreCasesChartsQuery
);

export default ExploreCasesCharts;
<|endoftext|>


<commit_before>import { app, BrowserWindow, shell } from 'electron';
import fs from 'fs-extra';
import path from 'path';

import windowStateKeeper from 'electron-window-state';

import { isDevMode, isWindows } from './environment';
import ipcApi from './electron/ipc-api';
import Tray from './lib/Tray';
import Settings from './electron/Settings';
import { appId } from './package.json'; // eslint-disable-line import/no-unresolved
import './electron/exception';

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
let willQuitApp = false;

// Ensure that the recipe directory exists
fs.ensureDir(path.join(app.getPath('userData'), 'recipes'));

// Set App ID for Windows
if (isWindows) {
  app.setAppUserModelId(appId);
}

// Force single window
if (process.platform !== 'darwin') {
  const isSecondInstance = app.makeSingleInstance(() => {
    if (mainWindow) {
      if (mainWindow.isMinimized()) mainWindow.restore();
      mainWindow.focus();
    }
  });

  if (isSecondInstance) {
    app.quit();
  }
}

// Initialize Settings
const settings = new Settings();

const createWindow = async () => {
  // Remember window size
  const mainWindowState = windowStateKeeper({
    defaultWidth: 800,
    defaultHeight: 600,
  });

  // Create the browser window.
  mainWindow = new BrowserWindow({
    x: mainWindowState.x,
    y: mainWindowState.y,
    width: mainWindowState.width,
    height: mainWindowState.height,
    minWidth: 800,
    minHeight: 600,
    titleBarStyle: 'hidden',
    backgroundColor: '#3498db',
    autoHideMenuBar: true,
  });

  // Initialize System Tray
  const trayIcon = new Tray();

  // Initialize ipcApi
  ipcApi({ mainWindow, settings, trayIcon });

  // Manage Window State
  mainWindowState.manage(mainWindow);

  // and load the index.html of the app.
  mainWindow.loadURL(`file://${__dirname}/index.html`);

  // Open the DevTools.
  if (isDevMode) {
    mainWindow.webContents.openDevTools();
  }

  // Emitted when the window is closed.
  mainWindow.on('close', (e) => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    if (!willQuitApp && (settings.get('runInBackground') === undefined || settings.get('runInBackground'))) {
      e.preventDefault();
      mainWindow.hide();

      if (process.platform === 'win32') {
        mainWindow.setSkipTaskbar(true);
      }
    } else {
      app.quit();
    }
  });

  // For Windows we need to store a flag to properly restore the window
  // if the window was maximized before minimizing it so system tray
  mainWindow.on('minimize', () => {
    app.wasMaximized = app.isMaximized;

    if (settings.get('minimizeToSystemTray')) {
      mainWindow.setSkipTaskbar(true);
      trayIcon.show();
    }
  });

  mainWindow.on('maximize', () => {
    app.isMaximized = true;
  });

  mainWindow.on('close', (e) => {
    if (settings.get('minimizeToSystemTray')) {
      e.preventDefault();
      mainWindow.minimize();
    }
  });

  mainWindow.on('unmaximize', () => {
    app.isMaximized = false;
  });

  mainWindow.on('restore', () => {
    mainWindow.setSkipTaskbar(false);

    if (app.wasMaximized) {
      mainWindow.maximize();
    }

    if (!settings.get('enableSystemTray')) {
      trayIcon.hide();
    }
  });

  mainWindow.on('show', () => {
    mainWindow.setSkipTaskbar(false);
  });

  app.mainWindow = mainWindow;
  app.isMaximized = mainWindow.isMaximized();

  mainWindow.webContents.on('new-window', (e, url) => {
    e.preventDefault();
    shell.openExternal(url);
  });
};

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (settings.get('runInBackground') === undefined
    || settings.get('runInBackground')) {
    app.quit();
  }
});

app.on('before-quit', () => {
  willQuitApp = true;
});

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  } else {
    mainWindow.show();
  }
});
<commit_msg>Clean recipe temp dir on start<commit_after>import { app, BrowserWindow, shell } from 'electron';
import fs from 'fs-extra';
import path from 'path';

import windowStateKeeper from 'electron-window-state';

import { isDevMode, isWindows } from './environment';
import ipcApi from './electron/ipc-api';
import Tray from './lib/Tray';
import Settings from './electron/Settings';
import { appId } from './package.json'; // eslint-disable-line import/no-unresolved
import './electron/exception';

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
let willQuitApp = false;

// Ensure that the recipe directory exists
fs.ensureDir(path.join(app.getPath('userData'), 'recipes'));
fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp'));

// Set App ID for Windows
if (isWindows) {
  app.setAppUserModelId(appId);
}

// Force single window
if (process.platform !== 'darwin') {
  const isSecondInstance = app.makeSingleInstance(() => {
    if (mainWindow) {
      if (mainWindow.isMinimized()) mainWindow.restore();
      mainWindow.focus();
    }
  });

  if (isSecondInstance) {
    app.quit();
  }
}

// Initialize Settings
const settings = new Settings();

const createWindow = async () => {
  // Remember window size
  const mainWindowState = windowStateKeeper({
    defaultWidth: 800,
    defaultHeight: 600,
  });

  // Create the browser window.
  mainWindow = new BrowserWindow({
    x: mainWindowState.x,
    y: mainWindowState.y,
    width: mainWindowState.width,
    height: mainWindowState.height,
    minWidth: 800,
    minHeight: 600,
    titleBarStyle: 'hidden',
    backgroundColor: '#3498db',
    autoHideMenuBar: true,
  });

  // Initialize System Tray
  const trayIcon = new Tray();

  // Initialize ipcApi
  ipcApi({ mainWindow, settings, trayIcon });

  // Manage Window State
  mainWindowState.manage(mainWindow);

  // and load the index.html of the app.
  mainWindow.loadURL(`file://${__dirname}/index.html`);

  // Open the DevTools.
  if (isDevMode) {
    mainWindow.webContents.openDevTools();
  }

  // Emitted when the window is closed.
  mainWindow.on('close', (e) => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    if (!willQuitApp && (settings.get('runInBackground') === undefined || settings.get('runInBackground'))) {
      e.preventDefault();
      mainWindow.hide();

      if (process.platform === 'win32') {
        mainWindow.setSkipTaskbar(true);
      }
    } else {
      app.quit();
    }
  });

  // For Windows we need to store a flag to properly restore the window
  // if the window was maximized before minimizing it so system tray
  mainWindow.on('minimize', () => {
    app.wasMaximized = app.isMaximized;

    if (settings.get('minimizeToSystemTray')) {
      mainWindow.setSkipTaskbar(true);
      trayIcon.show();
    }
  });

  mainWindow.on('maximize', () => {
    app.isMaximized = true;
  });

  mainWindow.on('close', (e) => {
    if (settings.get('minimizeToSystemTray')) {
      e.preventDefault();
      mainWindow.minimize();
    }
  });

  mainWindow.on('unmaximize', () => {
    app.isMaximized = false;
  });

  mainWindow.on('restore', () => {
    mainWindow.setSkipTaskbar(false);

    if (app.wasMaximized) {
      mainWindow.maximize();
    }

    if (!settings.get('enableSystemTray')) {
      trayIcon.hide();
    }
  });

  mainWindow.on('show', () => {
    mainWindow.setSkipTaskbar(false);
  });

  app.mainWindow = mainWindow;
  app.isMaximized = mainWindow.isMaximized();

  mainWindow.webContents.on('new-window', (e, url) => {
    e.preventDefault();
    shell.openExternal(url);
  });
};

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (settings.get('runInBackground') === undefined
    || settings.get('runInBackground')) {
    app.quit();
  }
});

app.on('before-quit', () => {
  willQuitApp = true;
});

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  } else {
    mainWindow.show();
  }
});
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

module.exports = function(grunt) {
  // Load the grunt related dev deps listed in package.json.
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  // Load our custom tasks.
  grunt.loadTasks('./build/tasks/');

  var browsers = grunt.option('browsers');
  if (browsers) {
    browsers = browsers.split(/\s*,\s*/g);
  } else {
    browsers = ['PhantomJS'];
  }

  grunt.initConfig({
    clean: {
      all: ['tmp', 'dist']
    },

    'closure-compiler': {
      check: {
        cwd: 'lib/',
        js: ['axiom/core/*.js',
             'axiom/fs/*.js',
             'axiom/fs/base/*.js',
             'axiom/fs/js/*.js',
             '../third_party/closure-compiler/contrib/externs/jasmine.js'
            ],
        jsOutputFile: 'tmp/closure/out.js',
        options: require('./build/closure-options.json')
      }
    },

    make_main_module: {
      test: {
        require: '__axiomRequire__',
        dest: 'tmp/test/test_main.js',
        cwd: 'lib/',
        modules: ['**/*.test.js']
      }
    },

    copy: {
      app_files: {
        files: [{
          expand: true,
          cwd: 'tmp/amd/lib/',
          src: ['**/*.js',
                '**/*.js.map'
          ],
          dest: 'tmp/app/js/'
        }]
      }
    },

    make_app_index: {
      app: {
        dest: 'tmp/app/index.html',
        title: 'Console',
        cwd: 'tmp/app/',
        modules: [
          '**/*.js',
          '!**/*.test.js'
        ]
      }
    },

    watch: {
      check: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js'],
        tasks: ['check']
      },
      test: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js', 'test/**/*.js'],
        tasks: ['transpile', 'make_main_module:test', 'karma:once']
      },
      check_test: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js', 'test/**/*.js'],
        tasks: ['check', 'transpile', 'make_main_module:test', 'karma:once']
      }
    },

    es6_transpile: {
      amd: {
        type: "amd",
        // Defines the "root" directories used by the transpiler to resolve
        // import to files.
        fileResolver: ['lib/'],
        files: [{
          expand: true,
          cwd: 'lib/',
          src: [
            'axiom/core/**/*.js',
            'axiom/fs/**/*.js'
          ],
          dest: 'tmp/amd/lib/'
        }]
      }
    },

    karma: {
      options: {
        browsers: browsers,
        frameworks: ['jasmine'],
        files: [
          'node_modules/es6-collections/index.js',
          'node_modules/es6-promise/dist/es6-promise.js',
          'polyfill/promise.js',
          'polyfill/bind.js',
          'loader/axiom_amd.js',
          'tmp/amd/lib/**/*.js',
          'tmp/test/test_main.js',
        ]
      },
      once: {
        singleRun: true
      }
    }
  });

  // Just transpile.
  grunt.registerTask('transpile', ['clean', 'es6_transpile']);

  // Static check with closure compiler.
  grunt.registerTask('check', ['closure-compiler:check']);
  grunt.registerTask('check-watch', ['watch:check']);

  // Transpile and test.
  grunt.registerTask('test', ['clean',
                              'es6_transpile',
                              'make_main_module:test',
                              'karma:once']);
  grunt.registerTask('test-watch', ['clean',
                                    'watch:test']);

  // Static check, transpile, test, repeat on changes.
  grunt.registerTask('check-test-watch', ['clean', 'watch:check_test']);

  grunt.registerTask('default', ['check', 'test']);

  grunt.registerTask('web_app', ['transpile',
                                 'copy:app_files',
                                 'make_app_index']);
};
<commit_msg>Copy amd loader into app so modules are loaded.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

module.exports = function(grunt) {
  // Load the grunt related dev deps listed in package.json.
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  // Load our custom tasks.
  grunt.loadTasks('./build/tasks/');

  var browsers = grunt.option('browsers');
  if (browsers) {
    browsers = browsers.split(/\s*,\s*/g);
  } else {
    browsers = ['PhantomJS'];
  }

  grunt.initConfig({
    clean: {
      all: ['tmp', 'dist']
    },

    'closure-compiler': {
      check: {
        cwd: 'lib/',
        js: ['axiom/core/*.js',
             'axiom/fs/*.js',
             'axiom/fs/base/*.js',
             'axiom/fs/js/*.js',
             '../third_party/closure-compiler/contrib/externs/jasmine.js'
            ],
        jsOutputFile: 'tmp/closure/out.js',
        options: require('./build/closure-options.json')
      }
    },

    make_main_module: {
      test: {
        require: '__axiomRequire__',
        dest: 'tmp/test/test_main.js',
        cwd: 'lib/',
        modules: ['**/*.test.js']
      }
    },

    copy: {
      app_files: {
        files: [{
          expand: true,
          cwd: 'tmp/amd/lib/',
          src: ['**/*.js',
                '**/*.js.map'
          ],
          dest: 'tmp/app/js/'
        },
        {
          expand: true,
          cwd: 'loader/',
          src: ['**/*.js',
                '**/*.js.map'
          ],
          dest: 'tmp/app/js/'
        }]
      }
    },

    make_app_index: {
      app: {
        dest: 'tmp/app/index.html',
        title: 'Console',
        cwd: 'tmp/app/',
        modules: [
          'js/axiom_amd.js',
          'js/**/*.js',
          '!**/*.test.js'
        ]
      }
    },

    watch: {
      check: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js'],
        tasks: ['check']
      },
      test: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js', 'test/**/*.js'],
        tasks: ['transpile', 'make_main_module:test', 'karma:once']
      },
      check_test: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js', 'test/**/*.js'],
        tasks: ['check', 'transpile', 'make_main_module:test', 'karma:once']
      }
    },

    es6_transpile: {
      amd: {
        type: "amd",
        // Defines the "root" directories used by the transpiler to resolve
        // import to files.
        fileResolver: ['lib/'],
        files: [{
          expand: true,
          cwd: 'lib/',
          src: [
            'axiom/core/**/*.js',
            'axiom/fs/**/*.js'
          ],
          dest: 'tmp/amd/lib/'
        }]
      }
    },

    karma: {
      options: {
        browsers: browsers,
        frameworks: ['jasmine'],
        files: [
          'node_modules/es6-collections/index.js',
          'node_modules/es6-promise/dist/es6-promise.js',
          'polyfill/promise.js',
          'polyfill/bind.js',
          'loader/axiom_amd.js',
          'tmp/amd/lib/**/*.js',
          'tmp/test/test_main.js',
        ]
      },
      once: {
        singleRun: true
      }
    }
  });

  // Just transpile.
  grunt.registerTask('transpile', ['clean', 'es6_transpile']);

  // Static check with closure compiler.
  grunt.registerTask('check', ['closure-compiler:check']);
  grunt.registerTask('check-watch', ['watch:check']);

  // Transpile and test.
  grunt.registerTask('test', ['clean',
                              'es6_transpile',
                              'make_main_module:test',
                              'karma:once']);
  grunt.registerTask('test-watch', ['clean',
                                    'watch:test']);

  // Static check, transpile, test, repeat on changes.
  grunt.registerTask('check-test-watch', ['clean', 'watch:check_test']);

  grunt.registerTask('default', ['check', 'test']);

  grunt.registerTask('web_app', ['es6_transpile',
                                 'copy:app_files',
                                 'make_app_index']);
};
<|endoftext|>


<commit_before>require( './Tracking_SocialWorkerHistory' ),
require( './List_State' );
require( './Agency' );

var keystone				= require( 'keystone' ),
	async 					= require( 'async' ),
	Types					= keystone.Field.Types,
	SocialWorkerHistory		= keystone.list( 'Social Worker History' ),
	User					= require( './User' );
	ChangeHistoryMiddleware	= require( '../routes/middleware/models_change-history' );

// Create model
var SocialWorker = new keystone.List( 'Social Worker', {
	inherits	: User,
	track		: true,
	map			: { name: 'name.full' },
	defaultSort	: 'name.full',
	hidden		: false
});

// Create fields
SocialWorker.add( 'Permissions', {

	permissions: {
		isVerified: { type: Boolean, label: 'has a verified email address', default: false, noedit: true },
		isActive: { type: Boolean, label: 'is active', default: false }
	}

}, 'General Information', {

	name: {
		first: { type: Types.Text, label: 'first name', required: true, initial: true },
		last: { type: Types.Text, label: 'last name', required: true, initial: true },
		full: { type: Types.Text, label: 'name', hidden: true, noedit: true, initial: false }
	},

	avatar: { type: Types.CloudinaryImage, label: 'avatar', folder: 'users/social workers', select: true, selectPrefix: 'users/social workers', autoCleanup: true } // TODO: add publicID attribute for better naming in Cloudinary

}, 'Contact Information', {

	phone: {
		work: { type: Types.Text, label: 'work phone number', initial: true },
		mobile: { type: Types.Text, label: 'mobile phone number', initial: true },
		preferred: { type: Types.Select, label: 'preferred phone', options: 'work, mobile', initial: true }
	}

}, 'Social Worker Information', {

	// position: { type: Types.Relationship, label: 'Position', ref: 'Social Worker Position', initial: true },
	position: { type: Types.Select, options: 'adoption worker, recruitment worker, supervisor, administrator, family worker, other', label: 'position', initial: true },
	agency: { type: Types.Relationship, label: 'agency', ref: 'Agency', initial: true },
	agencyNotListed: { type: Types.Boolean, label: 'agency isn\'t listed', initial: true },
	agencyText: { type: Types.Text, label: 'agency', dependsOn: { agencyNotListed: true }, initial: true },

	address: {
	    street1: { type: Types.Text, label: 'street 1', initial: true },
		street2: { type: Types.Text, label: 'street 2', initial: true },
		city: { type: Types.Text, label: 'city', initial: true },
		state: { type: Types.Relationship, label: 'state', ref: 'State', initial: true },
		zipCode: { type: Types.Text, label: 'zip code', initial: true }
	},

	title: { type: Types.Text, label: 'title', initial: true },
	notes: { type: Types.Textarea, label: 'notes', initial: true }

}, 'User Selections', {

	bookmarkedChildren: { type: Types.Relationship, label: 'bookmarked children', ref: 'Child', many: true, noedit: true },
	bookmarkedSiblings: { type: Types.Relationship, label: 'bookmarked sibling group children', ref: 'Child', many: true, noedit: true }

/* Container for data migration fields ( these should be kept until after phase 2 and the old system is phased out completely ) */
}, {
	// system field to store an appropriate file prefix
	oldId: { type: Types.Text, hidden: true }

});

// Set up relationship values to show up at the bottom of the model if any exist
SocialWorker.relationship( { ref: 'Child', refPath: 'adoptionWorker', path: 'children', label: 'children' } );
SocialWorker.relationship( { ref: 'Inquiry', refPath: 'socialWorker', path: 'my-inquiries', label: 'my inquiries' } );
SocialWorker.relationship( { ref: 'Inquiry', refPath: 'childsSocialWorker', path: 'family-inquiries', label: 'family inquiries' } );
SocialWorker.relationship( { ref: 'Mailing List', refPath: 'socialWorkerSubscribers', path: 'mailing-lists', label: 'mailing lists' } );
SocialWorker.relationship( { ref: 'Event', refPath: 'socialWorkerAttendees', path: 'events', label: 'events' } );
SocialWorker.relationship( { ref: 'Internal Note', refPath: 'socialWorker', path: 'internal-notes', label: 'internal notes' } );
SocialWorker.relationship( { ref: 'Social Worker History', refPath: 'socialWorker', path: 'social-worker-histories', label: 'change history' } );

// Post Init - used to store all the values before anything is changed
SocialWorker.schema.post( 'init', function() {
	'use strict';

	this._original = this.toObject();
});

// Pre Save
SocialWorker.schema.pre('save', function(next) {
	'use strict';

	var model = this;
	// TODO: get rid of model = this and all model references.  You'll need to verify all functionality still works
	async.series([
		done => { model.setFullName(done); }, // Create a full name for the child based on their first, middle, and last names
		done => { model.setUserType(done); }, // Create an identifying name for file uploads
		done => { ChangeHistoryMiddleware.setUpdatedby( this, done ); }, // we need this id in case the family was created via the website and udpatedBy is empty
		done => { model.setChangeHistory(done); } // Process change history
	], () => {

		console.log( 'social worker information updated' );

		next();
	});
});

/* TODO: VERY IMPORTANT:  Need to fix this to provide the link to access the keystone admin panel again */
/* 						  Changing names or reworking this file changed the check in node_modules/keystone/templates/views/signin.jade
/*						  for user.isAdmin on line 14 */
// Provide access to Keystone
SocialWorker.schema.virtual( 'canAccessKeystone' ).get( function() {
	'use strict';

	return false;
});

SocialWorker.schema.methods.setFullName = function( done ) {
	'use strict';

	// Populate the full name string for better identification when linking through Relationship field types
	this.name.full = `${ this.name.first } ${ this.name.last }`;

	done();
};

SocialWorker.schema.methods.setUserType = function( done ) {
	'use strict'

	// Set the userType for role based page rendering
	this.userType = 'social worker';

	done();
};

SocialWorker.schema.methods.setChangeHistory = function setChangeHistory( done ) {
	'use strict';

	var modelBefore	= this._original,
		model		= this;

	var changeHistory = new SocialWorkerHistory.model({
		socialWorker	: this,
	    date			: Date.now(),
	    changes			: '',
	    modifiedBy		: this.updatedBy
	});

	// if the model is being saved for the first time, mark only that fact in an initial change history record
	if( !model._original ) {

		changeHistory.changes = 'record created';

		changeHistory.save( () => {
			console.log('record created change history saved successfully');
			done();
		}, err => {
			console.log( err );
			console.log( 'error saving record created change history' );
			done();
		});

	} else {
		// Any time a new field is added, it MUST be added to this list in order to be considered for display in change history
		// Computed fields and fields internal to the object SHOULD NOT be added to this list
		async.parallel([
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'permissions',
											name: 'isVerified',
											label: 'is verified',
											type: 'boolean' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'permissions',
											name: 'isActive',
											label: 'is active',
											type: 'boolean' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'name',
											name: 'first',
											label: 'first name',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'name',
											name: 'last',
											label: 'last name',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'email',
											label: 'email address',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'phone',
											name: 'work',
											label: 'work phone number',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'phone',
											name: 'mobile',
											label: 'mobile phone number',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'phone',
											name: 'preferred',
											label: 'preferred phone',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'position',
											label: 'position',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'agency',
											targetField: 'name',
											label: 'agency',
											type: 'relationship',
											model: 'Agency' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'agencyNotListed',
											label: 'agency isnt listed',
											type: 'boolean' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'agencyText',
											label: 'agency (free text)',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'street1',
											label: 'street 1',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'street2',
											label: 'street 2',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'city',
											label: 'city',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'state',
											targetField: 'state',
											label: 'state',
											type: 'relationship',
											model: 'State' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'zipCode',
											label: 'zip code',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'title',
											label: 'title',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'notes',
											label: 'notes',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'bookmarkedChildren',
											targetParent: 'name',
											targetField: 'full',
											label: 'bookmarked children',
											type: 'relationship',
											model: 'Child' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'bookmarkedSiblings',
											targetParent: 'name',
											targetField: 'full',
											label: 'bookmarked sibling group children',
											type: 'relationship',
											model: 'Child' }, model, modelBefore, changeHistory, done);
			}

		], () => {

			if ( changeHistory.changes === '' ) {
				done();
			} else {
				changeHistory.save( () => {
					console.log( 'change history saved successfully' );
					done();
				}, err => {
					console.log( err );
					console.log( 'error saving change history' );
					done();
				});
			}
		});
	}
};

// Define default columns in the admin interface and register the model
SocialWorker.defaultColumns = 'name.full, phone.work, phone.home, phone.cell, phone.preferred, email, permissions.isActive';
SocialWorker.register();

// Export to make it available using require.  The keystone.list import throws a ReferenceError when importing a list
// that comes later when sorting alphabetically
exports = module.exports = SocialWorker;<commit_msg>#23 | make family relationship visible from the social worker model<commit_after>require( './Tracking_SocialWorkerHistory' ),
require( './List_State' );
require( './Agency' );

var keystone				= require( 'keystone' ),
	async 					= require( 'async' ),
	Types					= keystone.Field.Types,
	SocialWorkerHistory		= keystone.list( 'Social Worker History' ),
	User					= require( './User' );
	ChangeHistoryMiddleware	= require( '../routes/middleware/models_change-history' );

// Create model
var SocialWorker = new keystone.List( 'Social Worker', {
	inherits	: User,
	track		: true,
	map			: { name: 'name.full' },
	defaultSort	: 'name.full',
	hidden		: false
});

// Create fields
SocialWorker.add( 'Permissions', {

	permissions: {
		isVerified: { type: Boolean, label: 'has a verified email address', default: false, noedit: true },
		isActive: { type: Boolean, label: 'is active', default: false }
	}

}, 'General Information', {

	name: {
		first: { type: Types.Text, label: 'first name', required: true, initial: true },
		last: { type: Types.Text, label: 'last name', required: true, initial: true },
		full: { type: Types.Text, label: 'name', hidden: true, noedit: true, initial: false }
	},

	avatar: { type: Types.CloudinaryImage, label: 'avatar', folder: 'users/social workers', select: true, selectPrefix: 'users/social workers', autoCleanup: true } // TODO: add publicID attribute for better naming in Cloudinary

}, 'Contact Information', {

	phone: {
		work: { type: Types.Text, label: 'work phone number', initial: true },
		mobile: { type: Types.Text, label: 'mobile phone number', initial: true },
		preferred: { type: Types.Select, label: 'preferred phone', options: 'work, mobile', initial: true }
	}

}, 'Social Worker Information', {

	// position: { type: Types.Relationship, label: 'Position', ref: 'Social Worker Position', initial: true },
	position: { type: Types.Select, options: 'adoption worker, recruitment worker, supervisor, administrator, family worker, other', label: 'position', initial: true },
	agency: { type: Types.Relationship, label: 'agency', ref: 'Agency', initial: true },
	agencyNotListed: { type: Types.Boolean, label: 'agency isn\'t listed', initial: true },
	agencyText: { type: Types.Text, label: 'agency', dependsOn: { agencyNotListed: true }, initial: true },

	address: {
	    street1: { type: Types.Text, label: 'street 1', initial: true },
		street2: { type: Types.Text, label: 'street 2', initial: true },
		city: { type: Types.Text, label: 'city', initial: true },
		state: { type: Types.Relationship, label: 'state', ref: 'State', initial: true },
		zipCode: { type: Types.Text, label: 'zip code', initial: true }
	},

	title: { type: Types.Text, label: 'title', initial: true },
	notes: { type: Types.Textarea, label: 'notes', initial: true }

}, 'User Selections', {

	bookmarkedChildren: { type: Types.Relationship, label: 'bookmarked children', ref: 'Child', many: true, noedit: true },
	bookmarkedSiblings: { type: Types.Relationship, label: 'bookmarked sibling group children', ref: 'Child', many: true, noedit: true }

/* Container for data migration fields ( these should be kept until after phase 2 and the old system is phased out completely ) */
}, {
	// system field to store an appropriate file prefix
	oldId: { type: Types.Text, hidden: true }

});

// Set up relationship values to show up at the bottom of the model if any exist
SocialWorker.relationship( { ref: 'Child', refPath: 'adoptionWorker', path: 'children', label: 'children' } );
SocialWorker.relationsihp( { ref: 'Family', refPath: 'socialWorker', path: 'families', label: 'families' } );
SocialWorker.relationship( { ref: 'Inquiry', refPath: 'socialWorker', path: 'my-inquiries', label: 'my inquiries' } );
SocialWorker.relationship( { ref: 'Inquiry', refPath: 'childsSocialWorker', path: 'family-inquiries', label: 'family inquiries' } );
SocialWorker.relationship( { ref: 'Mailing List', refPath: 'socialWorkerSubscribers', path: 'mailing-lists', label: 'mailing lists' } );
SocialWorker.relationship( { ref: 'Event', refPath: 'socialWorkerAttendees', path: 'events', label: 'events' } );
SocialWorker.relationship( { ref: 'Internal Note', refPath: 'socialWorker', path: 'internal-notes', label: 'internal notes' } );
SocialWorker.relationship( { ref: 'Social Worker History', refPath: 'socialWorker', path: 'social-worker-histories', label: 'change history' } );

// Post Init - used to store all the values before anything is changed
SocialWorker.schema.post( 'init', function() {
	'use strict';

	this._original = this.toObject();
});

// Pre Save
SocialWorker.schema.pre('save', function(next) {
	'use strict';

	var model = this;
	// TODO: get rid of model = this and all model references.  You'll need to verify all functionality still works
	async.series([
		done => { model.setFullName(done); }, // Create a full name for the child based on their first, middle, and last names
		done => { model.setUserType(done); }, // Create an identifying name for file uploads
		done => { ChangeHistoryMiddleware.setUpdatedby( this, done ); }, // we need this id in case the family was created via the website and udpatedBy is empty
		done => { model.setChangeHistory(done); } // Process change history
	], () => {

		console.log( 'social worker information updated' );

		next();
	});
});

/* TODO: VERY IMPORTANT:  Need to fix this to provide the link to access the keystone admin panel again */
/* 						  Changing names or reworking this file changed the check in node_modules/keystone/templates/views/signin.jade
/*						  for user.isAdmin on line 14 */
// Provide access to Keystone
SocialWorker.schema.virtual( 'canAccessKeystone' ).get( function() {
	'use strict';

	return false;
});

SocialWorker.schema.methods.setFullName = function( done ) {
	'use strict';

	// Populate the full name string for better identification when linking through Relationship field types
	this.name.full = `${ this.name.first } ${ this.name.last }`;

	done();
};

SocialWorker.schema.methods.setUserType = function( done ) {
	'use strict'

	// Set the userType for role based page rendering
	this.userType = 'social worker';

	done();
};

SocialWorker.schema.methods.setChangeHistory = function setChangeHistory( done ) {
	'use strict';

	var modelBefore	= this._original,
		model		= this;

	var changeHistory = new SocialWorkerHistory.model({
		socialWorker	: this,
	    date			: Date.now(),
	    changes			: '',
	    modifiedBy		: this.updatedBy
	});

	// if the model is being saved for the first time, mark only that fact in an initial change history record
	if( !model._original ) {

		changeHistory.changes = 'record created';

		changeHistory.save( () => {
			console.log('record created change history saved successfully');
			done();
		}, err => {
			console.log( err );
			console.log( 'error saving record created change history' );
			done();
		});

	} else {
		// Any time a new field is added, it MUST be added to this list in order to be considered for display in change history
		// Computed fields and fields internal to the object SHOULD NOT be added to this list
		async.parallel([
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'permissions',
											name: 'isVerified',
											label: 'is verified',
											type: 'boolean' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'permissions',
											name: 'isActive',
											label: 'is active',
											type: 'boolean' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'name',
											name: 'first',
											label: 'first name',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'name',
											name: 'last',
											label: 'last name',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'email',
											label: 'email address',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'phone',
											name: 'work',
											label: 'work phone number',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'phone',
											name: 'mobile',
											label: 'mobile phone number',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'phone',
											name: 'preferred',
											label: 'preferred phone',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'position',
											label: 'position',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'agency',
											targetField: 'name',
											label: 'agency',
											type: 'relationship',
											model: 'Agency' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'agencyNotListed',
											label: 'agency isnt listed',
											type: 'boolean' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'agencyText',
											label: 'agency (free text)',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'street1',
											label: 'street 1',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'street2',
											label: 'street 2',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'city',
											label: 'city',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'state',
											targetField: 'state',
											label: 'state',
											type: 'relationship',
											model: 'State' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											parent: 'address',
											name: 'zipCode',
											label: 'zip code',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'title',
											label: 'title',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'notes',
											label: 'notes',
											type: 'string' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'bookmarkedChildren',
											targetParent: 'name',
											targetField: 'full',
											label: 'bookmarked children',
											type: 'relationship',
											model: 'Child' }, model, modelBefore, changeHistory, done);
			},
			done => {
				ChangeHistoryMiddleware.checkFieldForChanges({
											name: 'bookmarkedSiblings',
											targetParent: 'name',
											targetField: 'full',
											label: 'bookmarked sibling group children',
											type: 'relationship',
											model: 'Child' }, model, modelBefore, changeHistory, done);
			}

		], () => {

			if ( changeHistory.changes === '' ) {
				done();
			} else {
				changeHistory.save( () => {
					console.log( 'change history saved successfully' );
					done();
				}, err => {
					console.log( err );
					console.log( 'error saving change history' );
					done();
				});
			}
		});
	}
};

// Define default columns in the admin interface and register the model
SocialWorker.defaultColumns = 'name.full, phone.work, phone.home, phone.cell, phone.preferred, email, permissions.isActive';
SocialWorker.register();

// Export to make it available using require.  The keystone.list import throws a ReferenceError when importing a list
// that comes later when sorting alphabetically
exports = module.exports = SocialWorker;<|endoftext|>


<commit_before>define(['xaml!sprd/view/svg/SpecialFlexConfigurationRenderer'], function (Renderer) {

    return Renderer.inherit("sprd.view.svg.DesignConfigurationRenderer", {

        defaults: {
            tagName: "g",
            maskId: null,
            isSpecialFlex: "{isSpecialFlex()}",
            largeSize: "{largeSize()}",

            filter: "{filter()}"
        },

        url: function () {

            if (this.$.imageService && this.$.configuration && this.$.configuration.$.design && this.$.configuration.$.printColors) {

                var maxSize = Math.min(this.$._width, 600),
                    options = {},
                    design = this.$.configuration.$.design;

                if (this.$.width >= this.$.height) {
                    options.width = maxSize;
                } else {
                    options.height = maxSize;
                }

                options.printColors = this.$.configuration.getPrintColorsAsRGB();
                options.version = design.$.version;

                if (!design.isVectorDesign()) {
                    return this.$.configuration.$.processedImage || design.$.localImage || this.$.imageService.designImage(design.$.wtfMbsId, options);

                } else {
                    return this.$.imageService.designImage(design.$.wtfMbsId, options)
                }

            }
            return null;
        }.onChange("design", "_width", "_height", "configuration.processedImage").on(["configuration.printColors", "reset"]),

        maskUrl: function() {

            if (this.$.imageService && this.$.configuration && this.$.configuration.$.design) {

                var maxSize = Math.min(this.$._width, 600),
                options = {},
                design = this.$.configuration.$.design;

                if (this.$.width >= this.$.height) {
                    options.width = maxSize;
                } else {
                    options.height = maxSize;
                }

                var colors = this.$.configuration.$.printColors.size(),
                    printColors = [];
                for (var i = 0; i < colors; i++) {
                    printColors.push("FFFFFF");
                }

                options.printColors = printColors;
                options.version = design.$.version;

                if (!design.isVectorDesign()) {
                    return this.$.configuration.$.processedImage || design.$.localImage || this.$.imageService.designImage(design.$.wtfMbsId, options);
                } else {
                    return this.$.imageService.designImage(design.$.wtfMbsId, options)
                }

            }

            return null;
        }.onChange("design", "_width", "_height").on(["configuration.printColors", "reset"])

    })
});<commit_msg>added mask id as data-mask-id attribute<commit_after>define(['xaml!sprd/view/svg/SpecialFlexConfigurationRenderer'], function (Renderer) {

    return Renderer.inherit("sprd.view.svg.DesignConfigurationRenderer", {

        defaults: {
            tagName: "g",
            maskId: null,
            "data-mask-id": "{configuration.afterEffect.id}",
            isSpecialFlex: "{isSpecialFlex()}",
            largeSize: "{largeSize()}",
            filter: "{filter()}"
        },

        url: function () {

            if (this.$.imageService && this.$.configuration && this.$.configuration.$.design && this.$.configuration.$.printColors) {

                var maxSize = Math.min(this.$._width, 600),
                    options = {},
                    design = this.$.configuration.$.design;

                if (this.$.width >= this.$.height) {
                    options.width = maxSize;
                } else {
                    options.height = maxSize;
                }

                options.printColors = this.$.configuration.getPrintColorsAsRGB();
                options.version = design.$.version;

                if (!design.isVectorDesign()) {
                    return this.$.configuration.$.processedImage || design.$.localImage || this.$.imageService.designImage(design.$.wtfMbsId, options);

                } else {
                    return this.$.imageService.designImage(design.$.wtfMbsId, options)
                }

            }
            return null;
        }.onChange("design", "_width", "_height", "configuration.processedImage").on(["configuration.printColors", "reset"]),

        maskUrl: function() {

            if (this.$.imageService && this.$.configuration && this.$.configuration.$.design) {

                var maxSize = Math.min(this.$._width, 600),
                options = {},
                design = this.$.configuration.$.design;

                if (this.$.width >= this.$.height) {
                    options.width = maxSize;
                } else {
                    options.height = maxSize;
                }

                var colors = this.$.configuration.$.printColors.size(),
                    printColors = [];
                for (var i = 0; i < colors; i++) {
                    printColors.push("FFFFFF");
                }

                options.printColors = printColors;
                options.version = design.$.version;

                if (!design.isVectorDesign()) {
                    return this.$.configuration.$.processedImage || design.$.localImage || this.$.imageService.designImage(design.$.wtfMbsId, options);
                } else {
                    return this.$.imageService.designImage(design.$.wtfMbsId, options)
                }

            }

            return null;
        }.onChange("design", "_width", "_height").on(["configuration.printColors", "reset"])

    })
});<|endoftext|>