<commit_before>// Copyright 2015, University of Colorado Boulder

/**
 * Random number generator with an optional seed.
 *
 * @author John Blanco
 * @author Mohamed Safi
 * @author Aaron Davis
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var Util = require( 'DOT/Util' );
  var dot = require( 'DOT/dot' );

  /**
   *
   * @param [Object] options
   * @constructor
   */
  function Random( options ) {
    options = _.extend( {

      // {Tandem} for deterministic playback in randomized sims
      tandem: null,

      // {number|null} seed for the random number generator.
      //               when seed is null, Math.random() is used
      seed: null,

      // {boolean} if true, use the seed specified statically in the preloads for replicable playback in phet-io
      // this is a convenience option since it will be a common occurrence to use the replicable playback seed
      // if staticSeed and seed are both specified, there will be an assertion error.
      staticSeed: false

    }, options );

    // The tandem is required when brand==='phet-io'
    // Like Tandem.validateOptions, but without depending on tandem
    assert &&
    phet &&
    phet.chipper &&
    phet.chipper.brand &&
    phet.chipper.brand === 'phet-io' &&
    phet.chipper.getQueryParameter( 'phet-io.validateTandems' ) !== 'false' &&
    assert( options.tandem,
      'When running as PhET-iO, a tandem must be specified for each user interface component' );

    if ( options.seed !== null && options.staticSeed ) {
      assert && assert( false, 'cannot specify seed and useChipperSeed, use one or the other' );
    }

    var seed = options.staticSeed ? window.phet.chipper.randomSeed : options.seed;
    this.setSeed( seed );

    options.tandem && options.tandem.addInstance( this );
  }

  dot.register( 'Random', Random );

  Random.prototype = {

    constructor: Random,

    /**
     * Sets the seed of the random number generator. Setting it to null reverts the random generator to Math.random()
     * @param {number|null} seed
     */
    setSeed: function( seed ) {
      this.seed = seed;

      // Use "new" to create a local prng without altering Math.random.
      this.seedrandom = this.seed !== null ? new Math.seedrandom( this.seed + '' ) : null;
    },

    /**
     * Returns the value of the seed, null indicates that Math.random() is used
     * @public
     * @returns {number|null}
     */
    getSeed: function() {
      return this.seed;
    },

    /**
     * Returns a floating-point number in the range [0, 1), i.e. from 0 (inclusive) to 1 (exclusive)
     * The random number can be seeded
     * @public
     * @returns {number}
     */
    random: function() {
      return this.seed === null ? Math.random() : this.seedrandom();
    },

    /**
     * Returns the next pseudo-random boolean
     * @public
     * @returns {boolean}
     */
    nextBoolean: function() {
      return this.random() >= 0.5;
    },

    /**
     * Returns the next pseudo random number from this random number generator sequence.
     * The random number is an integer ranging from 0 to n-1.
     * @public
     * @param {number} n
     * @returns {number} - an integer
     */
    nextInt: function( n ) {
      var value = this.random() * n;
      return value | 0; // convert to int by removing the decimal places
    },

    /**
     * Returns the next pseudo random number from this random number generator sequence in the range [0, 1)
     * The distribution of the random numbers is uniformly distributed across the interval
     * @public
     * @returns {number} - a float
     */
    nextDouble: function() {
      var vv = this.random();
      return vv;
    },

    /**
     * Returns the next pseudo random number from this random number generator sequence.
     * The distribution of the random numbers is gaussian, with a mean =0  and standard deviation = 1
     * This random number is not seeded
     * @public
     * @returns {number}
     * // TODO: Seed this
     */
    nextGaussian: function() {
      return Util.boxMullerTransform( 0, 1 );
    }
  };

  return Random;
} );<commit_msg>Added support for lodash-ish random methods, see https://github.com/phetsims/area-builder/issues/98<commit_after>// Copyright 2015, University of Colorado Boulder

/**
 * Random number generator with an optional seed.
 *
 * @author John Blanco
 * @author Mohamed Safi
 * @author Aaron Davis
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var Util = require( 'DOT/Util' );
  var dot = require( 'DOT/dot' );

  /**
   *
   * @param [Object] options
   * @constructor
   */
  function Random( options ) {
    options = _.extend( {

      // {Tandem} for deterministic playback in randomized sims
      tandem: null,

      // {number|null} seed for the random number generator.
      //               when seed is null, Math.random() is used
      seed: null,

      // {boolean} if true, use the seed specified statically in the preloads for replicable playback in phet-io
      // this is a convenience option since it will be a common occurrence to use the replicable playback seed
      // if staticSeed and seed are both specified, there will be an assertion error.
      staticSeed: false

    }, options );

    // The tandem is required when brand==='phet-io'
    // Like Tandem.validateOptions, but without depending on tandem
    assert &&
    phet &&
    phet.chipper &&
    phet.chipper.brand &&
    phet.chipper.brand === 'phet-io' &&
    phet.chipper.getQueryParameter( 'phet-io.validateTandems' ) !== 'false' &&
    assert( options.tandem,
      'When running as PhET-iO, a tandem must be specified for each user interface component' );

    if ( options.seed !== null && options.staticSeed ) {
      assert && assert( false, 'cannot specify seed and useChipperSeed, use one or the other' );
    }

    var seed = options.staticSeed ? window.phet.chipper.randomSeed : options.seed;
    this.setSeed( seed );

    options.tandem && options.tandem.addInstance( this );
  }

  dot.register( 'Random', Random );

  Random.prototype = {

    constructor: Random,

    /**
     * Sets the seed of the random number generator. Setting it to null reverts the random generator to Math.random()
     * @param {number|null} seed
     */
    setSeed: function( seed ) {
      this.seed = seed;

      // Use "new" to create a local prng without altering Math.random.
      this.seedrandom = this.seed !== null ? new Math.seedrandom( this.seed + '' ) : null;
    },

    /**
     * Returns the value of the seed, null indicates that Math.random() is used
     * @public
     * @returns {number|null}
     */
    getSeed: function() {
      return this.seed;
    },

    /**
     * Returns a floating-point number in the range [0, 1), i.e. from 0 (inclusive) to 1 (exclusive)
     * The random number can be seeded
     * @public
     * @returns {number}
     */
    random: function() {
      return this.seed === null ? Math.random() : this.seedrandom();
    },

    /**
     * Returns the next pseudo-random boolean
     * @public
     * @returns {boolean}
     */
    nextBoolean: function() {
      return this.random() >= 0.5;
    },

    /**
     * Returns the next pseudo random number from this random number generator sequence.
     * The random number is an integer ranging from 0 to n-1.
     * @public
     * @param {number} n
     * @returns {number} - an integer
     */
    nextInt: function( n ) {
      var value = this.random() * n;
      return value | 0; // convert to int by removing the decimal places
    },

    // inclusive, to match underscore
    randomIntegerBetween: function( min, max, floaty ) {

      assert && assert( floaty === undefined, '3rd arg not supported' );

      // underscore support, where only 1 arg is supplied as max and min=0 is inferred
      if ( typeof max !== 'number' ) {
        max = min;
        min = 0;
      }

      if ( max === min ) {
        return max;
      }
      var range = max - min;
      return this.nextInt( range + 1 ) + min;
    },

    /**
     * Creates an array of shuffled values, using a version of the Fisher-Yates
     * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
     *
     * @static
     * @memberOf _
     * @category Collections
     * @param {Array|Object|string} collection The collection to shuffle.
     * @returns {Array} Returns a new shuffled collection.
     * @example
     *
     * _.shuffle([1, 2, 3, 4, 5, 6]);
     * // => [4, 1, 6, 3, 5, 2]
     *
     * Adapted from lodash-2.4.1 by Sam Reid on Aug 16, 2016
     */
    shuffle: function( collection ) {
      var r = this;
      var index = -1;
      var length = collection ? collection.length : 0;
      var result = Array( typeof length === 'number' ? length : 0 );

      _.forEach( collection, function( value ) {
        var rand = r.randomIntegerBetween( 0, ++index );
        result[ index ] = result[ rand ];
        result[ rand ] = value;
      } );
      return result;
    },

    /**
     * Returns the next pseudo random number from this random number generator sequence in the range [0, 1)
     * The distribution of the random numbers is uniformly distributed across the interval
     * @public
     * @returns {number} - a float
     */
    nextDouble: function() {
      var vv = this.random();
      return vv;
    },

    /**
     * Returns the next pseudo random number from this random number generator sequence.
     * The distribution of the random numbers is gaussian, with a mean =0  and standard deviation = 1
     * This random number is not seeded
     * @public
     * @returns {number}
     * // TODO: Seed this
     */
    nextGaussian: function() {
      return Util.boxMullerTransform( 0, 1 );
    }
  };

  return Random;
} );<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
	View,
	StyleSheet,
	Text,
	ScrollView,
	Image,
} from 'react-native';
import { connect } from 'react-redux';
import { Actions } from 'react-native-router-flux';
import moment from 'moment';
import Icon from 'react-native-vector-icons/Ionicons';

import css from '../../styles/css';
import general from '../../util/general';
import logger from '../../util/logger';
import SpecialEventsListView from './SpecialEventsListView';
import {
	COLOR_PRIMARY,
	COLOR_LGREY,
	COLOR_MGREY,
	COLOR_DGREY,
	COLOR_WHITE,
} from '../../styles/ColorConstants';
import {
	TAB_BAR_HEIGHT,
	NAVIGATOR_HEIGHT,
	WINDOW_WIDTH,
} from '../../styles/LayoutConstants';
import Touchable from '../common/Touchable';
import MultiSelect from './MultiSelect';

class SpecialEventsView extends Component {
	constructor(props) {
		super(props);

		// Calculate selected day
		let selectedDay;

		for (let i = 0; i < props.days.length; ++i) {
			selectedDay = i;
			if (moment(props.days[i]).isSameOrAfter(moment(), 'day')) {
				break;
			}
		}

		this.state = {
			personal: this.props.personal,
			onFilter: false,
			selectedDay,
		};
	}

	componentDidMount() {
		logger.ga('View Loaded: SpecialEventsView');

		Actions.refresh({
			backButton: this.renderBackButton(this.state.onFilter),
			filterButton: this.renderFilterButton(),
			specialEventsTitle: this.props.specialEventsTitle,
		});
	}

	handleFullPress = () => {
		Actions.refresh({
			filterButton: this.renderFilterButton(this.state.onFilter)
		});
		this.setState({ personal: false });
	}

	handleMinePress = () => {
		Actions.refresh({
			filterButton: null
		});
		this.setState({ personal: true });
	}

	handleFilterPress = () => {
		Actions.refresh({
			backButton: this.renderBackButton(!this.state.onFilter),
			filterButton: this.renderFilterButton(!this.state.onFilter)
		});
		this.setState({ onFilter: !this.state.onFilter });
	}

	handleFilterSelect = (labels) => {
		this.props.updateSpecialEventsLabels(labels);
	}

	handleDayPress = (index) => {
		this.setState({ selectedDay: index });
	}

	renderFilterButton = (onFilter) => {
		if (!onFilter) {
			return (
				<Touchable
					onPress={this.handleFilterPress}
				>
					<Text
						style={general.platformIOS() ? css.navButtonTextIOS : css.navButtonTextAndroid}
					>
						Filter
						</Text>
				</Touchable>
			);
		} else {
			return null;
		}
	}

