<commit_before>'use strict';

require('./km.css');
var _ = require('./underscore_ext');
var React = require('react');
var { PropTypes } = React;
var Modal = require('react-bootstrap/lib/Modal');
import {Button} from 'react-toolbox/lib/button';
var Axis = require('./Axis');
var {deepPureRenderMixin} = require('./react-utils');
var {linear, linearTicks} = require('./scale');
var pdf = require('./kmpdf');
var NumberForm = require('./views/NumberForm');

// Basic sizes. Should make these responsive. How to make the svg responsive?
var margin = {top: 20, right: 30, bottom: 30, left: 50};
const HOVER = 'hover';

// XXX point at 100%? [xdomain[0] - 1, 1]
function line(xScale, yScale, values) {
	var coords = values.map(({t, s}) => [xScale(t), yScale(s)]);
	return ['M0,0', ...coords.map(([t, s]) => `H${t}V${s}`)].join(' ');
}

function censorLines(xScale, yScale, censors, className) {
	return censors.map(({t, s}, i) =>
		<line
			key={i}
			className={className}
			x1={0} x2={0} y1={-5} y2={5}
			transform={`translate(${xScale(t)},${yScale(s)})`} />
	);
}

function calcDims (viewDims, sizeRatios) {
	return _.mapObject(sizeRatios, (section) => {
		return _.mapObject(section, (ratio, side) => viewDims[side] * ratio);
	});
}

function checkIfActive(currentLabel, activeLabel) {
	// check whether this line group should be set to Active
	return !!activeLabel && (activeLabel === currentLabel);
}

var LineGroup = React.createClass({
	shouldComponentUpdate: function(newProps) {
		return !_.isEqual(_.omit(newProps, 'xScale', 'yScale'), _.omit(this.props, 'xScale', 'yScale'));
	},

	render: function() {
		let {xScale, yScale, g, setActiveLabel, isActive} = this.props;
		let [color, label, curve] = g;
		var censors = curve.filter(pt => !pt.e);
		let activeLabelClassName = isActive ? HOVER : '';

		return (
			<g key={label} className='subgroup' stroke={color}
				onMouseOver={(e) => setActiveLabel(e, label)}
				onMouseOut={(e) => setActiveLabel(e, '')}>
				<path className={`outline ${activeLabelClassName}`} d={line(xScale, yScale, curve)}/>
				<path className={`line ${activeLabelClassName}`} d={line(xScale, yScale, curve)}/>
				{censorLines(xScale, yScale, censors, `outline ${activeLabelClassName}`)}
				{censorLines(xScale, yScale, censors, `line' ${activeLabelClassName}`)}
			</g>
		);
	}
});

var bounds = x => [_.min(x), _.max(x)];

function svg({colors, labels, curves}, setActiveLabel, activeLabel, size) {
	var height = size.height - margin.top - margin.bottom,
		width = size.width - margin.left - margin.right,
		xdomain = bounds(_.pluck(_.flatten(curves), 't')),
		xrange = [0, width],
		ydomain = [0, 1],
		yrange = [height, 0],
		xScale = linear(xdomain, xrange),
		yScale = linear(ydomain, yrange);

	var groupSvg = _.zip(colors, labels, curves).map((g, index) => {
		let [, label] = g;
		// passing bounds to force update when scales change
		return (<LineGroup
				key={index}
				bounds={[xdomain, xrange, ydomain, yrange]}
				xScale={xScale}
				yScale={yScale}
				g={g}
				isActive={label === activeLabel}
				setActiveLabel={setActiveLabel} />);
	});

	return (
		<svg width={size.width} height={size.height}>
			<g transform={`translate(${margin.left}, ${margin.top})`}>
				<Axis
					groupProps={{
						className: 'x axis',
						transform: `translate(0, ${height})`
					}}
					domain={xdomain}
					range={xrange}
					scale={xScale}
					tickfn={linearTicks}
					orientation='bottom'
				/>
				<Axis
					groupProps={{
						className: 'y axis'
					}}
					domain={ydomain}
					range={yrange}
					scale={yScale}
					tickfn={linearTicks}
					orientation='left'>

					<text
						transform='rotate(-90)'
						y='6'
						x={-height}
						dy='.71em'
						textAnchor='start'>
						Survival probability
					</text>
				</Axis>
				{groupSvg}
			</g>
		</svg>
	);
}

var formatPValue = v => v == null ? String.fromCharCode(8709) : v.toPrecision(4);

var WarningTrigger = React.createClass({
	getInitialState() {
		return { show: false };
	},

	render() {
		let close = () => this.setState({ show: false});
		let {header, body} = this.props;
		return (

				<Button
					onClick = {() => this.setState({ show: true})}
				 >

				</Button>

				<Modal
					show={this.state.show}
					onHide={close}
					container={this}
					aria-labelledby="contained-modal-title"
				>
					<Modal.Header closeButton>
						<Modal.Title id="contained-modal-title">{header}</Modal.Title>
					</Modal.Header>
					<Modal.Body>
						{body}
					</Modal.Body>
					<Modal.Footer>
						<Button onClick={close}>Close</Button>
					</Modal.Footer>
				</Modal>

		);
	}
});

var PValue = React.createClass({
	mixins: [deepPureRenderMixin],
	render: function () {
		var {logRank, pValue, patientWarning} = this.props;
		return (

					P-value = {formatPValue(pValue)}
					{' '}
					{patientWarning ?
						<WarningTrigger
							header="P value warning"
							body={patientWarning}
						/> : null}

					Log-rank test statistics = {formatPValue(logRank)}

		);
	}
});

// Sample count is 'n' at 1st time point.
function sampleCount(curve) {
	return _.getIn(curve, [0, 'n'], String.fromCharCode(8709));
}

function makeLegendKey([color, curves, label], setActiveLabel, activeLabel) {
	// show colored line and category of curve
	let isActive = checkIfActive(label, activeLabel);
	let activeLabelClassName = isActive ? 'grey' : '';
	let legendLineStyle = {
		backgroundColor: color,
		border: (isActive ? 2 : 1).toString() + 'px solid',
		display: 'inline-block',
		height: 6,
		width: 25,
		verticalAlign: 'middle'
	};

	return (
		<li
			key={label}
			className={`list-group-item ${activeLabelClassName}`}
			onMouseOver={(e) => setActiveLabel(e, label)}
			onMouseOut={(e) => setActiveLabel(e, '')}>
			 {label} (n={sampleCount(curves)})

	);
}

var Legend = React.createClass({
	mixins: [deepPureRenderMixin],
	propTypes: {
		activeLabel: PropTypes.string,
		columns: PropTypes.number,
		groups: PropTypes.object,
		setActiveLabel: PropTypes.func
	},

	render: function () {
		let { groups, setActiveLabel, activeLabel } = this.props;
		let { colors, curves, labels } = groups;
		let sets = _.zip(colors, curves, labels)
					.map(set => makeLegendKey(set, setActiveLabel, activeLabel));

		return (

{sets}

		);
	}
});

function makeGraph(groups, setActiveLabel, activeLabel, size) {
	return (

			{svg(groups, setActiveLabel, activeLabel, size)}

	);
}

function makeSplits(splits, onSplits) {
	return (
		<form className='form-horizonal'>

					<input value={2} type="radio" name="splits" checked={splits === 2} onChange={onSplits}/>2 groups

					<input value={3} type="radio" name="splits" checked={splits === 3} onChange={onSplits}/>3 groups

		</form>);
}

function makeDefinitions(groups, setActiveLabel, activeLabel, size, maySplit, splits, onSplits) {
	// get new size based on size ratio for definitions column

	return (

			<PValue pValue={groups.pValue} logRank={groups.KM_stats}
				patientWarning={groups.patientWarning}/>

			{maySplit ? makeSplits(splits, onSplits) : null}

			<Legend groups={groups}
					setActiveLabel={setActiveLabel}
					activeLabel={activeLabel} />

	);
}

var KmPlot = React.createClass({
	mixins: [deepPureRenderMixin],
	propTypes: {
		eventClose: PropTypes.string,
		dims: PropTypes.object
	},
	size: {
		ratios: {
			graph: {
				width: 0.75,
				height: 1.0
			},
			definitions: {
				width: 0.4,
				height: 1.0
			}
		}
	},

	getDefaultProps: () => ({
		eventClose: 'km-close',
		dims: {
			height: 450,
			width: 700
		}
	}),

	getInitialState: function() {
		return { activeLabel: '' };
	},

	hide: function () {
		let {callback, eventClose} = this.props;
		callback([eventClose]);
	},

	// cutoff needs to rewrite the group calc, but we need
	// the full range in order to range-check the bound. So
	// the compute should stash the domain.
	onCutoff: function (v) {
		let {callback} = this.props;
		callback(['km-cutoff', v]);
	},

	setActiveLabel: function (e, label) {
		this.setState({ activeLabel: label });
	},

	pdf: function () {
		pdf(this.props.km.groups);
	},

	onSplits(ev) {
		var {callback} = this.props;
		callback(['km-splits', parseInt(ev.target.value, 10)]);
	},

	render: function () {
		let {km: {splits = 2, title, label, groups, cutoff}, dims} = this.props,
			// groups may be undefined if data hasn't loaded yet.
			maySplit = _.get(groups, 'maySplit', false),
			min = _.getIn(groups, ['domain', 0]),
			max = _.getIn(groups, ['domain', 1]),
			warning = _.get(groups, 'warning'),
			fullLabel = warning ? `${label} (${warning})` : label,
			{activeLabel} = this.state,
			sectionDims = calcDims(dims, this.size.ratios);

		let Content = _.isEmpty(groups)
			?

Loading...

			: (_.isEmpty(groups.colors)
				?

Unfortunately, KM plot can not be made. There is no survival data overlapping column data.

				:

					<Button onClick={this.pdf}>PDF</Button>
					help with KM
					{makeGraph(groups, this.setActiveLabel, activeLabel, sectionDims.graph)}
					{makeDefinitions(groups, this.setActiveLabel, activeLabel, sectionDims.definitions, maySplit, splits, this.onSplits)}

						<NumberForm
							labelClassName="col-md-4"
							wrapperClassName="col-md-3"
							onChange={this.onCutoff}
							dflt={max}
							min={min}
							max={max}
							initialValue={cutoff}/>

			);

		return (

				<Modal autoFocus={false} enforceFocus={false} container={this} show={true} bsSize='large' className='kmDialog' onHide={this.hide} ref="kmPlot">
					<Modal.Header closeButton className="container-fluid">

							<Modal.Title>Kaplan Meier</Modal.Title>

						{title}
					</Modal.Header>
					<Modal.Body className="container-fluid">
						{Content}
					</Modal.Body>
					<Modal.Footer className="container-fluid">
						<samp className='featureLabel'>{fullLabel}</samp>
					</Modal.Footer>
				</Modal>

		);
	}
});

