<commit_before>/**
 * Se encarga de crear y añadir a la escena los distintos objetos del juego
 *
 * @class XEngine.ObjectFactory
 * @constructor
 * @param {XEngine.Game} game - referencia al objeto del juego
 */
XEngine.ObjectFactory = function (game) {
	this.game = game;
};

XEngine.ObjectFactory.prototype = {
	/**
	 * Añade un objeto ya existente (creado con new) al juego
	 * @method XEngine.ObjectFacory#existing
	 * @param {XEngine.BaseObject} gameObject - Objeto a añadir
	 * @return {Object}
	 */
	existing: function (gameObject, update = true, render = true) { //Añade un objeto que ya ha sido creado
		if(update)
			this.game.updateQueue.push(gameObject); //Añadimos el objeto al array de objetos
		if(render)
			this.game.renderQueue.push(gameObject);
		gameObject.parent = this.game; //Asignamos el padre del objeto
		gameObject._onInitialize();
		if (gameObject.start != undefined) {
			gameObject.start();
		}
		return gameObject;
	},

	/**
	 * Crea y añade un sprite al juego
	 * @method XEngine.ObjectFacory#sprite
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} sprite - keyName del sprite
	 * @return {XEngine.Sprite}
	 */
	sprite: function (posX, posY, sprite, frame) { //Creamos y añadimos un sprite a partir de los datos proporcionados
		var gameObject = new XEngine.Sprite(this.game, posX, posY, sprite, frame);
		return this.existing(gameObject, true, true);
	},

	/**
	 * Crea y añade una imagen al juego
	 * @method XEngine.ObjectFacory#sprite
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} sprite - keyName del sprite
	 * @return {XEngine.Sprite}
	 */
	sprite: function (posX, posY, sprite, frame) { //Creamos y añadimos un sprite a partir de los datos proporcionados
		var gameObject = new XEngine.Sprite(this.game, posX, posY, sprite, frame);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade una imagen que se repite
	 * @method XEngine.ObjectFacory#tilled
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} sprite - keyName de la imagen
	 * @param {Number} width - ancho de la imagen
	 * @param {Number} height - alto de la imagen
	 * @return {XEngine.TilledImage}
	 */
	tilled: function (posX, posY, sprite, width, height) { //Creamos y añadimos una imagen que se puede tilear
		var gameObject = new XEngine.TilledImage(this.game, posX, posY, sprite, width, height);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade una imagen que hace la función de bottón
	 * @method XEngine.ObjectFacory#button
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} sprite - keyName de la imagen
	 * @param {String} spriteDown - keyName de la imagen cuando se pulsa el botón
	 * @param {String} spriteOver - keyName de la imagen cuando se pasa el ratón por encima
	 * @param {String} spriteUp - keyName de la imagen cuando se levanta el input
	 * @return {XEngine.Button}
	 */
	button: function (posX, posY, sprite, frameIdle, spriteDown, spriteOver, spriteUp) {
		var gameObject = new XEngine.Button(this.game, posX, posY, sprite, frameIdle, spriteDown, spriteOver, spriteUp);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade un rectangulo de color
	 * @method XEngine.ObjectFacory#rect
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {Number} width - ancho de la imagen
	 * @param {Number} height - alto de la imagen
	 * @param {String} color - color en hexadecimal con formato rgb
	 * @return {XEngine.Rect}
	 */
	rect: function (posX, posY, width, height, color) { //Creamos un rectangulo a partir de los datos proporcionados
		var gameObject = new XEngine.Rect(this.game, posX, posY, width, height, color);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade un circulo de color
	 * @method XEngine.ObjectFacory#circle
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {Number} width - ancho del circulo
	 * @param {Number} height - alto del circulo
	 * @return {XEngine.Circe}
	 */
	circle: function (posX, posY, width, height) { //Creamos un rectangulo a partir de los datos proporcionados
		var gameObject = new XEngine.Circle(this.game, posX, posY, width, height);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade un objeto de texto
	 * @method XEngine.ObjectFacory#text
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} text - texto a mostrar
	 * @param {Object} textStyle - objeto que contiene los parametros de estilo
	 * @return {XEngine.Text}
	 */
	text: function (posX, posY, text, textStyle) {
		var gameObject = new XEngine.Text(this.game, posX, posY, text, textStyle);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade un objeto de audio
	 * @method XEngine.ObjectFacory#audio
	 * @param {String} audio - keyName del archivo de audio a reproducir
	 * @param {Boolean} autoStart - indica si empieza al crearse o no
	 * @param {Number} volume - indica el volumen del audio;
	 * @return {XEngine.Audio}
	 */
	audio: function (audio, autoStart, volume) {
		var audioObject = new XEngine.Audio(this.game, audio, autoStart, volume);
		return this.existing(audioObject, true, false);
	},

	/**
	 * Crea y añade un contenedor de objetos
	 * @method XEngine.ObjectFacory#group
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @return {XEngine.Group}
	 */
	group: function (posX, posY) { //Creamos y añadimos un grupo
		var x = posX || 0;
		var y = posY || 0;
		var gameObject = new XEngine.Group(this.game, x, y);
		return this.existing(gameObject, true, false);
	}
};<commit_msg>fix in object factory<commit_after>/**
 * Se encarga de crear y añadir a la escena los distintos objetos del juego
 *
 * @class XEngine.ObjectFactory
 * @constructor
 * @param {XEngine.Game} game - referencia al objeto del juego
 */
XEngine.ObjectFactory = function (game) {
	this.game = game;
};

XEngine.ObjectFactory.prototype = {
	/**
	 * Añade un objeto ya existente (creado con new) al juego
	 * @method XEngine.ObjectFacory#existing
	 * @param {XEngine.BaseObject} gameObject - Objeto a añadir
	 * @return {Object}
	 */
	existing: function (gameObject, update = true, render = true) { //Añade un objeto que ya ha sido creado
		if(update)
			this.game.updateQueue.push(gameObject); //Añadimos el objeto al array de objetos
		if(render)
			this.game.renderQueue.push(gameObject);
		gameObject.parent = this.game; //Asignamos el padre del objeto
		gameObject._onInitialize();
		if (gameObject.start != undefined) {
			gameObject.start();
		}
		return gameObject;
	},

	/**
	 * Crea y añade un sprite al juego
	 * @method XEngine.ObjectFacory#sprite
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} sprite - keyName del sprite
	 * @return {XEngine.Sprite}
	 */
	sprite: function (posX, posY, sprite, frame) { //Creamos y añadimos un sprite a partir de los datos proporcionados
		var gameObject = new XEngine.Sprite(this.game, posX, posY, sprite, frame);
		return this.existing(gameObject, true, true);
	},

	/**
	 * Crea y añade una imagen al juego
	 * @method XEngine.ObjectFacory#sprite
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} sprite - keyName del sprite
	 * @return {XEngine.Sprite}
	 */
	image: function (posX, posY, sprite, frame) { //Creamos y añadimos un sprite a partir de los datos proporcionados
		var gameObject = new XEngine.Sprite(this.game, posX, posY, sprite, frame);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade una imagen que se repite
	 * @method XEngine.ObjectFacory#tilled
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} sprite - keyName de la imagen
	 * @param {Number} width - ancho de la imagen
	 * @param {Number} height - alto de la imagen
	 * @return {XEngine.TilledImage}
	 */
	tilled: function (posX, posY, sprite, width, height) { //Creamos y añadimos una imagen que se puede tilear
		var gameObject = new XEngine.TilledImage(this.game, posX, posY, sprite, width, height);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade una imagen que hace la función de bottón
	 * @method XEngine.ObjectFacory#button
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} sprite - keyName de la imagen
	 * @param {String} spriteDown - keyName de la imagen cuando se pulsa el botón
	 * @param {String} spriteOver - keyName de la imagen cuando se pasa el ratón por encima
	 * @param {String} spriteUp - keyName de la imagen cuando se levanta el input
	 * @return {XEngine.Button}
	 */
	button: function (posX, posY, sprite, frameIdle, spriteDown, spriteOver, spriteUp) {
		var gameObject = new XEngine.Button(this.game, posX, posY, sprite, frameIdle, spriteDown, spriteOver, spriteUp);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade un rectangulo de color
	 * @method XEngine.ObjectFacory#rect
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {Number} width - ancho de la imagen
	 * @param {Number} height - alto de la imagen
	 * @param {String} color - color en hexadecimal con formato rgb
	 * @return {XEngine.Rect}
	 */
	rect: function (posX, posY, width, height, color) { //Creamos un rectangulo a partir de los datos proporcionados
		var gameObject = new XEngine.Rect(this.game, posX, posY, width, height, color);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade un circulo de color
	 * @method XEngine.ObjectFacory#circle
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {Number} width - ancho del circulo
	 * @param {Number} height - alto del circulo
	 * @return {XEngine.Circe}
	 */
	circle: function (posX, posY, width, height) { //Creamos un rectangulo a partir de los datos proporcionados
		var gameObject = new XEngine.Circle(this.game, posX, posY, width, height);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade un objeto de texto
	 * @method XEngine.ObjectFacory#text
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @param {String} text - texto a mostrar
	 * @param {Object} textStyle - objeto que contiene los parametros de estilo
	 * @return {XEngine.Text}
	 */
	text: function (posX, posY, text, textStyle) {
		var gameObject = new XEngine.Text(this.game, posX, posY, text, textStyle);
		return this.existing(gameObject, false, true);
	},

	/**
	 * Crea y añade un objeto de audio
	 * @method XEngine.ObjectFacory#audio
	 * @param {String} audio - keyName del archivo de audio a reproducir
	 * @param {Boolean} autoStart - indica si empieza al crearse o no
	 * @param {Number} volume - indica el volumen del audio;
	 * @return {XEngine.Audio}
	 */
	audio: function (audio, autoStart, volume) {
		var audioObject = new XEngine.Audio(this.game, audio, autoStart, volume);
		return this.existing(audioObject, true, false);
	},

	/**
	 * Crea y añade un contenedor de objetos
	 * @method XEngine.ObjectFacory#group
	 * @param {Number} posX - Posición X del objeto
	 * @param {Number} posY - Posición Y del objeto
	 * @return {XEngine.Group}
	 */
	group: function (posX, posY) { //Creamos y añadimos un grupo
		var x = posX || 0;
		var y = posY || 0;
		var gameObject = new XEngine.Group(this.game, x, y);
		return this.existing(gameObject, true, false);
	}
};<|endoftext|>


<commit_before>import { PureComponent } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import isEmpty from 'lodash/isEmpty';
import reducerRegistry from 'app/registry';
import { CancelToken } from 'axios';

import * as actions from './actions';
import reducers, { initialState } from './reducers';
import { getAreasProps } from './selectors';

class AreasProvider extends PureComponent {
  static propTypes = {
    areas: PropTypes.array,
    getAreas: PropTypes.func.isRequired,
    getArea: PropTypes.func.isRequired,
    loggedIn: PropTypes.bool,
    loading: PropTypes.bool,
    location: PropTypes.object
  };

  componentDidMount() {
    const { getArea, areas, loggedIn, location, loading } = this.props;
    if (!loading && isEmpty(areas) && loggedIn) {
      this.handleGetAreas();
    }

    if (!loading && !loggedIn && location.type === 'aoi') {
      getArea(location.adm0);
    }
  }

  componentDidUpdate(prevProps) {
    const { loggedIn, loading } = this.props;
    const { loggedIn: prevLoggedIn } = prevProps;

    if (!loading && loggedIn && loggedIn !== prevLoggedIn) {
      this.handleGetAreas();
    }
  }

  handleGetAreas = () => {
    const { getAreas } = this.props;
    this.cancelAreasFetch();
    this.areasFetch = CancelToken.source();

    getAreas(this.areasFetch.token);
  };

  cancelAreasFetch = () => {
    if (this.areasFetch) {
      this.areasFetch.cancel('Cancelling areas fetches');
    }
  };

  render() {
    return null;
  }
}

reducerRegistry.registerModule('areas', {
  actions,
  reducers,
  initialState
});

export default connect(getAreasProps, actions)(AreasProvider);
<commit_msg>check for areas when fetching single area<commit_after>import { PureComponent } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import isEmpty from 'lodash/isEmpty';
import reducerRegistry from 'app/registry';
import { CancelToken } from 'axios';

import * as actions from './actions';
import reducers, { initialState } from './reducers';
import { getAreasProps } from './selectors';

class AreasProvider extends PureComponent {
  static propTypes = {
    areas: PropTypes.array,
    getAreas: PropTypes.func.isRequired,
    getArea: PropTypes.func.isRequired,
    loggedIn: PropTypes.bool,
    loading: PropTypes.bool,
    location: PropTypes.object
  };

  componentDidMount() {
    const { getArea, areas, loggedIn, location, loading } = this.props;
    if (!loading && isEmpty(areas) && loggedIn) {
      this.handleGetAreas();
    }

    if (!loading && !loggedIn && isEmpty(areas) && location.type === 'aoi') {
      getArea(location.adm0);
    }
  }

  componentDidUpdate(prevProps) {
    const { loggedIn, loading } = this.props;
    const { loggedIn: prevLoggedIn } = prevProps;

    if (!loading && loggedIn && loggedIn !== prevLoggedIn) {
      this.handleGetAreas();
    }
  }

  handleGetAreas = () => {
    const { getAreas } = this.props;
    this.cancelAreasFetch();
    this.areasFetch = CancelToken.source();

    getAreas(this.areasFetch.token);
  };

  cancelAreasFetch = () => {
    if (this.areasFetch) {
      this.areasFetch.cancel('Cancelling areas fetches');
    }
  };

  render() {
    return null;
  }
}

reducerRegistry.registerModule('areas', {
  actions,
  reducers,
  initialState
});

export default connect(getAreasProps, actions)(AreasProvider);
<|endoftext|>


<commit_before>'use strict';

// Requirements
var npm = require('npm');
var changelog = require('changelog');
var cmp = require('semver-compare');
var async = require('async');
var chalk = require('chalk');

var rslt = {};
var showMax = false;

function worker(packages, unwanted) {
	if (unwanted) {
		showMax = true;
	}
	npm.load({
		parseable: false
	}, function(err, npm) {
		if (err) throw err;
		npm.commands.outdated(packages, function(err, data) {
			if (err) throw err;
			rslt = {};
			// For each npm outdated module
			async.forEachOf(data, workerChangelog, prettyData);

		});
	});
}

function workerChangelog(value, key, callback) {
	// Generate changelog
	changelog.generate(value[1])
		.then(function(data) {
			var tmpArray = [];
			// Keep only changelog versions between the current and the target
			if (data.versions.length) {
				data.versions.forEach(function(version) {
					if (cmp(version.version, value[2]) === 1 && (cmp(version.version, value[3]) <= 0 || showMax)) {
						tmpArray.push(version);
					}
				});
				data.versions = tmpArray;
			}
			// Generate terminal output
			rslt[value[1]] = changelog.terminal(data);
			callback();
		})
		.catch(function(err) {
            if (typeof err === 'string') {
                console.error(err);
            } else {
                throw err;
            }
            callback();
        })
        .done();

}

function prettyData(err) {
	if (err) throw err;
	async.forEachOf(rslt, function(value, key) {
		if (value.length) {
			printData('\r');
			printData(chalk.red(key));
		}
		printData(value);
	});
}

function printData(data) {
	console.info(data);
}

module.exports = worker;<commit_msg>fix(outdatedlog): handle missing version<commit_after>'use strict';

// Requirements
var npm = require('npm');
var changelog = require('changelog');
var cmp = require('semver-compare');
var async = require('async');
var chalk = require('chalk');

var rslt = {};
var showMax = false;

function worker(packages, unwanted) {
	if (unwanted) {
		showMax = true;
	}
	npm.load({
		parseable: false
	}, function(err, npm) {
		if (err) throw err;
		npm.commands.outdated(packages, function(err, data) {
			if (err) throw err;
			rslt = {};
			// For each npm outdated module
			async.forEachOf(data, workerChangelog, prettyData);

		});
	});
}

function workerChangelog(value, key, callback) {
	// Generate changelog
	changelog.generate(value[1])
		.then(function(data) {
			var tmpArray = [];
			// Keep only changelog versions between the current and the target
			if (data.versions.length && value[2]) {
				data.versions.forEach(function(version) {
					if (cmp(version.version, value[2]) === 1 && (cmp(version.version, value[3]) <= 0 || showMax)) {
						tmpArray.push(version);
					}
				});
			}
			data.versions = tmpArray;
			// Generate terminal output
			rslt[value[1]] = changelog.terminal(data);
			callback();
		})
		.catch(function(err) {
			if (typeof err === 'string') {
				console.error(err);
			}
			else {
				throw err;
			}
			callback();
		})
		.done();

}

function prettyData(err) {
	if (err) throw err;
	async.forEachOf(rslt, function(value, key) {
		if (value.length) {
			printData('\r');
			printData(chalk.red(key));
			printData(value);
		}
	});
}

function printData(data) {
	console.info(data);
}

module.exports = worker;<|endoftext|>


<commit_before>import React from "react";
import { Link } from "react-router";
import Loader from "../../core/Loader";
import DataComponent from "../base/DataComponent";
import DataError from "../base/DataError";
import ResourceAction from "../base/ResourceAction";
import Template from "../../core/Template";
import history from "../../history";

/**
 * @author Niklas Keller
 */
class ExperimentDetail extends DataComponent {
    getDataUri() {
        return "experiments/" + this.props.params.id;
    }

    componentWillReceiveProps(next) {
        let oldId = this.props.params.id;
        let newId = next.params.id;

        if (oldId !== newId) {
            this.fetchData();
        }
    }

    render() {
        let content = null;

        if (this.state.loaded) {
            if (this.state.failed) {
                content = (
                    <DataError />
                );
            } else {
                let editButton = this.state.data.state === "DRAFT" ? (
                    <Link to={this.props.location.pathname + "/edit"} className="action">

                        Edit
                    </Link>
                ) : null;

                let stateButton = null;

                if (this.state.data.state === "DRAFT") {
                    stateButton = (
                        <button className="action action-constructive" type="button"
                                disabled={this.state.data.populations.length === 0}
                                title={this.state.data.populations.length === 0 ? "Add at least one population to publish an experiment" : ""}
                                onClick={this._onPublishClick.bind(this)}>

                            Publish
                        </button>
                    );
                } else if (this.state.data.state === "PUBLISHED") {
                    stateButton = (
                        <button className="action action-destructive" type="button"
                                onClick={this._onAbortClick.bind(this)}>

                            Abort
                        </button>
                    );
                }

                let description = Object.keys(this.state.data.placeholders).length > 0
                    ? Template.apply(this.state.data.description, this.state.data.placeholders)
                    : this.state.data.description;

                content = (

                            {stateButton}

                            <Link className="action" to={this.props.location.pathname + "/platforms"}>

                                Edit Populations
                            </Link>

                            {editButton}

                            <ResourceAction icon="trash" method="DELETE" uri={"experiments/" + this.props.params.id}
                                            onClick={() => window.confirm("Do you really want to delete this experiment?")}
                                            onSuccess={() => history.replaceState(null, "/experiments")}
                                            onError={() => window.alert("Deletion failed.")}
                                            backend={this.props.backend}>
                                Delete
                            </ResourceAction>

Experiment: {this.state.data.title}

                        Parameters

                                Answer Type
                                {this.state.data.answerType === "TEXT" ? "Text" : "Images"}
                                Needed Answers
                                {this.state.data.neededAnswers || 0}

                                Answers / Worker
                                {this.state.data.answersPerWorker || 0}
                                Base Payment
                                {this.state.data.paymentBase || 0}

                                Ratings / Worker
                                {this.state.data.ratingsPerWorker || 0}
                                Payment / Answer
                                {this.state.data.paymentAnswer || 0}

                                Ratings / Answer
                                {this.state.data.ratingsPerAnswer || 0}
                                Payment / Rating
                                {this.state.data.paymentRating || 0}

                        Description

{description}

                );
            }
        }

        return (
            <Loader loaded={this.state.loaded} className="loader">
                {content}
            </Loader>
        );
    }

    _onPublishClick() {
        this.props.backend.request("PATCH", "experiments/" + this.props.params.id, {
            state: "PUBLISHED"
        }).then(() => {
            alert("Experiment has been published.");
        }).catch(() => {
            alert("Experiment could not be published.");
        });
    }

    _onAbortClick() {
        this.props.backend.request("PATCH", "experiments/" + this.props.params.id, {
            state: "CREATIVE_STOPPED"
        }).then(() => {
            alert("No more creative answers will be collected.");
        }).catch(() => {
            alert("Experiment could not be stopped.");
        });
    }
}

export default ExperimentDetail;<commit_msg>Encapsulate integer values in ExperimentDetail<commit_after>import React from "react";
import { Link } from "react-router";
import Loader from "../../core/Loader";
import DataComponent from "../base/DataComponent";
import DataError from "../base/DataError";
import ResourceAction from "../base/ResourceAction";
import Template from "../../core/Template";
import history from "../../history";

/**
 * @author Niklas Keller
 */
class ExperimentDetail extends DataComponent {
    getDataUri() {
        return "experiments/" + this.props.params.id;
    }

    componentWillReceiveProps(next) {
        let oldId = this.props.params.id;
        let newId = next.params.id;

        if (oldId !== newId) {
            this.fetchData();
        }
    }

    render() {
        let content = null;

        if (this.state.loaded) {
            if (this.state.failed) {
                content = (
                    <DataError />
                );
            } else {
                let editButton = this.state.data.state === "DRAFT" ? (
                    <Link to={this.props.location.pathname + "/edit"} className="action">

                        Edit
                    </Link>
                ) : null;

                let stateButton = null;

                if (this.state.data.state === "DRAFT") {
                    stateButton = (
                        <button className="action action-constructive" type="button"
                                disabled={this.state.data.populations.length === 0}
                                title={this.state.data.populations.length === 0 ? "Add at least one population to publish an experiment" : ""}
                                onClick={this._onPublishClick.bind(this)}>

                            Publish
                        </button>
                    );
                } else if (this.state.data.state === "PUBLISHED") {
                    stateButton = (
                        <button className="action action-destructive" type="button"
                                onClick={this._onAbortClick.bind(this)}>

                            Abort
                        </button>
                    );
                }

                let description = Object.keys(this.state.data.placeholders).length > 0
                    ? Template.apply(this.state.data.description, this.state.data.placeholders)
                    : this.state.data.description;

                content = (

                            {stateButton}

                            <Link className="action" to={this.props.location.pathname + "/platforms"}>

                                Edit Populations
                            </Link>

                            {editButton}

                            <ResourceAction icon="trash" method="DELETE" uri={"experiments/" + this.props.params.id}
                                            onClick={() => window.confirm("Do you really want to delete this experiment?")}
                                            onSuccess={() => history.replaceState(null, "/experiments")}
                                            onError={() => window.alert("Deletion failed.")}
                                            backend={this.props.backend}>
                                Delete
                            </ResourceAction>

Experiment: {this.state.data.title}

                        Parameters

                                Answer Type
                                {this.state.data.answerType === "TEXT" ? "Text" : "Images"}
                                Needed Answers
                                {this.state.data.neededAnswers.value}

                                Answers / Worker
                                {this.state.data.answersPerWorker.value}
                                Base Payment
                                {this.state.data.paymentBase.value}

                                Ratings / Worker
                                {this.state.data.ratingsPerWorker.value}
                                Payment / Answer
                                {this.state.data.paymentAnswer.value}

                                Ratings / Answer
                                {this.state.data.ratingsPerAnswer.value}
                                Payment / Rating
                                {this.state.data.paymentRating.value}

                        Description

{description}

                );
            }
        }

        return (
            <Loader loaded={this.state.loaded} className="loader">
                {content}
            </Loader>
        );
    }

    _onPublishClick() {
        this.props.backend.request("PATCH", "experiments/" + this.props.params.id, {
            state: "PUBLISHED"
        }).then(() => {
            alert("Experiment has been published.");
        }).catch(() => {
            alert("Experiment could not be published.");
        });
    }

    _onAbortClick() {
        this.props.backend.request("PATCH", "experiments/" + this.props.params.id, {
            state: "CREATIVE_STOPPED"
        }).then(() => {
            alert("No more creative answers will be collected.");
        }).catch(() => {
            alert("Experiment could not be stopped.");
        });
    }
}

export default ExperimentDetail;<|endoftext|>


<commit_before>
'use strict';

var path = require('path');
var platform = require('os').platform();
/* istanbul ignore next */
var HOME = platform !== 'win32' ? process.env.HOME : process.env.USERPROFILE;
var CONFDIR = path.join(HOME, '.storjshare');
var utils = require('./utils');
var merge = require('merge');
var fs = require('fs');
var storj = require('storj-lib');

/**
 * Config Manager
 * @constructor
 * @param {String} farmerId - farmers unique identifier
 * @param {Object} config - Optional config with params for the farmer
 * @param {Object} config.farmerConf -
 * @param {Object} config.telemetry -
 * @param {Integer} config.loglevel -
 * @param {Object} config.storage - storage config for farmer
 *
 */
function ConfigManager(farmerId, config) {
  if (!(this instanceof ConfigManager)) {
    return new ConfigManager(farmerId, config);
  }

  if (!farmerId) {
    throw new Error('A unique farmerId must be passed in');
  }

  this.id = farmerId;
  this.confPath = path.join(CONFDIR, farmerId+'-settings.json');
  this.config = this._readConf();

  if (config) {
    merge.recursive(
      this.config,
      config
    );
  }

}

/**
 * Load config from filesystem based on this.ConfPath
 */
ConfigManager.prototype._readConf = function() {
  var self = this;
  var parsed;
  if (!utils.existsSync(this.confPath)) {
    return merge.recursive(true, ConfigManager.DEFAULTS);
  }

  parsed = JSON.parse(fs.readFileSync(self.confPath).toString());

  return merge.recursive(Object.create(ConfigManager.DEFAULTS), parsed);

};

/**
 * Save the configuration at the given index
 */
ConfigManager.prototype.saveConfigSync = function() {
  fs.writeFileSync(this.confPath, JSON.stringify(this.config, null, 2));
};

/**
 * Save the configuration at the given index
 */
ConfigManager.prototype.saveConfig = function(callback) {
  fs.writeFile(this.confPath, JSON.stringify(this.config, null, 2), callback);
};

/**
 * Save the configuration at the given index
 */
ConfigManager.prototype.updateConfig = function(config) {
  merge.recursive(this.config, config);
};

/**
 * Returns a trimmed address
 */
ConfigManager.prototype.getAddress = function() {
  return this.config.farmerConf.paymentAddress.trim();
};

ConfigManager.DEFAULTS = {
  farmerConf: {
    keyPair: null, // Instance of KeyPair
    paymentAddress: '',
    storageManager: {}, // Instance of StorageManager
    rpcAddress: '127.0.0.1',
    maxOfferConcurrency: storj.FarmerInterface.DEFAULTS.maxOfferConcurrency,
    rpcPort: 0,
    maxConnections: storj.Network.DEFAULTS.maxConnections,
    seedList: [],
    renterWhitelist: [],
    doNotTraverseNat: true,
    logger: {}, // Instance of a logger
    tunnelServerPort: 0,
    maxTunnels: 0,
    tunnelGatewayRange: {
      max: 0,
      min: 0
    },
    opcodeSubscriptions: storj.FarmerInterface.DEFAULTS.opcodeSubscriptions
  },
  contracts: {
    total: 0
  },
  usedspace: {
    size: 0,
    unit: 'B'
  },
  remainingspace: {
    size: 0,
    unit: 'B'
  },
  connectedPeers: 0,
  telemetry: {
    service: 'https://status.storj.io',
    enabled: false
  },
  loglevel: 0,
  storage: {
    path: '',
    dataDir: '',
    size: 0,
    unit: 'GB'
  },
  pipe: true
};

module.exports = ConfigManager;
<commit_msg>Added bridgeUri default<commit_after>
'use strict';

var path = require('path');
var platform = require('os').platform();
/* istanbul ignore next */
var HOME = platform !== 'win32' ? process.env.HOME : process.env.USERPROFILE;
var CONFDIR = path.join(HOME, '.storjshare');
var utils = require('./utils');
var merge = require('merge');
var fs = require('fs');
var storj = require('storj-lib');

/**
 * Config Manager
 * @constructor
 * @param {String} farmerId - farmers unique identifier
 * @param {Object} config - Optional config with params for the farmer
 * @param {Object} config.farmerConf -
 * @param {Object} config.telemetry -
 * @param {Integer} config.loglevel -
 * @param {Object} config.storage - storage config for farmer
 *
 */
function ConfigManager(farmerId, config) {
  if (!(this instanceof ConfigManager)) {
    return new ConfigManager(farmerId, config);
  }

  if (!farmerId) {
    throw new Error('A unique farmerId must be passed in');
  }

  this.id = farmerId;
  this.confPath = path.join(CONFDIR, farmerId+'-settings.json');
  this.config = this._readConf();

  if (config) {
    merge.recursive(
      this.config,
      config
    );
  }

}

/**
 * Load config from filesystem based on this.ConfPath
 */
ConfigManager.prototype._readConf = function() {
  var self = this;
  var parsed;
  if (!utils.existsSync(this.confPath)) {
    return merge.recursive(true, ConfigManager.DEFAULTS);
  }

  parsed = JSON.parse(fs.readFileSync(self.confPath).toString());

  return merge.recursive(Object.create(ConfigManager.DEFAULTS), parsed);

};

/**
 * Save the configuration at the given index
 */
ConfigManager.prototype.saveConfigSync = function() {
  fs.writeFileSync(this.confPath, JSON.stringify(this.config, null, 2));
};

/**
 * Save the configuration at the given index
 */
ConfigManager.prototype.saveConfig = function(callback) {
  fs.writeFile(this.confPath, JSON.stringify(this.config, null, 2), callback);
};

/**
 * Save the configuration at the given index
 */
ConfigManager.prototype.updateConfig = function(config) {
  merge.recursive(this.config, config);
};

/**
 * Returns a trimmed address
 */
ConfigManager.prototype.getAddress = function() {
  return this.config.farmerConf.paymentAddress.trim();
};

ConfigManager.DEFAULTS = {
  farmerConf: {
    bridgeUri: 'https://api.storj.io',
    keyPair: null, // Instance of KeyPair
    paymentAddress: '',
    storageManager: {}, // Instance of StorageManager
    rpcAddress: '127.0.0.1',
    maxOfferConcurrency: storj.FarmerInterface.DEFAULTS.maxOfferConcurrency,
    rpcPort: 0,
    maxConnections: storj.Network.DEFAULTS.maxConnections,
    seedList: [],
    renterWhitelist: [],
    doNotTraverseNat: true,
    logger: {}, // Instance of a logger
    tunnelServerPort: 0,
    maxTunnels: 0,
    tunnelGatewayRange: {
      max: 0,
      min: 0
    },
    opcodeSubscriptions: storj.FarmerInterface.DEFAULTS.opcodeSubscriptions
  },
  contracts: {
    total: 0
  },
  usedspace: {
    size: 0,
    unit: 'B'
  },
  remainingspace: {
    size: 0,
    unit: 'B'
  },
  connectedPeers: 0,
  telemetry: {
    service: 'https://status.storj.io',
    enabled: false
  },
  loglevel: 0,
  storage: {
    path: '',
    dataDir: '',
    size: 0,
    unit: 'GB'
  },
  pipe: true
};

module.exports = ConfigManager;
<|endoftext|>


<commit_before>const { execFileSync } = require("child_process");
const fs = require("fs");
const { EOL } = require("os");
const path = require("path");

const BASE_DIR = path.join(__dirname, "..");
const TMP_DIR = path.join(BASE_DIR, "tmp") + path.sep;
const DEBUG = process.env.DEBUG === "true";
const PATH = path.join(process.cwd(), "node_modules", ".bin") + path.delimiter + process.env.PATH;

const log = (msg) => {
  if (DEBUG) {
    process.stdout.write(`${msg}${EOL}`);
  }
};

const $ = (cmd, ...args) => {
  const cmdArgs = args.filter((arg) => typeof arg === "string");
  const options = args.find((arg) => typeof arg === "object" && arg !== null) || {};
  log(`> ${cmd} '${cmdArgs.join("' '")}'`);
  const stdout = execFileSync(cmd, cmdArgs, {
    ...options,
    encoding: "utf8",
    env: { ...process.env, ...options.env, PATH },
  }).trim();
  const maxLines = 20;
  const lines = stdout.split(EOL);
  if (lines.length < maxLines) {
    log(stdout);
    return stdout;
  }
  const trimmed = lines.slice(0, maxLines).join(EOL);
  log(`${trimmed + EOL}(...)${EOL}`);
  return stdout;
};

const sandbox = (callback) => {
  if (!fs.existsSync(TMP_DIR)) {
    fs.mkdirSync(TMP_DIR);
  }

  const workDir = fs.mkdtempSync(TMP_DIR);
  try {
    process.chdir(workDir);
    return callback(workDir);
  } catch (err) {
    const { stdout, stderr } = err;
    if (typeof stdout === "string" && stdout !== "") {
      process.stdout.write(`> STDOUT =========================================${EOL}`);
      process.stdout.write(`${stdout}${EOL}`);
      process.stdout.write(`< STDOUT =========================================${EOL}`);
    }
    if (typeof stderr === "string" && stderr !== "") {
      process.stderr.write(`> STDERR =========================================${EOL}`);
      process.stderr.write(`${stderr}${EOL}`);
      process.stderr.write(`< STDERR =========================================${EOL}`);
    }
    throw err;
  } finally {
    process.chdir(BASE_DIR);
    fs.rmdirSync(TMP_DIR, { recursive: true });
  }
};

module.exports = { $, sandbox };
<commit_msg>refactor: test helper (#979)<commit_after>const { execFileSync } = require("child_process");
const { mkdirSync, mkdtempSync, rmdirSync } = require("fs");
const { EOL } = require("os");
const path = require("path");

const BASE_DIR = path.join(__dirname, "..");
const TMP_DIR = path.join(BASE_DIR, "tmp") + path.sep;
const DEBUG = process.env.DEBUG === "true";
const PATH = path.join(process.cwd(), "node_modules", ".bin") + path.delimiter + process.env.PATH;

const log = (msg) => {
  if (DEBUG) {
    process.stdout.write(`${msg}${EOL}`);
  }
};

const $ = (cmd, ...args) => {
  const cmdArgs = args.filter((arg) => typeof arg === "string");
  const options = args.find((arg) => typeof arg === "object" && arg !== null) || {};
  log(`> ${cmd} '${cmdArgs.join("' '")}'`);
  const stdout = execFileSync(cmd, cmdArgs, {
    ...options,
    encoding: "utf8",
    env: { ...process.env, ...options.env, PATH },
  }).trim();
  const maxLines = 20;
  const lines = stdout.split(EOL);
  if (lines.length < maxLines) {
    log(stdout);
    return stdout;
  }
  const trimmed = lines.slice(0, maxLines).join(EOL);
  log(`${trimmed + EOL}(...)${EOL}`);
  return stdout;
};

const sandbox = (callback) => {
  mkdirSync(TMP_DIR, { recursive: true });

  const workDir = mkdtempSync(TMP_DIR);
  try {
    process.chdir(workDir);
    return callback(workDir);
  } catch (err) {
    const { stdout, stderr } = err;
    if (typeof stdout === "string" && stdout !== "") {
      process.stdout.write(`> STDOUT =========================================${EOL}`);
      process.stdout.write(`${stdout}${EOL}`);
      process.stdout.write(`< STDOUT =========================================${EOL}`);
    }
    if (typeof stderr === "string" && stderr !== "") {
      process.stderr.write(`> STDERR =========================================${EOL}`);
      process.stderr.write(`${stderr}${EOL}`);
      process.stderr.write(`< STDERR =========================================${EOL}`);
    }
    throw err;
  } finally {
    process.chdir(BASE_DIR);
    rmdirSync(TMP_DIR, { recursive: true });
  }
};

module.exports = { $, sandbox };
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {Panel, Grid, Row, Col, Button, FormControl} from 'react-bootstrap';

class SetDialog extends Component {
  render() {
    return (
      <Panel header='Settings'>
        <Grid>

          <Row>
            <Col md={2}>Ro</Col>
            <Col md={1}>
              <FormControl type='text' value={16}/>
            </Col>
            <Col md={2}>Ry</Col>
            <Col md={1}>
              <FormControl type='text' value={16}/>
            </Col>
          </Row>

          <Row>
            <Col md={2}>Threading size</Col>
            <Col md={1}>
              <FormControl type='text' value={16}/>
            </Col>
            <Col md={2}>Treadling size</Col>
            <Col md={1}>
              <FormControl type='text' value={16}/>
            </Col>
          </Row>

          <Row>
            <Col md={2}>Element size</Col>
            <Col md={1}>
              <FormControl type='text' value={16}/>
            </Col>
            <Col md={2} />
            <Col md={1} />
          </Row>

          <Row>
            <Col md={2} />
            <Col md={1} />
            <Col md={2} />
            <Col md={1}>
              <Button>OK</Button>
            </Col>
          </Row>

        </Grid>
      </Panel>
    );
  }
}

export default SetDialog;
<commit_msg>Added handlers<commit_after>import React, { Component } from 'react';
import {Panel, Grid, Row, Col, Button, FormControl} from 'react-bootstrap';

class SetDialog extends Component {
  constructor() {
    super();
    this.state = {
      ro: '16',
      ry: '16',
      threadingSize: '16',
      treadlingSize: '16',
      elementSize: '16'
    };

    this.handleOkClick = this.handleOkClick.bind(this);
  }

  handleOkClick() {
    console.log('ok!');
  }

  render() {
    return (
      <Panel header='Settings'>
        <Grid>

          <Row>
            <Col md={2}>Ro</Col>
            <Col md={1}>
              <FormControl
                type='text'
                value={this.state.ro}
                onChange={(e) => {this.setState({ro: e.target.value})}} />
            </Col>
            <Col md={2}>Ry</Col>
            <Col md={1}>
              <FormControl
                type='text'
                value={this.state.ry}
                onChange={(e) => {this.setState({ry: e.target.value})}} />
            </Col>
          </Row>

          <Row>
            <Col md={2}>Threading size</Col>
            <Col md={1}>
              <FormControl
                type='text'
                value={this.state.threadingSize}
                onChange={(e) => {this.setState({threadingSize: e.target.value})}} />
            </Col>
            <Col md={2}>Treadling size</Col>
            <Col md={1}>
              <FormControl
                type='text'
                value={this.state.treadlingSize}
                onChange={(e) => {this.setState({treadlingSize: e.target.value})}} />
            </Col>
          </Row>

          <Row>
            <Col md={2}>Element size</Col>
            <Col md={1}>
              <FormControl
                type='text'
                value={this.state.elementSize}
                onChange={(e) => {this.setState({elementSize: e.target.value})}} />
            </Col>
            <Col md={2} />
            <Col md={1} />
          </Row>

          <Row>
            <Col md={2} />
            <Col md={1} />
            <Col md={2} />
            <Col md={1}>
              <Button onClick={this.handleOkClick}>OK</Button>
            </Col>
          </Row>

        </Grid>
      </Panel>
    );
  }
}

export default SetDialog;
<|endoftext|>


<commit_before><commit_msg>skipping board game phase for maths skills<commit_after><|endoftext|>


<commit_before>import React, { PropTypes, Component } from 'react';
import ProfileData from './ProfileData'

export default class OtherProfileDataList extends Component {

    static propTypes = {
        profileWithMetadata: PropTypes.array.isRequired
    };

    render() {
        const {profileWithMetadata} = this.props;
        let lines = [];
        profileWithMetadata.forEach(
            category => {
                if (Object.keys(category.fields).length === 0 || !Object.keys(category.fields).some(profileDataKey => category.fields[profileDataKey].value)) {
                    return;
                }
                lines.push(

{category.label}

);
                Object.keys(category.fields).forEach(
                    profileDataKey => {
                        if (category.fields[profileDataKey].value) {
                            lines.push(<ProfileData key={profileDataKey} name={category.fields[profileDataKey].text} value={category.fields[profileDataKey].value} forceLong={category.fields[profileDataKey].value === 'textarea'}/>);
                        }
                    });
            });
        return (

                {lines}

        );
    }

}
<commit_msg>QS-1189: Copy/Paste typo<commit_after>import React, { PropTypes, Component } from 'react';
import ProfileData from './ProfileData'

export default class OtherProfileDataList extends Component {

    static propTypes = {
        profileWithMetadata: PropTypes.array.isRequired
    };

    render() {
        const {profileWithMetadata} = this.props;
        let lines = [];
        profileWithMetadata.forEach(
            category => {
                if (Object.keys(category.fields).length === 0 || !Object.keys(category.fields).some(profileDataKey => category.fields[profileDataKey].value)) {
                    return;
                }
                lines.push(

{category.label}

);
                Object.keys(category.fields).forEach(
                    profileDataKey => {
                        if (category.fields[profileDataKey].value) {
                            lines.push(<ProfileData key={profileDataKey} name={category.fields[profileDataKey].text} value={category.fields[profileDataKey].value} forceLong={category.fields[profileDataKey].type === 'textarea'}/>);
                        }
                    });
            });
        return (

                {lines}

        );
    }

}
<|endoftext|>


<commit_before>/**
 * Common tools for test
 */

var chance = require('chance').Chance();
var populator = require('../index.js');
var dbUtil = require('../helper');
var async = require('async');
var MongoClient = require('mongodb').MongoClient;
var debug = require('debug')('dataset:testUtil');

var defaultOptions = {
  host: 'localhost',
  port: '27017',
  db: 'test',
  collection: 'dataset'
};

var regex = {
  phone: /(\(\d{3}\)\s*)(\d{3})-(\d{4})/,
  exp: /(\d{2})\/(\d{4})/
};

// close the connection, drop the test collection
function tearDown (connection, fn) {
  connection.collection.drop();
  connection.db.close();
  if (typeof fn === 'function') fn();
}

// connects to the target collection, and possibly clear its content
function setUp (testOpts, callback) {
  var opts = merge_objects(defaultOptions, testOpts);
  dbUtil.parseUserOpts(opts, function (opts) {
    MongoClient.connect(opts.uri, opts.clientOptions, function(err, db) {
      debug('INFO: connected to MongoDB @ ', opts.uri);
      if(err) return callback(err);
      var collection = db.collection(opts.collection);
      collection.remove({}, function(err, res) {
        if(err) return callback(err);
        populator(opts, function () {
          var connection = {
            db: db,
            collection: collection
          };
          callback(null, connection);
        });
      });
    });
  });
}

function getResults (testOpts, callback) {
  setUp(testOpts, function (err, connection) {
    if (err) return callback(err);
    connection.collection.find().toArray(function (err, items) {
      if (err) return callback(err);
      callback(null, items);
      tearDown(connection);
    });
  });
}

function merge_objects(defaults, instance) {
  var obj3 = {}, attrname;
  for (attrname in defaults) { obj3[attrname] = defaults[attrname]; }
  for (attrname in instance) { obj3[attrname] = instance[attrname]; }
  return obj3;
}

function sampleAndStrip(array, count, fn) {
  var sample = chance.pick(array, count);
  async.each(sample,
    function (item, callback) {
      item._id = undefined;
      callback();
    },
    function (err) {
      if (err) throw err;
      fn(sample);
  });
}

// test utility functions
module.exports.setUp = setUp;
module.exports.tearDown = tearDown;
// general utilities
module.exports.sampleAndStrip = sampleAndStrip;
module.exports.regex = regex;
module.exports.mergeObjects = merge_objects;
module.exports.getResults = getResults;
<commit_msg>use _.defaults<commit_after>/**
 * Common tools for test
 */

var chance = require('chance').Chance();
var populator = require('../index.js');
var dbUtil = require('../helper');
var async = require('async');
var MongoClient = require('mongodb').MongoClient;
var debug = require('debug')('dataset:testUtil');
var _ = require('underscore');

var defaults = {
  host: 'localhost',
  port: '27017',
  db: 'test',
  collection: 'dataset'
};

var regex = {
  phone: /(\(\d{3}\)\s*)(\d{3})-(\d{4})/,
  exp: /(\d{2})\/(\d{4})/
};

// close the connection, drop the test collection
function tearDown (connection, fn) {
  connection.collection.drop();
  connection.db.close();
  if (typeof fn === 'function') fn();
}

// connects to the target collection, and possibly clear its content
function setUp (testOpts, callback) {
  var opts = _.defaults(testOpts, defaults);
  dbUtil.parseUserOpts(opts, function (opts) {
    MongoClient.connect(opts.uri, opts.clientOptions, function(err, db) {
      debug('INFO: connected to MongoDB @ ', opts.uri);
      if(err) return callback(err);
      var collection = db.collection(opts.collection);
      collection.remove({}, function(err, res) {
        if(err) return callback(err);
        populator(opts, function () {
          var connection = {
            db: db,
            collection: collection
          };
          callback(null, connection);
        });
      });
    });
  });
}

function getResults (testOpts, callback) {
  setUp(testOpts, function (err, connection) {
    if (err) return callback(err);
    connection.collection.find().toArray(function (err, items) {
      if (err) return callback(err);
      callback(null, items);
      tearDown(connection);
    });
  });
}

function sampleAndStrip(array, count, fn) {
  var sample = chance.pick(array, count);
  async.each(sample,
    function (item, callback) {
      item._id = undefined;
      callback();
    },
    function (err) {
      if (err) throw err;
      fn(sample);
  });
}

// test utility functions
module.exports.setUp = setUp;
module.exports.tearDown = tearDown;
// general utilities
module.exports.sampleAndStrip = sampleAndStrip;
module.exports.regex = regex;
module.exports.getResults = getResults;
<|endoftext|>


<commit_before>'use strict';

const fse = require('fs-extra');

const { examplesDir } = require('./config');
const pageBuilderUtils = require('./pageBuilderUtils');
const processor = require('./processor');
const tabbedPageBuilder = require('./tabbedPageBuilder');

/**
 * Traverse the list of pages, and uses the meta data to generate the final
 * HTML source documents to `/docs/pages/[css|js]`
 * @param {object} pages - An object containing directives for building the pages
 *
 * Example object:
 *
 * "borderTopColor": {
 *     "baseTmpl": "tmpl/live-css-tmpl.html",
 *     "cssExampleSrc": "../../live-examples/css-examples/css/border-top-color.css",
 *     "exampleCode": "live-examples/css-examples/border-top-color.html",
 *     "fileName": "border-top-color.html",
 *     "type": "css"
 * }
 *
 */
function buildPages(pages) {
    for (let page in pages) {
        let currentPage = pages[page];
        let cssSource = currentPage.cssExampleSrc;
        let jsSource = currentPage.jsExampleSrc;
        let tmpl = fse.readFileSync(currentPage.baseTmpl, 'utf-8');
        let type = currentPage.type;
        let outputHTML = '';

        const exampleCode = fse.readFileSync(currentPage.exampleCode, 'utf-8');
        const outputPath =
            examplesDir + currentPage.type + '/' + currentPage.fileName;

        if (type === 'tabbed') {
            fse.outputFileSync(
                outputPath,
                tabbedPageBuilder.buildTabbedExample(tmpl, currentPage)
            );
            return;
        }

        // is there a linked CSS file
        if (cssSource) {
            // inject the link tag into the source
            tmpl = processor.processInclude('css', tmpl, cssSource);
        } else {
            // clear out the template string
            tmpl = tmpl.replace('%example-css-src%', '');
        }

        // is there a linked JS file
        if (jsSource) {
            // inject the script tag into the source
            tmpl = processor.processInclude('js', tmpl, jsSource);
        } else {
            // clear out the template string
            tmpl = tmpl.replace('%example-js-src%', '');
        }

        // set main title
        tmpl = pageBuilderUtils.setMainTitle(currentPage, tmpl);

        if (currentPage.type === 'html') {
            let processedHTML = processor.preprocessHTML(exampleCode);
            /* Note: Using String.prototype.replace's replacement function instead of
            replacement string at 2nd argument because replacement string has weird
            behavior to $ (dollar sign). More info:
            https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter */
            outputHTML = tmpl.replace('%example-code%', () => processedHTML);
        } else {
            outputHTML = tmpl.replace('%example-code%', () => exampleCode);
        }

        fse.outputFileSync(outputPath, outputHTML);
    }
}

module.exports = {
    buildPages
};
<commit_msg>Allow more than one tabbed example (#614)<commit_after>'use strict';

const fse = require('fs-extra');

const { examplesDir } = require('./config');
const pageBuilderUtils = require('./pageBuilderUtils');
const processor = require('./processor');
const tabbedPageBuilder = require('./tabbedPageBuilder');

/**
 * Traverse the list of pages, and uses the meta data to generate the final
 * HTML source documents to `/docs/pages/[css|js]`
 * @param {object} pages - An object containing directives for building the pages
 *
 * Example object:
 *
 * "borderTopColor": {
 *     "baseTmpl": "tmpl/live-css-tmpl.html",
 *     "cssExampleSrc": "../../live-examples/css-examples/css/border-top-color.css",
 *     "exampleCode": "live-examples/css-examples/border-top-color.html",
 *     "fileName": "border-top-color.html",
 *     "type": "css"
 * }
 *
 */
function buildPages(pages) {
    for (let page in pages) {
        let currentPage = pages[page];
        let cssSource = currentPage.cssExampleSrc;
        let jsSource = currentPage.jsExampleSrc;
        let tmpl = fse.readFileSync(currentPage.baseTmpl, 'utf-8');
        let type = currentPage.type;
        let outputHTML = '';

        const exampleCode = fse.readFileSync(currentPage.exampleCode, 'utf-8');
        const outputPath =
            examplesDir + currentPage.type + '/' + currentPage.fileName;

        if (type === 'tabbed') {
            fse.outputFileSync(
                outputPath,
                tabbedPageBuilder.buildTabbedExample(tmpl, currentPage)
            );
        } else {
            // is there a linked CSS file
            if (cssSource) {
                // inject the link tag into the source
                tmpl = processor.processInclude('css', tmpl, cssSource);
            } else {
                // clear out the template string
                tmpl = tmpl.replace('%example-css-src%', '');
            }

            // is there a linked JS file
            if (jsSource) {
                // inject the script tag into the source
                tmpl = processor.processInclude('js', tmpl, jsSource);
            } else {
                // clear out the template string
                tmpl = tmpl.replace('%example-js-src%', '');
            }

            // set main title
            tmpl = pageBuilderUtils.setMainTitle(currentPage, tmpl);

            if (currentPage.type === 'html') {
                let processedHTML = processor.preprocessHTML(exampleCode);
                /* Note: Using String.prototype.replace's replacement function instead of
                replacement string at 2nd argument because replacement string has weird
                behavior to $ (dollar sign). More info:
                https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter */
                outputHTML = tmpl.replace('%example-code%', () => processedHTML);
            } else {
                outputHTML = tmpl.replace('%example-code%', () => exampleCode);
            }

            fse.outputFileSync(outputPath, outputHTML);
        }
    }
}

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


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import {StickyContainer, Sticky} from 'react-sticky';
import CodeBlock from '../components/CodeBlock';
import Swipeable from 'react-swipeable';

const Blockquote = (props) => {
  return (

        {props.quote.ja}

        {props.quote.en}

          {props.name.ja}
        {' '}

          {props.name.en}

  );
};

Blockquote.propTypes = {
  quote: PropTypes.object.isRequired,
  name: PropTypes.object.isRequired,
};

const CodeBlockWrapper = (props) => {
  return (

          HTML

        <CodeBlock rounded={false} language="html">
          {'<link href="https://fonts.googleapis.com/earlyaccess/' +
            props.font +
            '.css" rel="stylesheet" />'}
        </CodeBlock>

          CSS

        <CodeBlock rounded={false} language="css">
          {'.wf-' +
            props.font +
            ' { font-family: "' +
            (props.google_fonts_id || props.name.en || props.name.ja) +
            '"; }'}
        </CodeBlock>

  );
};

CodeBlockWrapper.defaultProps = {};
CodeBlockWrapper.propTypes = {
  font: PropTypes.object.isRequired,
  google_fonts_id: PropTypes.string,
  name: PropTypes.object,
};

const SidebarArrow = (props) => {
  let className = `pb2 speak-none select-none ${!props.visible ? 'hide' : ''}`;

  // Arrow SVG via Apache 2.0 via https://design.google.com/icons/#ic_arrow_forward */}
  return (

      <span
        className="inline-block"
        style={{
          transform: `rotate(${props.deg}deg)`,
          transition: 'transform 0.5s 0.15s ease-in-out',
        }}>
        <svg height="24" viewBox="0 0 24 24" width="24">
          <path d="M0 0h24v24H0z" fill="none" />
          <path
            d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"
            fill="inherit"
          />
        </svg>

  );
};

SidebarArrow.defaultProps = {
  visible: false,
  deg: 0,
};

SidebarArrow.propTypes = {
  visible: PropTypes.bool.isRequired,
  deg: PropTypes.number.isRequired,
};

const MainWrapper = (props) => {
  return (

{props.children[0]}

        {props.children[1]}

  );
};

MainWrapper.propTypes = {
  children: PropTypes.array.isRequired,
};

class SidebarColophon extends React.Component {
  getColorClasses() {
    const props = this.props;

    let classes = [];

    if (props.backgroundColor === 'white') {
      classes.push('bg-white');
    } else {
      classes.push('bg-lighten-3');
    }

    if (props.backgroundColor === 'black' || props.backgroundColor === 'gray') {
      classes.push('white fill-white');
    } else {
      classes.push('');
    }

    return classes.join(' ');
  }

  render() {
    const props = this.props;
    let data = props.data;
    let font = data.fonts[props.font];
    let desc = null;
    let quote = null;
    let codeBlock = null;
    let sidebarStyle = {};
    let fontNameHeading = font.name.ja;
    let sidebarLargeScreen = props.viewport.width > props.sidebarMaxWidth;

    let fontNameEn =
      font.name.ja === font.name.en ? (

      ) : (

          {font.name.en}

      );
    let fontDesignerNameEn =
      font.designer.name.ja === font.designer.name.en ? (
        ''
      ) : (

          {' '}
          {font.designer.name.en}

      );

    if (sidebarLargeScreen) {
      sidebarStyle.left = 0;
    } else {
      sidebarStyle.left = (props.show ? 25 : 83.3333333) + '%';
    }

    // TODO switch to toggle
    // There are no translated versions of the descriptions right now
    // if (font.description) {
    //   if (font.description.ja && font.description.en) {
    //     desc =

{font.description.ja}

{font.description.en}

    //   } else {
    //     desc =

{font.description.en ? font.description.en : font.description.ja}

    //   }
    // }
    if (font.description && font.description.en) {
      desc = (

          {font.description.en}

      );
    }

    if (font.designer.quote.ja || font.designer.quote.en) {
      quote = (

      );
    }

    if (props.showCodeBlock !== false) {
      codeBlock = <CodeBlockWrapper font={props.font} {...font} />;
    }

    return (
      <StickyContainer style={{zIndex: 5, overflow: 'hidden'}}>
        <MainWrapper>
          {props.children}

            <Sticky
              style={{zIndex: 10, height: 0}}
              onClick={props.onClickSidebar}>
              {({style}) => {
                // bottomOffset could be set to this computed height
                return (
                  <div style={style} className={`bg-${props.backgroundColor}`}>
                    <Swipeable
                      onSwipedLeft={props.onSwipedLeft}
                      onSwipedRight={props.onSwipedRight}>

                        <div
                          className={`h5 md-h4 animate-bg bg-${
                            props.backgroundColor
                          }`}
                          style={{height: `100vh`}}>
                          <div
                            className={`p2 md-p3 animate-bg transition-color transition-sidebar ${this.getColorClasses()}}`}
                            style={{minHeight: `100vh`}}>
                            <SidebarArrow
                              visible={!sidebarLargeScreen}
                              deg={props.show ? 540 : 0}
                            />

                              {fontNameHeading}
                              {fontNameEn}

                            {/* Fixes heights so the changing content is less jarring */}
                            {/* TODO might need to change this minHeight based on CSS breakpoints */}

                              {desc}

                              {quote}

                            {codeBlock}

                    </Swipeable>

                );
              }}
            </Sticky>

        </MainWrapper>
      </StickyContainer>
    );
  }
}

SidebarColophon.defaultProps = {
  backgroundColor: 'silver',
  onClickSidebar: false,
  onSwipedLeft: false,
  onSwipedRight: false,
  showCodeBlock: true,
  viewport: {
    width: 1024,
    height: 768,
  },
};

SidebarColophon.propTypes = {
  backgroundColor: PropTypes.string,
  onClickSidebar: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
  onSwipedLeft: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
  onSwipedRight: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
  showCodeBlock: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
  viewport: PropTypes.object.isRequired,
  children: PropTypes.object.isRequired,
};

export default SidebarColophon;
<commit_msg>Improves conditional display of earlyAccess code sample<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import {StickyContainer, Sticky} from 'react-sticky';
import CodeBlock from '../components/CodeBlock';
import Swipeable from 'react-swipeable';

const Blockquote = (props) => {
  return (

        {props.quote.ja}

        {props.quote.en}

          {props.name.ja}
        {' '}

          {props.name.en}

  );
};

Blockquote.propTypes = {
  quote: PropTypes.object.isRequired,
  name: PropTypes.object.isRequired,
};

const CodeBlockWrapper = (props) => {
  let cssHref = `https://fonts.googleapis.com/css?family=${props.google_fonts_id.split(' ').join('+')}`

  if (props.earlyAccess === true) {
    cssHref = `https://fonts.googleapis.com/earlyaccess/${props.google_fonts_id.toLowerCase()}.css`
  }

  return (

          HTML

        <CodeBlock rounded={false} language="html">
          {`<link href="${cssHref}" rel="stylesheet">`}
        </CodeBlock>

          CSS

        <CodeBlock rounded={false} language="css">
          {'.wf-' +
            props.font +
            ' { font-family: "' +
            (props.google_fonts_id || props.name.en || props.name.ja) +
            '"; }'}
        </CodeBlock>

  );
};

CodeBlockWrapper.defaultProps = {
  earlyAccess: false
};

CodeBlockWrapper.propTypes = {
  font: PropTypes.object.isRequired,
  google_fonts_id: PropTypes.string.isRequired,
  earlyAccess: PropTypes.bool,
  name: PropTypes.object,
};

const SidebarArrow = (props) => {
  let className = `pb2 speak-none select-none ${!props.visible ? 'hide' : ''}`;

  // Arrow SVG via Apache 2.0 via https://design.google.com/icons/#ic_arrow_forward */}
  return (

      <span
        className="inline-block"
        style={{
          transform: `rotate(${props.deg}deg)`,
          transition: 'transform 0.5s 0.15s ease-in-out',
        }}>
        <svg height="24" viewBox="0 0 24 24" width="24">
          <path d="M0 0h24v24H0z" fill="none" />
          <path
            d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"
            fill="inherit"
          />
        </svg>

  );
};

SidebarArrow.defaultProps = {
  visible: false,
  deg: 0,
};

SidebarArrow.propTypes = {
  visible: PropTypes.bool.isRequired,
  deg: PropTypes.number.isRequired,
};

const MainWrapper = (props) => {
  return (

{props.children[0]}

        {props.children[1]}

  );
};

MainWrapper.propTypes = {
  children: PropTypes.array.isRequired,
};

class SidebarColophon extends React.Component {
  getColorClasses() {
    const props = this.props;

    let classes = [];

    if (props.backgroundColor === 'white') {
      classes.push('bg-white');
    } else {
      classes.push('bg-lighten-3');
    }

    if (props.backgroundColor === 'black' || props.backgroundColor === 'gray') {
      classes.push('white fill-white');
    } else {
      classes.push('');
    }

    return classes.join(' ');
  }

  render() {
    const props = this.props;
    let data = props.data;
    let font = data.fonts[props.font];
    let desc = null;
    let quote = null;
    let codeBlock = null;
    let sidebarStyle = {};
    let fontNameHeading = font.name.ja;
    let sidebarLargeScreen = props.viewport.width > props.sidebarMaxWidth;

    let fontNameEn =
      font.name.ja === font.name.en ? (

      ) : (

          {font.name.en}

      );
    let fontDesignerNameEn =
      font.designer.name.ja === font.designer.name.en ? (
        ''
      ) : (

          {' '}
          {font.designer.name.en}

      );

    if (sidebarLargeScreen) {
      sidebarStyle.left = 0;
    } else {
      sidebarStyle.left = (props.show ? 25 : 83.3333333) + '%';
    }

    // TODO switch to toggle
    // There are no translated versions of the descriptions right now
    // if (font.description) {
    //   if (font.description.ja && font.description.en) {
    //     desc =

{font.description.ja}

{font.description.en}

    //   } else {
    //     desc =

{font.description.en ? font.description.en : font.description.ja}

    //   }
    // }
    if (font.description && font.description.en) {
      desc = (

          {font.description.en}

      );
    }

    if (font.designer.quote.ja || font.designer.quote.en) {
      quote = (

      );
    }

    if (props.showCodeBlock !== false) {
      codeBlock = <CodeBlockWrapper font={props.font} {...font} />;
    }

    return (
      <StickyContainer style={{zIndex: 5, overflow: 'hidden'}}>
        <MainWrapper>
          {props.children}

            <Sticky
              style={{zIndex: 10, height: 0}}
              onClick={props.onClickSidebar}>
              {({style}) => {
                // bottomOffset could be set to this computed height
                return (
                  <div style={style} className={`bg-${props.backgroundColor}`}>
                    <Swipeable
                      onSwipedLeft={props.onSwipedLeft}
                      onSwipedRight={props.onSwipedRight}>

                        <div
                          className={`h5 md-h4 animate-bg bg-${
                            props.backgroundColor
                          }`}
                          style={{height: `100vh`}}>
                          <div
                            className={`p2 md-p3 animate-bg transition-color transition-sidebar ${this.getColorClasses()}}`}
                            style={{minHeight: `100vh`}}>
                            <SidebarArrow
                              visible={!sidebarLargeScreen}
                              deg={props.show ? 540 : 0}
                            />

                              {fontNameHeading}
                              {fontNameEn}

                            {/* Fixes heights so the changing content is less jarring */}
                            {/* TODO might need to change this minHeight based on CSS breakpoints */}

                              {desc}

                              {quote}

                            {codeBlock}

                    </Swipeable>

                );
              }}
            </Sticky>

        </MainWrapper>
      </StickyContainer>
    );
  }
}

SidebarColophon.defaultProps = {
  backgroundColor: 'silver',
  onClickSidebar: false,
  onSwipedLeft: false,
  onSwipedRight: false,
  showCodeBlock: true,
  viewport: {
    width: 1024,
    height: 768,
  },
};

SidebarColophon.propTypes = {
  backgroundColor: PropTypes.string,
  onClickSidebar: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
  onSwipedLeft: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
  onSwipedRight: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
  showCodeBlock: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
  viewport: PropTypes.object.isRequired,
  children: PropTypes.object.isRequired,
};

export default SidebarColophon;
<|endoftext|>


<commit_before>/*
 * Translated default messages for bootstrap-select.
 * Locale: PT (Portuguese; português)
 * Region: BR (Brazil; Brasil)
 * Author: Rodrigo de Avila <rodrigo@avila.net.br>
 */
(function ($) {
  $.fn.selectpicker.defaults = {
    noneSelectedText: 'Nada selecionado',
    noneResultsText: 'Nada encontrado contendo {0}',
    countSelectedText: 'Selecionado {0} de {1}',
    maxOptionsText: ['Limite excedido (máx. {n} {var})', 'Limite do grupo excedido (máx. {n} {var})', ['itens', 'item']],
    multipleSeparator: ', ',
    selectAllText: 'Selecionar Tudo',
    deselectAllText: 'Desmarcar Todos'
  };
})(jQuery);
<commit_msg>pt_BR translation<commit_after>/*
 * Translated default messages for bootstrap-select.
 * Locale: PT (Portuguese; português)
 * Region: BR (Brazil; Brasil)
 * Author: Rodrigo de Avila <rodrigo@avila.net.br>
 */
(function ($) {
  $.fn.selectpicker.defaults = {
    noneSelectedText: 'Nada selecionado',
    noneResultsText: 'Nada encontrado contendo {0}',
    countSelectedText: 'Selecionado {0} de {1}',
    maxOptionsText: ['Limite excedido (máx. {n} {var})', 'Limite do grupo excedido (máx. {n} {var})', ['itens', 'item']],
    multipleSeparator: ', ',
    selectAllText: 'Selecionar Todos',
    deselectAllText: 'Desmarcar Todos'
  };
})(jQuery);
<|endoftext|>


<commit_before>// Evaluate configuration of supervisor, based on command line options,
// strong-cluster-control configuration, and strong-agent configuration.

var cluster = require('cluster');
var control = require('strong-cluster-control');
var dotenv = require('dotenv');
var fs = require('fs');
var path = require('path');
var open = require('fs').openSync;
var transformer = require('strong-log-transformer');
var Logger = require('./logger');

var logger = new Logger(process.stderr);

if(cluster.isWorker) {
  module.exports = control.loadOptions();
  module.exports.profile = process.env.supervisor_profile != 'false';
  return;
}

var detach = require('./detach');
var options = require('./options').parse(process.argv);
var pidfile = require('./pidfile');
var LogWriter = require('./log-writer');
var generateLogName = require('./logname').generate;
var SysLogStream = options.syslog && require('./syslog-stream');

if(options.help) {
  console.log(options.HELP, '\n');
  process.exit(0);
}

if(options.version) {
  console.log('v%s', require('../package.json').version);
  process.exit(0);
}

// Reset argv to include only the options for the runner before letting
// cluster-control look for its configuration (it examines process.argv).
process.argv = options.argv;
var config = control.loadOptions({
  cluster: process.env.NODE_ENV === 'production' ? 'CPUs' : undefined
});

// Allow module consumers to use our logger
config.logger = logger;

// Reset argv so the runner options are not seen by app
process.argv = process.argv.slice(0, 2).concat(options.args);

// Communicate profile option to the worker using the environment, and master
// using config.
process.env.supervisor_profile = options.profile;
config.profile = options.profile;

// Communicate detach option to the master using config.
config.detach = options.detach;

var app = process.argv[2];
var dirname, basename;

try {
  var stat = fs.statSync(app);
} catch(er) {
  console.error('Invalid app (%s), try `%s --help`.\n', er, options.NAME);
  process.exit(1);
}

// We want to be in the directory of the file we are running, so we can pick up
// configuration stored in it's working directory.

if(stat.isFile()) {
  // The app is a file, we'll run it from its directory.
  process.chdir(path.dirname(app));
  app = path.basename(app);
}

if(stat.isDirectory()) {
  // The app is a directory (such as '.'), we'll look for what to run from it.
  process.chdir(app);

  // The canonical way to run is with `npm start`, but we can't do that for a
  // cluster worker, because the worker must start the runner (so it can require
  // strong-agent). Instead, we search for a runnable file, and if that fails,
  // just require the directory and let node do the right thing (which should be
  // to use package.main if it exists, index.js otherwise).
  function existing(file) {
    return fs.existsSync(file) ? file : null;
  }
  app = existing('server.js') || existing('app.js') || '.';
}

options.args[0] = app;
process.argv[2] = app;

// Load the app's .env after we are in its working directory, and before
// cluster.setupMaster() snapshots the environment.
dotenv.load();

cluster.setupMaster({
  // XXX(rmg): node 0.11.x broke compatibility with 0.10.x for when process.argv
  //           is read and loaded into cluster.settings, so we have to manually
  //           reset args, exec, and execArgv after our changes
  //           see https://github.com/joyent/node/pull/7682 for upstream fix.
  args: process.argv.slice(2),
  exec: process.argv[1],
  execArgv: process.execArgv,
  // All worker output is being processed as individual log streams, so we can't
  // just let the supervisor's stdout/stderr be inherited.
  silent: true,
});

var supervisorLog = process.stdout;
// If the logname doesn't change with input, the logs aren't per-worker
var isPerWorker = ( generateLogName(options.log, {pid: 1, id: 1}) !==
                    generateLogName(options.log, {pid: 2, id: 2}) )

if (options.syslog) {
  var errorLogger = new SysLogStream({level: 'CRIT'});
  var stdLogger = new SysLogStream({level: 'NOTICE'});
  supervisorLog = stdLogger;
  console.error('supervisor (%d) logging to syslog', process.pid);
} else if (!options.syslog && options.log && options.log !== '-') {
  supervisorLog = new LogWriter(process, options);
  console.error('supervisor (%d) logging to \'%s\'',
                process.pid, supervisorLog.name);
}

// In the recommended mode where worker logs are piped through the
// supervisor's stdout, each worker adds 6 listeners (3 per output stream)
// for piping alone. The default is 10.
supervisorLog.setMaxListeners(0);

logger.sink = transformer({ tag: { pid: process.pid, worker: 'supervisor' },
                            timeStamp: options.timeStampSupervisorLogs });
logger.sink.pipe(supervisorLog);

config.start = function start() {
  if(options.detach) {
    // Daemon shouldn't detach, runner does it.
    options.argv.forEach(function(v, i, a) {
      var substitute = {'-d':'--no-detach', '--detach':'--no-detach'};
      a[i] = substitute[v] || v;
    });
    try {
      var supervisorLogName = generateLogName(options.log,
                                              { id: 'supervisor',
                                                pid: process.pid });
      process.env.supervisor_detached = true;
      var child = detach(options.argv.concat(options.args), supervisorLogName);
      console.error('supervisor %d detached process %d, output logged to \'%s\'',
        process.pid, child.pid, supervisorLogName);
      process.exit();  // XXX should not be necessary!
    } catch(er) {
      console.error('supervisor failed to start: %s', er);
      console.error('%s', er.stack);
      process.exit(1); // XXX should not be necessary!
    }
    return;
  }

  cluster.on('fork', function(worker) {
    var tag = { pid: worker.process.pid, worker: worker.id };
    var logStream = isPerWorker
                  ? new LogWriter(worker, options)  // cleaned up by pipe()
                  : supervisorLog;                  // cleaned up by exit()
    var outLog = transformer({ timeStamp: options.timeStampWorkerLogs,
                               tag: tag });
    var errLog = transformer({ timeStamp: options.timeStampWorkerLogs,
                               tag: tag,
                               mergeLines: true });
    // When we have per-worker logs, each worker gets their own LogWriter, which
    // gets cleaned up when the stream piped into it emits 'end'.
    // When we don't have per-worker logs, we need to suppress the propagation
    // of 'end' from the pipe so we don't close the supervisor's log the first
    // time a worker exits.
    worker.process.stdout.pipe(outLog)
                         .pipe(stdLogger || logStream, {end: isPerWorker});
    worker.process.stderr.pipe(errLog)
                         .pipe(errorLogger || logStream, {end: isPerWorker});
    worker.logFile = logStream;
  });

  console.error('supervisor starting (pid %d)', process.pid);

  if(options.pid) {
    try {
      pidfile.create(options.pid);
    } catch(er) {
      console.error('supervisor failed to create pid file: %s', er.message);
      process.exit(1);
    }
  }

  // Re-require this so that strong-agent (which may be required by now)
  // notices, and attaches cluster control instrumentation.
  require('strong-cluster-control');

  control.on('start', function(addr) {
    logger.info('supervisor listening on \'%s\'', addr);
  });
  control.on('setSize', function() {
    logger.info('supervisor size set to', this.options.size);
  });
  control.on('resize', function() {
    logger.info('supervisor resized to', this.options.size);
  });
  control.on('startWorker', function(w) {
    logger.info('supervisor started worker %d (pid %d)', w.id, w.process.pid);
  });
  control.on('stopWorker', function(w) {
    logger.info('supervisor stopped worker %d (pid %d)', w.id, w.process.pid);
  });
  control.on('stop', function(w) {
    logger.info('supervisor stopped');
    process.exit(); // XXX should not be necessary!
  });
  cluster.on('exit', function(worker, code, signal) {
    var exit = worker.suicide ? 'expected' : 'accidental';
    logger.error('supervisor worker id %s (pid %d) %s exit with %s',
                  worker.id, worker.process.pid, exit, signal || code
                 );
  });
  process.on('exit', function(code) {
    logger.error('supervisor exiting with code %d', code);
  });
  process.on('SIGINT', function() {
    control.stop();
  });
  process.on('SIGTERM', function() {
    control.stop();
  });
  process.on('SIGHUP', function() {
    control.restart();
  });
  if (supervisorLog !== process.stdout) {
    process.on('SIGUSR2', function() {
      logger.info('reopening log files');
      supervisorLog.reOpen();
      for (var id in cluster.workers) {
        if (cluster.workers[id].logFile !== supervisorLog) {
          cluster.workers[id].logFile.reOpen();
        }
      }
      logger.info('log files reopened');
    });
  }
  return control.start(config);
};

module.exports = config;
<commit_msg>Record supervisor start/stop/restart in log<commit_after>// Evaluate configuration of supervisor, based on command line options,
// strong-cluster-control configuration, and strong-agent configuration.

var cluster = require('cluster');
var control = require('strong-cluster-control');
var dotenv = require('dotenv');
var fs = require('fs');
var path = require('path');
var open = require('fs').openSync;
var transformer = require('strong-log-transformer');
var Logger = require('./logger');

var logger = new Logger(process.stderr);

if(cluster.isWorker) {
  module.exports = control.loadOptions();
  module.exports.profile = process.env.supervisor_profile != 'false';
  return;
}

var detach = require('./detach');
var options = require('./options').parse(process.argv);
var pidfile = require('./pidfile');
var LogWriter = require('./log-writer');
var generateLogName = require('./logname').generate;
var SysLogStream = options.syslog && require('./syslog-stream');

if(options.help) {
  console.log(options.HELP, '\n');
  process.exit(0);
}

if(options.version) {
  console.log('v%s', require('../package.json').version);
  process.exit(0);
}

// Reset argv to include only the options for the runner before letting
// cluster-control look for its configuration (it examines process.argv).
process.argv = options.argv;
var config = control.loadOptions({
  cluster: process.env.NODE_ENV === 'production' ? 'CPUs' : undefined
});

// Allow module consumers to use our logger
config.logger = logger;

// Reset argv so the runner options are not seen by app
process.argv = process.argv.slice(0, 2).concat(options.args);

// Communicate profile option to the worker using the environment, and master
// using config.
process.env.supervisor_profile = options.profile;
config.profile = options.profile;

// Communicate detach option to the master using config.
config.detach = options.detach;

var app = process.argv[2];
var dirname, basename;

try {
  var stat = fs.statSync(app);
} catch(er) {
  console.error('Invalid app (%s), try `%s --help`.\n', er, options.NAME);
  process.exit(1);
}

// We want to be in the directory of the file we are running, so we can pick up
// configuration stored in it's working directory.

if(stat.isFile()) {
  // The app is a file, we'll run it from its directory.
  process.chdir(path.dirname(app));
  app = path.basename(app);
}

if(stat.isDirectory()) {
  // The app is a directory (such as '.'), we'll look for what to run from it.
  process.chdir(app);

  // The canonical way to run is with `npm start`, but we can't do that for a
  // cluster worker, because the worker must start the runner (so it can require
  // strong-agent). Instead, we search for a runnable file, and if that fails,
  // just require the directory and let node do the right thing (which should be
  // to use package.main if it exists, index.js otherwise).
  function existing(file) {
    return fs.existsSync(file) ? file : null;
  }
  app = existing('server.js') || existing('app.js') || '.';
}

options.args[0] = app;
process.argv[2] = app;

// Load the app's .env after we are in its working directory, and before
// cluster.setupMaster() snapshots the environment.
dotenv.load();

cluster.setupMaster({
  // XXX(rmg): node 0.11.x broke compatibility with 0.10.x for when process.argv
  //           is read and loaded into cluster.settings, so we have to manually
  //           reset args, exec, and execArgv after our changes
  //           see https://github.com/joyent/node/pull/7682 for upstream fix.
  args: process.argv.slice(2),
  exec: process.argv[1],
  execArgv: process.execArgv,
  // All worker output is being processed as individual log streams, so we can't
  // just let the supervisor's stdout/stderr be inherited.
  silent: true,
});

var supervisorLog = process.stdout;
// If the logname doesn't change with input, the logs aren't per-worker
var isPerWorker = ( generateLogName(options.log, {pid: 1, id: 1}) !==
                    generateLogName(options.log, {pid: 2, id: 2}) )

if (options.syslog) {
  var errorLogger = new SysLogStream({level: 'CRIT'});
  var stdLogger = new SysLogStream({level: 'NOTICE'});
  supervisorLog = stdLogger;
  console.error('supervisor (%d) logging to syslog', process.pid);
} else if (!options.syslog && options.log && options.log !== '-') {
  supervisorLog = new LogWriter(process, options);
  console.error('supervisor (%d) logging to \'%s\'',
                process.pid, supervisorLog.name);
}

// In the recommended mode where worker logs are piped through the
// supervisor's stdout, each worker adds 6 listeners (3 per output stream)
// for piping alone. The default is 10.
supervisorLog.setMaxListeners(0);

logger.sink = transformer({ tag: { pid: process.pid, worker: 'supervisor' },
                            timeStamp: options.timeStampSupervisorLogs });
logger.sink.pipe(supervisorLog);

config.start = function start() {
  if(options.detach) {
    // Daemon shouldn't detach, runner does it.
    options.argv.forEach(function(v, i, a) {
      var substitute = {'-d':'--no-detach', '--detach':'--no-detach'};
      a[i] = substitute[v] || v;
    });
    try {
      var supervisorLogName = generateLogName(options.log,
                                              { id: 'supervisor',
                                                pid: process.pid });
      process.env.supervisor_detached = true;
      var child = detach(options.argv.concat(options.args), supervisorLogName);
      console.error('supervisor %d detached process %d, output logged to \'%s\'',
        process.pid, child.pid, supervisorLogName);
      process.exit();  // XXX should not be necessary!
    } catch(er) {
      console.error('supervisor failed to start: %s', er);
      console.error('%s', er.stack);
      process.exit(1); // XXX should not be necessary!
    }
    return;
  }

  cluster.on('fork', function(worker) {
    var tag = { pid: worker.process.pid, worker: worker.id };
    var logStream = isPerWorker
                  ? new LogWriter(worker, options)  // cleaned up by pipe()
                  : supervisorLog;                  // cleaned up by exit()
    var outLog = transformer({ timeStamp: options.timeStampWorkerLogs,
                               tag: tag });
    var errLog = transformer({ timeStamp: options.timeStampWorkerLogs,
                               tag: tag,
                               mergeLines: true });
    // When we have per-worker logs, each worker gets their own LogWriter, which
    // gets cleaned up when the stream piped into it emits 'end'.
    // When we don't have per-worker logs, we need to suppress the propagation
    // of 'end' from the pipe so we don't close the supervisor's log the first
    // time a worker exits.
    worker.process.stdout.pipe(outLog)
                         .pipe(stdLogger || logStream, {end: isPerWorker});
    worker.process.stderr.pipe(errLog)
                         .pipe(errorLogger || logStream, {end: isPerWorker});
    worker.logFile = logStream;
  });

  logger.info('supervisor starting (pid %d)', process.pid);

  if(options.pid) {
    try {
      pidfile.create(options.pid);
    } catch(er) {
      console.error('supervisor failed to create pid file: %s', er.message);
      process.exit(1);
    }
  }

  // Re-require this so that strong-agent (which may be required by now)
  // notices, and attaches cluster control instrumentation.
  require('strong-cluster-control');

  control.on('start', function(addr) {
    logger.info('supervisor listening on \'%s\'', addr);
  });
  control.on('setSize', function() {
    logger.info('supervisor size set to', this.options.size);
  });
  control.on('resize', function() {
    logger.info('supervisor resized to', this.options.size);
  });
  control.on('startWorker', function(w) {
    logger.info('supervisor started worker %d (pid %d)', w.id, w.process.pid);
  });
  control.on('stopWorker', function(w) {
    logger.info('supervisor stopped worker %d (pid %d)', w.id, w.process.pid);
  });
  control.on('stop', function(w) {
    logger.info('supervisor stopped');
    process.exit(); // XXX should not be necessary!
  });
  cluster.on('exit', function(worker, code, signal) {
    var exit = worker.suicide ? 'expected' : 'accidental';
    logger.error('supervisor worker id %s (pid %d) %s exit with %s',
                  worker.id, worker.process.pid, exit, signal || code
                 );
  });
  process.on('exit', function(code) {
    logger.error('supervisor exiting with code %d', code);
  });
  process.on('SIGINT', function() {
    logger.warn('received SIGINT, shutting down');
    control.stop();
  });
  process.on('SIGTERM', function() {
    logger.warn('received SIGTERM, shutting down');
    control.stop();
  });
  process.on('SIGHUP', function() {
    logger.warn('received SIGHUP, restarting workers');
    control.restart();
  });
  if (supervisorLog !== process.stdout) {
    process.on('SIGUSR2', function() {
      logger.warn('received SIGUSR2, re-opening log files');
      supervisorLog.reOpen();
      for (var id in cluster.workers) {
        if (cluster.workers[id].logFile !== supervisorLog) {
          cluster.workers[id].logFile.reOpen();
        }
      }
      logger.info('log files reopened');
    });
  }
  return control.start(config);
};

module.exports = config;
<|endoftext|>