	renderBackButton = (onFilter) => {
		return (
			<Touchable
				onPress={() => (onFilter) ? (this.handleFilterPress()) : (Actions.pop())}
			>
				<View style={styles.backButtonContainer}>
					<Icon
						name={'ios-arrow-back'}
						size={33}
						style={styles.backButtonImage}
					/>
					<Text
						style={general.platformIOS() ? css.navButtonTextIOS : css.navButtonTextAndroid}
					>
						Back
					</Text>
				</View>
			</Touchable>
		);
	}

	render() {
		if (this.state.onFilter) {
			return (
				<View
					style={[styles.main_container, styles.greybg]}
				>
					<MultiSelect
						items={this.props.specialEventsLabels}
						themes={this.props.specialEventsLabelThemes}
						selected={this.props.labels}
						onSelect={this.handleFilterSelect}
						applyFilters={this.handleFilterPress}
					/>
				</View>
			);
		} else {
			return (
				<View
					style={[styles.main_container, styles.greybg]}
				>
					<DaysBar
						days={this.props.days}
						selectedDay={this.state.selectedDay}
						handleDayPress={this.handleDayPress}
					/>
					<SpecialEventsListView
						style={styles.specialEventsListView}
						scrollEnabled={true}
						personal={this.state.personal}
						selectedDay={this.props.days[this.state.selectedDay]}
						clearFilters={() => this.handleFilterSelect([])}
					/>
					<FakeTabBar
						personal={this.state.personal}
						handleFullPress={this.handleFullPress}
						handleMinePress={this.handleMinePress}
					/>
				</View>
			);
		}
	}
}

const mapStateToProps = (state) => (
	{
		specialEventsTitle: (state.specialEvents.data) ? state.specialEvents.data.name : '',
		specialEventsLabels: state.specialEvents.data.labels,
		specialEventsLabelThemes: state.specialEvents.data['label-themes'],
		labels: state.specialEvents.labels,
		days: state.specialEvents.data.dates,
	}
);

const mapDispatchToProps = (dispatch) => (
	{
		updateSpecialEventsLabels: (labels) => {
			dispatch({ type: 'UPDATE_SPECIAL_EVENTS_LABELS', labels });
		},
	}
);

export default connect(mapStateToProps, mapDispatchToProps)(SpecialEventsView);

const FakeTabBar = ({ personal, handleFullPress, handleMinePress }) => (
	<View style={styles.tabBar}>
		<View
			style={styles.buttonContainer}
		>
			<Touchable
				style={personal ? styles.plainButton : styles.selectedButton}
				onPress={() => handleFullPress()}
			>
				<Text
					style={personal ? styles.plainText : styles.selectedText}
				>
					Full Schedule
				</Text>
			</Touchable>
			<Touchable
				style={personal ? styles.selectedButton : styles.plainButton}
				onPress={() => handleMinePress()}
			>
				<Text
					style={personal ? styles.selectedText : styles.plainText}
				>
					My Schedule
				</Text>
			</Touchable>
		</View>
	</View>
);

const DaysBar = ({ days, selectedDay, handleDayPress }) => {
	return (
		<View style={styles.daysBar}>
			<ScrollView
				horizontal
				showsHorizontalScrollIndicator={false}
				style={styles.scrollButtonContainer}
				contentContainerStyle={styles.scrollContentContainer}
			>
				{
					days.map((day, index) =>
						<Touchable
							key={day}
							style={index === 0 ? styles.plainButtonFirst : styles.plainButton }
							onPress={() => handleDayPress(index)}
						>
							<Text
								style={index !== selectedDay ? styles.plainText : styles.selectedDayText}
							>
								{moment(day).format('MMM D')}
							</Text>
						</Touchable>
					)
				}
			</ScrollView>
		</View>
	);
};

const styles = StyleSheet.create({
	main_container: { flex: 1, backgroundColor: COLOR_MGREY, marginTop: NAVIGATOR_HEIGHT },
	specialEventsListView: { flex: 1 },
	greybg: { backgroundColor: COLOR_LGREY },
	scrollButtonContainer: { flexDirection: 'row' },
	scrollContentContainer: { flexGrow: 1 },
	buttonContainer: { flex: 1, flexDirection: 'row', alignItems: 'center' },
	selectedButton: { flexGrow: 1, minWidth: WINDOW_WIDTH / 4, height: TAB_BAR_HEIGHT, alignItems: 'center', justifyContent: 'center', backgroundColor: COLOR_PRIMARY },
	plainButtonFirst: { flexGrow: 1, minWidth: WINDOW_WIDTH / 4, height: TAB_BAR_HEIGHT, alignItems: 'center', justifyContent: 'center', backgroundColor: COLOR_WHITE },
	plainButton: { flexGrow: 1, minWidth: WINDOW_WIDTH / 4, height: TAB_BAR_HEIGHT, alignItems: 'center', justifyContent: 'center', backgroundColor: COLOR_WHITE, borderLeftWidth: 1, borderLeftColor: COLOR_MGREY },
	selectedText: { textAlign: 'center', fontSize: 18, color: 'white' },
	plainText: { textAlign: 'center', fontSize: 18, opacity: 0.5 },
	tabBar: { borderTopWidth: 1, borderColor: COLOR_DGREY, backgroundColor: COLOR_WHITE, height: TAB_BAR_HEIGHT },
	daysBar: { borderBottomWidth: 1, borderColor: COLOR_MGREY, backgroundColor: COLOR_WHITE, height: TAB_BAR_HEIGHT },
	selectedDayText: { textAlign: 'center', fontSize: 18, color: COLOR_PRIMARY },
	filterText: { textAlign: 'center', fontSize: 17, color: 'white' },
	backButtonContainer: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', marginTop: -6 },
	backButtonImage: { color: COLOR_WHITE, marginRight: 7 },
});
<commit_msg>Handle android back button on filters<commit_after>import React, { Component } from 'react';
import {
	View,
	StyleSheet,
	Text,
	ScrollView,
	BackAndroid,
} from 'react-native';
import { connect } from 'react-redux';
import { Actions } from 'react-native-router-flux';
import moment from 'moment';
import Icon from 'react-native-vector-icons/Ionicons';

import css from '../../styles/css';
import general from '../../util/general';
import logger from '../../util/logger';
import SpecialEventsListView from './SpecialEventsListView';
import {
	COLOR_PRIMARY,
	COLOR_LGREY,
	COLOR_MGREY,
	COLOR_DGREY,
	COLOR_WHITE,
} from '../../styles/ColorConstants';
import {
	TAB_BAR_HEIGHT,
	NAVIGATOR_HEIGHT,
	WINDOW_WIDTH,
} from '../../styles/LayoutConstants';
import Touchable from '../common/Touchable';
import MultiSelect from './MultiSelect';

class SpecialEventsView extends Component {
	constructor(props) {
		super(props);

		// Calculate selected day
		let selectedDay;

		for (let i = 0; i < props.days.length; ++i) {
			selectedDay = i;
			if (moment(props.days[i]).isSameOrAfter(moment(), 'day')) {
				break;
			}
		}

		this.state = {
			personal: this.props.personal,
			onFilter: false,
			selectedDay,
		};
	}

	componentDidMount() {
		logger.ga('View Loaded: SpecialEventsView');
		BackAndroid.addEventListener('hardwareBackPress', this.handleBackPress);

		Actions.refresh({
			backButton: this.renderBackButton(this.state.onFilter),
			filterButton: this.renderFilterButton(),
			specialEventsTitle: this.props.specialEventsTitle,
		});
	}

	componentWillUnmount() {
		BackAndroid.removeEventListener('hardwareBackPress', this.handleBackPress);
	}

	// Returns true so router-flux back handler is ignored
	handleBackPress = () => {
		if (this.state.onFilter) {
			this.handleFilterPress();
			return true;
		} else {
			return false;
		}
	}

	handleFullPress = () => {
		Actions.refresh({
			filterButton: this.renderFilterButton(this.state.onFilter)
		});
		this.setState({ personal: false });
	}

	handleMinePress = () => {
		Actions.refresh({
			filterButton: null
		});
		this.setState({ personal: true });
	}

	handleFilterPress = () => {
		Actions.refresh({
			backButton: this.renderBackButton(!this.state.onFilter),
			filterButton: this.renderFilterButton(!this.state.onFilter)
		});
		this.setState({ onFilter: !this.state.onFilter });
	}

	handleFilterSelect = (labels) => {
		this.props.updateSpecialEventsLabels(labels);
	}

	handleDayPress = (index) => {
		this.setState({ selectedDay: index });
	}

	renderFilterButton = (onFilter) => {
		if (!onFilter) {
			return (
				<Touchable
					onPress={this.handleFilterPress}
				>
					<Text
						style={general.platformIOS() ? css.navButtonTextIOS : css.navButtonTextAndroid}
					>
						Filter
						</Text>
				</Touchable>
			);
		} else {
			return null;
		}
	}

	renderBackButton = (onFilter) => {
		return (
			<Touchable
				onPress={() => (onFilter) ? (this.handleFilterPress()) : (Actions.pop())}
			>
				<View style={styles.backButtonContainer}>
					<Icon
						name={'ios-arrow-back'}
						size={33}
						style={styles.backButtonImage}
					/>
					<Text
						style={general.platformIOS() ? css.navButtonTextIOS : css.navButtonTextAndroid}
					>
						Back
					</Text>
				</View>
			</Touchable>
		);
	}

	render() {
		if (this.state.onFilter) {
			return (
				<View
					style={[styles.main_container, styles.greybg]}
				>
					<MultiSelect
						items={this.props.specialEventsLabels}
						themes={this.props.specialEventsLabelThemes}
						selected={this.props.labels}
						onSelect={this.handleFilterSelect}
						applyFilters={this.handleFilterPress}
					/>
				</View>
			);
		} else {
			return (
				<View
					style={[styles.main_container, styles.greybg]}
				>
					<DaysBar
						days={this.props.days}
						selectedDay={this.state.selectedDay}
						handleDayPress={this.handleDayPress}
					/>
					<SpecialEventsListView
						style={styles.specialEventsListView}
						scrollEnabled={true}
						personal={this.state.personal}
						selectedDay={this.props.days[this.state.selectedDay]}
						clearFilters={() => this.handleFilterSelect([])}
					/>
					<FakeTabBar
						personal={this.state.personal}
						handleFullPress={this.handleFullPress}
						handleMinePress={this.handleMinePress}
					/>
				</View>
			);
		}
	}
}

const mapStateToProps = (state) => (
	{
		specialEventsTitle: (state.specialEvents.data) ? state.specialEvents.data.name : '',
		specialEventsLabels: state.specialEvents.data.labels,
		specialEventsLabelThemes: state.specialEvents.data['label-themes'],
		labels: state.specialEvents.labels,
		days: state.specialEvents.data.dates,
	}
);

const mapDispatchToProps = (dispatch) => (
	{
		updateSpecialEventsLabels: (labels) => {
			dispatch({ type: 'UPDATE_SPECIAL_EVENTS_LABELS', labels });
		},
	}
);

export default connect(mapStateToProps, mapDispatchToProps)(SpecialEventsView);

const FakeTabBar = ({ personal, handleFullPress, handleMinePress }) => (
	<View style={styles.tabBar}>
		<View
			style={styles.buttonContainer}
		>
			<Touchable
				style={personal ? styles.plainButton : styles.selectedButton}
				onPress={() => handleFullPress()}
			>
				<Text
					style={personal ? styles.plainText : styles.selectedText}
				>
					Full Schedule
				</Text>
			</Touchable>
			<Touchable
				style={personal ? styles.selectedButton : styles.plainButton}
				onPress={() => handleMinePress()}
			>
				<Text
					style={personal ? styles.selectedText : styles.plainText}
				>
					My Schedule
				</Text>
			</Touchable>
		</View>
	</View>
);