module.exports = KmPlot;
<commit_msg>Fix KmPlot export.<commit_after>'use strict';

require('./km.css');
var _ = require('./underscore_ext');
var React = require('react');
var { PropTypes } = React;
var Modal = require('react-bootstrap/lib/Modal');
import {Button} from 'react-toolbox/lib/button';
var Axis = require('./Axis');
var {deepPureRenderMixin} = require('./react-utils');
var {linear, linearTicks} = require('./scale');
var pdf = require('./kmpdf');
var NumberForm = require('./views/NumberForm');

// Basic sizes. Should make these responsive. How to make the svg responsive?
var margin = {top: 20, right: 30, bottom: 30, left: 50};
const HOVER = 'hover';

// XXX point at 100%? [xdomain[0] - 1, 1]
function line(xScale, yScale, values) {
	var coords = values.map(({t, s}) => [xScale(t), yScale(s)]);
	return ['M0,0', ...coords.map(([t, s]) => `H${t}V${s}`)].join(' ');
}

function censorLines(xScale, yScale, censors, className) {
	return censors.map(({t, s}, i) =>
		<line
			key={i}
			className={className}
			x1={0} x2={0} y1={-5} y2={5}
			transform={`translate(${xScale(t)},${yScale(s)})`} />
	);
}

function calcDims (viewDims, sizeRatios) {
	return _.mapObject(sizeRatios, (section) => {
		return _.mapObject(section, (ratio, side) => viewDims[side] * ratio);
	});
}

function checkIfActive(currentLabel, activeLabel) {
	// check whether this line group should be set to Active
	return !!activeLabel && (activeLabel === currentLabel);
}

var LineGroup = React.createClass({
	shouldComponentUpdate: function(newProps) {
		return !_.isEqual(_.omit(newProps, 'xScale', 'yScale'), _.omit(this.props, 'xScale', 'yScale'));
	},

	render: function() {
		let {xScale, yScale, g, setActiveLabel, isActive} = this.props;
		let [color, label, curve] = g;
		var censors = curve.filter(pt => !pt.e);
		let activeLabelClassName = isActive ? HOVER : '';

		return (
			<g key={label} className='subgroup' stroke={color}
				onMouseOver={(e) => setActiveLabel(e, label)}
				onMouseOut={(e) => setActiveLabel(e, '')}>
				<path className={`outline ${activeLabelClassName}`} d={line(xScale, yScale, curve)}/>
				<path className={`line ${activeLabelClassName}`} d={line(xScale, yScale, curve)}/>
				{censorLines(xScale, yScale, censors, `outline ${activeLabelClassName}`)}
				{censorLines(xScale, yScale, censors, `line' ${activeLabelClassName}`)}
			</g>
		);
	}
});

var bounds = x => [_.min(x), _.max(x)];

function svg({colors, labels, curves}, setActiveLabel, activeLabel, size) {
	var height = size.height - margin.top - margin.bottom,
		width = size.width - margin.left - margin.right,
		xdomain = bounds(_.pluck(_.flatten(curves), 't')),
		xrange = [0, width],
		ydomain = [0, 1],
		yrange = [height, 0],
		xScale = linear(xdomain, xrange),
		yScale = linear(ydomain, yrange);

	var groupSvg = _.zip(colors, labels, curves).map((g, index) => {
		let [, label] = g;
		// passing bounds to force update when scales change
		return (<LineGroup
				key={index}
				bounds={[xdomain, xrange, ydomain, yrange]}
				xScale={xScale}
				yScale={yScale}
				g={g}
				isActive={label === activeLabel}
				setActiveLabel={setActiveLabel} />);
	});

	return (
		<svg width={size.width} height={size.height}>
			<g transform={`translate(${margin.left}, ${margin.top})`}>
				<Axis
					groupProps={{
						className: 'x axis',
						transform: `translate(0, ${height})`
					}}
					domain={xdomain}
					range={xrange}
					scale={xScale}
					tickfn={linearTicks}
					orientation='bottom'
				/>
				<Axis
					groupProps={{
						className: 'y axis'
					}}
					domain={ydomain}
					range={yrange}
					scale={yScale}
					tickfn={linearTicks}
					orientation='left'>

					<text
						transform='rotate(-90)'
						y='6'
						x={-height}
						dy='.71em'
						textAnchor='start'>
						Survival probability
					</text>
				</Axis>
				{groupSvg}
			</g>
		</svg>
	);
}

var formatPValue = v => v == null ? String.fromCharCode(8709) : v.toPrecision(4);

var WarningTrigger = React.createClass({
	getInitialState() {
		return { show: false };
	},

	render() {
		let close = () => this.setState({ show: false});
		let {header, body} = this.props;
		return (

				<Button
					onClick = {() => this.setState({ show: true})}
				 >

				</Button>

				<Modal
					show={this.state.show}
					onHide={close}
					container={this}
					aria-labelledby="contained-modal-title"
				>
					<Modal.Header closeButton>
						<Modal.Title id="contained-modal-title">{header}</Modal.Title>
					</Modal.Header>
					<Modal.Body>
						{body}
					</Modal.Body>
					<Modal.Footer>
						<Button onClick={close}>Close</Button>
					</Modal.Footer>
				</Modal>

		);
	}
});

var PValue = React.createClass({
	mixins: [deepPureRenderMixin],
	render: function () {
		var {logRank, pValue, patientWarning} = this.props;
		return (

					P-value = {formatPValue(pValue)}
					{' '}
					{patientWarning ?
						<WarningTrigger
							header="P value warning"
							body={patientWarning}
						/> : null}

					Log-rank test statistics = {formatPValue(logRank)}

		);
	}
});

// Sample count is 'n' at 1st time point.
function sampleCount(curve) {
	return _.getIn(curve, [0, 'n'], String.fromCharCode(8709));
}

function makeLegendKey([color, curves, label], setActiveLabel, activeLabel) {
	// show colored line and category of curve
	let isActive = checkIfActive(label, activeLabel);
	let activeLabelClassName = isActive ? 'grey' : '';
	let legendLineStyle = {
		backgroundColor: color,
		border: (isActive ? 2 : 1).toString() + 'px solid',
		display: 'inline-block',
		height: 6,
		width: 25,
		verticalAlign: 'middle'
	};

	return (
		<li
			key={label}
			className={`list-group-item ${activeLabelClassName}`}
			onMouseOver={(e) => setActiveLabel(e, label)}
			onMouseOut={(e) => setActiveLabel(e, '')}>
			 {label} (n={sampleCount(curves)})

	);
}

var Legend = React.createClass({
	mixins: [deepPureRenderMixin],
	propTypes: {
		activeLabel: PropTypes.string,
		columns: PropTypes.number,
		groups: PropTypes.object,
		setActiveLabel: PropTypes.func
	},

	render: function () {
		let { groups, setActiveLabel, activeLabel } = this.props;
		let { colors, curves, labels } = groups;
		let sets = _.zip(colors, curves, labels)
					.map(set => makeLegendKey(set, setActiveLabel, activeLabel));

		return (

{sets}

		);
	}
});

function makeGraph(groups, setActiveLabel, activeLabel, size) {
	return (

			{svg(groups, setActiveLabel, activeLabel, size)}

	);
}

function makeSplits(splits, onSplits) {
	return (
		<form className='form-horizonal'>

					<input value={2} type="radio" name="splits" checked={splits === 2} onChange={onSplits}/>2 groups

					<input value={3} type="radio" name="splits" checked={splits === 3} onChange={onSplits}/>3 groups

		</form>);
}

function makeDefinitions(groups, setActiveLabel, activeLabel, size, maySplit, splits, onSplits) {
	// get new size based on size ratio for definitions column

	return (

			<PValue pValue={groups.pValue} logRank={groups.KM_stats}
				patientWarning={groups.patientWarning}/>

			{maySplit ? makeSplits(splits, onSplits) : null}

			<Legend groups={groups}
					setActiveLabel={setActiveLabel}
					activeLabel={activeLabel} />

	);
}