const DaysBar = ({ days, selectedDay, handleDayPress }) => {
	return (
		<View style={styles.daysBar}>
			<ScrollView
				horizontal
				showsHorizontalScrollIndicator={false}
				style={styles.scrollButtonContainer}
				contentContainerStyle={styles.scrollContentContainer}
			>
				{
					days.map((day, index) =>
						<Touchable
							key={day}
							style={index === 0 ? styles.plainButtonFirst : styles.plainButton }
							onPress={() => handleDayPress(index)}
						>
							<Text
								style={index !== selectedDay ? styles.plainText : styles.selectedDayText}
							>
								{moment(day).format('MMM D')}
							</Text>
						</Touchable>
					)
				}
			</ScrollView>
		</View>
	);
};

const styles = StyleSheet.create({
	main_container: { flex: 1, backgroundColor: COLOR_MGREY, marginTop: NAVIGATOR_HEIGHT },
	specialEventsListView: { flex: 1 },
	greybg: { backgroundColor: COLOR_LGREY },
	scrollButtonContainer: { flexDirection: 'row' },
	scrollContentContainer: { flexGrow: 1 },
	buttonContainer: { flex: 1, flexDirection: 'row', alignItems: 'center' },
	selectedButton: { flexGrow: 1, minWidth: WINDOW_WIDTH / 4, height: TAB_BAR_HEIGHT, alignItems: 'center', justifyContent: 'center', backgroundColor: COLOR_PRIMARY },
	plainButtonFirst: { flexGrow: 1, minWidth: WINDOW_WIDTH / 4, height: TAB_BAR_HEIGHT, alignItems: 'center', justifyContent: 'center', backgroundColor: COLOR_WHITE },
	plainButton: { flexGrow: 1, minWidth: WINDOW_WIDTH / 4, height: TAB_BAR_HEIGHT, alignItems: 'center', justifyContent: 'center', backgroundColor: COLOR_WHITE, borderLeftWidth: 1, borderLeftColor: COLOR_MGREY },
	selectedText: { textAlign: 'center', fontSize: 18, color: 'white' },
	plainText: { textAlign: 'center', fontSize: 18, opacity: 0.5 },
	tabBar: { borderTopWidth: 1, borderColor: COLOR_DGREY, backgroundColor: COLOR_WHITE, height: TAB_BAR_HEIGHT },
	daysBar: { borderBottomWidth: 1, borderColor: COLOR_MGREY, backgroundColor: COLOR_WHITE, height: TAB_BAR_HEIGHT },
	selectedDayText: { textAlign: 'center', fontSize: 18, color: COLOR_PRIMARY },
	filterText: { textAlign: 'center', fontSize: 17, color: 'white' },
	backButtonContainer: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', marginTop: -6 },
	backButtonImage: { color: COLOR_WHITE, marginRight: 7 },
});
<|endoftext|>


<commit_before>var LEVELS = require('./levels');

var compileFormat = require('./utils/message');

/**
 * Basic handler. Does not actually handle anything.
 * Usefull for extensions and stubs. All implementors must implement _handle(record)
 * method. record instance shared among all handlers, do not modify it.
 *
 */
function NullHandler() {
  this._level = LEVELS.ALL;
}

NullHandler.prototype = {

  /**
   * Set max accepted log level for this handler
   * @param  {string} level
   * @return {this}
   */
  setLevel: function(level) {
    if(typeof level === 'string') {
      level = LEVELS[level.toUpperCase()];
    }
    if(typeof level !== 'number' || !(level in LEVELS)) {
      throw new Error(level + ' does not exists');
    }
    this._level = level;
    return this;
  },

  _enabledFor: function(level) {
    return this._level <= level;
  },

  handle: function(record) {
    if(this._enabledFor(record.level)) {
      this._handle(record);
    }
  },

  _handle: function() {
  }
};

module.exports.NullHandler = NullHandler;

var DEFAULT_FORMAT = '%date %-5level %logger - %message%n%error';

/**
 * Used as base class for most handlers
 * All extensions should implement method `_handle(record)`
 */
function BaseHandler() {
  NullHandler.call(this);

  this.setFormat(DEFAULT_FORMAT);
}

BaseHandler.prototype = Object.create(NullHandler.prototype);

/**
 * Set log record format for this handler.
 * Default record format is `[%date] %-5level %logger - %message%n%error`
 *
 * Possible parameters:
 * - `%d{FORMAT}` or `%date{FORMAT}` - how to format record timestamp. `{FORMAT}` is optional stftime string, by default it is `%Y/%m/%d %H:%M:%S,%L`
 * - `%pid` - output process.pid
 * - `%level` or `%le` or `%p` - output record level name like ERROR or WARN
 * - `%logger` or `%lo` or `%c` - output logger name
 * - `%%` - output %
 * - `%n` - output EOL
 * - `%err` or `%error` - output stack trace of passed error
 * - `%x` or `%x{field}` - output JSON.stringified value of context field
 *
 * Also available text decorators (now only colors):
 * - `%highlight(text)` - will decorate passed text with record level decorator
 * - `%cyan(text)`
 * - other colors
 * - `%cyan.bold(text)`
 * - other bold colors
 *
 * Example: `%date000 %highlight(%5level) %cyan(%logger) - %message%n%error`
 *
 * Also it is possible to set it to function. One of possible examples jsonFormat (`require('huzzah/json-format')` ).
 * It can accept the same serializers bunyan can accept and you will have json output at the end.
 *
 * @param  {string|function} format - It is either formatted string as described, or function returning string and accepts just one argument log record
 * @return {this}
 */
BaseHandler.prototype.setFormat = function(format) {
  switch (typeof format) {
    case 'string':
      this.formatRecord = compileFormat(format);
      break;

    case 'function':
      this.formatRecord = format;
      break;
    default:
      throw new Error('`format` can be function or string');
  }
  return this;
};

module.exports.BaseHandler = BaseHandler;

/**
 * Just simple console handler
 */
function ConsoleHandler() {
  BaseHandler.call(this);
}

ConsoleHandler.prototype = Object.create(BaseHandler.prototype);
ConsoleHandler.prototype._handle = function(record) {
  var line = this.formatRecord(record);
  if(record.level > LEVELS.INFO) {
    process.stderr.write(line);
  } else {
    process.stdout.write(line);
  }
};

module.exports.ConsoleHandler = ConsoleHandler;

/**
 * Allow to pass records to stream
 */
function StreamHandler() {
  BaseHandler.call(this);

  this.setShouldFormat(true);
}

StreamHandler.prototype = Object.create(BaseHandler.prototype);
StreamHandler.prototype._handle = function(record) {
  var out = this._shouldFormat ? this.formatRecord(record) : record;
  this._stream.write(out);
};

/**
 * Should we format record before passing to stream? By default it is true
 * @param  {boolean} value
 * @return {this}
 */
StreamHandler.prototype.setShouldFormat = function(value) {
  this._shouldFormat = value;
  return this;
};

/**
 * Stream to pass records
 * @param  {WritableStream} stream
 * @return {this}
 */
StreamHandler.prototype.setStream = function(stream) {
  this._stream = stream;
  return this;
};

module.exports.StreamHandler = StreamHandler;
<commit_msg>Add RawConsoleLogger to output log records to console<commit_after>var LEVELS = require('./levels');

var compileFormat = require('./utils/message');

/**
 * Basic handler. Does not actually handle anything.
 * Usefull for extensions and stubs. All implementors must implement _handle(record)
 * method. record instance shared among all handlers, do not modify it.
 *
 */
function NullHandler() {
  this._level = LEVELS.ALL;
}

NullHandler.prototype = {

  /**
   * Set max accepted log level for this handler
   * @param  {string} level
   * @return {this}
   */
  setLevel: function(level) {
    if(typeof level === 'string') {
      level = LEVELS[level.toUpperCase()];
    }
    if(typeof level !== 'number' || !(level in LEVELS)) {
      throw new Error(level + ' does not exists');
    }
    this._level = level;
    return this;
  },

  _enabledFor: function(level) {
    return this._level <= level;
  },

  handle: function(record) {
    if(this._enabledFor(record.level)) {
      this._handle(record);
    }
  },

  _handle: function() {
  }
};

module.exports.NullHandler = NullHandler;

var DEFAULT_FORMAT = '%date %-5level %logger - %message%n%error';

/**
 * Used as base class for most handlers
 * All extensions should implement method `_handle(record)`
 */
function BaseHandler() {
  NullHandler.call(this);

  this.setFormat(DEFAULT_FORMAT);
}

BaseHandler.prototype = Object.create(NullHandler.prototype);

/**
 * Set log record format for this handler.
 * Default record format is `[%date] %-5level %logger - %message%n%error`
 *
 * Possible parameters:
 * - `%d{FORMAT}` or `%date{FORMAT}` - how to format record timestamp. `{FORMAT}` is optional stftime string, by default it is `%Y/%m/%d %H:%M:%S,%L`
 * - `%pid` - output process.pid
 * - `%level` or `%le` or `%p` - output record level name like ERROR or WARN
 * - `%logger` or `%lo` or `%c` - output logger name
 * - `%%` - output %
 * - `%n` - output EOL
 * - `%err` or `%error` - output stack trace of passed error
 * - `%x` or `%x{field}` - output JSON.stringified value of context field
 *
 * Also available text decorators (now only colors):
 * - `%highlight(text)` - will decorate passed text with record level decorator
 * - `%cyan(text)`
 * - other colors
 * - `%cyan.bold(text)`
 * - other bold colors
 *
 * Example: `%date000 %highlight(%5level) %cyan(%logger) - %message%n%error`
 *
 * Also it is possible to set it to function. One of possible examples jsonFormat (`require('huzzah/json-format')` ).
 * It can accept the same serializers bunyan can accept and you will have json output at the end.
 *
 * @param  {string|function} format - It is either formatted string as described, or function returning string and accepts just one argument log record
 * @return {this}
 */
BaseHandler.prototype.setFormat = function(format) {
  switch (typeof format) {
    case 'string':
      this.formatRecord = compileFormat(format);
      break;

    case 'function':
      this.formatRecord = format;
      break;
    default:
      throw new Error('`format` can be function or string');
  }
  return this;
};

module.exports.BaseHandler = BaseHandler;

/**
 * Just simple console handler
 */
function ConsoleHandler() {
  BaseHandler.call(this);
}

ConsoleHandler.prototype = Object.create(BaseHandler.prototype);
ConsoleHandler.prototype._handle = function(record) {
  var line = this.formatRecord(record);
  if(record.level > LEVELS.INFO) {
    process.stderr.write(line);
  } else {
    process.stdout.write(line);
  }
};

module.exports.ConsoleHandler = ConsoleHandler;

/**
 * Like ConsoleHandler but output whole record to console. This can be usefull
 * in browser to see inspections.
 */
function RawConsoleHandler() {
  BaseHandler.call(this);
}

RawConsoleHandler.prototype = Object.create(BaseHandler.prototype);
RawConsoleHandler.prototype._handle = function(record) {
  if(record.level < LEVELS.INFO) {
    console.log(record);
  } else if (record.level < LEVELS.WARN) {
    console.info(record);
  } else if (record.level < LEVELS.ERROR) {
    console.warn(record);
  } else {
    console.error(record);
  }
};

module.exports.RawConsoleHandler = RawConsoleHandler;

/**
 * Allow to pass records to stream
 */
function StreamHandler() {
  BaseHandler.call(this);

  this.setShouldFormat(true);
}

StreamHandler.prototype = Object.create(BaseHandler.prototype);
StreamHandler.prototype._handle = function(record) {
  var out = this._shouldFormat ? this.formatRecord(record) : record;
  this._stream.write(out);
};

/**
 * Should we format record before passing to stream? By default it is true
 * @param  {boolean} value
 * @return {this}
 */
StreamHandler.prototype.setShouldFormat = function(value) {
  this._shouldFormat = value;
  return this;
};

/**
 * Stream to pass records
 * @param  {WritableStream} stream
 * @return {this}
 */
StreamHandler.prototype.setStream = function(stream) {
  this._stream = stream;
  return this;
};

module.exports.StreamHandler = StreamHandler;
<|endoftext|>


<commit_before>var trivia = [
  "My favorite super hero is Spider-man.",
  "My favorite color is red (that's probably obvious).",
  "The first programming language I mastered was GML (Game Maker Language).",
  "I chose Bulbasaur as my first pokemon.",
  "I sang Mr. Grinch in a talent show; I didn't win.",
  "I have an army of Dwarfs.",
  "I've never seen Star Wars.",
  "I've hand made 2 bows and arrows.",
  "My favorite super hero movie is The Dark Knight.",
  "My favorite Chirstmas characters are The Grinch and Ebenezer Scrooge.",
  "Personally, I prefer Luigi to Mario.",
  "I can't whistle (yet).",
  "I have a bad habit of swallowing my gum (but I'm still alive).",
  "Captain America: Civil War was great, you should go see it!"
]

$(document).ready(function() {
  slides();
  projects();

  $("#trivia").text(trivia[Math.floor(Math.random() * trivia.length)]);
});
<commit_msg>Add trivia<commit_after>var trivia = [
  "My favorite super hero is Spider-man.",
  "My favorite color is red (that's probably obvious).",
  "The first programming language I mastered was GML (Game Maker Language).",
  "I chose Bulbasaur as my first pokemon.",
  "I sang Mr. Grinch in a talent show; I didn't win.",
  "I have an army of Dwarfs.",
  "I've never seen Star Wars.",
  "I've hand made 2 bows and arrows.",
  "My favorite super hero movie is The Dark Knight.",
  "My favorite Chirstmas characters are The Grinch and Ebenezer Scrooge.",
  "Personally, I prefer Luigi to Mario.",
  "I can't whistle (yet).",
  "I have a bad habit of swallowing my gum (but I'm still alive).",
  "Captain America: Civil War was great, you should go see it!",
  "The copyright statement at the bottom is only there to make the page look better."
]

$(document).ready(function() {
  slides();
  projects();

  $("#trivia").text(trivia[Math.floor(Math.random() * trivia.length)]);
});
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import _ from 'lodash';
import Joi from 'joi';
//
import * as Basic from '../../components/basic';
import * as Advanced from '../../components/advanced';
import * as Utils from '../../utils';
import * as Domain from '../../domain';
import { FormValueManager } from '../../redux';
import PersistentTypeEnum from '../../enums/PersistentTypeEnum';

const manager = new FormValueManager();

/**
 * Table of abstract form values.
 *
 * @author Roman Kučera
 * @author Radek Tomiška
 */
export class FormValueTable extends Advanced.AbstractTableContent {

  constructor(props, context) {
    super(props, context);
    this.state = {
      filterOpened: props.filterOpened,
      showLoading: true,
      persistentType: null
    };
  }

  getContentKey() {
    return 'content.form-values';
  }

  getManager() {
    return manager;
  }

  getUiKey() {
    return this.props.uiKey;
  }

  useFilter(event) {
    if (event) {
      event.preventDefault();
    }
    this.refs.table.useFilterForm(this.refs.filterForm);
  }

  cancelFilter(event) {
    if (event) {
      event.preventDefault();
    }
    this.setState({
      persistentType: null
    }, () => {
      this.refs.table.cancelFilter(this.refs.filterForm);
    });
  }

  /**
   * Loads filter from redux state or default.
   */
  loadFilter() {
    if (!this.refs.filterForm) {
      return;
    }
    //  filters from redux
    const _searchParameters = this.getSearchParameters();
    if (_searchParameters) {
      const filterData = {};
      _searchParameters.getFilters().forEach((v, k) => {
        filterData[k] = v;
      });
      // init persistent type by persisted filter in redux
      if (filterData.persistentType) {
        this.setState({
          persistentType: filterData.persistentType
        }, () => {
          this.refs.filterForm.setData(filterData);
        });
      } else {
        this.refs.filterForm.setData(filterData);
      }
    }
  }

  _onChangePersistentType(item) {
    this.setState({
      persistentType: item ? item.value : null,
    }, () => {
      this.refs.stringValueLike.setValue(null);
      this.refs.shortTextValueLike.setValue(null);
      this.refs.fromTill.setValue(null);
      this.refs.longValue.setValue(null);
      this.refs.doubleValue.setValue(null);
      this.refs.booleanValue.setValue(null);
      this.refs.uuidValue.setValue(null);
    });
  }

  render() {
    const { uiKey, forceSearchParameters, showFilter, columns, className } = this.props;
    const { filterOpened, persistentType } = this.state;
    //
    let _forceSearchParameters = forceSearchParameters || new Domain.SearchParameters();
    _forceSearchParameters = _forceSearchParameters.setFilter('addOwnerDto', true);
    //
    return (
      <Advanced.Table
        ref="table"
        uiKey={ uiKey }
        manager={ manager }
        forceSearchParameters={ _forceSearchParameters }
        showFilter={ showFilter }
        className={ className }
        showRowSelection
        filter={
          <Advanced.Filter onSubmit={this.useFilter.bind(this)}>
            <Basic.AbstractForm ref="filterForm">
              <Basic.Row>
                <Basic.Col lg={ 6 }>
                  <Advanced.Filter.TextField
                    ref="text"
                    placeholder={this.i18n('filter.text.placeholder')} />
                </Basic.Col>
                <Basic.Col lg={ 6 } className="text-right">
                  <Advanced.Filter.FilterButtons cancelFilter={this.cancelFilter.bind(this)} />
                </Basic.Col>
              </Basic.Row>
              <Basic.Row>
                <Basic.Col lg={ 4 }>
                  <Basic.EnumSelectBox
                    ref="persistentType"
                    placeholder={ this.i18n('filter.type.placeholder') }
                    multiSelect={ false }
                    enum={ PersistentTypeEnum }
                    onChange={ this._onChangePersistentType.bind(this) }/>
                </Basic.Col>
                <Basic.Col lg={ 8 }>
                  <Basic.TextField
                    ref="stringValueLike"
                    hidden={
                      persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.TEXT)
                        && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.CHAR)
                    }
                    placeholder={ this.i18n('filter.value.placeholder') }
                    help={ Advanced.Filter.getTextHelp() }
                  />
                  <Basic.TextField
                    ref="shortTextValueLike"
                    hidden={
                      persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.SHORTTEXT)
                       && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.CODELIST)
                       && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.ENUMERATION)
                    }
                    placeholder={ this.i18n('filter.value.placeholder') }
                    min={ 0 }
                    max={ 2000 }
                    help={ Advanced.Filter.getTextHelp() }
                  />
                  <Advanced.Filter.FilterDate
                    ref="fromTill"
                    hidden={
                      persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.DATE)
                        && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.DATETIME)
                    }
                    fromProperty="dateValueFrom"
                    tillProperty="dateValueTill"/>
                  <Basic.TextField
                    ref="longValue"
                    placeholder={ this.i18n('filter.value.placeholder') }
                    hidden={
                      persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.INT)
                        && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.LONG)
                    }
                    validation={ Joi.number().integer().min(-9223372036854775808).max(9223372036854775807) }/>
                  <Basic.TextField
                    ref="doubleValue"
                    placeholder={this.i18n('filter.value.placeholder')}
                    hidden={ persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.DOUBLE) }
                    validation={ Joi.number().min(-(10 ** 33)).max(10 ** 33) } />
                  <Basic.BooleanSelectBox
                    ref="booleanValue"
                    placeholder={ this.i18n('filter.value.placeholder') }
                    hidden={ persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.BOOLEAN) }
                    options={ [
                      { value: 'true', niceLabel: 'true' },
                      { value: 'false', niceLabel: 'false' }
                    ]}/>
                  <Basic.TextField
                    ref="uuidValue"
                    placeholder={ this.i18n('filter.value.placeholder') }
                    hidden={
                      persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.UUID)
                        && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.ATTACHMENT)
                    }/>
                </Basic.Col>
              </Basic.Row>
            </Basic.AbstractForm>
          </Advanced.Filter>
        }
        filterOpened={ filterOpened }
        _searchParameters={ this.getSearchParameters() }>

        <Advanced.Column
          property="ownerId"
          cell={
            ({ rowIndex, data }) => {
              return (
                <Advanced.EntityInfo
                  entityType={ Utils.Ui.getSimpleJavaType((data[rowIndex].ownerType)) }
                  entity={ data[rowIndex]._embedded ? data[rowIndex]._embedded.owner : null }
                  entityIdentifier={ data[rowIndex].ownerId }
                  showIcon
                  face="popover"
                  showEntityType />
              );
            }
          }
          rendered={ _.includes(columns, 'owner') }/>
        <Advanced.Column
          property="_embedded.formAttribute.code"
          header={ this.i18n('entity.FormAttribute.code.label')}
          sort
          sortProperty="formAttribute.code"
          rendered={ _.includes(columns, 'code') }/>
        <Advanced.Column
          property="_embedded.formAttribute.name"
          header={ this.i18n('entity.FormAttribute.name.label') }
          sort
          sortProperty="formAttribute.name"
          rendered={ _.includes(columns, 'name') }/>
        <Advanced.Column
          property="value"
          rendered={ _.includes(columns, 'value') }
          cell={
            ({ rowIndex, data, property }) => (
              Utils.Ui.toStringValue(data[rowIndex][property])
            )
          }/>
        <Advanced.Column
          property="persistentType"
          face="enum"
          enumClass={ PersistentTypeEnum }
          sort
          rendered={_.includes(columns, 'persistentType')}/>
        <Advanced.Column
          property="_embedded.formAttribute.defaultValue"
          header={ this.i18n('entity.FormAttribute.defaultValue')}
          sort
          sortProperty="formAttribute.defaultValue"
          rendered={ _.includes(columns, 'defaultValue') }/>
        <Advanced.Column
          property="_embedded.formAttribute.faceType"
          header={ this.i18n('entity.FormAttribute.faceType.label') }
          sort
          sortProperty="formAttribute.faceType"
          rendered={ _.includes(columns, 'faceType') }/>
      </Advanced.Table>
    );
  }
}

FormValueTable.propTypes = {
  filterOpened: PropTypes.bool,
  showFilter: PropTypes.bool,
  uiKey: PropTypes.string.isRequired,
  forceSearchParameters: PropTypes.object,
  columns: PropTypes.arrayOf(PropTypes.string),
};

FormValueTable.defaultProps = {
  filterOpened: true,
  showFilter: true,
  forceSearchParameters: null,
  columns: ['owner', 'code', 'name', 'value', 'persistentType', 'defaultValue', 'faceType'],
};

function select(state, component) {
  return {
    _searchParameters: Utils.Ui.getSearchParameters(state, component.uiKey)
  };
}

export default connect(select)(FormValueTable);
<commit_msg>#1195 FE: improve form value filter integer validation<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import _ from 'lodash';
import Joi from 'joi';
//
import * as Basic from '../../components/basic';
import * as Advanced from '../../components/advanced';
import * as Utils from '../../utils';
import * as Domain from '../../domain';
import { FormValueManager } from '../../redux';
import PersistentTypeEnum from '../../enums/PersistentTypeEnum';