var KmPlot = React.createClass({
	mixins: [deepPureRenderMixin],
	propTypes: {
		eventClose: PropTypes.string,
		dims: PropTypes.object
	},
	size: {
		ratios: {
			graph: {
				width: 0.75,
				height: 1.0
			},
			definitions: {
				width: 0.4,
				height: 1.0
			}
		}
	},

	getDefaultProps: () => ({
		eventClose: 'km-close',
		dims: {
			height: 450,
			width: 700
		}
	}),

	getInitialState: function() {
		return { activeLabel: '' };
	},

	hide: function () {
		let {callback, eventClose} = this.props;
		callback([eventClose]);
	},

	// cutoff needs to rewrite the group calc, but we need
	// the full range in order to range-check the bound. So
	// the compute should stash the domain.
	onCutoff: function (v) {
		let {callback} = this.props;
		callback(['km-cutoff', v]);
	},

	setActiveLabel: function (e, label) {
		this.setState({ activeLabel: label });
	},

	pdf: function () {
		pdf(this.props.km.groups);
	},

	onSplits(ev) {
		var {callback} = this.props;
		callback(['km-splits', parseInt(ev.target.value, 10)]);
	},

	render: function () {
		let {km: {splits = 2, title, label, groups, cutoff}, dims} = this.props,
			// groups may be undefined if data hasn't loaded yet.
			maySplit = _.get(groups, 'maySplit', false),
			min = _.getIn(groups, ['domain', 0]),
			max = _.getIn(groups, ['domain', 1]),
			warning = _.get(groups, 'warning'),
			fullLabel = warning ? `${label} (${warning})` : label,
			{activeLabel} = this.state,
			sectionDims = calcDims(dims, this.size.ratios);

		let Content = _.isEmpty(groups)
			?

Loading...

			: (_.isEmpty(groups.colors)
				?

Unfortunately, KM plot can not be made. There is no survival data overlapping column data.

				:

					<Button onClick={this.pdf}>PDF</Button>
					help with KM
					{makeGraph(groups, this.setActiveLabel, activeLabel, sectionDims.graph)}
					{makeDefinitions(groups, this.setActiveLabel, activeLabel, sectionDims.definitions, maySplit, splits, this.onSplits)}

						<NumberForm
							labelClassName="col-md-4"
							wrapperClassName="col-md-3"
							onChange={this.onCutoff}
							dflt={max}
							min={min}
							max={max}
							initialValue={cutoff}/>

			);

		return (

				<Modal autoFocus={false} enforceFocus={false} container={this} show={true} bsSize='large' className='kmDialog' onHide={this.hide} ref="kmPlot">
					<Modal.Header closeButton className="container-fluid">

							<Modal.Title>Kaplan Meier</Modal.Title>

						{title}
					</Modal.Header>
					<Modal.Body className="container-fluid">
						{Content}
					</Modal.Body>
					<Modal.Footer className="container-fluid">
						<samp className='featureLabel'>{fullLabel}</samp>
					</Modal.Footer>
				</Modal>

		);
	}
});

module.exports = {KmPlot};
<|endoftext|>


<commit_before>module.exports = {
    server: {
        options: {
            index: 'main.js'
        }
    }
}
<commit_msg>Suppression de la tache forever<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-iotagent-lib
 *
 * fiware-iotagent-lib is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * fiware-iotagent-lib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with fiware-iotagent-lib.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 *
 * Modified by: Federico M. Facca - Martel Innovate
 * Modified by: Daniel Calvo - ATOS Research & Innovation
 */

'use strict';

var request = require('request'),
    errors = require('../../errors'),
    logger = require('logops'),
    _ = require('underscore'),
    intoTrans = require('../common/domain').intoTrans,
    config = require('../../commonConfig'),
    ngsiParser = require('./../ngsi/ngsiParser'),
    context = {
        op: 'IoTAgentNGSI.DeviceService'
    };

/**
 * Generates a handler for the registration requests that checks all the possible errors derived from the registration.
 * The parameter information is needed in order to fulfill error information.
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 * @return {Function}              The generated handler.
 */
function createRegistrationHandler(unregister, deviceData, callback) {
    return function handleRegistrationResponse(error, response, body) {
        if (error) {
            logger.error(context, 'ORION-002: Connection error sending registrations to the Context Broker: %s', error);
            callback(error);
        } else if (response && body && response.statusCode === 200) {
            var errorField = ngsiParser.getErrorField(body);

            if (errorField) {
                logger.error(context, 'Registration error connecting to the Context Broker: %j', errorField);
                callback(new errors.BadRequest(JSON.stringify(errorField)));
            } else {
                logger.debug(context, 'Registration success.');
                callback(null, body);
            }
        } else {
            var errorObj;

            logger.error(context, 'ORION-003: Protocol error connecting to the Context Broker: %j', errorObj);

            if (unregister) {
                errorObj = new errors.UnregistrationError(deviceData.id, deviceData.type);
            } else {
                errorObj = new errors.RegistrationError(deviceData.id, deviceData.type);
            }

            callback(errorObj);
        }
    };
}

/**
 * Generates a handler for the registration requests that checks all the possible errors derived from the registration.
 * The parameter information is needed in order to fulfill error information.
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 * @return {Function}              The generated handler.
 */
function createRegistrationHandlerNgsi2(unregister, deviceData, callback) {
    return function handleRegistrationResponse(error, response, body) {
        if (error) {
            logger.error(context, 'ORION-002: Connection error sending registrations to the Context Broker: %s', error);
            callback(error);
        } else if (response && response.statusCode === 201 && response.headers.location && unregister === false) {
            logger.debug(context, 'Registration success.');
            callback(null, {registrationId:
                response.headers.location.substr(response.headers.location.lastIndexOf('/') + 1)});
        } else if (response && response.statusCode === 204 && unregister === true) {
            logger.debug(context, 'Unregistration success.');
            callback(null, null);
        }
        else if (response && response.statusCode && response.statusCode !== 500) {
            logger.error(context, 'Registration error connecting to the Context Broker: %j', response.statusCode);
            callback(new errors.BadRequest(JSON.stringify(response.statusCode)));
        }
        else {
            var errorObj;

            logger.error(context, 'ORION-003: Protocol error connecting to the Context Broker: %j', errorObj);

            if (unregister) {
                errorObj = new errors.UnregistrationError(deviceData.id, deviceData.type);
            } else {
                errorObj = new errors.RegistrationError(deviceData.id, deviceData.type);
            }

            callback(errorObj);
        }
    };
}

/**
 * Sends a Context Provider registration or unregistration request to the Context Broker using NGSIv1.
 * As registrations cannot be removed, an unregistration consists of an update of the existent registration
 * to make reduce its duration to 1 second.
 *
 * The entity type, entity name and lazy attributes list are needed in order to send the registration:
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendRegistrationsNgsi1(unregister, deviceData, callback) {
    var options = {
        url: config.getConfig().contextBroker.url + '/NGSI9/registerContext',
        method: 'POST',
        json: {
            contextRegistrations: [
                {
                    entities: [
                        {
                            type: deviceData.type,
                            isPattern: 'false',
                            id: String(deviceData.name)
                        }
                    ],
                    attributes: [],
                    providingApplication: config.getConfig().providerUrl
                }
            ],
            duration: (unregister) ? 'PT1S' : config.getConfig().deviceRegistrationDuration
        },
        headers: {
            'fiware-service': deviceData.service,
            'fiware-servicepath': deviceData.subservice
        }
    };

    function formatAttributes(originalVector) {
        var attributeList = [];

        if (originalVector && originalVector.length) {
            for (var i = 0; i < originalVector.length; i++) {
                attributeList.push({
                    name: originalVector[i].name,
                    type: originalVector[i].type,
                    isDomain: 'false'
                });
            }
        }

        return attributeList;
    }

    function mergeWithSameName(old, current) {
        var keys = _.pluck(old, 'name');

        if (keys.indexOf(current.name) < 0) {
            old.push(current);
        }

        return old;
    }

    if (deviceData.registrationId) {
        options.json.registrationId = deviceData.registrationId;
    }

    options.json.contextRegistrations[0].attributes = options.json.contextRegistrations[0].attributes.concat(
            formatAttributes(deviceData.lazy),
            formatAttributes(deviceData.commands)
        ).reduce(mergeWithSameName, []);

    if (options.json.contextRegistrations[0].attributes.length === 0) {
        logger.debug(context, 'No Context Provider registrations found for unregister');
        callback(null, deviceData);
    } else {
        logger.debug(context, 'Sending device registrations to Context Broker at [%s]', options.url);
        logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

        request(options, createRegistrationHandler(unregister, deviceData, callback));
    }
}

/**
 * Sends a Context Provider unregistration request to the Context Broker using NGSIv2.
 *
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendUnregistrationsNgsi2(deviceData, callback) {
    var options = {
        url: config.getConfig().contextBroker.url + '/v2/registrations/' + deviceData.registrationId,
        method: 'DELETE',
        json: true,
        headers: {
            'fiware-service': deviceData.service,
            'fiware-servicepath': deviceData.subservice
        }
    };

    logger.debug(context, 'Sending device unregistrations to Context Broker at [%s]', options.url);
    logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

    request(options, createRegistrationHandlerNgsi2(true, deviceData, callback));
}

/**
 * Sends a Context Provider registration or unregistration request to the Context Broker using NGSIv2.
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendRegistrationsNgsi2(unregister, deviceData, callback) {
    var options = {
        url: config.getConfig().contextBroker.url + '/v2/registrations',
        method: 'POST',
        json: {
            dataProvided: {
                entities:
                [
                    {
                        type: deviceData.type,
                        id: String(deviceData.name)
                    }
                ],
                attrs: [],
            },
            provider: {
                http: {
                    url: config.getConfig().providerUrl
                },
                legacyForwarding: true
            }
        },
        headers: {
            'fiware-service': deviceData.service,
            'fiware-servicepath': deviceData.subservice
        }
    };

    function formatAttributes(originalVector) {
        var attributeList = [];

        if (originalVector && originalVector.length) {
            for (var i = 0; i < originalVector.length; i++) {
                attributeList.push(originalVector[i].name);
            }
        }

        return attributeList;
    }

    function mergeWithSameName(old, current) {
        if (old.indexOf(current) < 0) {
            old.push(current);
        }

        return old;
    }

    if (unregister) {
        sendUnregistrationsNgsi2(deviceData, callback);
    } else {
        options.json.dataProvided.attrs = options.json.dataProvided.attrs.concat(
                formatAttributes(deviceData.lazy),
                formatAttributes(deviceData.commands)
            ).reduce(mergeWithSameName, []);

        if (options.json.dataProvided.attrs.length === 0) {
            logger.debug(context, 'No Context Provider registrations found for unregister');
            callback(null, deviceData);
        } else {
            logger.debug(context, 'Sending device registrations to Context Broker at [%s]', options.url);
            logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

            request(options, createRegistrationHandlerNgsi2(unregister, deviceData, callback));
        }
    }
}

/**
 * Sends a Context Provider registration or unregistration request to the Context Broker. As registrations cannot be
 * removed, an unregistration consists of an update of the existent registration to make reduce its duration to
 * 1 second.
 *
 * The entity type, entity name and lazy attributes list are needed in order to send the registration:
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendRegistrations(unregister, deviceData, callback) {
    if (config.checkNgsi2()) {
        sendRegistrationsNgsi2(unregister, deviceData, callback);
    } else {
        sendRegistrationsNgsi1(unregister, deviceData, callback);
    }
}

exports.sendRegistrations = intoTrans(context, sendRegistrations);
exports.createRegistrationHandler = intoTrans(context, createRegistrationHandler);
<commit_msg>NGSIv2 device provisioning considers expires attribute<commit_after>/*
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-iotagent-lib
 *
 * fiware-iotagent-lib is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * fiware-iotagent-lib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with fiware-iotagent-lib.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 *
 * Modified by: Federico M. Facca - Martel Innovate
 * Modified by: Daniel Calvo - ATOS Research & Innovation
 */