const manager = new FormValueManager();

/**
 * Table of abstract form values.
 *
 * @author Roman Kučera
 * @author Radek Tomiška
 */
export class FormValueTable extends Advanced.AbstractTableContent {

  constructor(props, context) {
    super(props, context);
    this.state = {
      filterOpened: props.filterOpened,
      showLoading: true,
      persistentType: null
    };
  }

  getContentKey() {
    return 'content.form-values';
  }

  getManager() {
    return manager;
  }

  getUiKey() {
    return this.props.uiKey;
  }

  useFilter(event) {
    if (event) {
      event.preventDefault();
    }
    this.refs.table.useFilterForm(this.refs.filterForm);
  }

  cancelFilter(event) {
    if (event) {
      event.preventDefault();
    }
    this.setState({
      persistentType: null
    }, () => {
      this.refs.table.cancelFilter(this.refs.filterForm);
    });
  }

  /**
   * Loads filter from redux state or default.
   */
  loadFilter() {
    if (!this.refs.filterForm) {
      return;
    }
    //  filters from redux
    const _searchParameters = this.getSearchParameters();
    if (_searchParameters) {
      const filterData = {};
      _searchParameters.getFilters().forEach((v, k) => {
        filterData[k] = v;
      });
      // init persistent type by persisted filter in redux
      if (filterData.persistentType) {
        this.setState({
          persistentType: filterData.persistentType
        }, () => {
          this.refs.filterForm.setData(filterData);
        });
      } else {
        this.refs.filterForm.setData(filterData);
      }
    }
  }

  _onChangePersistentType(item) {
    this.setState({
      persistentType: item ? item.value : null,
    }, () => {
      this.refs.stringValueLike.setValue(null);
      this.refs.shortTextValueLike.setValue(null);
      this.refs.fromTill.setValue(null);
      this.refs.longValue.setValue(null);
      this.refs.doubleValue.setValue(null);
      this.refs.booleanValue.setValue(null);
      this.refs.uuidValue.setValue(null);
    });
  }

  render() {
    const { uiKey, forceSearchParameters, showFilter, columns, className } = this.props;
    const { filterOpened, persistentType } = this.state;
    //
    let _forceSearchParameters = forceSearchParameters || new Domain.SearchParameters();
    _forceSearchParameters = _forceSearchParameters.setFilter('addOwnerDto', true);
    //
    return (
      <Advanced.Table
        ref="table"
        uiKey={ uiKey }
        manager={ manager }
        forceSearchParameters={ _forceSearchParameters }
        showFilter={ showFilter }
        className={ className }
        showRowSelection
        filter={
          <Advanced.Filter onSubmit={this.useFilter.bind(this)}>
            <Basic.AbstractForm ref="filterForm">
              <Basic.Row>
                <Basic.Col lg={ 6 }>
                  <Advanced.Filter.TextField
                    ref="text"
                    placeholder={this.i18n('filter.text.placeholder')} />
                </Basic.Col>
                <Basic.Col lg={ 6 } className="text-right">
                  <Advanced.Filter.FilterButtons cancelFilter={this.cancelFilter.bind(this)} />
                </Basic.Col>
              </Basic.Row>
              <Basic.Row>
                <Basic.Col lg={ 4 }>
                  <Basic.EnumSelectBox
                    ref="persistentType"
                    placeholder={ this.i18n('filter.type.placeholder') }
                    multiSelect={ false }
                    enum={ PersistentTypeEnum }
                    onChange={ this._onChangePersistentType.bind(this) }/>
                </Basic.Col>
                <Basic.Col lg={ 8 }>
                  <Basic.TextField
                    ref="stringValueLike"
                    hidden={
                      persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.TEXT)
                        && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.CHAR)
                    }
                    placeholder={ this.i18n('filter.value.placeholder') }
                    help={ Advanced.Filter.getTextHelp() }
                  />
                  <Basic.TextField
                    ref="shortTextValueLike"
                    hidden={
                      persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.SHORTTEXT)
                       && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.CODELIST)
                       && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.ENUMERATION)
                    }
                    placeholder={ this.i18n('filter.value.placeholder') }
                    min={ 0 }
                    max={ 2000 }
                    help={ Advanced.Filter.getTextHelp() }
                  />
                  <Advanced.Filter.FilterDate
                    ref="fromTill"
                    hidden={
                      persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.DATE)
                        && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.DATETIME)
                    }
                    fromProperty="dateValueFrom"
                    tillProperty="dateValueTill"/>
                  {
                    persistentType === PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.INT)
                    ?
                    <Basic.TextField
                      ref="longValue"
                      placeholder={ this.i18n('filter.value.placeholder') }
                      validation={ Joi.number().integer().min(-2147483648).max(2147483647) }/>
                    :
                    <Basic.TextField
                      ref="longValue"
                      placeholder={ this.i18n('filter.value.placeholder') }
                      hidden={
                        persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.INT)
                          && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.LONG)
                      }
                      validation={ Joi.number().integer().min(-9223372036854775808).max(9223372036854775807) }/>
                  }
                  <Basic.TextField
                    ref="doubleValue"
                    placeholder={ this.i18n('filter.value.placeholder') }
                    hidden={ persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.DOUBLE) }
                    validation={ Joi.number().min(-(10 ** 33)).max(10 ** 33) } />
                  <Basic.BooleanSelectBox
                    ref="booleanValue"
                    placeholder={ this.i18n('filter.value.placeholder') }
                    hidden={ persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.BOOLEAN) }
                    options={ [
                      { value: 'true', niceLabel: 'true' },
                      { value: 'false', niceLabel: 'false' }
                    ]}/>
                  <Basic.TextField
                    ref="uuidValue"
                    placeholder={ this.i18n('filter.value.placeholder') }
                    hidden={
                      persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.UUID)
                        && persistentType !== PersistentTypeEnum.findKeyBySymbol(PersistentTypeEnum.ATTACHMENT)
                    }/>
                </Basic.Col>
              </Basic.Row>
            </Basic.AbstractForm>
          </Advanced.Filter>
        }
        filterOpened={ filterOpened }
        _searchParameters={ this.getSearchParameters() }>

        <Advanced.Column
          property="ownerId"
          cell={
            ({ rowIndex, data }) => {
              return (
                <Advanced.EntityInfo
                  entityType={ Utils.Ui.getSimpleJavaType((data[rowIndex].ownerType)) }
                  entity={ data[rowIndex]._embedded ? data[rowIndex]._embedded.owner : null }
                  entityIdentifier={ data[rowIndex].ownerId }
                  showIcon
                  face="popover"
                  showEntityType />
              );
            }
          }
          rendered={ _.includes(columns, 'owner') }/>
        <Advanced.Column
          property="_embedded.formAttribute.code"
          header={ this.i18n('entity.FormAttribute.code.label')}
          sort
          sortProperty="formAttribute.code"
          rendered={ _.includes(columns, 'code') }/>
        <Advanced.Column
          property="_embedded.formAttribute.name"
          header={ this.i18n('entity.FormAttribute.name.label') }
          sort
          sortProperty="formAttribute.name"
          rendered={ _.includes(columns, 'name') }/>
        <Advanced.Column
          property="value"
          rendered={ _.includes(columns, 'value') }
          cell={
            ({ rowIndex, data, property }) => (
              Utils.Ui.toStringValue(data[rowIndex][property])
            )
          }/>
        <Advanced.Column
          property="persistentType"
          face="enum"
          enumClass={ PersistentTypeEnum }
          sort
          rendered={_.includes(columns, 'persistentType')}/>
        <Advanced.Column
          property="_embedded.formAttribute.defaultValue"
          header={ this.i18n('entity.FormAttribute.defaultValue')}
          sort
          sortProperty="formAttribute.defaultValue"
          rendered={ _.includes(columns, 'defaultValue') }/>
        <Advanced.Column
          property="_embedded.formAttribute.faceType"
          header={ this.i18n('entity.FormAttribute.faceType.label') }
          sort
          sortProperty="formAttribute.faceType"
          rendered={ _.includes(columns, 'faceType') }/>
      </Advanced.Table>
    );
  }
}

FormValueTable.propTypes = {
  filterOpened: PropTypes.bool,
  showFilter: PropTypes.bool,
  uiKey: PropTypes.string.isRequired,
  forceSearchParameters: PropTypes.object,
  columns: PropTypes.arrayOf(PropTypes.string),
};

FormValueTable.defaultProps = {
  filterOpened: true,
  showFilter: true,
  forceSearchParameters: null,
  columns: ['owner', 'code', 'name', 'value', 'persistentType', 'defaultValue', 'faceType'],
};

function select(state, component) {
  return {
    _searchParameters: Utils.Ui.getSearchParameters(state, component.uiKey)
  };
}

export default connect(select)(FormValueTable);
<|endoftext|>


<commit_before>var PARAMS = Object.freeze({
  COLLECTION_TIME: 1000,
  MAX_COLOR_BIAS: 3,
  MOVE_THRESHOLD: 200,
  MOVE_THRESHOLD_SMALL: 50,
  MOVE_ADJUSTMENT_MULTIPLIER: 2,
  INPUT_WIDTH: 300,
  INPUT_HEIGHT: 250,
  CANVAS_WIDTH: 500,
  CANVAS_HEIGHT: 300,
  PIXEL_SIZE: 5,
  INVADER_COUNT: 7
});

document.addEventListener('DOMContentLoaded', function(){

  var runCount = 0;
  var ctx = document.getElementById('fleet-display').getContext('2d');
  var progressButton = document.getElementById('button-progress');
  var clickHandler = function(){ startGeneration(); };
  progressButton.addEventListener('click', clickHandler);

  // Only one half, a 6x8 grid is stored for an invader, because they are
  // symmetrical to the vertical axis (making their final size 11x8 pixels).
  // The half of the "standard" space invader looks like this:
  //[0,0,1,0,0,0],
  //[0,0,0,1,0,0],
  //[0,0,1,1,1,1],
  //[0,1,1,0,1,1],
  //[1,1,1,1,1,1],
  //[1,0,1,1,1,1],
  //[1,0,1,0,0,0],
  //[0,0,0,1,1,0],
  //but it's not necessary to store this, because the mutators recreate it if there's no mouse input

  var baseInvader = [
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
  ];

  var mutators = [hullMutator, antennaMutator, weaponMutator, thrusterMutator];

  function resetMutators(){
    mutators = [hullMutator, antennaMutator, weaponMutator, thrusterMutator];
  }

  function startGeneration() {
    if(runCount === 0){
      ctx.clearRect(0,0,PARAMS.CANVAS_WIDTH,PARAMS.CANVAS_HEIGHT);
      //TODO: draw black background so that "save image as" saves background too
    }
    runCount++;
    collectInput(function(inputs){
      // --- add a special random mutator, without a dedicated collection interval
      // it gets the same input as the first mutator
      mutators.push(randomMutator);
      inputs.push(inputs[0]);
      // ----
      var invader = mutateInvader(baseInvader, inputs, mutators);
      display(invader);
    });
  }

  function collectInput(callback){
    var inputArea = document.getElementById('input-area');
    var inputWidth = inputArea.getBoundingClientRect().width; //NB this includes borders
    var inputHeight = inputArea.getBoundingClientRect().height;
    var inputSeed = [];
    var moveCount = 0;
    var firstMove;
    var lastMove;
    var moveCounter = function(event){
      moveCount++;
      var X = event.clientX - this.getBoundingClientRect().left;
      var Y = event.clientY - this.getBoundingClientRect().top;
      if(firstMove){
        lastMove = {x: X, y: Y};
      } else {
        firstMove = {x: X, y: Y};
      }
    };

    inputArea.addEventListener('mousemove', moveCounter);

    progressButton.removeEventListener('click', clickHandler);
    progressButton.innerHTML = 'Generating row... (0/'+mutators.length+')';

    //Dispatch a timeout for each mutator, with increasing delays. Mouse moves are
    // collected between the callbacks, creating the input seed for each mutator.
    mutators.forEach(function(_, i){
      setTimeout(function(){
        progressButton.innerHTML = 'Generating row... ('+(i+1)+'/'+mutators.length+')';
        inputSeed.push({
          moveCount: moveCount,
          firstMove: firstMove,
          lastMove: lastMove
        });
        moveCount = 0;
        firstMove = undefined;
        lastMove = undefined;
        if(i===mutators.length-1){
          inputArea.removeEventListener('mousemove', moveCounter);
          callback(inputSeed);
          progressButton.innerHTML = 'Fleet generated. (Click to restart)';
          resetMutators();
          progressButton.addEventListener('click', clickHandler);
          if(runCount < 3){
            clickHandler();
          } else {
            runCount = 0;
          }
        }
      }, PARAMS.COLLECTION_TIME*(i+1));
    });

  }

  function display(invader){
    var colWidth = (11+3)*PARAMS.PIXEL_SIZE;
    var rowHeight = (8+3)*PARAMS.PIXEL_SIZE;
    for(var i=0;i<PARAMS.INVADER_COUNT;i++){
      for(var row=0;row<2;row++){
        drawInvader(
          ctx,
          2*PARAMS.PIXEL_SIZE+(i*colWidth),
          -(rowHeight)+2*PARAMS.PIXEL_SIZE+(row*rowHeight)+((runCount-1)*2*rowHeight),
          invader
        );
      }
    }
  }

});

function deepCopy(obj){
  return JSON.parse(JSON.stringify(obj));
}

function mutateInvader(base, inputs, mutators){
  var invader = deepCopy(base);
  mutators.forEach(function(mutator, i){
    invader = mutator(invader, inputs[i]);
  });
  return invader;
}

function hullMutator(invader, input){
  var p = { //base pixel
    color: getColorString(input.moveCount)
  };
  var s = deepCopy(p); //secondary pixel
  if(input.firstMove && input.lastMove){
    var x0 = input.firstMove.x;
    var y0 = input.firstMove.y;
    var x1 = input.lastMove.x;
    var y1 = input.lastMove.y;
    if(Math.abs(x0-x1)<100 && Math.abs(y0-y1)<100){
      s.color = getColorString(input.moveCount, 0.8, 0.8, 1)
    }
  }
  var e = 0; //eye pixel
  if(input.firstMove && input.lastMove){
    //only color eyes if movement was downwards - should be rare due to layout
    if(input.firstMove.y < input.lastMove.y ){
      e = {
        color: input.firstMove.x < input.lastMove.x? 'rgb(200,15,15)' : 'rgb(50,175,20)'
      };
    }
  }
  var part = [
    [0,0,0,s], // antenna will overwrite first 3 anyway
    [s,e,s,p],
    [p,s,p,s],
    [s,p,s,p]
  ];
  return applyPart(invader, part, 2, 2);
}

function antennaMutator(invader, input){
  var biasR = 1;
  var biasG = 1;
  var biasB = 1;
  if(input.firstMove && input.lastMove){
    biasR = input.firstMove.x/PARAMS.INPUT_WIDTH;
    biasG = input.firstMove.y/PARAMS.INPUT_HEIGHT;
    biasB = input.lastMove.x/PARAMS.INPUT_WIDTH;
  }
  var p = {
    color: getColorString(input.moveCount, biasR, biasG, biasB)
  };
  var part = [
    [p,0,0,0],
    [0,p,0,0],
    [p,p,p,null]
  ];
  var antenna = [[]];
  //tilt antennae based on movement direction:
  if(input.firstMove && input.lastMove){
    var antenna;
    if( Math.abs(input.firstMove.x-input.lastMove.x)<100 ){
      antenna = [
        [0,p],
        [0,p]
      ];
    } else if (input.firstMove.x < input.lastMove.x){
      antenna = [
        [0,0,p],
        [0,p,0]
      ];
    }
  }
  part = applyPart(part, antenna, 0, 0);
  return applyPart(invader, part, 2, 0);
}

function weaponMutator(invader, input){
  var p = {
    color: getColorString(input.moveCount)
  };
  var part = [
    [0,0],
    [0,0],
    [0,0],
    [0,p],
    [p,p],
    [p,0],
    [p,0],
    [0,0]
  ];
  var weapon = [
    [0,0],
    [0,0],
    [0,0],
    [0,p],
    [p,p]
  ];
  if(input.moveCount > PARAMS.MOVE_THRESHOLD_SMALL){
    weapon = [];
    var binArray = input.moveCount.toString(2).split('');
    //normalize and replace 1s with base pixel
    binArray = binArray.map(function(el){
      return el==='1'? p: 0;
    });
    while(binArray.length > 0) {
      weapon.push(binArray.splice(0,2));
    }
  }
  part = applyPart(part, weapon, 0, 0);
  return applyPart(invader, part, 0, 0);
}

function thrusterMutator(invader, input){
  var biasR = 1;
  var biasG = 1;
  var biasB = 1;
  if(input.lastMove){
    var biasR = Math.min(PARAMS.MAX_COLOR_BIAS/2, input.lastMove.x/input.lastMove.y);
    var biasG = input.lastMove.x > input.lastMove.y? 1: 0;
    var biasB = (input.lastMove.x<20 && input.lastMove.y<20)? 0: 1;
  }
  var p = {
    color: getColorString(input.moveCount, biasR, biasG, biasB)
  };
  var part = [
    [0,0,0,0],
    [0,0,0,0]
  ];
  var thrusters = [
    [p,0,0],
    [0,p,p]
  ];
  if(input.firstMove && input.lastMove){
    if(input.moveCount%3 === 1){
      thrusters = [
        [p,p,p,p],
        [p,0,0,p]
      ];
    } else if(input.moveCount%3 === 2){
      thrusters = [
        [p,p,0,0],
        [0,0,0,0]
      ];
    } else if(input.moveCount > PARAMS.MOVE_THRESHOLD_SMALL){
      thrusters = [
        [p,0,p,0],
        [0,p,0,p]
      ]
    }
  }
  part = applyPart(part, thrusters, 0, 0);
  return applyPart(invader, part, 2, 6);
}

function randomMutator(invader, input){
  var p = {
    color: getColorString(input.moveCount, 0.5, 0.5, 0.5)
  };
  var mutation = [
    [0,0],
    [0,0]
  ];
  if(input.moveCount){
    var _ = (input.moveCount%2)? 0 : null; //50% chance to clear
    switch(input.moveCount%5){
      case 0:
        mutation = [
          [_,p],
          [_,p]
        ];
        break;
      case 1:
        mutation = [
          [_,_],
          [p,p]
        ];
        break;
      case 2:
        mutation = [
          [p,_],
          [_,p]
        ];
        break;
      case 3:
        mutation = [
          [_,p],
          [p,_]
        ];
        break;
      case 4:
        mutation = [
          [_,p],
          [p,p]
        ];
        break;
    }
  }
  // +4 offset ensures that it does not clear anything from the standard invader
  // if there was no input (clears between antennae)
  // The min call ensures that we don't override cells outside of the invader boundary
  var x = Math.min( (input.moveCount+4) % invader[0].length, invader[0].length-mutation[0].length );
  var y = Math.min( (input.moveCount*101) % invader.length, invader.length-mutation.length);
  return applyPart(invader, mutation, x, y);
}

function getColorString(moveCount, biasR, biasG, biasB){
  var n = 256-Math.min(PARAMS.MOVE_THRESHOLD,moveCount*PARAMS.MOVE_ADJUSTMENT_MULTIPLIER);
  var R = 1;
  var G = 1;
  var B = 1;
  if(biasR) R=biasR;
  if(biasG) G=biasG;
  if(biasB) B=biasB;
  //NB: non-integer values are not valid here!
  return 'rgb('+Math.floor(n*R)+','+Math.floor(n*G)+','+Math.floor(n*B)+')';
}

function applyPart(base, part, x, y){
  var invader = deepCopy(base);
  for(var i=0;i<part.length;i++){
    for(var j=0;j<part[i].length;j++){
      if(part[i][j] != null){ // null signals ignore, 0 signals overwrite with empty
        invader[y+i][x+j] = part[i][j];
      }
    }
  }
  return invader;
}

function drawInvader(context, x0, y0, invader){
  for(var y=0;y<invader.length;y++){
    var len = invader[y].length;
    //we're mirroring every column but the last
    for(var x=0;x<len*2-1;x++){
      var xPos = x>=len? x-(x-len+1)*2 : x;
      if(invader[y][xPos]){
        context.fillStyle = invader[y][xPos].color;
        context.fillRect(
          x0+x*PARAMS.PIXEL_SIZE,
          y0+y*PARAMS.PIXEL_SIZE,
          PARAMS.PIXEL_SIZE,
          PARAMS.PIXEL_SIZE
        );
      }
    }
  }
}<commit_msg>add painted background so 'save as image' works as expected<commit_after>var PARAMS = Object.freeze({
  COLLECTION_TIME: 1000,
  MAX_COLOR_BIAS: 3,
  MOVE_THRESHOLD: 200,
  MOVE_THRESHOLD_SMALL: 50,
  MOVE_ADJUSTMENT_MULTIPLIER: 2,
  INPUT_WIDTH: 300,
  INPUT_HEIGHT: 250,
  CANVAS_WIDTH: 500,
  CANVAS_HEIGHT: 300,
  PIXEL_SIZE: 5,
  INVADER_COUNT: 7
});