'use strict';

var request = require('request'),
    errors = require('../../errors'),
    logger = require('logops'),
    _ = require('underscore'),
    intoTrans = require('../common/domain').intoTrans,
    config = require('../../commonConfig'),
    ngsiParser = require('./../ngsi/ngsiParser'),
    context = {
        op: 'IoTAgentNGSI.DeviceService'
    },
    moment = require('moment');

/**
 * Generates a handler for the registration requests that checks all the possible errors derived from the registration.
 * The parameter information is needed in order to fulfill error information.
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 * @return {Function}              The generated handler.
 */
function createRegistrationHandler(unregister, deviceData, callback) {
    return function handleRegistrationResponse(error, response, body) {
        if (error) {
            logger.error(context, 'ORION-002: Connection error sending registrations to the Context Broker: %s', error);
            callback(error);
        } else if (response && body && response.statusCode === 200) {
            var errorField = ngsiParser.getErrorField(body);

            if (errorField) {
                logger.error(context, 'Registration error connecting to the Context Broker: %j', errorField);
                callback(new errors.BadRequest(JSON.stringify(errorField)));
            } else {
                logger.debug(context, 'Registration success.');
                callback(null, body);
            }
        } else {
            var errorObj;

            logger.error(context, 'ORION-003: Protocol error connecting to the Context Broker: %j', errorObj);

            if (unregister) {
                errorObj = new errors.UnregistrationError(deviceData.id, deviceData.type);
            } else {
                errorObj = new errors.RegistrationError(deviceData.id, deviceData.type);
            }

            callback(errorObj);
        }
    };
}

/**
 * Generates a handler for the registration requests that checks all the possible errors derived from the registration.
 * The parameter information is needed in order to fulfill error information.
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 * @return {Function}              The generated handler.
 */
function createRegistrationHandlerNgsi2(unregister, deviceData, callback) {
    return function handleRegistrationResponse(error, response, body) {
        if (error) {
            logger.error(context, 'ORION-002: Connection error sending registrations to the Context Broker: %s', error);
            callback(error);
        } else if (response && response.statusCode === 201 && response.headers.location && unregister === false) {
            logger.debug(context, 'Registration success.');
            callback(null, {registrationId:
                response.headers.location.substr(response.headers.location.lastIndexOf('/') + 1)});
        } else if (response && response.statusCode === 204 && unregister === true) {
            logger.debug(context, 'Unregistration success.');
            callback(null, null);
        }
        else if (response && response.statusCode && response.statusCode !== 500) {
            logger.error(context, 'Registration error connecting to the Context Broker: %j', response.statusCode);
            callback(new errors.BadRequest(JSON.stringify(response.statusCode)));
        }
        else {
            var errorObj;

            logger.error(context, 'ORION-003: Protocol error connecting to the Context Broker: %j', errorObj);

            if (unregister) {
                errorObj = new errors.UnregistrationError(deviceData.id, deviceData.type);
            } else {
                errorObj = new errors.RegistrationError(deviceData.id, deviceData.type);
            }

            callback(errorObj);
        }
    };
}

/**
 * Sends a Context Provider registration or unregistration request to the Context Broker using NGSIv1.
 * As registrations cannot be removed, an unregistration consists of an update of the existent registration
 * to make reduce its duration to 1 second.
 *
 * The entity type, entity name and lazy attributes list are needed in order to send the registration:
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendRegistrationsNgsi1(unregister, deviceData, callback) {
    var options = {
        url: config.getConfig().contextBroker.url + '/NGSI9/registerContext',
        method: 'POST',
        json: {
            contextRegistrations: [
                {
                    entities: [
                        {
                            type: deviceData.type,
                            isPattern: 'false',
                            id: String(deviceData.name)
                        }
                    ],
                    attributes: [],
                    providingApplication: config.getConfig().providerUrl
                }
            ],
            duration: (unregister) ? 'PT1S' : config.getConfig().deviceRegistrationDuration
        },
        headers: {
            'fiware-service': deviceData.service,
            'fiware-servicepath': deviceData.subservice
        }
    };

    function formatAttributes(originalVector) {
        var attributeList = [];

        if (originalVector && originalVector.length) {
            for (var i = 0; i < originalVector.length; i++) {
                attributeList.push({
                    name: originalVector[i].name,
                    type: originalVector[i].type,
                    isDomain: 'false'
                });
            }
        }

        return attributeList;
    }

    function mergeWithSameName(old, current) {
        var keys = _.pluck(old, 'name');

        if (keys.indexOf(current.name) < 0) {
            old.push(current);
        }

        return old;
    }

    if (deviceData.registrationId) {
        options.json.registrationId = deviceData.registrationId;
    }

    options.json.contextRegistrations[0].attributes = options.json.contextRegistrations[0].attributes.concat(
            formatAttributes(deviceData.lazy),
            formatAttributes(deviceData.commands)
        ).reduce(mergeWithSameName, []);

    if (options.json.contextRegistrations[0].attributes.length === 0) {
        logger.debug(context, 'No Context Provider registrations found for unregister');
        callback(null, deviceData);
    } else {
        logger.debug(context, 'Sending device registrations to Context Broker at [%s]', options.url);
        logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

        request(options, createRegistrationHandler(unregister, deviceData, callback));
    }
}

/**
 * Sends a Context Provider unregistration request to the Context Broker using NGSIv2.
 *
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendUnregistrationsNgsi2(deviceData, callback) {
    var options = {
        url: config.getConfig().contextBroker.url + '/v2/registrations/' + deviceData.registrationId,
        method: 'DELETE',
        json: true,
        headers: {
            'fiware-service': deviceData.service,
            'fiware-servicepath': deviceData.subservice
        }
    };

    logger.debug(context, 'Sending device unregistrations to Context Broker at [%s]', options.url);
    logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

    request(options, createRegistrationHandlerNgsi2(true, deviceData, callback));
}

/**
 * Sends a Context Provider registration or unregistration request to the Context Broker using NGSIv2.
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendRegistrationsNgsi2(unregister, deviceData, callback) {
    var options = {
        url: config.getConfig().contextBroker.url + '/v2/registrations',
        method: 'POST',
        json: {
            dataProvided: {
                entities:
                [
                    {
                        type: deviceData.type,
                        id: String(deviceData.name)
                    }
                ],
                attrs: [],
            },
            provider: {
                http: {
                    url: config.getConfig().providerUrl
                },
                legacyForwarding: true
            }
        },
        headers: {
            'fiware-service': deviceData.service,
            'fiware-servicepath': deviceData.subservice
        }
    };

    function formatAttributes(originalVector) {
        var attributeList = [];

        if (originalVector && originalVector.length) {
            for (var i = 0; i < originalVector.length; i++) {
                attributeList.push(originalVector[i].name);
            }
        }

        return attributeList;
    }

    function mergeWithSameName(old, current) {
        if (old.indexOf(current) < 0) {
            old.push(current);
        }

        return old;
    }

    if (unregister) {
        sendUnregistrationsNgsi2(deviceData, callback);
    } else {

        if (config.getConfig().deviceRegistrationDuration) {
            options.json.expires = moment().add(moment.duration(config.getConfig().deviceRegistrationDuration));
        }

        options.json.dataProvided.attrs = options.json.dataProvided.attrs.concat(
                formatAttributes(deviceData.lazy),
                formatAttributes(deviceData.commands)
            ).reduce(mergeWithSameName, []);

        if (options.json.dataProvided.attrs.length === 0) {
            logger.debug(context, 'No Context Provider registrations found for unregister');
            callback(null, deviceData);
        } else {
            logger.debug(context, 'Sending device registrations to Context Broker at [%s]', options.url);
            logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

            request(options, createRegistrationHandlerNgsi2(unregister, deviceData, callback));
        }
    }
}

/**
 * Sends a Context Provider registration or unregistration request to the Context Broker. As registrations cannot be
 * removed, an unregistration consists of an update of the existent registration to make reduce its duration to
 * 1 second.
 *
 * The entity type, entity name and lazy attributes list are needed in order to send the registration:
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendRegistrations(unregister, deviceData, callback) {
    if (config.checkNgsi2()) {
        sendRegistrationsNgsi2(unregister, deviceData, callback);
    } else {
        sendRegistrationsNgsi1(unregister, deviceData, callback);
    }
}

exports.sendRegistrations = intoTrans(context, sendRegistrations);
exports.createRegistrationHandler = intoTrans(context, createRegistrationHandler);
<|endoftext|>


<commit_before>/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
/*

  The MIT License (MIT)

  Copyright (c) 2007-2013 Einar Lielmanis and contributors.

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation files
  (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge,
  publish, distribute, sublicense, and/or sell copies of the Software,
  and to permit persons to whom the Software is furnished to do so,
  subject to the following conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.

 CSS Beautifier
---------------

    Written by Harutyun Amirjanyan, (amirjanyan@gmail.com)

    Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
        http://jsbeautifier.org/

    Usage:
        css_beautify(source_text);
        css_beautify(source_text, options);

    The options are (default in brackets):
        indent_size (4)             — indentation size,
        indent_char (space)         — character to indent with,
        selector_separator (\n)     - string to separate selectors
                                      (e.g. "a,\nbr" or "a, br")
        end_with_newline (false)    - end with a newline

    e.g

    css_beautify(css_source_text, {
      'indent_size': 1,
      'indent_char': '\t',
      'selector_separator': ' ',
      'end_with_newline': false,
    });
*/