document.addEventListener('DOMContentLoaded', function(){

  var runCount = 0;
  var ctx = document.getElementById('fleet-display').getContext('2d');
  var progressButton = document.getElementById('button-progress');
  var clickHandler = function(){ startGeneration(); };
  progressButton.addEventListener('click', clickHandler);

  // Only one half, a 6x8 grid is stored for an invader, because they are
  // symmetrical to the vertical axis (making their final size 11x8 pixels).
  // The half of the "standard" space invader looks like this:
  //[0,0,1,0,0,0],
  //[0,0,0,1,0,0],
  //[0,0,1,1,1,1],
  //[0,1,1,0,1,1],
  //[1,1,1,1,1,1],
  //[1,0,1,1,1,1],
  //[1,0,1,0,0,0],
  //[0,0,0,1,1,0],
  //but it's not necessary to store this, because the mutators recreate it if there's no mouse input

  var baseInvader = [
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,0,0],
  ];

  var mutators = [hullMutator, antennaMutator, weaponMutator, thrusterMutator];

  function resetMutators(){
    mutators = [hullMutator, antennaMutator, weaponMutator, thrusterMutator];
  }

  function startGeneration() {
    if(runCount === 0){
      ctx.clearRect(0,0,PARAMS.CANVAS_WIDTH,PARAMS.CANVAS_HEIGHT);
      ctx.fillSTyle = 'black';
      ctx.fillRect(0,0,PARAMS.CANVAS_WIDTH,PARAMS.CANVAS_HEIGHT);
    }
    runCount++;
    collectInput(function(inputs){
      // --- add a special random mutator, without a dedicated collection interval
      // it gets the same input as the first mutator
      mutators.push(randomMutator);
      inputs.push(inputs[0]);
      // ----
      var invader = mutateInvader(baseInvader, inputs, mutators);
      display(invader);
    });
  }

  function collectInput(callback){
    var inputArea = document.getElementById('input-area');
    var inputWidth = inputArea.getBoundingClientRect().width; //NB this includes borders
    var inputHeight = inputArea.getBoundingClientRect().height;
    var inputSeed = [];
    var moveCount = 0;
    var firstMove;
    var lastMove;
    var moveCounter = function(event){
      moveCount++;
      var X = event.clientX - this.getBoundingClientRect().left;
      var Y = event.clientY - this.getBoundingClientRect().top;
      if(firstMove){
        lastMove = {x: X, y: Y};
      } else {
        firstMove = {x: X, y: Y};
      }
    };

    inputArea.addEventListener('mousemove', moveCounter);

    progressButton.removeEventListener('click', clickHandler);
    progressButton.innerHTML = 'Generating row... (0/'+mutators.length+')';

    //Dispatch a timeout for each mutator, with increasing delays. Mouse moves are
    // collected between the callbacks, creating the input seed for each mutator.
    mutators.forEach(function(_, i){
      setTimeout(function(){
        progressButton.innerHTML = 'Generating row... ('+(i+1)+'/'+mutators.length+')';
        inputSeed.push({
          moveCount: moveCount,
          firstMove: firstMove,
          lastMove: lastMove
        });
        moveCount = 0;
        firstMove = undefined;
        lastMove = undefined;
        if(i===mutators.length-1){
          inputArea.removeEventListener('mousemove', moveCounter);
          callback(inputSeed);
          progressButton.innerHTML = 'Fleet generated. (Click to restart)';
          resetMutators();
          progressButton.addEventListener('click', clickHandler);
          if(runCount < 3){
            clickHandler();
          } else {
            runCount = 0;
          }
        }
      }, PARAMS.COLLECTION_TIME*(i+1));
    });

  }

  function display(invader){
    var colWidth = (11+3)*PARAMS.PIXEL_SIZE;
    var rowHeight = (8+3)*PARAMS.PIXEL_SIZE;
    for(var i=0;i<PARAMS.INVADER_COUNT;i++){
      for(var row=0;row<2;row++){
        drawInvader(
          ctx,
          2*PARAMS.PIXEL_SIZE+(i*colWidth),
          -(rowHeight)+2*PARAMS.PIXEL_SIZE+(row*rowHeight)+((runCount-1)*2*rowHeight),
          invader
        );
      }
    }
  }

});

function deepCopy(obj){
  return JSON.parse(JSON.stringify(obj));
}

function mutateInvader(base, inputs, mutators){
  var invader = deepCopy(base);
  mutators.forEach(function(mutator, i){
    invader = mutator(invader, inputs[i]);
  });
  return invader;
}

function hullMutator(invader, input){
  var p = { //base pixel
    color: getColorString(input.moveCount)
  };
  var s = deepCopy(p); //secondary pixel
  if(input.firstMove && input.lastMove){
    var x0 = input.firstMove.x;
    var y0 = input.firstMove.y;
    var x1 = input.lastMove.x;
    var y1 = input.lastMove.y;
    if(Math.abs(x0-x1)<100 && Math.abs(y0-y1)<100){
      s.color = getColorString(input.moveCount, 0.8, 0.8, 1)
    }
  }
  var e = 0; //eye pixel
  if(input.firstMove && input.lastMove){
    //only color eyes if movement was downwards - should be rare due to layout
    if(input.firstMove.y < input.lastMove.y ){
      e = {
        color: input.firstMove.x < input.lastMove.x? 'rgb(200,15,15)' : 'rgb(50,175,20)'
      };
    }
  }
  var part = [
    [0,0,0,s], // antenna will overwrite first 3 anyway
    [s,e,s,p],
    [p,s,p,s],
    [s,p,s,p]
  ];
  return applyPart(invader, part, 2, 2);
}

function antennaMutator(invader, input){
  var biasR = 1;
  var biasG = 1;
  var biasB = 1;
  if(input.firstMove && input.lastMove){
    biasR = input.firstMove.x/PARAMS.INPUT_WIDTH;
    biasG = input.firstMove.y/PARAMS.INPUT_HEIGHT;
    biasB = input.lastMove.x/PARAMS.INPUT_WIDTH;
  }
  var p = {
    color: getColorString(input.moveCount, biasR, biasG, biasB)
  };
  var part = [
    [p,0,0,0],
    [0,p,0,0],
    [p,p,p,null]
  ];
  var antenna = [[]];
  //tilt antennae based on movement direction:
  if(input.firstMove && input.lastMove){
    var antenna;
    if( Math.abs(input.firstMove.x-input.lastMove.x)<100 ){
      antenna = [
        [0,p],
        [0,p]
      ];
    } else if (input.firstMove.x < input.lastMove.x){
      antenna = [
        [0,0,p],
        [0,p,0]
      ];
    }
  }
  part = applyPart(part, antenna, 0, 0);
  return applyPart(invader, part, 2, 0);
}

function weaponMutator(invader, input){
  var p = {
    color: getColorString(input.moveCount)
  };
  var part = [
    [0,0],
    [0,0],
    [0,0],
    [0,p],
    [p,p],
    [p,0],
    [p,0],
    [0,0]
  ];
  var weapon = [
    [0,0],
    [0,0],
    [0,0],
    [0,p],
    [p,p]
  ];
  if(input.moveCount > PARAMS.MOVE_THRESHOLD_SMALL){
    weapon = [];
    var binArray = input.moveCount.toString(2).split('');
    //normalize and replace 1s with base pixel
    binArray = binArray.map(function(el){
      return el==='1'? p: 0;
    });
    while(binArray.length > 0) {
      weapon.push(binArray.splice(0,2));
    }
  }
  part = applyPart(part, weapon, 0, 0);
  return applyPart(invader, part, 0, 0);
}

function thrusterMutator(invader, input){
  var biasR = 1;
  var biasG = 1;
  var biasB = 1;
  if(input.lastMove){
    var biasR = Math.min(PARAMS.MAX_COLOR_BIAS/2, input.lastMove.x/input.lastMove.y);
    var biasG = input.lastMove.x > input.lastMove.y? 1: 0;
    var biasB = (input.lastMove.x<20 && input.lastMove.y<20)? 0: 1;
  }
  var p = {
    color: getColorString(input.moveCount, biasR, biasG, biasB)
  };
  var part = [
    [0,0,0,0],
    [0,0,0,0]
  ];
  var thrusters = [
    [p,0,0],
    [0,p,p]
  ];
  if(input.firstMove && input.lastMove){
    if(input.moveCount%3 === 1){
      thrusters = [
        [p,p,p,p],
        [p,0,0,p]
      ];
    } else if(input.moveCount%3 === 2){
      thrusters = [
        [p,p,0,0],
        [0,0,0,0]
      ];
    } else if(input.moveCount > PARAMS.MOVE_THRESHOLD_SMALL){
      thrusters = [
        [p,0,p,0],
        [0,p,0,p]
      ]
    }
  }
  part = applyPart(part, thrusters, 0, 0);
  return applyPart(invader, part, 2, 6);
}

function randomMutator(invader, input){
  var p = {
    color: getColorString(input.moveCount, 0.5, 0.5, 0.5)
  };
  var mutation = [
    [0,0],
    [0,0]
  ];
  if(input.moveCount){
    var _ = (input.moveCount%2)? 0 : null; //50% chance to clear
    switch(input.moveCount%5){
      case 0:
        mutation = [
          [_,p],
          [_,p]
        ];
        break;
      case 1:
        mutation = [
          [_,_],
          [p,p]
        ];
        break;
      case 2:
        mutation = [
          [p,_],
          [_,p]
        ];
        break;
      case 3:
        mutation = [
          [_,p],
          [p,_]
        ];
        break;
      case 4:
        mutation = [
          [_,p],
          [p,p]
        ];
        break;
    }
  }
  // +4 offset ensures that it does not clear anything from the standard invader
  // if there was no input (clears between antennae)
  // The min call ensures that we don't override cells outside of the invader boundary
  var x = Math.min( (input.moveCount+4) % invader[0].length, invader[0].length-mutation[0].length );
  var y = Math.min( (input.moveCount*101) % invader.length, invader.length-mutation.length);
  return applyPart(invader, mutation, x, y);
}

function getColorString(moveCount, biasR, biasG, biasB){
  var n = 256-Math.min(PARAMS.MOVE_THRESHOLD,moveCount*PARAMS.MOVE_ADJUSTMENT_MULTIPLIER);
  var R = 1;
  var G = 1;
  var B = 1;
  if(biasR) R=biasR;
  if(biasG) G=biasG;
  if(biasB) B=biasB;
  //NB: non-integer values are not valid here!
  return 'rgb('+Math.floor(n*R)+','+Math.floor(n*G)+','+Math.floor(n*B)+')';
}

function applyPart(base, part, x, y){
  var invader = deepCopy(base);
  for(var i=0;i<part.length;i++){
    for(var j=0;j<part[i].length;j++){
      if(part[i][j] != null){ // null signals ignore, 0 signals overwrite with empty
        invader[y+i][x+j] = part[i][j];
      }
    }
  }
  return invader;
}

function drawInvader(context, x0, y0, invader){
  for(var y=0;y<invader.length;y++){
    var len = invader[y].length;
    //we're mirroring every column but the last
    for(var x=0;x<len*2-1;x++){
      var xPos = x>=len? x-(x-len+1)*2 : x;
      if(invader[y][xPos]){
        context.fillStyle = invader[y][xPos].color;
        context.fillRect(
          x0+x*PARAMS.PIXEL_SIZE,
          y0+y*PARAMS.PIXEL_SIZE,
          PARAMS.PIXEL_SIZE,
          PARAMS.PIXEL_SIZE
        );
      }
    }
  }
}<|endoftext|>


<commit_before>/*!
    Copyright (C) 2013 Google Inc., authors, and contributors <see AUTHORS file>
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
    Created By: brad@reciprocitylabs.com
    Maintained By: brad@reciprocitylabs.com
*/

(function(can, $) {
/*  RefreshQueue
 *
 *  enqueue(obj, force=false) -> queue or null
 *  trigger() -> Deferred
 */

can.Construct("ModelRefreshQueue", {
}, {
    init: function(model) {
      this.model = model;
      this.ids = [];
      this.deferred = new $.Deferred();
      this.triggered = false;
      this.completed = false;
      this.updated_at = Date.now();
    }

  , enqueue: function(id) {
      if (this.triggered)
        return null;
      else {
        if (this.ids.indexOf(id) === -1) {
          this.ids.push(id);
          this.updated_at = Date.now();
        }
        return this;
      }
    }

  , trigger: function() {
      var self = this;
      if (!this.triggered) {
        this.triggered = true;
        if (this.ids.length > 0)
          this.model.findAll({ id__in: this.ids.join(",") }).then(function() {
            self.completed = true;
            self.deferred.resolve();
          }, function() {
            self.deferred.reject.apply(self.deferred, arguments);
          });
        else {
          this.completed = true;
          this.deferred.resolve();
        }
      }
      return this.deferred;
    }

  , trigger_with_debounce: function(delay, manager) {
      var ms_to_wait = (delay || 0) + this.updated_at - Date.now();

      if (!this.triggered) {
        if (ms_to_wait < 0 && (!manager || manager.triggered_queues().length < 6))
          this.trigger();
        else
          setTimeout(this.proxy("trigger_with_debounce", delay, manager), ms_to_wait);
      }

      return this.deferred;
    }
});

can.Construct("RefreshQueueManager", {
    model_bases: {
      // This won't work until Relatable/Documentable/etc mixins can handle
      // queries with multiple `type` values.
      //  Regulation: 'Directive'
      //, Contract: 'Directive'
      //, Policy: 'Directive'
      //, Standard: 'Directive'
      //, System: 'SystemOrProcess'
      //, Process: 'SystemOrProcess'
    }
}, {
    init: function() {
      this.null_queue = new ModelRefreshQueue(null);
      this.queues = [];
    }

  , triggered_queues: function() {
      return can.map(this.queues, function(queue) {
        if (queue.triggered)
          return queue;
      });
    }

  , enqueue: function(obj, force) {
      var self = this
        , model = obj.constructor
        , model_name = model.shortName
        , found_queue = null
        , id = obj.id
        ;

      if (!obj.selfLink) {
        if (obj instanceof can.Model) {
          model_name = obj.constructor.shortName;
        } else if (obj.type) {
          // FIXME: obj.kind is to catch invalid stubs coming from Directives
          model_name = obj.type || obj.kind;
        }
      }
      model = CMS.Models[model_name];

      if (this.constructor.model_bases[model_name]) {
        model_name = this.constructor.model_bases[model_name];
        model = CMS.Models[model_name];
      }

      if (!force)
        // Check if the ID is already contained in another queue
        can.each(this.queues, function(queue) {
          if (!found_queue
              && queue.model === model && queue.ids.indexOf(id) > -1)
            found_queue = queue;
        });

      if (!found_queue) {
        can.each(this.queues, function(queue) {
          if (!found_queue && queue.model === model
              && !queue.triggered && queue.ids.length < 50) {
            found_queue = queue.enqueue(id);
            return false;
          }
        });
        if (!found_queue) {
          found_queue = new ModelRefreshQueue(model);
          this.queues.push(found_queue)
          found_queue.enqueue(id);
          found_queue.deferred.done(function() {
            var index = self.queues.indexOf(found_queue);
            if (index > -1)
              self.queues.splice(index, 1);
          });
        }
      }

      return found_queue;
    }
});

can.Construct("RefreshQueue", {
    refresh_queue_manager: new RefreshQueueManager(),
    refresh_all: function(instance, props, force) {
      var dfd = new $.Deferred();

      _refresh_all(instance, props, dfd);
      return dfd;

      // Helper function called recursively for each property
      function _refresh_all(instance, props, dfd) {
        var prop = props[0],
            next_props = props.slice(1),
            next = instance[prop],
            refresh_queue = new RefreshQueue(),
            dfds = [],
            deferred;

        if (next) {
          refresh_queue.enqueue(next, force);
          deferred = refresh_queue.trigger();
        } else if (instance.get_binding) {
          next = instance.get_binding(prop);
          if (next) {
            deferred = next.refresh_list();
          }
        }
        if (deferred) {
          deferred.then(function(refreshed_items) {
            if (next_props.length) {
              can.each(refreshed_items, function(item) {
                var d = new $.Deferred();
                _refresh_all(item, next_props, d);
                dfds.push(d);
              });
              // Resolve the original deferred only when all list deferreds
              //   have been resolved
              $.when.apply($, dfds).then(function() {
                dfd.resolve();
              });
              return;
            }
            // All items were refreshed, resolve the deferred
            if (next.push || next.list) {
              // Last refreshed property was a list
              dfd.resolve(refreshed_items);
            }
            // Last refreshed property was a single instance, return it as such
            dfd.resolve(refreshed_items[0]);
          });
        } else {
          console.warn("refresh_all failed at", prop);
        }
      }
    },
}, {
    init: function() {
      this.objects = [];
      this.queues = [];
      this.deferred = new $.Deferred();
      this.triggered = false;
      this.completed = false;
    }

  , enqueue: function(obj, force) {
      var that = this;
      if (!obj)
        return;
      if (this.triggered)
        return null;
      if (obj.push) {
        can.each(obj, function(o) {
          that.enqueue(o, force);
        });
        return this;
      }

      this.objects.push(obj);
      if (force || !obj.selfLink) {
        queue = this.constructor.refresh_queue_manager.enqueue(obj, force);
        if (this.queues.indexOf(queue) === -1)
          this.queues.push(queue);
      }
      return this;
    }

  , trigger: function(delay) {
      var self = this
        , deferreds = []
        ;

      if (!delay)
        delay = 50;

      this.triggered = true;
      can.each(this.queues, function(queue) {
        deferreds.push(queue.trigger_with_debounce(
            50, self.constructor.refresh_queue_manager));
      });

      if (deferreds.length > 0)
        $.when.apply($, deferreds).then(function() {
          self.deferred.resolve(can.map(self.objects, function(obj) {
            return obj.reify();
          }));
        }, function() {
          self.deferred.reject.apply(self.deferred, arguments);
        });
      else
        return this.deferred.resolve(this.objects);

      return this.deferred;
    }
});

})(window.can, window.can.$);
<commit_msg>Add missing resolve parameter to refresh_all<commit_after>/*!
    Copyright (C) 2013 Google Inc., authors, and contributors <see AUTHORS file>
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
    Created By: brad@reciprocitylabs.com
    Maintained By: brad@reciprocitylabs.com
*/

(function(can, $) {
/*  RefreshQueue
 *
 *  enqueue(obj, force=false) -> queue or null
 *  trigger() -> Deferred
 */

can.Construct("ModelRefreshQueue", {
}, {
    init: function(model) {
      this.model = model;
      this.ids = [];
      this.deferred = new $.Deferred();
      this.triggered = false;
      this.completed = false;
      this.updated_at = Date.now();
    }

  , enqueue: function(id) {
      if (this.triggered)
        return null;
      else {
        if (this.ids.indexOf(id) === -1) {
          this.ids.push(id);
          this.updated_at = Date.now();
        }
        return this;
      }
    }

  , trigger: function() {
      var self = this;
      if (!this.triggered) {
        this.triggered = true;
        if (this.ids.length > 0)
          this.model.findAll({ id__in: this.ids.join(",") }).then(function() {
            self.completed = true;
            self.deferred.resolve();
          }, function() {
            self.deferred.reject.apply(self.deferred, arguments);
          });
        else {
          this.completed = true;
          this.deferred.resolve();
        }
      }
      return this.deferred;
    }

  , trigger_with_debounce: function(delay, manager) {
      var ms_to_wait = (delay || 0) + this.updated_at - Date.now();

      if (!this.triggered) {
        if (ms_to_wait < 0 && (!manager || manager.triggered_queues().length < 6))
          this.trigger();
        else
          setTimeout(this.proxy("trigger_with_debounce", delay, manager), ms_to_wait);
      }

      return this.deferred;
    }
});

can.Construct("RefreshQueueManager", {
    model_bases: {
      // This won't work until Relatable/Documentable/etc mixins can handle
      // queries with multiple `type` values.
      //  Regulation: 'Directive'
      //, Contract: 'Directive'
      //, Policy: 'Directive'
      //, Standard: 'Directive'
      //, System: 'SystemOrProcess'
      //, Process: 'SystemOrProcess'
    }
}, {
    init: function() {
      this.null_queue = new ModelRefreshQueue(null);
      this.queues = [];
    }

  , triggered_queues: function() {
      return can.map(this.queues, function(queue) {
        if (queue.triggered)
          return queue;
      });
    }

  , enqueue: function(obj, force) {
      var self = this
        , model = obj.constructor
        , model_name = model.shortName
        , found_queue = null
        , id = obj.id
        ;

      if (!obj.selfLink) {
        if (obj instanceof can.Model) {
          model_name = obj.constructor.shortName;
        } else if (obj.type) {
          // FIXME: obj.kind is to catch invalid stubs coming from Directives
          model_name = obj.type || obj.kind;
        }
      }
      model = CMS.Models[model_name];

      if (this.constructor.model_bases[model_name]) {
        model_name = this.constructor.model_bases[model_name];
        model = CMS.Models[model_name];
      }

      if (!force)
        // Check if the ID is already contained in another queue
        can.each(this.queues, function(queue) {
          if (!found_queue
              && queue.model === model && queue.ids.indexOf(id) > -1)
            found_queue = queue;
        });

      if (!found_queue) {
        can.each(this.queues, function(queue) {
          if (!found_queue && queue.model === model
              && !queue.triggered && queue.ids.length < 50) {
            found_queue = queue.enqueue(id);
            return false;
          }
        });
        if (!found_queue) {
          found_queue = new ModelRefreshQueue(model);
          this.queues.push(found_queue)
          found_queue.enqueue(id);
          found_queue.deferred.done(function() {
            var index = self.queues.indexOf(found_queue);
            if (index > -1)
              self.queues.splice(index, 1);
          });
        }
      }

      return found_queue;
    }
});

can.Construct("RefreshQueue", {
    refresh_queue_manager: new RefreshQueueManager(),
    refresh_all: function(instance, props, force) {
      var dfd = new $.Deferred();

      _refresh_all(instance, props, dfd);
      return dfd;

      // Helper function called recursively for each property
      function _refresh_all(instance, props, dfd) {
        var prop = props[0],
            next_props = props.slice(1),
            next = instance[prop],
            refresh_queue = new RefreshQueue(),
            dfds = [],
            deferred;

        if (next) {
          refresh_queue.enqueue(next, force);
          deferred = refresh_queue.trigger();
        } else if (instance.get_binding) {
          next = instance.get_binding(prop);
          if (next) {
            deferred = next.refresh_list();
          }
        }
        if (deferred) {
          deferred.then(function(refreshed_items) {
            if (next_props.length) {
              can.each(refreshed_items, function(item) {
                var d = new $.Deferred();
                _refresh_all(item, next_props, d);
                dfds.push(d);
              });
              // Resolve the original deferred only when all list deferreds
              //   have been resolved
              $.when.apply($, dfds).then(function(items) {
                dfd.resolve(items);
              });
              return;
            }
            // All items were refreshed, resolve the deferred
            if (next.push || next.list) {
              // Last refreshed property was a list
              dfd.resolve(refreshed_items);
            }
            // Last refreshed property was a single instance, return it as such
            dfd.resolve(refreshed_items[0]);
          });
        } else {
          console.warn("refresh_all failed at", prop);
        }
      }
    },
}, {
    init: function() {
      this.objects = [];
      this.queues = [];
      this.deferred = new $.Deferred();
      this.triggered = false;
      this.completed = false;
    }

  , enqueue: function(obj, force) {
      var that = this;
      if (!obj)
        return;
      if (this.triggered)
        return null;
      if (obj.push) {
        can.each(obj, function(o) {
          that.enqueue(o, force);
        });
        return this;
      }

      this.objects.push(obj);
      if (force || !obj.selfLink) {
        queue = this.constructor.refresh_queue_manager.enqueue(obj, force);
        if (this.queues.indexOf(queue) === -1)
          this.queues.push(queue);
      }
      return this;
    }

  , trigger: function(delay) {
      var self = this
        , deferreds = []
        ;

      if (!delay)
        delay = 50;

      this.triggered = true;
      can.each(this.queues, function(queue) {
        deferreds.push(queue.trigger_with_debounce(
            50, self.constructor.refresh_queue_manager));
      });

      if (deferreds.length > 0)
        $.when.apply($, deferreds).then(function() {
          self.deferred.resolve(can.map(self.objects, function(obj) {
            return obj.reify();
          }));
        }, function() {
          self.deferred.reject.apply(self.deferred, arguments);
        });
      else
        return this.deferred.resolve(this.objects);

      return this.deferred;
    }
});

})(window.can, window.can.$);
<|endoftext|>