// http://www.w3.org/TR/CSS21/syndata.html#tokenization
// http://www.w3.org/TR/css3-syntax/

(function () {
    function css_beautify(source_text, options) {
        options = options || {};
        var indentSize = options.indent_size || 4;
        var indentCharacter = options.indent_char || ' ';
        var selectorSeparatorNewline = true;
        if (options.selector_separator_newline != undefined)
            selectorSeparatorNewline = options.selector_separator_newline;
        var endWithNewline = options.end_with_newline || false;

        // compatibility
        if (typeof indentSize === "string") {
            indentSize = parseInt(indentSize, 10);
        }

        // tokenizer
        var whiteRe = /^\s+$/;
        var wordRe = /[\w$\-_]/;

        var pos = -1,
            ch;

        function next() {
            ch = source_text.charAt(++pos);
            return ch;
        }

        function peek() {
            return source_text.charAt(pos + 1);
        }

        function eatString(endChar) {
            var start = pos;
            while (next()) {
                if (ch === "\\") {
                    next();
                    next();
                } else if (ch === endChar) {
                    break;
                } else if (ch === "\n") {
                    break;
                }
            }
            return source_text.substring(start, pos + 1);
        }

        function eatWhitespace() {
            var start = pos;
            while (whiteRe.test(peek())) {
                pos++;
            }
            return pos !== start;
        }

        function skipWhitespace() {
            var start = pos;
            do {} while (whiteRe.test(next()));
            return pos !== start + 1;
        }

        function eatComment() {
            var start = pos;
            next();
            while (next()) {
                if (ch === "*" && peek() === "/") {
                    pos++;
                    break;
                }
            }

            return source_text.substring(start, pos + 1);
        }

        function lookBack(str) {
            return source_text.substring(pos - str.length, pos).toLowerCase() ===
                str;
        }

        // printer
        var indentString = source_text.match(/^[\r\n]*[\t ]*/)[0];
        var singleIndent = Array(indentSize + 1).join(indentCharacter);
        var indentLevel = 0;

        function indent() {
            indentLevel++;
            indentString += singleIndent;
        }

        function outdent() {
            indentLevel--;
            indentString = indentString.slice(0, -indentSize);
        }

        var print = {};
        print["{"] = function (ch) {
            print.singleSpace();
            output.push(ch);
            print.newLine();
        };
        print["}"] = function (ch) {
            print.newLine();
            output.push(ch);
            print.newLine();
        };

        print._lastCharWhitespace = function () {
            return whiteRe.test(output[output.length - 1]);
        }

        print.newLine = function (keepWhitespace) {
            if (!keepWhitespace) {
                while (print._lastCharWhitespace()) {
                    output.pop();
                }
            }

            if (output.length) {
                output.push('\n');
            }
            if (indentString) {
                output.push(indentString);
            }
        };
        print.singleSpace = function () {
            if (output.length && !print._lastCharWhitespace()) {
                output.push(' ');
            }
        };
        var output = [];
        if (indentString) {
            output.push(indentString);
        }
        /*_____________________--------------------_____________________*/

        var insideRule = false;
        while (true) {
            var isAfterSpace = skipWhitespace();

            if (!ch) {
                break;
            } else if (ch === '/' && peek() === '*') { // comment
                print.newLine();
                output.push(eatComment(), "\n", indentString);
                var header = lookBack("")
                if (header) {
                    print.newLine();
                }
            } else if (ch === '{') {
                eatWhitespace();
                if (peek() == '}') {
                    next();
                    output.push(" {}");
                } else {
                    indent();
                    print["{"](ch);
                }
            } else if (ch === '}') {
                outdent();
                print["}"](ch);
                insideRule = false;
            } else if (ch === ":") {
                eatWhitespace();
                output.push(ch, " ");
                insideRule = true;
            } else if (ch === '"' || ch === '\'') {
                output.push(eatString(ch));
            } else if (ch === ';') {
                output.push(ch, '\n', indentString);
            } else if (ch === '(') { // may be a url
                if (lookBack("url")) {
                    output.push(ch);
                    eatWhitespace();
                    if (next()) {
                        if (ch !== ')' && ch !== '"' && ch !== '\'') {
                            output.push(eatString(')'));
                        } else {
                            pos--;
                        }
                    }
                } else {
                    if (isAfterSpace) {
                        print.singleSpace();
                    }
                    output.push(ch);
                    eatWhitespace();
                }
            } else if (ch === ')') {
                output.push(ch);
            } else if (ch === ',') {
                eatWhitespace();
                output.push(ch);
                if (!insideRule && selectorSeparatorNewline) {
                    print.newLine();
                } else {
                    print.singleSpace();
                }
            } else if (ch === ']') {
                output.push(ch);
            } else if (ch === '[' || ch === '=') { // no whitespace before or after
                eatWhitespace();
                output.push(ch);
            } else {
                if (isAfterSpace) {
                    print.singleSpace();
                }

                output.push(ch);
            }
        }

        var sweetCode = output.join('').replace(/[\n ]+$/, '');

        // establish end_with_newline
        var should = endWithNewline;
        var actually = /\n$/.test(sweetCode)
        if (should && !actually)
            sweetCode += "\n";
        else if (!should && actually)
            sweetCode = sweetCode.slice(0, -1);

        return sweetCode;
    }

    if (typeof define === "function") {
        // Add support for require.js
        define(function (require, exports, module) {
            exports.css_beautify = css_beautify;
        });
    } else if (typeof exports !== "undefined") {
        // Add support for CommonJS. Just put this file somewhere on your require.paths
        // and you will be able to `var html_beautify = require("beautify").html_beautify`.
        exports.css_beautify = css_beautify;
    } else if (typeof window !== "undefined") {
        // If we're running a web page and don't have either of the above, add our one global
        window.css_beautify = css_beautify;
    } else if (typeof global !== "undefined") {
        // If we don't even have window, try global.
        global.css_beautify = css_beautify;
    }

}());<commit_msg>correct options comment<commit_after>/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
/*

  The MIT License (MIT)

  Copyright (c) 2007-2013 Einar Lielmanis and contributors.

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation files
  (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge,
  publish, distribute, sublicense, and/or sell copies of the Software,
  and to permit persons to whom the Software is furnished to do so,
  subject to the following conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.

 CSS Beautifier
---------------

    Written by Harutyun Amirjanyan, (amirjanyan@gmail.com)

    Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
        http://jsbeautifier.org/

    Usage:
        css_beautify(source_text);
        css_beautify(source_text, options);

    The options are (default in brackets):
        indent_size (4)                   — indentation size,
        indent_char (space)               — character to indent with,
        selector_separator_newline (true) - separate selectors with newline or
                                            not (e.g. "a,\nbr" or "a, br")
        end_with_newline (false)          - end with a newline

    e.g

    css_beautify(css_source_text, {
      'indent_size': 1,
      'indent_char': '\t',
      'selector_separator': ' ',
      'end_with_newline': false,
    });
*/

// http://www.w3.org/TR/CSS21/syndata.html#tokenization
// http://www.w3.org/TR/css3-syntax/

(function () {
    function css_beautify(source_text, options) {
        options = options || {};
        var indentSize = options.indent_size || 4;
        var indentCharacter = options.indent_char || ' ';
        var selectorSeparatorNewline = true;
        if (options.selector_separator_newline != undefined)
            selectorSeparatorNewline = options.selector_separator_newline;
        var endWithNewline = options.end_with_newline || false;

        // compatibility
        if (typeof indentSize === "string") {
            indentSize = parseInt(indentSize, 10);
        }

        // tokenizer
        var whiteRe = /^\s+$/;
        var wordRe = /[\w$\-_]/;

        var pos = -1,
            ch;

        function next() {
            ch = source_text.charAt(++pos);
            return ch;
        }

        function peek() {
            return source_text.charAt(pos + 1);
        }

        function eatString(endChar) {
            var start = pos;
            while (next()) {
                if (ch === "\\") {
                    next();
                    next();
                } else if (ch === endChar) {
                    break;
                } else if (ch === "\n") {
                    break;
                }
            }
            return source_text.substring(start, pos + 1);
        }

        function eatWhitespace() {
            var start = pos;
            while (whiteRe.test(peek())) {
                pos++;
            }
            return pos !== start;
        }

        function skipWhitespace() {
            var start = pos;
            do {} while (whiteRe.test(next()));
            return pos !== start + 1;
        }

        function eatComment() {
            var start = pos;
            next();
            while (next()) {
                if (ch === "*" && peek() === "/") {
                    pos++;
                    break;
                }
            }

            return source_text.substring(start, pos + 1);
        }

        function lookBack(str) {
            return source_text.substring(pos - str.length, pos).toLowerCase() ===
                str;
        }

        // printer
        var indentString = source_text.match(/^[\r\n]*[\t ]*/)[0];
        var singleIndent = Array(indentSize + 1).join(indentCharacter);
        var indentLevel = 0;

        function indent() {
            indentLevel++;
            indentString += singleIndent;
        }

        function outdent() {
            indentLevel--;
            indentString = indentString.slice(0, -indentSize);
        }

        var print = {};
        print["{"] = function (ch) {
            print.singleSpace();
            output.push(ch);
            print.newLine();
        };
        print["}"] = function (ch) {
            print.newLine();
            output.push(ch);
            print.newLine();
        };

        print._lastCharWhitespace = function () {
            return whiteRe.test(output[output.length - 1]);
        }

        print.newLine = function (keepWhitespace) {
            if (!keepWhitespace) {
                while (print._lastCharWhitespace()) {
                    output.pop();
                }
            }

            if (output.length) {
                output.push('\n');
            }
            if (indentString) {
                output.push(indentString);
            }
        };
        print.singleSpace = function () {
            if (output.length && !print._lastCharWhitespace()) {
                output.push(' ');
            }
        };
        var output = [];
        if (indentString) {
            output.push(indentString);
        }
        /*_____________________--------------------_____________________*/

        var insideRule = false;
        while (true) {
            var isAfterSpace = skipWhitespace();

            if (!ch) {
                break;
            } else if (ch === '/' && peek() === '*') { // comment
                print.newLine();
                output.push(eatComment(), "\n", indentString);
                var header = lookBack("")
                if (header) {
                    print.newLine();
                }
            } else if (ch === '{') {
                eatWhitespace();
                if (peek() == '}') {
                    next();
                    output.push(" {}");
                } else {
                    indent();
                    print["{"](ch);
                }
            } else if (ch === '}') {
                outdent();
                print["}"](ch);
                insideRule = false;
            } else if (ch === ":") {
                eatWhitespace();
                output.push(ch, " ");
                insideRule = true;
            } else if (ch === '"' || ch === '\'') {
                output.push(eatString(ch));
            } else if (ch === ';') {
                output.push(ch, '\n', indentString);
            } else if (ch === '(') { // may be a url
                if (lookBack("url")) {
                    output.push(ch);
                    eatWhitespace();
                    if (next()) {
                        if (ch !== ')' && ch !== '"' && ch !== '\'') {
                            output.push(eatString(')'));
                        } else {
                            pos--;
                        }
                    }
                } else {
                    if (isAfterSpace) {
                        print.singleSpace();
                    }
                    output.push(ch);
                    eatWhitespace();
                }
            } else if (ch === ')') {
                output.push(ch);
            } else if (ch === ',') {
                eatWhitespace();
                output.push(ch);
                if (!insideRule && selectorSeparatorNewline) {
                    print.newLine();
                } else {
                    print.singleSpace();
                }
            } else if (ch === ']') {
                output.push(ch);
            } else if (ch === '[' || ch === '=') { // no whitespace before or after
                eatWhitespace();
                output.push(ch);
            } else {
                if (isAfterSpace) {
                    print.singleSpace();
                }

                output.push(ch);
            }
        }

        var sweetCode = output.join('').replace(/[\n ]+$/, '');

        // establish end_with_newline
        var should = endWithNewline;
        var actually = /\n$/.test(sweetCode)
        if (should && !actually)
            sweetCode += "\n";
        else if (!should && actually)
            sweetCode = sweetCode.slice(0, -1);

        return sweetCode;
    }

    if (typeof define === "function") {
        // Add support for require.js
        define(function (require, exports, module) {
            exports.css_beautify = css_beautify;
        });
    } else if (typeof exports !== "undefined") {
        // Add support for CommonJS. Just put this file somewhere on your require.paths
        // and you will be able to `var html_beautify = require("beautify").html_beautify`.
        exports.css_beautify = css_beautify;
    } else if (typeof window !== "undefined") {
        // If we're running a web page and don't have either of the above, add our one global
        window.css_beautify = css_beautify;
    } else if (typeof global !== "undefined") {
        // If we don't even have window, try global.
        global.css_beautify = css_beautify;
    }

}());<|endoftext|>


<commit_before>Simplicity.Level1 = function (game) { };

Simplicity.Level1.prototype =
{
  create: function () {

    // Create a group for our tiles.
    isoGroup = game.add.group();

    this.canPlay = false;
    this.winTriggered = false;
    this.dead = false;
    this.steps = 8;
    this.stepcount = 0;
    this.timer = 2;
    this.cursors = game.input.keyboard.createCursorKeys();
    this.hasStepped = false;
    this.timerStarted = false;
    this.game.input.keyboard.addKeyCapture([
      Phaser.Keyboard.LEFT,
      Phaser.Keyboard.RIGHT,
      Phaser.Keyboard.UP,
      Phaser.Keyboard.DOWN,
      Phaser.Keyboard.SPACEBAR
    ]);

    this.layout = [[2, 2, 2, 2, 2, 1, 1],
    [0, 0, 0, 0, 2, 0, 1],
    [0, 0, 0, 0, 2, 0, 1],
    [0, 0, 0, 0, 2, 1, 1],
    [0, 0, 0, 0, 3, 1, ],
  ];

  this.bubble = game.world.add(new SpeechBubble(game, 180, 190, 200, "Get me to the green tile"));

    this.spawnTiles();
    this.spawnPlayer();

  },
  update: function () {

    if(!game.tweens.isTweening(this.bubble)){
      game.add.tween(this.bubble).to({ x: this.player.x, y: this.player.y-19}, 140, Phaser.Easing.Linear.None, true);
    }

    if(!game.tweens.isTweening(this.player) && this.canPlay){

      if(this.hasStepped && !this.timerStarted) {
        this.timerStarted = true;
        this.timerLoop = game.time.events.loop(100, function() {
          this.timer -= 0.1;
          if(this.timer < 0) {
            game.time.events.remove(this.timerLoop);
            this.canPlay = false;
            this.changeLevel('Level1')
          }
        }, this);
      }
      var currentTileX = ((this.player.isoX-50)/38);
      var currentTileY = ((this.player.isoY-50)/38);

      var nextPosX = this.player.isoX, nextPosY = this.player.isoY, moved = false;

      if (this.cursors.down.isDown) {
        nextPosX = this.player.isoX + 38;
        nextPosY = this.player.isoY;
        moved = true;
      } else if (this.cursors.up.isDown) {
        nextPosX = this.player.isoX - 38;
        nextPosY = this.player.isoY;
        moved = true;
      } else if (this.cursors.right.isDown) {
        nextPosX = this.player.isoX;
        nextPosY = this.player.isoY - 38;
        moved = true;
      } else if (this.cursors.left.isDown) {
        nextPosX = this.player.isoX;
        nextPosY = this.player.isoY +  38;
        moved = true;
      }

      if(this.checkTile(currentTileX, currentTileY) === 0) {
        game.iso.simpleSort(isoGroup);
        moved = false;
        if(!this.dead) {
          this.changeBubble(failureStrings[Math.floor(Math.random() * failureStrings.length)]);

          game.time.events.add(Phaser.Timer.SECOND, function() {
            this.changeLevel('Level1')
          }, this);

          this.dropSprite(this.player, 200, -500, function(){this.canPlay = true}.bind(this))
          game.time.events.remove(this.timerLoop);
          this.dead = true;
        }
      } else if(this.checkTile(currentTileX, currentTileY) === 3) {
        if(!this.winTriggered) {
          game.time.events.remove(this.timerLoop);
          this.complete();
        }
        moved = false;
      }

      if(moved) {
        this.hasStepped = true;
        this.stepcount++;
        this.timer = 2.1;
        game.add.tween(this.player).to({ isoX: nextPosX, isoY: nextPosY}, 200, Phaser.Easing.Quadratic.InOut, true);
        if(this.stepcount > this.steps) {
          game.time.events.remove(this.timerLoop);
          this.canPlay = false;
          this.changeLevel('Level1')
        }
      }
    }
  },
  render: function () {
    game.debug.text(game.time.fps || '--', 2, 14, "#a7aebe");
    game.debug.text(this.stepcount + ' / ' + this.steps , 2, 42, "#a7aebe");
    game.debug.text(Math.round(this.timer*10)/10, 2, 28, "#a7aebe");
  },
  spawnTiles: function () {
  this.tiles = []
  var tile;

  dropTile = function(tile, delay) {
    game.time.events.add(delay, function() {
      game.add.tween(tile).to({ isoZ: 0 }, 150, Phaser.Easing.Linear.None, true);
    }, this);

  }

  this.delay = 0;

  for (var y = 0; y < this.layout.length; y++) {
    this.tiles.push([]);
    for (var x = 0; x < this.layout[y].length; x++) {
      // Create a tile using the new game.add.isoSprite factory method at the specified position.
      // The last parameter is the group you want to add it to (just like game.add.sprite)
      if(this.layout[y][x] > 0) {

        this.tiles[y][x] = game.add.isoSprite((x*38)+50, (y*38)+50, 500, 'tile', 0, isoGroup);
        this.tiles[y][x].anchor.set(0.5, 0);
        this.delay += 100;
        this.dropSprite(this.tiles[y][x], this.delay, 0)
      }
      if(this.layout[y][x] === 2){
        this.tiles[y][x].tint = 0x86bfda;
      }
      if(this.layout[y][x] === 3){
        this.tiles[y][x].tint = 0x00FF00;
      }

    }
  }
},

spawnPlayer: function() {
  this.player = game.add.isoSprite(50, 50, 500, 'cube', 0, isoGroup);
  this.player.tint = 0x86bfda;
  this.player.anchor.set(0.5);
  this.bubble.x = this.player.x;
  this.bubble.y = this.player.y;
  this.dropSprite(this.player, this.delay+100, 0, function(){this.canPlay = true}.bind(this))

},

checkTile: function(x,y) {
  if((x < 0 || y < 0)) {
    return 0;
  }

  if(this.layout[y] !== undefined) {
    if(this.layout[y][x] === undefined) {
      return 0;
    } else if(this.layout[y][x] === 0){
      return 0;
    } else {
      return this.layout[y][x];
    }
  } else {
    return 0;
  }
},
changeBubble: function(text) {
  this.bubble.kill();
  this.bubble = game.world.add(new SpeechBubble(game, 180, 190, 200, text));
  this.bubble.x = this.player.x;
  this.bubble.y = this.player.y;
},
complete: function() {
  this.changeBubble('WE WON')

  this.changeLevel('Level1');

  this.winTriggered = true;
},
changeLevel: function(level){
  var level = level;

  var delay = 0;

  for (var y = 0; y < this.layout.length; y++) {
    for (var x = 0; x < this.layout[y].length; x++) {
      if(this.layout[y][x] > 0) {
        delay += 100;
        this.dropSprite(this.tiles[y][x], delay, -500)
        if((this.player.isoX-50)/38 === x && (this.player.isoY-50)/38 == y) {
          this.canPlay = false
          this.dropSprite(this.player, delay+500, -500)

        }
      }

    }
  }

  game.time.events.add(delay+1000, function() {
    game.world.removeAll()
    game.state.start(level, false, true);
  }, this);

},
dropSprite: function(sprite, delay, to, cb) {
  game.time.events.add(delay, function() {
    game.add.tween(sprite).to({ isoZ: to }, 150, Phaser.Easing.Linear.None, true);
    if(cb) {
      cb();
    }
  }, this);

}
};

game.state.add('Level1', Simplicity.Level1);
<commit_msg>goal tile now falls last<commit_after>Simplicity.Level1 = function (game) { };

Simplicity.Level1.prototype =
{
  create: function () {

    // Create a group for our tiles.
    isoGroup = game.add.group();

    this.canPlay = false;
    this.winTriggered = false;
    this.dead = false;
    this.steps = 8;
    this.stepcount = 0;
    this.timer = 2;
    this.cursors = game.input.keyboard.createCursorKeys();
    this.hasStepped = false;
    this.timerStarted = false;
    this.game.input.keyboard.addKeyCapture([
      Phaser.Keyboard.LEFT,
      Phaser.Keyboard.RIGHT,
      Phaser.Keyboard.UP,
      Phaser.Keyboard.DOWN,
      Phaser.Keyboard.SPACEBAR
    ]);

    this.layout = [[2, 2, 2, 2, 2, 1, 1],
    [0, 0, 0, 0, 2, 0, 1],
    [0, 0, 0, 0, 2, 0, 1],
    [0, 0, 0, 0, 2, 1, 1],
    [0, 0, 0, 0, 3, 1, ],
  ];

  this.bubble = game.world.add(new SpeechBubble(game, 180, 190, 200, "Get me to the green tile"));

    this.spawnTiles();
    this.spawnPlayer();

  },
  update: function () {

    if(!game.tweens.isTweening(this.bubble)){
      game.add.tween(this.bubble).to({ x: this.player.x, y: this.player.y-19}, 140, Phaser.Easing.Linear.None, true);
    }

    if(!game.tweens.isTweening(this.player) && this.canPlay){

      if(this.hasStepped && !this.timerStarted) {
        this.timerStarted = true;
        this.timerLoop = game.time.events.loop(100, function() {
          this.timer -= 0.1;
          if(this.timer < 0) {
            game.time.events.remove(this.timerLoop);
            this.canPlay = false;
            this.changeLevel('Level1')
          }
        }, this);
      }
      var currentTileX = ((this.player.isoX-50)/38);
      var currentTileY = ((this.player.isoY-50)/38);

      var nextPosX = this.player.isoX, nextPosY = this.player.isoY, moved = false;

      if (this.cursors.down.isDown) {
        nextPosX = this.player.isoX + 38;
        nextPosY = this.player.isoY;
        moved = true;
      } else if (this.cursors.up.isDown) {
        nextPosX = this.player.isoX - 38;
        nextPosY = this.player.isoY;
        moved = true;
      } else if (this.cursors.right.isDown) {
        nextPosX = this.player.isoX;
        nextPosY = this.player.isoY - 38;
        moved = true;
      } else if (this.cursors.left.isDown) {
        nextPosX = this.player.isoX;
        nextPosY = this.player.isoY +  38;
        moved = true;
      }

      if(this.checkTile(currentTileX, currentTileY) === 0) {
        game.iso.simpleSort(isoGroup);
        moved = false;
        if(!this.dead) {
          this.changeBubble(failureStrings[Math.floor(Math.random() * failureStrings.length)]);

          game.time.events.add(Phaser.Timer.SECOND, function() {
            this.changeLevel('Level1')
          }, this);

          this.dropSprite(this.player, 200, -500, function(){this.canPlay = true}.bind(this))
          game.time.events.remove(this.timerLoop);
          this.dead = true;
        }
      } else if(this.checkTile(currentTileX, currentTileY) === 3) {
        if(!this.winTriggered) {
          game.time.events.remove(this.timerLoop);
          this.complete();
        }
        moved = false;
      }

      if(moved) {
        this.hasStepped = true;
        this.stepcount++;
        this.timer = 2.1;
        game.add.tween(this.player).to({ isoX: nextPosX, isoY: nextPosY}, 200, Phaser.Easing.Quadratic.InOut, true);
        if(this.stepcount > this.steps) {
          game.time.events.remove(this.timerLoop);
          this.canPlay = false;
          this.changeLevel('Level1')
        }
      }
    }
  },
  render: function () {
    game.debug.text(game.time.fps || '--', 2, 14, "#a7aebe");
    game.debug.text(this.stepcount + ' / ' + this.steps , 2, 42, "#a7aebe");
    game.debug.text(Math.round(this.timer*10)/10, 2, 28, "#a7aebe");
  },
  spawnTiles: function () {
  this.tiles = []
  var tile;

  dropTile = function(tile, delay) {
    game.time.events.add(delay, function() {
      game.add.tween(tile).to({ isoZ: 0 }, 150, Phaser.Easing.Linear.None, true);
    }, this);

  }

  this.delay = 0;
  var goalTile;

  for (var y = 0; y < this.layout.length; y++) {
    this.tiles.push([]);
    for (var x = 0; x < this.layout[y].length; x++) {
      // Create a tile using the new game.add.isoSprite factory method at the specified position.
      // The last parameter is the group you want to add it to (just like game.add.sprite)
      if(this.layout[y][x] > 0) {
        this.tiles[y][x] = game.add.isoSprite((x*38)+50, (y*38)+50, 500, 'tile', 0, isoGroup);
        this.tiles[y][x].anchor.set(0.5, 0);
        this.delay += 100;
        if(this.layout[y][x] !== 3) {
          this.dropSprite(this.tiles[y][x], this.delay, 0)
        }
      }
      if(this.layout[y][x] === 2){
        this.tiles[y][x].tint = 0x86bfda;

      }
      if(this.layout[y][x] === 3){
        goalTile = this.tiles[y][x];
        this.tiles[y][x].tint = 0x00FF00;
      }

    }
  }
  this.delay += 500;
  this.dropSprite(goalTile, this.delay, 0)
},

spawnPlayer: function() {
  this.player = game.add.isoSprite(50, 50, 500, 'cube', 0, isoGroup);
  this.player.tint = 0x86bfda;
  this.player.anchor.set(0.5);
  this.bubble.x = this.player.x;
  this.bubble.y = this.player.y;
  this.dropSprite(this.player, this.delay+500, 0, function(){this.canPlay = true}.bind(this))

},

checkTile: function(x,y) {
  if((x < 0 || y < 0)) {
    return 0;
  }

  if(this.layout[y] !== undefined) {
    if(this.layout[y][x] === undefined) {
      return 0;
    } else if(this.layout[y][x] === 0){
      return 0;
    } else {
      return this.layout[y][x];
    }
  } else {
    return 0;
  }
},
changeBubble: function(text) {
  this.bubble.kill();
  this.bubble = game.world.add(new SpeechBubble(game, 180, 190, 200, text));
  this.bubble.x = this.player.x;
  this.bubble.y = this.player.y;
},
complete: function() {
  this.changeBubble('WE WON')

  this.changeLevel('Level1');

  this.winTriggered = true;
},
changeLevel: function(level){
  var level = level;

  var delay = 0;
  var goalTile;
  var isOnGoal;
  for (var y = 0; y < this.layout.length; y++) {
    for (var x = 0; x < this.layout[y].length; x++) {
      if(this.layout[y][x] > 0) {
        if(this.layout[y][x] !== 3) {
          delay += 100;
          this.dropSprite(this.tiles[y][x], delay, -500)
          if((this.player.isoX-50)/38 === x && (this.player.isoY-50)/38 == y) {
            this.canPlay = false
            this.dropSprite(this.player, delay+500, -500)
          }
        } else {
          goalTile = this.tiles[y][x]
          if((this.player.isoX-50)/38 === x && (this.player.isoY-50)/38 == y) {
            isOnGoal = true;
          }
        }
      }

    }
  }
  delay += 500;
  this.dropSprite(goalTile, delay, -500);

  if(isOnGoal) {
    this.canPlay = false
    this.dropSprite(this.player, delay+500, -500)
  }

  game.time.events.add(delay+1000, function() {
    game.world.removeAll()
    game.state.start(level, false, true);
  }, this);

},
dropSprite: function(sprite, delay, to, cb) {
  game.time.events.add(delay, function() {
    game.add.tween(sprite).to({ isoZ: to }, 150, Phaser.Easing.Linear.None, true);
    if(cb) {
      cb();
    }
  }, this);

}
};

game.state.add('Level1', Simplicity.Level1);
<|endoftext|>


<commit_before>var webpack = require( "webpack" );

module.exports = function( grunt ) {

	grunt.config.set( "webpack", {
		options: {
			entry: "./src/index.js",
			output: {
				path: "public/assets/",
				filename: "bundle.js",
				publicPath: "/assets/"
			},
			module: {
				loaders: [
					{

						// test: /\.jsx?$/,
						// include: [ "src" ],
						loader: "babel",
						query: {

							// https://github.com/babel/babel-loader#options
							cacheDirectory: false,
							presets: [ "react", "stage-1", "es2015"  ]
						}
					}
				]
			}
		},
		dev: {
			watch: false,
			cache: true,
			debug: true,
			devtool: "eval",
			plugins: [
				new webpack.optimize.DedupePlugin(),
				new webpack.optimize.UglifyJsPlugin()
			]
		},
		build: {
			watch: false,
			debug: false,
			cache: true,
			plugins: [
				new webpack.optimize.DedupePlugin(),
				new webpack.optimize.UglifyJsPlugin( { compress: { warnings: false } } )
			]
		},
		test: {
			entry: "./tests/unit/index.js",
			output: {
				path: "tests/",
				filename: "bundle.js",
				publicPath: "/"
			},
			watch: false,
			cache: false,
			debug: true,
			devtool: "eval",
			plugins: [
				new webpack.optimize.DedupePlugin(),
				new webpack.optimize.UglifyJsPlugin()
			]
		}
	} );

	grunt.loadNpmTasks( "grunt-webpack" );

};
<commit_msg>webpack build use process.env.APP_ENV<commit_after>var webpack = require( "webpack" );

module.exports = function( grunt ) {

	grunt.config.set( "webpack", {
		options: {
			entry: "./src/index.js",
			output: {
				path: "public/assets/",
				filename: "bundle.js",
				publicPath: "/assets/"
			},
			module: {
				loaders: [
					{

						// test: /\.jsx?$/,
						// include: [ "src" ],
						loader: "babel",
						query: {

							// https://github.com/babel/babel-loader#options
							cacheDirectory: false,
							presets: [ "react", "stage-1", "es2015"  ]
						}
					}
				]
			}
		},
		dev: {
			watch: false,
			cache: true,
			debug: true,
			devtool: "eval",
			plugins: [
				new webpack.optimize.DedupePlugin(),
				new webpack.optimize.UglifyJsPlugin()
			]
		},
		build: {

			debug: false,
			plugins: [
				new webpack.DefinePlugin({
          APP_ENV: JSON.stringify( process.env.APP_ENV || "development" ),
        }),
				new webpack.optimize.DedupePlugin(),
				new webpack.optimize.UglifyJsPlugin( { compress: { warnings: false } } )
			]
		},
		test: {
			entry: "./tests/unit/index.js",
			output: {
				path: "tests/",
				filename: "bundle.js",
				publicPath: "/"
			},
			watch: false,
			cache: false,
			debug: true,
			devtool: "eval",
			plugins: [
				new webpack.optimize.DedupePlugin(),
				new webpack.optimize.UglifyJsPlugin()
			]
		}
	} );

	grunt.loadNpmTasks( "grunt-webpack" );

};
<|endoftext|>


<commit_before>const shortid = require('shortid');
const GAMES = require('./games.js');

let joinPartyHandle = (socket, dispatchRoom, dispatch, db, user, party_code) => {
  let handlePartyDb = (party, matches, games, all_users, current_user, new_user) => {
    try {
      let users_nickname = party.users.map((u_code) => {
        return all_users.filter((u) => { return u._id == u_code; })[0].nickname;
      });
      let info = {name: party.name, users: party.users, currentUser: current_user,
        code: party_code, loading: false, usersNickname: users_nickname };
      dispatch({type: 'SET_DOWN_MAPPING', downMapping: party.downMapping});
      dispatch({type: 'SET_GAMES', games});
      dispatch({type: 'SET_MATCHES', matches});
      let set_info_message = {type: 'SET_INFO', info};
      dispatch(set_info_message);
      socket.join('party-' + party._id);
      if (new_user) {
        dispatchRoom('party-' + party._id,
                     set_info_message);
      }
    } catch (err) {
      console.error(err);
    }
  };
  //Do Mongo DB request
  db.collection('parties').findOne({_id: party_code}, (err, party) => {
    try {
      if (!party)
        return;
      let new_user = false;
      let current_user = party.users.indexOf(user._id);
      if (current_user == -1) {
        new_user = true;
        current_user = party.users.length;
        party.users.push(user._id);
        db.collection('parties').save(party);
      }
      db.collection('users').find({_id: {$in: party.users}}, (err, users_cur) => {
        users_cur.toArray((err, all_users) => {
          db.collection('matches').find({party_id:  party_code,
            status: 'ACTIVE'})
            .toArray((err, matches) => {
              let games = GAMES.list;
              handlePartyDb(party, matches, games, all_users, current_user, new_user);
            });
        });
      });
    } catch (err) {
      console.error(err);
    }
  });
};

let leavePartyHandle = (socket, dispatchRoom, dispatch, db, user, party_code) => {
  socket.leave('party-' + party_code);
};

let downHandle = (socket, dispatchRoom, dispatch, db,
                  user, party_code, game_code) => {
  db.collection('parties').findOne({_id: party_code}, (err, party) => {
    try {
      let game = GAMES.map[game_code];
      let maxPlayers = game.maxPlayers;
      let downMapping = party.downMapping;
      if (party.users.indexOf(user._id) == -1) // User not in the party
        return;
      if (!(game_code in downMapping)) {
        downMapping[game_code] = [];
      }
      if (downMapping[game_code].indexOf(user._id) == -1) { //New player
        downMapping[game_code].unshift(user._id);
        if (downMapping[game_code].length == maxPlayers) {
          db.collection('matches').insertOne({party_id: party_code,
            _id: shortid.generate(),
            game_code,
            game_name: game.name,
            status: 'ACTIVE',
            players: downMapping[game_code]
          }, () => {
            db.collection('matches').find({party_id:  party_code,
              status: 'ACTIVE'})
              .toArray((err, matches) => {
                try {
                  dispatchRoom('party-' + party._id,
                               {type: 'SET_MATCHES', matches}, true);
                } catch (err) {
                  console.error(err);
                }
              });
          });
          downMapping[game_code] = [];
        }
      } else { //Removing player
        downMapping[game_code].splice(
          downMapping[game_code].indexOf(user._id), 1);
      }

      db.collection('parties').updateOne({_id: party_code},
        { $set: {downMapping: downMapping} });
      dispatchRoom('party-' + party._id,
                   {type: 'SET_DOWN_MAPPING', downMapping: downMapping}, true);
    } catch (err) {
      console.error(err);
    }
  });
};

module.exports = { joinPartyHandle, leavePartyHandle, downHandle };
<commit_msg>Better handling mismatch between JWT and db.<commit_after>const shortid = require('shortid');
const GAMES = require('./games.js');

let joinPartyHandle = (socket, dispatchRoom, dispatch, db, user, party_code) => {
  let handlePartyDb = (party, matches, games, all_users, current_user, new_user) => {
    try {
      let users_nickname = party.users.map((u_code) => {
        let users = all_users.filter((u) => { return u._id == u_code; });
        if (users.length == 1) {
          return users[0].nickname;
        } else {
          //This should only happen if we lose users on the db, but they still
          //have the JWT token.
          return u_code;
        }
      });
      let info = {name: party.name, users: party.users, currentUser: current_user,
        code: party_code, loading: false, usersNickname: users_nickname };
      dispatch({type: 'SET_DOWN_MAPPING', downMapping: party.downMapping});
      dispatch({type: 'SET_GAMES', games});
      dispatch({type: 'SET_MATCHES', matches});
      let set_info_message = {type: 'SET_INFO', info};
      dispatch(set_info_message);
      socket.join('party-' + party._id);
      if (new_user) {
        dispatchRoom('party-' + party._id,
                     set_info_message);
      }
    } catch (err) {
      console.error(err);
    }
  };
  //Do Mongo DB request
  db.collection('parties').findOne({_id: party_code}, (err, party) => {
    try {
      if (!party)
        return;
      let new_user = false;
      let current_user = party.users.indexOf(user._id);
      if (current_user == -1) {
        new_user = true;
        current_user = party.users.length;
        party.users.push(user._id);
        db.collection('parties').save(party);
      }
      db.collection('users').find({_id: {$in: party.users}}, (err, users_cur) => {
        users_cur.toArray((err, all_users) => {
          db.collection('matches').find({party_id:  party_code,
            status: 'ACTIVE'})
            .toArray((err, matches) => {
              let games = GAMES.list;
              handlePartyDb(party, matches, games, all_users, current_user, new_user);
            });
        });
      });
    } catch (err) {
      console.error(err);
    }
  });
};

let leavePartyHandle = (socket, dispatchRoom, dispatch, db, user, party_code) => {
  socket.leave('party-' + party_code);
};

let downHandle = (socket, dispatchRoom, dispatch, db,
                  user, party_code, game_code) => {
  db.collection('parties').findOne({_id: party_code}, (err, party) => {
    try {
      let game = GAMES.map[game_code];
      let maxPlayers = game.maxPlayers;
      let downMapping = party.downMapping;
      if (party.users.indexOf(user._id) == -1) // User not in the party
        return;
      if (!(game_code in downMapping)) {
        downMapping[game_code] = [];
      }
      if (downMapping[game_code].indexOf(user._id) == -1) { //New player
        downMapping[game_code].unshift(user._id);
        if (downMapping[game_code].length == maxPlayers) {
          db.collection('matches').insertOne({party_id: party_code,
            _id: shortid.generate(),
            game_code,
            game_name: game.name,
            status: 'ACTIVE',
            players: downMapping[game_code]
          }, () => {
            db.collection('matches').find({party_id:  party_code,
              status: 'ACTIVE'})
              .toArray((err, matches) => {
                try {
                  dispatchRoom('party-' + party._id,
                               {type: 'SET_MATCHES', matches}, true);
                } catch (err) {
                  console.error(err);
                }
              });
          });
          downMapping[game_code] = [];
        }
      } else { //Removing player
        downMapping[game_code].splice(
          downMapping[game_code].indexOf(user._id), 1);
      }

      db.collection('parties').updateOne({_id: party_code},
        { $set: {downMapping: downMapping} });
      dispatchRoom('party-' + party._id,
                   {type: 'SET_DOWN_MAPPING', downMapping: downMapping}, true);
    } catch (err) {
      console.error(err);
    }
  });
};

module.exports = { joinPartyHandle, leavePartyHandle, downHandle };
<|endoftext|>