<commit_before>'use strict';

var _ = require('lodash');
var util = require('util');
var os = require('os');

/**
 * replace tabs by indent value
 *
 * @param line
 * @param indent
 * @return string
 */
function properIndentation(line, indent) {
    return line.replace(/\t/, indent || '');
}

/**
 * count leading whitespace chars
 *
 * @param line
 * @return integer
 */
function countWhitespace(line) {
    // return a somewhat high value for empty lines
    return line.length ? line.match(/^\s*/)[0].length : 9999;
}

/**
 * get lowest value of leading whitespace in a given block
 *
 * @param previous
 * @param current
 * @returns integer
 */
function getLeadingWhitespace(previous, current) {
    return previous <= current ? previous : current;
}

/**
 * raise offset in lines
 *
 * @param lines
 * @param offset
 * @returns {Array}
 */
function raiseIndent(lines, offset) {
    offset = offset || '    ';

    return lines.map(function (line) {
        return offset + line;
    });
}

/**
 * Formalize any given value as wrap object
 *
 * @param wrap
 * @returns {{before: '', after: ''}}
 */
function formalizeWrap(wrap) {
    var result = {before: '', after: ''};

    if ((typeof wrap === 'string' && wrap.length > 0) || typeof wrap === 'number') {
        result.before = result.after = wrap;
    } else if  (Array.isArray(wrap) && wrap.length > 0) {
        result.before = [].slice.call(wrap, 0, 1)[0];
        result.after = wrap.length > 1 ? [].slice.call(wrap, 1, 2)[0] : result.before;
    } else if (_.isPlainObject(wrap)) {
        var i = 0;
        var el;

        // crappy method getting the value of the first and second item in object
        for (el in wrap) {
            if (!wrap.hasOwnProperty(el)) {
                continue;
            }

            if (i < 2) {
                result.before = wrap[el];
            }

            i++;
        }

        // set value of after to the value of before if after is empty
        result.after = result.after.length < 1 ? result.before : result.after;
    }

    return result;
}

/**
 * read options from annotation
 *
 * e.g.:
 * gets:
 * {
     *   extract: 'teaser/content-teaser--small.html',
     *   viewWrap: {before: '
', after: '
'}
     * }
 *
 * @param annotation
 * @param defaults
 * @returns {{}}
 */
function getBlockOptions(annotation, defaults) {
    var optionValues = annotation.split(/\w+:/).map(function (item) {
        return item.replace(/|^\s+|\s+$/, '');
    }).filter(function (item) {
        return !!item.length;
    });
    var optionKeys = annotation.match(/(\w+):/g).map(function (item) {
        return item.replace(/[^\w]/, '');
    });

    defaults = defaults || {
        viewWrap: {before: '', after: ''}
    };

    var opts = {};

    optionValues.forEach(function (v, i) {
        var k = optionKeys[i];

        if (typeof k !== 'string') {
            return;
        }

        // Treat option value as array if it has a colon
        // @todo: Allow escaped colons to be ignored
        // RegEx lookbehind negate does not work :(
        // Should be /(?<!\\):/
        if (v.indexOf(':') > -1) {
            v = v.split(':');
        }

        opts[k] = v;
    });

    // Process options
    opts.wrap = formalizeWrap(opts.wrap || defaults.viewWrap);

    return opts;
}

/**
 * Format options as string of HTML data parameters
 *
 * @param options
 * @returns {string}
 */
function optionsToDataString(options) {
    if (typeof options !== 'object') {
        return '';
    }

    var prepared = [];
    var el;
    var processedOptions = _.assign({}, options);

    // prepare wrap option
    if (processedOptions.hasOwnProperty('wrap')) {
        processedOptions['wrap-before'] = processedOptions.wrap.before;
        processedOptions['wrap-after'] = processedOptions.wrap.after;

        delete(processedOptions.wrap);
    }

    // create data attributes
    for (el in processedOptions) {
        if (processedOptions.hasOwnProperty(el) === false) {
            continue;
        }

        var value = processedOptions[el];
        var preparedVal = JSON.stringify(processedOptions[el]);
        var param = '';

        // Ignore callbacks
        if (typeof value === 'function') {
            continue;
        }

        // Cleanup: Remove leading and trailing " and ', replace " by ' (e.g. in stringified objects)
        preparedVal = preparedVal.replace(/^['"]|['"]$/g, '').replace(/\\?"/g, "'");

        // Build data parameter: data-name="value"
        param = 'data-' + el + '="' + preparedVal + '"';

        prepared.push(param);
    }

    return prepared.join(' ');
}

/**
 * trim given number of leading characters
 *
 * @param lines
 * @param num Number of chars to be removed
 * @returns Array
 */
function trimLines(lines, num) {
    return lines.map(function (line) {
        return line.substr(num);
    });
}

/**
 * module
 * @param data
 * @returns {*}
 */
module.exports = function (data) {

    "use strict";

    // default options
    var defaultParseOptions = {
        flatten: false,
        indent: '    ',
        origin: '',
        templateWrap: { before: '', after: '' },
        viewWrap: { before: '', after: '' }
    };

    data = data || {};

    // set default properties
    var inventoryObject = {
        category:       data.category || undefined,
        dest:           data.dest,
        filename:       data.filename,
        lines:          data.lines,
        name:           data.name,
        options:        data.options,
        optionsData:    data.optionsData,
        origin:         data.origin,
        partial:        data.partial,
        path:           data.path,
        template:       data.template,
        view:           data.view
    };

    /**
     * parse data from extracted part
     *
     * @param src
     * @param opts
     */
    inventoryObject.parseData = function(src, opts) {
        opts = _.assign({}, defaultParseOptions, opts);

        var parts = src.match(/((?:.|\n)*?)/i);
        var blockOpts = getBlockOptions(parts[1], opts);
        var content = _.trim(parts[2]);
        var category = '';
        var name = '';

        // continue if path is empty
        if (!blockOpts.hasOwnProperty('extract')) {
            return;
        }

        // get filename from extract option
        var matchFilename = blockOpts.extract.match(/\/([^\/^\s]+)$/i);
        var filename = (matchFilename && matchFilename.length > -1) ? matchFilename[1] : blockOpts.extract;

        // get path from extract option
        var matchPath = blockOpts.extract.match(/^([^\s]+\/)/i);
        var path = (matchPath && matchPath.length > -1) ? matchPath[1] : '';

        // set first folder as category name if not in item options
        if (!blockOpts.hasOwnProperty('category')) {
            var matchCategory = blockOpts.extract.match(/^([^\s\/]+)\//i);
            category = (matchCategory && matchCategory.length > -1) ? matchCategory[1] : false;
            category = typeof category === 'string' ? _.startCase(category) : false;
        } else {
            category = _.startCase(blockOpts.category);
        }

        // get name from filename if not in options
         if (!blockOpts.hasOwnProperty('name')) {
             var matchName = filename.match(/^([^\s]+)\./i);
             name = (matchName && matchName.length > -1) ? matchName[1] : '';
             name = typeof name === 'string' ? _.startCase(name) : '';
         } else {
             name = blockOpts.name;
         }

        // remove nested path from dest if required
        var dest = opts.flatten ? filename : blockOpts.extract;
        var lines = content.split('\n').map(function(line) {
            // remove possibly existing CR
            return _.trimRight(line);
        }).map(function (line) {
            return properIndentation(line, opts.indent);
        });
        var leadingWhitespace = lines.map(countWhitespace);
        var crop = leadingWhitespace.reduce(getLeadingWhitespace);
        var viewWrap = blockOpts.wrap;
        var templateWrapOptions = optionsToDataString(blockOpts);

        lines = trimLines(lines, crop);

        var viewLines = util._extend([], lines);
        var templateLines = util._extend([], lines);

        // wrap partial if inline option viewWrap: exists
        if (viewWrap.before.length) {
            viewLines = raiseIndent(viewLines);
            viewLines.unshift('');
            viewLines.unshift(viewWrap.before);
            viewLines.push('');
            viewLines.push(viewWrap.after);
        }

        // add templateWrap
        if (typeof opts.templateWrap === 'object') {
            var before = opts.templateWrap.before || '';
            var after = opts.templateWrap.after || '';

            before = before.replace('{{wrapData}}', templateWrapOptions);
            after = after.replace('{{wrapData}}', templateWrapOptions);

            templateLines.unshift(before);
            templateLines.push(after);
        }

        // set properties
        this.category       = category;
        this.dest           = dest;
        this.filename       = filename;
        this.lines          = lines;
        this.name           = name;
        this.options        = blockOpts;
        this.optionsData    = templateWrapOptions;
        this.partial        = lines.join(os.EOL);
        this.path           = path;
        this.template       = templateLines.join(os.EOL);
        this.view           = viewLines.join(os.EOL);
    };

    /**
     * return inventory object
     */
    return inventoryObject;
};<commit_msg>Proper data initialization<commit_after>'use strict';

var _ = require('lodash');
var util = require('util');
var os = require('os');

/**
 * replace tabs by indent value
 *
 * @param line
 * @param indent
 * @return string
 */
function properIndentation(line, indent) {
    return line.replace(/\t/, indent || '');
}

/**
 * count leading whitespace chars
 *
 * @param line
 * @return integer
 */
function countWhitespace(line) {
    // return a somewhat high value for empty lines
    return line.length ? line.match(/^\s*/)[0].length : 9999;
}

/**
 * get lowest value of leading whitespace in a given block
 *
 * @param previous
 * @param current
 * @returns integer
 */
function getLeadingWhitespace(previous, current) {
    return previous <= current ? previous : current;
}

/**
 * raise offset in lines
 *
 * @param lines
 * @param offset
 * @returns {Array}
 */
function raiseIndent(lines, offset) {
    offset = offset || '    ';

    return lines.map(function (line) {
        return offset + line;
    });
}

/**
 * Formalize any given value as wrap object
 *
 * @param wrap
 * @returns {{before: '', after: ''}}
 */
function formalizeWrap(wrap) {
    var result = {before: '', after: ''};

    if ((typeof wrap === 'string' && wrap.length > 0) || typeof wrap === 'number') {
        result.before = result.after = wrap;
    } else if  (Array.isArray(wrap) && wrap.length > 0) {
        result.before = [].slice.call(wrap, 0, 1)[0];
        result.after = wrap.length > 1 ? [].slice.call(wrap, 1, 2)[0] : result.before;
    } else if (_.isPlainObject(wrap)) {
        var i = 0;
        var el;

        // crappy method getting the value of the first and second item in object
        for (el in wrap) {
            if (!wrap.hasOwnProperty(el)) {
                continue;
            }

            if (i < 2) {
                result.before = wrap[el];
            }

            i++;
        }

        // set value of after to the value of before if after is empty
        result.after = result.after.length < 1 ? result.before : result.after;
    }

    return result;
}

/**
 * read options from annotation
 *
 * e.g.:
 * gets:
 * {
     *   extract: 'teaser/content-teaser--small.html',
     *   viewWrap: {before: '
', after: '
'}
     * }
 *
 * @param annotation
 * @param defaults
 * @returns {{}}
 */
function getBlockOptions(annotation, defaults) {
    var optionValues = annotation.split(/\w+:/).map(function (item) {
        return item.replace(/|^\s+|\s+$/, '');
    }).filter(function (item) {
        return !!item.length;
    });
    var optionKeys = annotation.match(/(\w+):/g).map(function (item) {
        return item.replace(/[^\w]/, '');
    });

    defaults = defaults || {
        viewWrap: {before: '', after: ''}
    };

    var opts = {};

    optionValues.forEach(function (v, i) {
        var k = optionKeys[i];

        if (typeof k !== 'string') {
            return;
        }

        // Treat option value as array if it has a colon
        // @todo: Allow escaped colons to be ignored
        // RegEx lookbehind negate does not work :(
        // Should be /(?<!\\):/
        if (v.indexOf(':') > -1) {
            v = v.split(':');
        }

        opts[k] = v;
    });

    // Process options
    opts.wrap = formalizeWrap(opts.wrap || defaults.viewWrap);

    return opts;
}

/**
 * Format options as string of HTML data parameters
 *
 * @param options
 * @returns {string}
 */
function optionsToDataString(options) {
    if (typeof options !== 'object') {
        return '';
    }

    var prepared = [];
    var el;
    var processedOptions = _.assign({}, options);

    // prepare wrap option
    if (processedOptions.hasOwnProperty('wrap')) {
        processedOptions['wrap-before'] = processedOptions.wrap.before;
        processedOptions['wrap-after'] = processedOptions.wrap.after;

        delete(processedOptions.wrap);
    }

    // create data attributes
    for (el in processedOptions) {
        if (processedOptions.hasOwnProperty(el) === false) {
            continue;
        }

        var value = processedOptions[el];
        var preparedVal = JSON.stringify(processedOptions[el]);
        var param = '';

        // Ignore callbacks
        if (typeof value === 'function') {
            continue;
        }

        // Cleanup: Remove leading and trailing " and ', replace " by ' (e.g. in stringified objects)
        preparedVal = preparedVal.replace(/^['"]|['"]$/g, '').replace(/\\?"/g, "'");

        // Build data parameter: data-name="value"
        param = 'data-' + el + '="' + preparedVal + '"';

        prepared.push(param);
    }

    return prepared.join(' ');
}

/**
 * trim given number of leading characters
 *
 * @param lines
 * @param num Number of chars to be removed
 * @returns Array
 */
function trimLines(lines, num) {
    return lines.map(function (line) {
        return line.substr(num);
    });
}

/**
 * module
 * @param data
 * @returns {*}
 */
module.exports = function (data) {

    "use strict";

    // default options
    var defaultParseOptions = {
        flatten: false,
        indent: '    ',
        origin: '',
        templateWrap: { before: '', after: '' },
        viewWrap: { before: '', after: '' }
    };

    data = data || {};

    // set default properties (property whitelist)
    var inventoryObject = {
        category:       data.hasOwnProperty('category') ? data.category : undefined,
        dest:           data.hasOwnProperty('dest') ? data.dest : '',
        filename:       data.hasOwnProperty('filename') ? data.filename : '',
        id:             data.hasOwnProperty('id') ? data.id : '',
        lines:          data.hasOwnProperty('lines') ? data.lines : -1,
        name:           data.hasOwnProperty('name') ? data.name : '',
        options:        data.hasOwnProperty('options') ? data.options : {},
        optionsData:    data.hasOwnProperty('optionsData') ? data.optionsData : '',
        origin:         data.hasOwnProperty('origin') ? data.origin : '',
        partial:        data.hasOwnProperty('partial') ? data.partial : '',
        path:           data.hasOwnProperty('path') ? data.path : '',
        template:       data.hasOwnProperty('template') ? data.template : '',
        view:           data.hasOwnProperty('view') ? data.view : ''
    };

    /**
     * parse data from extracted part
     *
     * @param src
     * @param opts
     */
    inventoryObject.parseData = function(src, opts) {
        opts = _.assign({}, defaultParseOptions, opts);

        var parts = src.match(/((?:.|\n)*?)/i);
        var blockOpts = getBlockOptions(parts[1], opts);
        var content = _.trim(parts[2]);
        var category = '';
        var name = '';

        // continue if path is empty
        if (!blockOpts.hasOwnProperty('extract')) {
            return;
        }

        // get filename from extract option
        var matchFilename = blockOpts.extract.match(/\/([^\/^\s]+)$/i);
        var filename = (matchFilename && matchFilename.length > -1) ? matchFilename[1] : blockOpts.extract;

        // get path from extract option
        var matchPath = blockOpts.extract.match(/^([^\s]+\/)/i);
        var path = (matchPath && matchPath.length > -1) ? matchPath[1] : '';

        // set first folder as category name if not in item options
        if (!blockOpts.hasOwnProperty('category')) {
            var matchCategory = blockOpts.extract.match(/^([^\s\/]+)\//i);
            category = (matchCategory && matchCategory.length > -1) ? matchCategory[1] : false;
            category = typeof category === 'string' ? _.startCase(category) : false;
        } else {
            category = _.startCase(blockOpts.category);
        }

        // get name from filename if not in options
         if (!blockOpts.hasOwnProperty('name')) {
             var matchName = filename.match(/^([^\s]+)\./i);
             name = (matchName && matchName.length > -1) ? matchName[1] : '';
             name = typeof name === 'string' ? _.startCase(name) : '';
         } else {
             name = blockOpts.name;
         }

        // remove nested path from dest if required
        var dest = opts.flatten ? filename : blockOpts.extract;
        var lines = content.split('\n').map(function(line) {
            // remove possibly existing CR
            return _.trimRight(line);
        }).map(function (line) {
            return properIndentation(line, opts.indent);
        });
        var leadingWhitespace = lines.map(countWhitespace);
        var crop = leadingWhitespace.reduce(getLeadingWhitespace);
        var viewWrap = blockOpts.wrap;
        var templateWrapOptions = optionsToDataString(blockOpts);

        lines = trimLines(lines, crop);

        var viewLines = util._extend([], lines);
        var templateLines = util._extend([], lines);

        // wrap partial if inline option viewWrap: exists
        if (viewWrap.before.length) {
            viewLines = raiseIndent(viewLines);
            viewLines.unshift('');
            viewLines.unshift(viewWrap.before);
            viewLines.push('');
            viewLines.push(viewWrap.after);
        }

        // add templateWrap
        if (typeof opts.templateWrap === 'object') {
            var before = opts.templateWrap.before || '';
            var after = opts.templateWrap.after || '';

            before = before.replace('{{wrapData}}', templateWrapOptions);
            after = after.replace('{{wrapData}}', templateWrapOptions);

            templateLines.unshift(before);
            templateLines.push(after);
        }

        // set properties
        this.category       = category;
        this.dest           = dest;
        this.filename       = filename;
        this.lines          = lines;
        this.name           = name;
        this.options        = blockOpts;
        this.optionsData    = templateWrapOptions;
        this.partial        = lines.join(os.EOL);
        this.path           = path;
        this.template       = templateLines.join(os.EOL);
        this.view           = viewLines.join(os.EOL);
    };

    /**
     * return inventory object
     */
    return inventoryObject;
};<|endoftext|>


<commit_before>// Copyright 2016-2018, University of Colorado Boulder

/**
 * base class for energy sources, i.e. model elements that produce energy and can supply it to other energy system
 * components, such as energy converters or energy users
 *
 * @author  John Blanco
 * @author  Andrew Adare
 * @author  Jesse Greenberg
 */
define( function( require ) {
  'use strict';

  var energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );
  var EnergySystemElement = require( 'ENERGY_FORMS_AND_CHANGES/systems/model/EnergySystemElement' );
  var inherit = require( 'PHET_CORE/inherit' );

  /**
   * @param {Image} iconImage Image to identify source on carousel menu
   * @constructor
   */
  function EnergySource( iconImage ) {
    EnergySystemElement.call( this, iconImage );
    this.outgoingEnergyChunks = [];
  }

  energyFormsAndChanges.register( 'EnergySource', EnergySource );

  return inherit( EnergySystemElement, EnergySource, {

    /**
     * Get the energy chunks that this source wants to transfer to the next energy system element. This is a mutating
     * operation: it removes all outgoing chunks from both this.energyChunkList and this.outgoingEnergyChunks.
     * @returns {EnergyChunk[]} List of energy chunks to transfer
     * @public
     */
    extractOutgoingEnergyChunks: function() {

      // remove all outgoing chunks from this.energyChunkList
      this.energyChunkList.removeAll( this.outgoingEnergyChunks );

      // return a copy of the outgoing chunk list and clear it in one fell swoop
      return this.outgoingEnergyChunks.splice( 0 );
    },

    /**
     * clear internal list of energy chunks and outgoing energy chunks
     * @public
     * @override
     */
    clearEnergyChunks: function() {
      EnergySystemElement.prototype.clearEnergyChunks.call( this );
      this.outgoingEnergyChunks.length = 0;
    }
  } );
} );

<commit_msg>Convert to ES6, see https://github.com/phetsims/energy-forms-and-changes/issues/211<commit_after>// Copyright 2016-2019, University of Colorado Boulder

/**
 * base class for energy sources, i.e. model elements that produce energy and can supply it to other energy system
 * components, such as energy converters or energy users
 *
 * @author John Blanco
 * @author Andrew Adare
 * @author Jesse Greenberg
 */
define( require => {
  'use strict';

  const energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );
  const EnergySystemElement = require( 'ENERGY_FORMS_AND_CHANGES/systems/model/EnergySystemElement' );

  class EnergySource extends EnergySystemElement {

    /**
     * @param {Image} iconImage Image to identify source on carousel menu
     */
    constructor( iconImage ) {
      super( iconImage );
      this.outgoingEnergyChunks = [];
    }

    /**
     * Get the energy chunks that this source wants to transfer to the next energy system element. This is a mutating
     * operation: it removes all outgoing chunks from both this.energyChunkList and this.outgoingEnergyChunks.
     * @returns {EnergyChunk[]} List of energy chunks to transfer
     * @public
     */
    extractOutgoingEnergyChunks() {

      // remove all outgoing chunks from this.energyChunkList
      this.energyChunkList.removeAll( this.outgoingEnergyChunks );

      // return a copy of the outgoing chunk list and clear it in one fell swoop
      return this.outgoingEnergyChunks.splice( 0 );
    }

    /**
     * clear internal list of energy chunks and outgoing energy chunks
     * @public
     * @override
     */
    clearEnergyChunks() {
      EnergySystemElement.prototype.clearEnergyChunks.call( this );
      this.outgoingEnergyChunks.length = 0;
    }
  }

  return energyFormsAndChanges.register( 'EnergySource', EnergySource );
} );

<|endoftext|>


<commit_before>/**
 * Tools.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * This class contains various utlity functions. These are also exposed
 * directly on the tinymce namespace.
 *
 * @class tinymce.util.Tools
 */
define("tinymce/util/Tools", [
	"tinymce/Env"
], function(Env) {
	/**
	 * Removes whitespace from the beginning and end of a string.
	 *
	 * @method trim
	 * @param {String} s String to remove whitespace from.
	 * @return {String} New string with removed whitespace.
	 */
	var whiteSpaceRegExp = /^\s*|\s*$/g;

	function trim(str) {
		return (str === null || str === undefined) ? '' : ("" + str).replace(whiteSpaceRegExp, '');
	}

	/**
	 * Returns true/false if the object is an array or not.
	 *
	 * @method isArray
	 * @param {Object} obj Object to check.
	 * @return {boolean} true/false state if the object is an array or not.
	 */
	var isArray = Array.isArray || function(obj) {
		return Object.prototype.toString.call(obj) === "[object Array]";
	};

	/**
	 * Checks if a object is of a specific type for example an array.
	 *
	 * @method is
	 * @param {Object} obj Object to check type of.
	 * @param {string} type Optional type to check for.
	 * @return {Boolean} true/false if the object is of the specified type.
	 */
	function is(obj, type) {
		if (!type) {
			return obj !== undefined;
		}

		if (type == 'array' && isArray(obj)) {
			return true;
		}

		return typeof obj == type;
	}

	/**
	 * Converts the specified object into a real JavaScript array.
	 *
	 * @method toArray
	 * @param {Object} obj Object to convert into array.
	 * @return {Array} Array object based in input.
	 */
	function toArray(obj) {
		var array = obj, i, l;

		if (!isArray(obj)) {
			array = [];
			for (i = 0, l = obj.length; i < l; i++) {
				array[i] = obj[i];
			}
		}

		return array;
	}

	/**
	 * Makes a name/object map out of an array with names.
	 *
	 * @method makeMap
	 * @param {Array/String} items Items to make map out of.
	 * @param {String} delim Optional delimiter to split string by.
	 * @param {Object} map Optional map to add items to.
	 * @return {Object} Name/value map of items.
	 */
	function makeMap(items, delim, map) {
		var i;

		items = items || [];
		delim = delim || ',';

		if (typeof items == "string") {
			items = items.split(delim);
		}

		map = map || {};

		i = items.length;
		while (i--) {
			map[items[i]] = {};
		}

		return map;
	}

	/**
	 * Performs an iteration of all items in a collection such as an object or array. This method will execure the
	 * callback function for each item in the collection, if the callback returns false the iteration will terminate.
	 * The callback has the following format: cb(value, key_or_index).
	 *
	 * @method each
	 * @param {Object} o Collection to iterate.
	 * @param {function} cb Callback function to execute for each item.
	 * @param {Object} s Optional scope to execute the callback in.
	 * @example
	 * // Iterate an array
	 * tinymce.each([1,2,3], function(v, i) {
	 *     console.debug("Value: " + v + ", Index: " + i);
	 * });
	 *
	 * // Iterate an object
	 * tinymce.each({a: 1, b: 2, c: 3], function(v, k) {
	 *     console.debug("Value: " + v + ", Key: " + k);
	 * });
	 */
	function each(o, cb, s) {
		var n, l;

		if (!o) {
			return 0;
		}

		s = s || o;

		if (o.length !== undefined) {
			// Indexed arrays, needed for Safari
			for (n = 0, l = o.length; n < l; n++) {
				if (cb.call(s, o[n], n, o) === false) {
					return 0;
				}
			}
		} else {
			// Hashtables
			for (n in o) {
				if (o.hasOwnProperty(n)) {
					if (cb.call(s, o[n], n, o) === false) {
						return 0;
					}
				}
			}
		}

		return 1;
	}

	/**
	 * Creates a new array by the return value of each iteration function call. This enables you to convert
	 * one array list into another.
	 *
	 * @method map
	 * @param {Array} array Array of items to iterate.
	 * @param {function} callback Function to call for each item. It's return value will be the new value.
	 * @return {Array} Array with new values based on function return values.
	 */
	function map(array, callback) {
		var out = [];

		each(array, function(item) {
			out.push(callback(item));
		});

		return out;
	}

	/**
	 * Filters out items from the input array by calling the specified function for each item.
	 * If the function returns false the item will be excluded if it returns true it will be included.
	 *
	 * @method grep
	 * @param {Array} a Array of items to loop though.
	 * @param {function} f Function to call for each item. Include/exclude depends on it's return value.
	 * @return {Array} New array with values imported and filtered based in input.
	 * @example
	 * // Filter out some items, this will return an array with 4 and 5
	 * var items = tinymce.grep([1,2,3,4,5], function(v) {return v > 3;});
	 */
	function grep(a, f) {
		var o = [];

		each(a, function(v) {
			if (!f || f(v)) {
				o.push(v);
			}
		});

		return o;
	}

	/**
	 * Creates a class, subclass or static singleton.
	 * More details on this method can be found in the Wiki.
	 *
	 * @method create
	 * @param {String} s Class name, inheritage and prefix.
	 * @param {Object} p Collection of methods to add to the class.
	 * @param {Object} root Optional root object defaults to the global window object.
	 * @example
	 * // Creates a basic class
	 * tinymce.create('tinymce.somepackage.SomeClass', {
	 *     SomeClass: function() {
	 *         // Class constructor
	 *     },
	 *
	 *     method: function() {
	 *         // Some method
	 *     }
	 * });
	 *
	 * // Creates a basic subclass class
	 * tinymce.create('tinymce.somepackage.SomeSubClass:tinymce.somepackage.SomeClass', {
	 *     SomeSubClass: function() {
	 *         // Class constructor
	 *         this.parent(); // Call parent constructor
	 *     },
	 *
	 *     method: function() {
	 *         // Some method
	 *         this.parent(); // Call parent method
	 *     },
	 *
	 *     'static': {
	 *         staticMethod: function() {
	 *             // Static method
	 *         }
	 *     }
	 * });
	 *
	 * // Creates a singleton/static class
	 * tinymce.create('static tinymce.somepackage.SomeSingletonClass', {
	 *     method: function() {
	 *         // Some method
	 *     }
	 * });
	 */
	function create(s, p, root) {
		var self = this, sp, ns, cn, scn, c, de = 0;

		// Parse : <prefix> <class>:<super class>
		s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
		cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name

		// Create namespace for new class
		ns = self.createNS(s[3].replace(/\.\w+$/, ''), root);

		// Class already exists
		if (ns[cn]) {
			return;
		}

		// Make pure static class
		if (s[2] == 'static') {
			ns[cn] = p;

			if (this.onCreate) {
				this.onCreate(s[2], s[3], ns[cn]);
			}

			return;
		}

		// Create default constructor
		if (!p[cn]) {
			p[cn] = function() {};
			de = 1;
		}

		// Add constructor and methods
		ns[cn] = p[cn];
		self.extend(ns[cn].prototype, p);

		// Extend
		if (s[5]) {
			sp = self.resolve(s[5]).prototype;
			scn = s[5].match(/\.(\w+)$/i)[1]; // Class name

			// Extend constructor
			c = ns[cn];
			if (de) {
				// Add passthrough constructor
				ns[cn] = function() {
					return sp[scn].apply(this, arguments);
				};
			} else {
				// Add inherit constructor
				ns[cn] = function() {
					this.parent = sp[scn];
					return c.apply(this, arguments);
				};
			}
			ns[cn].prototype[cn] = ns[cn];

			// Add super methods
			self.each(sp, function(f, n) {
				ns[cn].prototype[n] = sp[n];
			});

			// Add overridden methods
			self.each(p, function(f, n) {
				// Extend methods if needed
				if (sp[n]) {
					ns[cn].prototype[n] = function() {
						this.parent = sp[n];
						return f.apply(this, arguments);
					};
				} else {
					if (n != cn) {
						ns[cn].prototype[n] = f;
					}
				}
			});
		}

		// Add static methods
		/*jshint sub:true*/
		/*eslint dot-notation:0*/
		self.each(p['static'], function(f, n) {
			ns[cn][n] = f;
		});
	}

	/**
	 * Returns the index of a value in an array, this method will return -1 if the item wasn't found.
	 *
	 * @method inArray
	 * @param {Array} a Array/Object to search for value in.
	 * @param {Object} v Value to check for inside the array.
	 * @return {Number/String} Index of item inside the array inside an object. Or -1 if it wasn't found.
	 * @example
	 * // Get index of value in array this will alert 1 since 2 is at that index
	 * alert(tinymce.inArray([1,2,3], 2));
	 */
	function inArray(a, v) {
		var i, l;

		if (a) {
			for (i = 0, l = a.length; i < l; i++) {
				if (a[i] === v) {
					return i;
				}
			}
		}

		return -1;
	}

	function extend(obj, ext) {
		var i, l, name, args = arguments, value;

		for (i = 1, l = args.length; i < l; i++) {
			ext = args[i];
			for (name in ext) {
				if (ext.hasOwnProperty(name)) {
					value = ext[name];

					if (value !== undefined) {
						obj[name] = value;
					}
				}
			}
		}

		return obj;
	}

	/**
	 * Executed the specified function for each item in a object tree.
	 *
	 * @method walk
	 * @param {Object} o Object tree to walk though.
	 * @param {function} f Function to call for each item.
	 * @param {String} n Optional name of collection inside the objects to walk for example childNodes.
	 * @param {String} s Optional scope to execute the function in.
	 */
	function walk(o, f, n, s) {
		s = s || this;

		if (o) {
			if (n) {
				o = o[n];
			}

			each(o, function(o, i) {
				if (f.call(s, o, i, n) === false) {
					return false;
				}

				walk(o, f, n, s);
			});
		}
	}

	/**
	 * Creates a namespace on a specific object.
	 *
	 * @method createNS
	 * @param {String} n Namespace to create for example a.b.c.d.
	 * @param {Object} o Optional object to add namespace to, defaults to window.
	 * @return {Object} New namespace object the last item in path.
	 * @example
	 * // Create some namespace
	 * tinymce.createNS('tinymce.somepackage.subpackage');
	 *
	 * // Add a singleton
	 * var tinymce.somepackage.subpackage.SomeSingleton = {
	 *     method: function() {
	 *         // Some method
	 *     }
	 * };
	 */
	function createNS(n, o) {
		var i, v;

		o = o || window;

		n = n.split('.');
		for (i = 0; i < n.length; i++) {
			v = n[i];

			if (!o[v]) {
				o[v] = {};
			}

			o = o[v];
		}

		return o;
	}

	/**
	 * Resolves a string and returns the object from a specific structure.
	 *
	 * @method resolve
	 * @param {String} n Path to resolve for example a.b.c.d.
	 * @param {Object} o Optional object to search though, defaults to window.
	 * @return {Object} Last object in path or null if it couldn't be resolved.
	 * @example
	 * // Resolve a path into an object reference
	 * var obj = tinymce.resolve('a.b.c.d');
	 */
	function resolve(n, o) {
		var i, l;

		o = o || window;

		n = n.split('.');
		for (i = 0, l = n.length; i < l; i++) {
			o = o[n[i]];

			if (!o) {
				break;
			}
		}

		return o;
	}

	/**
	 * Splits a string but removes the whitespace before and after each value.
	 *
	 * @method explode
	 * @param {string} s String to split.
	 * @param {string} d Delimiter to split by.
	 * @example
	 * // Split a string into an array with a,b,c
	 * var arr = tinymce.explode('a, b,   c');
	 */
	function explode(s, d) {
		if (!s || is(s, 'array')) {
			return s;
		}

		return map(s.split(d || ','), trim);
	}

	function constant(value) {
		return function() {
			return value;
		};
	}

	function reduce(collection, iteratee, accumulator, thisArg) {
		for (var i = 0; i < collection.length; i++) {
			accumulator = iteratee.call(thisArg, accumulator, collection[i], i);
		}

		return accumulator;
	}

	function _addCacheSuffix(url) {
		var cacheSuffix = Env.cacheSuffix;

		if (cacheSuffix) {
			url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
		}

		return url;
	}

	return {
		trim: trim,
		isArray: isArray,
		is: is,
		toArray: toArray,
		makeMap: makeMap,
		each: each,
		map: map,
		grep: grep,
		filter: grep,
		inArray: inArray,
		extend: extend,
		create: create,
		walk: walk,
		createNS: createNS,
		resolve: resolve,
		explode: explode,
		constant: constant,
		reduce: reduce,
		_addCacheSuffix: _addCacheSuffix
	};
});<commit_msg>Fixed issue with reduce initial value.<commit_after>/**
 * Tools.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * This class contains various utlity functions. These are also exposed
 * directly on the tinymce namespace.
 *
 * @class tinymce.util.Tools
 */
define("tinymce/util/Tools", [
	"tinymce/Env"
], function(Env) {
	/**
	 * Removes whitespace from the beginning and end of a string.
	 *
	 * @method trim
	 * @param {String} s String to remove whitespace from.
	 * @return {String} New string with removed whitespace.
	 */
	var whiteSpaceRegExp = /^\s*|\s*$/g;

	function trim(str) {
		return (str === null || str === undefined) ? '' : ("" + str).replace(whiteSpaceRegExp, '');
	}

	/**
	 * Returns true/false if the object is an array or not.
	 *
	 * @method isArray
	 * @param {Object} obj Object to check.
	 * @return {boolean} true/false state if the object is an array or not.
	 */
	var isArray = Array.isArray || function(obj) {
		return Object.prototype.toString.call(obj) === "[object Array]";
	};

	/**
	 * Checks if a object is of a specific type for example an array.
	 *
	 * @method is
	 * @param {Object} obj Object to check type of.
	 * @param {string} type Optional type to check for.
	 * @return {Boolean} true/false if the object is of the specified type.
	 */
	function is(obj, type) {
		if (!type) {
			return obj !== undefined;
		}

		if (type == 'array' && isArray(obj)) {
			return true;
		}

		return typeof obj == type;
	}

	/**
	 * Converts the specified object into a real JavaScript array.
	 *
	 * @method toArray
	 * @param {Object} obj Object to convert into array.
	 * @return {Array} Array object based in input.
	 */
	function toArray(obj) {
		var array = obj, i, l;

		if (!isArray(obj)) {
			array = [];
			for (i = 0, l = obj.length; i < l; i++) {
				array[i] = obj[i];
			}
		}

		return array;
	}

	/**
	 * Makes a name/object map out of an array with names.
	 *
	 * @method makeMap
	 * @param {Array/String} items Items to make map out of.
	 * @param {String} delim Optional delimiter to split string by.
	 * @param {Object} map Optional map to add items to.
	 * @return {Object} Name/value map of items.
	 */
	function makeMap(items, delim, map) {
		var i;

		items = items || [];
		delim = delim || ',';

		if (typeof items == "string") {
			items = items.split(delim);
		}

		map = map || {};

		i = items.length;
		while (i--) {
			map[items[i]] = {};
		}

		return map;
	}

	/**
	 * Performs an iteration of all items in a collection such as an object or array. This method will execure the
	 * callback function for each item in the collection, if the callback returns false the iteration will terminate.
	 * The callback has the following format: cb(value, key_or_index).
	 *
	 * @method each
	 * @param {Object} o Collection to iterate.
	 * @param {function} cb Callback function to execute for each item.
	 * @param {Object} s Optional scope to execute the callback in.
	 * @example
	 * // Iterate an array
	 * tinymce.each([1,2,3], function(v, i) {
	 *     console.debug("Value: " + v + ", Index: " + i);
	 * });
	 *
	 * // Iterate an object
	 * tinymce.each({a: 1, b: 2, c: 3], function(v, k) {
	 *     console.debug("Value: " + v + ", Key: " + k);
	 * });
	 */
	function each(o, cb, s) {
		var n, l;

		if (!o) {
			return 0;
		}

		s = s || o;

		if (o.length !== undefined) {
			// Indexed arrays, needed for Safari
			for (n = 0, l = o.length; n < l; n++) {
				if (cb.call(s, o[n], n, o) === false) {
					return 0;
				}
			}
		} else {
			// Hashtables
			for (n in o) {
				if (o.hasOwnProperty(n)) {
					if (cb.call(s, o[n], n, o) === false) {
						return 0;
					}
				}
			}
		}

		return 1;
	}

	/**
	 * Creates a new array by the return value of each iteration function call. This enables you to convert
	 * one array list into another.
	 *
	 * @method map
	 * @param {Array} array Array of items to iterate.
	 * @param {function} callback Function to call for each item. It's return value will be the new value.
	 * @return {Array} Array with new values based on function return values.
	 */
	function map(array, callback) {
		var out = [];

		each(array, function(item) {
			out.push(callback(item));
		});

		return out;
	}

	/**
	 * Filters out items from the input array by calling the specified function for each item.
	 * If the function returns false the item will be excluded if it returns true it will be included.
	 *
	 * @method grep
	 * @param {Array} a Array of items to loop though.
	 * @param {function} f Function to call for each item. Include/exclude depends on it's return value.
	 * @return {Array} New array with values imported and filtered based in input.
	 * @example
	 * // Filter out some items, this will return an array with 4 and 5
	 * var items = tinymce.grep([1,2,3,4,5], function(v) {return v > 3;});
	 */
	function grep(a, f) {
		var o = [];

		each(a, function(v) {
			if (!f || f(v)) {
				o.push(v);
			}
		});

		return o;
	}

	/**
	 * Creates a class, subclass or static singleton.
	 * More details on this method can be found in the Wiki.
	 *
	 * @method create
	 * @param {String} s Class name, inheritage and prefix.
	 * @param {Object} p Collection of methods to add to the class.
	 * @param {Object} root Optional root object defaults to the global window object.
	 * @example
	 * // Creates a basic class
	 * tinymce.create('tinymce.somepackage.SomeClass', {
	 *     SomeClass: function() {
	 *         // Class constructor
	 *     },
	 *
	 *     method: function() {
	 *         // Some method
	 *     }
	 * });
	 *
	 * // Creates a basic subclass class
	 * tinymce.create('tinymce.somepackage.SomeSubClass:tinymce.somepackage.SomeClass', {
	 *     SomeSubClass: function() {
	 *         // Class constructor
	 *         this.parent(); // Call parent constructor
	 *     },
	 *
	 *     method: function() {
	 *         // Some method
	 *         this.parent(); // Call parent method
	 *     },
	 *
	 *     'static': {
	 *         staticMethod: function() {
	 *             // Static method
	 *         }
	 *     }
	 * });
	 *
	 * // Creates a singleton/static class
	 * tinymce.create('static tinymce.somepackage.SomeSingletonClass', {
	 *     method: function() {
	 *         // Some method
	 *     }
	 * });
	 */
	function create(s, p, root) {
		var self = this, sp, ns, cn, scn, c, de = 0;

		// Parse : <prefix> <class>:<super class>
		s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
		cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name

		// Create namespace for new class
		ns = self.createNS(s[3].replace(/\.\w+$/, ''), root);

		// Class already exists
		if (ns[cn]) {
			return;
		}

		// Make pure static class
		if (s[2] == 'static') {
			ns[cn] = p;

			if (this.onCreate) {
				this.onCreate(s[2], s[3], ns[cn]);
			}

			return;
		}

		// Create default constructor
		if (!p[cn]) {
			p[cn] = function() {};
			de = 1;
		}

		// Add constructor and methods
		ns[cn] = p[cn];
		self.extend(ns[cn].prototype, p);

		// Extend
		if (s[5]) {
			sp = self.resolve(s[5]).prototype;
			scn = s[5].match(/\.(\w+)$/i)[1]; // Class name

			// Extend constructor
			c = ns[cn];
			if (de) {
				// Add passthrough constructor
				ns[cn] = function() {
					return sp[scn].apply(this, arguments);
				};
			} else {
				// Add inherit constructor
				ns[cn] = function() {
					this.parent = sp[scn];
					return c.apply(this, arguments);
				};
			}
			ns[cn].prototype[cn] = ns[cn];

			// Add super methods
			self.each(sp, function(f, n) {
				ns[cn].prototype[n] = sp[n];
			});

			// Add overridden methods
			self.each(p, function(f, n) {
				// Extend methods if needed
				if (sp[n]) {
					ns[cn].prototype[n] = function() {
						this.parent = sp[n];
						return f.apply(this, arguments);
					};
				} else {
					if (n != cn) {
						ns[cn].prototype[n] = f;
					}
				}
			});
		}

		// Add static methods
		/*jshint sub:true*/
		/*eslint dot-notation:0*/
		self.each(p['static'], function(f, n) {
			ns[cn][n] = f;
		});
	}

	/**
	 * Returns the index of a value in an array, this method will return -1 if the item wasn't found.
	 *
	 * @method inArray
	 * @param {Array} a Array/Object to search for value in.
	 * @param {Object} v Value to check for inside the array.
	 * @return {Number/String} Index of item inside the array inside an object. Or -1 if it wasn't found.
	 * @example
	 * // Get index of value in array this will alert 1 since 2 is at that index
	 * alert(tinymce.inArray([1,2,3], 2));
	 */
	function inArray(a, v) {
		var i, l;

		if (a) {
			for (i = 0, l = a.length; i < l; i++) {
				if (a[i] === v) {
					return i;
				}
			}
		}

		return -1;
	}

	function extend(obj, ext) {
		var i, l, name, args = arguments, value;

		for (i = 1, l = args.length; i < l; i++) {
			ext = args[i];
			for (name in ext) {
				if (ext.hasOwnProperty(name)) {
					value = ext[name];

					if (value !== undefined) {
						obj[name] = value;
					}
				}
			}
		}

		return obj;
	}

	/**
	 * Executed the specified function for each item in a object tree.
	 *
	 * @method walk
	 * @param {Object} o Object tree to walk though.
	 * @param {function} f Function to call for each item.
	 * @param {String} n Optional name of collection inside the objects to walk for example childNodes.
	 * @param {String} s Optional scope to execute the function in.
	 */
	function walk(o, f, n, s) {
		s = s || this;

		if (o) {
			if (n) {
				o = o[n];
			}

			each(o, function(o, i) {
				if (f.call(s, o, i, n) === false) {
					return false;
				}

				walk(o, f, n, s);
			});
		}
	}

	/**
	 * Creates a namespace on a specific object.
	 *
	 * @method createNS
	 * @param {String} n Namespace to create for example a.b.c.d.
	 * @param {Object} o Optional object to add namespace to, defaults to window.
	 * @return {Object} New namespace object the last item in path.
	 * @example
	 * // Create some namespace
	 * tinymce.createNS('tinymce.somepackage.subpackage');
	 *
	 * // Add a singleton
	 * var tinymce.somepackage.subpackage.SomeSingleton = {
	 *     method: function() {
	 *         // Some method
	 *     }
	 * };
	 */
	function createNS(n, o) {
		var i, v;

		o = o || window;

		n = n.split('.');
		for (i = 0; i < n.length; i++) {
			v = n[i];

			if (!o[v]) {
				o[v] = {};
			}

			o = o[v];
		}

		return o;
	}

	/**
	 * Resolves a string and returns the object from a specific structure.
	 *
	 * @method resolve
	 * @param {String} n Path to resolve for example a.b.c.d.
	 * @param {Object} o Optional object to search though, defaults to window.
	 * @return {Object} Last object in path or null if it couldn't be resolved.
	 * @example
	 * // Resolve a path into an object reference
	 * var obj = tinymce.resolve('a.b.c.d');
	 */
	function resolve(n, o) {
		var i, l;

		o = o || window;

		n = n.split('.');
		for (i = 0, l = n.length; i < l; i++) {
			o = o[n[i]];

			if (!o) {
				break;
			}
		}

		return o;
	}

	/**
	 * Splits a string but removes the whitespace before and after each value.
	 *
	 * @method explode
	 * @param {string} s String to split.
	 * @param {string} d Delimiter to split by.
	 * @example
	 * // Split a string into an array with a,b,c
	 * var arr = tinymce.explode('a, b,   c');
	 */
	function explode(s, d) {
		if (!s || is(s, 'array')) {
			return s;
		}

		return map(s.split(d || ','), trim);
	}

	function constant(value) {
		return function() {
			return value;
		};
	}

	function reduce(collection, iteratee, accumulator, thisArg) {
		var i = 0;

		if (arguments.length < 3) {
			accumulator = collection[0];
			i = 1;
		}

		for (; i < collection.length; i++) {
			accumulator = iteratee.call(thisArg, accumulator, collection[i], i);
		}

		return accumulator;
	}

	function _addCacheSuffix(url) {
		var cacheSuffix = Env.cacheSuffix;

		if (cacheSuffix) {
			url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
		}

		return url;
	}

	return {
		trim: trim,
		isArray: isArray,
		is: is,
		toArray: toArray,
		makeMap: makeMap,
		each: each,
		map: map,
		grep: grep,
		filter: grep,
		inArray: inArray,
		extend: extend,
		create: create,
		walk: walk,
		createNS: createNS,
		resolve: resolve,
		explode: explode,
		constant: constant,
		reduce: reduce,
		_addCacheSuffix: _addCacheSuffix
	};
});<|endoftext|>


<commit_before>// Copyright 2015

/**
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var shapeshift = require( 'SHAPESHIFT/shapeshift' );
  var Node = require( 'SCENERY/nodes/Node' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var VBox = require( 'SCENERY/nodes/VBox' );
  var BodyNode = require( 'SHAPESHIFT/view/BodyNode' );
  var OperationButton = require( 'SHAPESHIFT/view/OperationButton' );
  var Eyebrow = require( 'SHAPESHIFT/view/Eyebrow' );
  var Eyeball = require( 'SHAPESHIFT/view/Eyeball' );
  var FontAwesomeNode = require( 'SUN/FontAwesomeNode' );
  var Plane = require( 'SCENERY/nodes/Plane' );
  var TitledPanel = require( 'SHAPESHIFT/view/TitledPanel' );
  var Text = require( 'SCENERY/nodes/Text' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var ResetAllButton = require( 'SCENERY_PHET/buttons/ResetAllButton' );
  var Vector2 = require( 'DOT/Vector2' );
  var Panel = require( 'SUN/Panel' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var MultiLineText = require( 'SCENERY_PHET/MultiLineText' );
  var Image = require( 'SCENERY/nodes/Image' );
  var ShapeshiftModel = require( 'SHAPESHIFT/model/ShapeshiftModel' );
  var TextPushButton = require( 'SUN/buttons/TextPushButton' );
  var RoundPushButton = require( 'SUN/buttons/RoundPushButton' );
  var VStrut = require( 'SCENERY/nodes/VStrut' );

  // operations
  var Reflect = require( 'SHAPESHIFT/model/operations/Reflect' );
  var Rotate = require( 'SHAPESHIFT/model/operations/Rotate' );
  var ConvexHull = require( 'SHAPESHIFT/model/operations/ConvexHull' );
  var RadialDoubling = require( 'SHAPESHIFT/model/operations/RadialDoubling' );
  var SelfFractal = require( 'SHAPESHIFT/model/operations/SelfFractal' );
  var DeleteVertices = require( 'SHAPESHIFT/model/operations/DeleteVertices' );
  var Snowflake = require( 'SHAPESHIFT/model/operations/Snowflake' );
  var Subdivide = require( 'SHAPESHIFT/model/operations/Subdivide' );
  var Shear = require( 'SHAPESHIFT/model/operations/Shear' );
  var ArcadeLevelDesign = require( 'SHAPESHIFT/view/arcade/ArcadeLevelDesign' );
  var ArcadeGameModel = require( 'SHAPESHIFT/view/arcade/ArcadeGameModel' );

  // images
  var bannerImage = require( 'image!SHAPESHIFT/banner.png' );

  function ArcadeGameNode( blah, layoutBounds, visibleBoundsProperty, showHomeScreen ) {
    Node.call( this );
    this.layoutBounds = layoutBounds;

    var ground = new Rectangle( -1000, 480, 3000, 1000, { fill: 'green' } );
    this.ground = ground;
    this.time = 0;

    var levels = new ArcadeLevelDesign().getLevels();
    var model = new ArcadeGameModel( levels );
    this.visibleBoundsProperty = visibleBoundsProperty;

    // So the eyes can watch the mouse wherever it goes
    this.addChild( new Plane( { fill: '#5555ff' } ) );
    this.addChild( ground );

    this.model = model;
    this.layoutBounds = layoutBounds;

    this.shapeLayer = new Node( {
      translation: layoutBounds.center
    } );
    this.addChild( this.shapeLayer );

    this.buttonLayer = new HBox( {
      spacing: 25
    } );
    this.addChild( this.buttonLayer );

    this.bodyNodeMap = {}; // body.id => BodyNode

    this.operationButtons = [];

    // listen
    this.model.bodies.addItemAddedListener( this.addBody.bind( this ) );
    this.model.bodies.addItemRemovedListener( this.removeBody.bind( this ) );

    // add
    this.model.bodies.forEach( this.addBody.bind( this ) );

    // this.addOperation( new Reflect() );
    this.addOperation( new Rotate( Math.PI / 2 ) );
    this.addOperation( new ConvexHull() );
    this.addOperation( new RadialDoubling() );
    this.addOperation( new Snowflake() );
    // this.addOperation( new DeleteVertices( 2 ) );
    this.addOperation( new DeleteVertices( 3 ) );
    // this.addOperation( new SelfFractal() ); // makes things slow in preview for many others
    this.addOperation( new Subdivide() );
    this.addOperation( new Shear() );

    var leftEye = new Eyeball();
    var rightEye = new Eyeball();
    leftEye.centerX = this.layoutBounds.centerX - leftEye.width;
    this.addChild( leftEye.mutate( { y: 300 } ) );
    this.addChild( rightEye.mutate( { left: leftEye.right + leftEye.width, y: leftEye.y } ) );

    this.leftEyebrow = new Eyebrow();
    this.rightEyebrow = new Eyebrow();
    this.addChild( this.leftEyebrow.mutate( { x: leftEye.x, y: leftEye.y - 30 } ) );
    this.addChild( this.rightEyebrow.mutate( { x: rightEye.x, y: leftEye.y - 30, scale: new Vector2( -1, 1 ) } ) );

    this.addInputListener( {
      move: function( event ) {
        leftEye.lookAt( event.pointer.point );
        rightEye.lookAt( event.pointer.point );
      }
    } );

    var goalNode = new VBox( { spacing: 10 } );
    this.goalNode = goalNode;
    var update = function() {
      goalNode.children = model.goalBodies.map( function( b ) {
        return new BodyNode( b ).mutate( { scale: 0.5 } );
      } ).getArray();
      if ( goalNode.children.length > 0 ) {
        goalNode.right = visibleBoundsProperty.value.right - 10;
      }
    };
    this.model.goalBodies.addItemAddedListener( update );
    this.model.goalBodies.addItemRemovedListener( update );
    update();

    this.addChild( goalNode );

    model.levelStartedEmitter.addListener( function() {
      self.goalNode.bottom = layoutBounds.top;
    } );

    var resetAllButton = new ResetAllButton();
    resetAllButton.addListener( function() {
      model.reset();
    } );
    resetAllButton.mutate( {
      scale: this.buttonLayer.height / resetAllButton.height * 0.75,
    } );

    var homeButton = new RoundPushButton( { scale: 1.5, content: new FontAwesomeNode( 'home', { fill: 'black' } ) } );
    homeButton.addListener( showHomeScreen );
    this.addChild( homeButton );

    visibleBoundsProperty.link( function( visibleBounds ) {
      resetAllButton.right = visibleBounds.right - 10;

      homeButton.top = visibleBounds.top + 10;
      homeButton.left = visibleBounds.left + 10;
    } );
    this.addChild( resetAllButton );

    var self = this;
    visibleBoundsProperty.link( function( visibleBounds ) {
      self.buttonLayer.bottom = visibleBounds.bottom - 20;
      resetAllButton.bottom = self.buttonLayer.bottom;
    } );

    var levelDescriptionNode = new MultiLineText( 'default text', {
      align: 'left',
      font: new PhetFont( { size: 23 } )
    } );
    var quote = new Panel( levelDescriptionNode );
    var updateTextLocation = function() {
      var visibleBounds = self.visibleBoundsProperty.value;
      quote.top = visibleBounds.top + 10;
      quote.centerX = visibleBounds.centerX;
    };
    visibleBoundsProperty.link( updateTextLocation );

    this.addChild( quote );

    model.levelProperty.link( function( level ) {
      levelDescriptionNode.setText( 'Level: ' + (model.levels.indexOf( level ) + 1) );
      updateTextLocation();
    } );

    model.successEmitter.addListener( function( callback ) {
      var textPushButton = new TextPushButton( 'Continue', { scale: 4 } );
      var levelText = (model.levels.indexOf( model.level ) + 1) + '';
      var createSuccessPanelChildren = [
        new Text( 'Level ' + levelText + ' cleared!', { fontSize: 48 } ),
        textPushButton
      ];
      var panel = new Panel( new VBox( {
        children: createSuccessPanelChildren
      } ), {
        centerX: layoutBounds.centerX,
        bottom: layoutBounds.bottom - 10
      } );
      textPushButton.addListener( function() {
        self.removeChild( panel );
        callback();
      } );
      self.addChild( panel );
    } );

    model.levelProperty.link( function( level ) {
      self.clearOperations();
      for ( var i = 0; i < level.availableOperations.length; i++ ) {
        var obj = level.availableOperations[ i ];
        self.addOperation( obj );
      }
      self.goalNode.bottom = layoutBounds.top;
    } );
    this.speed = 1;

    var tryAgainButton = new TextPushButton( 'Try Again', {
      scale: 3
    } );
    tryAgainButton.addListener( function() {

      // blah
      var currentIndex = self.model.levels.indexOf( self.model.level );
      self.model.startLevel( self.model.levels[ currentIndex ] );

      self.goalNode.bottom = layoutBounds.top;
      self.gameOver = false;

      self.gameOverPanel.visible = false;
    } );
    var gameOverPanel = new Panel( new VBox( {
      spacing: 20,
      children: [
        new MultiLineText( 'Game Over', {
          font: new PhetFont( 48 )
        } ),
        tryAgainButton
      ],
      center: this.layoutBounds.center
    } ) );
    this.addChild( gameOverPanel );
    this.gameOverPanel = gameOverPanel;
    gameOverPanel.visible = false;
  }

  shapeshift.register( 'ArcadeGameNode', ArcadeGameNode );

  return inherit( Node, ArcadeGameNode, {
    clearOperations: function() {
      this.buttonLayer.children = [];
      this.operationButtons.length = 0;
    },
    addOperation: function( operation ) {
      var operationButton = new OperationButton( this.model, operation );
      this.buttonLayer.addChild( operationButton );
      this.operationButtons.push( operationButton );

      this.layoutOperationButtons();
    },

    layoutOperationButtons: function() {
      this.buttonLayer.centerX = this.layoutBounds.centerX;
    },

    addBody: function( body ) {
      var bodyNode = new BodyNode( body );
      this.shapeLayer.addChild( bodyNode );
      this.bodyNodeMap[ body.id ] = bodyNode;
    },

    removeBody: function( body ) {
      this.shapeLayer.removeChild( this.bodyNodeMap[ body.id ] );
      delete this.bodyNodeMap[ body.id ];
    },

    step: function( dt ) {
      if ( !this.gameOver ) {
        this.time += dt;
        this.model.step( dt );
        this.operationButtons.forEach( function( operationButton ) {
          operationButton.update();
        } );
        this.leftEyebrow.step( dt );
        this.rightEyebrow.step( dt );
        this.goalNode.translate( 0, this.speed );
        if ( this.goalNode.globalBounds.intersectsBounds( this.ground.globalBounds ) ) {
          this.gameOver = true;
          this.gameOverPanel.visible = true;
          this.gameOverPanel.center = this.layoutBounds.center;
        }
      }
    }
  } );
} );<commit_msg>Removed reset button (redundant), see #3<commit_after>// Copyright 2015

/**
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var shapeshift = require( 'SHAPESHIFT/shapeshift' );
  var Node = require( 'SCENERY/nodes/Node' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var VBox = require( 'SCENERY/nodes/VBox' );
  var BodyNode = require( 'SHAPESHIFT/view/BodyNode' );
  var OperationButton = require( 'SHAPESHIFT/view/OperationButton' );
  var Eyebrow = require( 'SHAPESHIFT/view/Eyebrow' );
  var Eyeball = require( 'SHAPESHIFT/view/Eyeball' );
  var FontAwesomeNode = require( 'SUN/FontAwesomeNode' );
  var Plane = require( 'SCENERY/nodes/Plane' );
  var TitledPanel = require( 'SHAPESHIFT/view/TitledPanel' );
  var Text = require( 'SCENERY/nodes/Text' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var Vector2 = require( 'DOT/Vector2' );
  var Panel = require( 'SUN/Panel' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var MultiLineText = require( 'SCENERY_PHET/MultiLineText' );
  var Image = require( 'SCENERY/nodes/Image' );
  var ShapeshiftModel = require( 'SHAPESHIFT/model/ShapeshiftModel' );
  var TextPushButton = require( 'SUN/buttons/TextPushButton' );
  var RoundPushButton = require( 'SUN/buttons/RoundPushButton' );
  var VStrut = require( 'SCENERY/nodes/VStrut' );

  // operations
  var Reflect = require( 'SHAPESHIFT/model/operations/Reflect' );
  var Rotate = require( 'SHAPESHIFT/model/operations/Rotate' );
  var ConvexHull = require( 'SHAPESHIFT/model/operations/ConvexHull' );
  var RadialDoubling = require( 'SHAPESHIFT/model/operations/RadialDoubling' );
  var SelfFractal = require( 'SHAPESHIFT/model/operations/SelfFractal' );
  var DeleteVertices = require( 'SHAPESHIFT/model/operations/DeleteVertices' );
  var Snowflake = require( 'SHAPESHIFT/model/operations/Snowflake' );
  var Subdivide = require( 'SHAPESHIFT/model/operations/Subdivide' );
  var Shear = require( 'SHAPESHIFT/model/operations/Shear' );
  var ArcadeLevelDesign = require( 'SHAPESHIFT/view/arcade/ArcadeLevelDesign' );
  var ArcadeGameModel = require( 'SHAPESHIFT/view/arcade/ArcadeGameModel' );

  // images
  var bannerImage = require( 'image!SHAPESHIFT/banner.png' );

  function ArcadeGameNode( blah, layoutBounds, visibleBoundsProperty, showHomeScreen ) {
    Node.call( this );
    this.layoutBounds = layoutBounds;

    var ground = new Rectangle( -1000, 480, 3000, 1000, { fill: 'green' } );
    this.ground = ground;
    this.time = 0;

    var levels = new ArcadeLevelDesign().getLevels();
    var model = new ArcadeGameModel( levels );
    this.visibleBoundsProperty = visibleBoundsProperty;

    // So the eyes can watch the mouse wherever it goes
    this.addChild( new Plane( { fill: '#5555ff' } ) );
    this.addChild( ground );

    this.model = model;
    this.layoutBounds = layoutBounds;

    this.shapeLayer = new Node( {
      translation: layoutBounds.center
    } );
    this.addChild( this.shapeLayer );

    this.buttonLayer = new HBox( {
      spacing: 25
    } );
    this.addChild( this.buttonLayer );

    this.bodyNodeMap = {}; // body.id => BodyNode

    this.operationButtons = [];

    // listen
    this.model.bodies.addItemAddedListener( this.addBody.bind( this ) );
    this.model.bodies.addItemRemovedListener( this.removeBody.bind( this ) );

    // add
    this.model.bodies.forEach( this.addBody.bind( this ) );

    // this.addOperation( new Reflect() );
    this.addOperation( new Rotate( Math.PI / 2 ) );
    this.addOperation( new ConvexHull() );
    this.addOperation( new RadialDoubling() );
    this.addOperation( new Snowflake() );
    // this.addOperation( new DeleteVertices( 2 ) );
    this.addOperation( new DeleteVertices( 3 ) );
    // this.addOperation( new SelfFractal() ); // makes things slow in preview for many others
    this.addOperation( new Subdivide() );
    this.addOperation( new Shear() );

    var leftEye = new Eyeball();
    var rightEye = new Eyeball();
    leftEye.centerX = this.layoutBounds.centerX - leftEye.width;
    this.addChild( leftEye.mutate( { y: 300 } ) );
    this.addChild( rightEye.mutate( { left: leftEye.right + leftEye.width, y: leftEye.y } ) );

    this.leftEyebrow = new Eyebrow();
    this.rightEyebrow = new Eyebrow();
    this.addChild( this.leftEyebrow.mutate( { x: leftEye.x, y: leftEye.y - 30 } ) );
    this.addChild( this.rightEyebrow.mutate( { x: rightEye.x, y: leftEye.y - 30, scale: new Vector2( -1, 1 ) } ) );

    this.addInputListener( {
      move: function( event ) {
        leftEye.lookAt( event.pointer.point );
        rightEye.lookAt( event.pointer.point );
      }
    } );

    var goalNode = new VBox( { spacing: 10 } );
    this.goalNode = goalNode;
    var update = function() {
      goalNode.children = model.goalBodies.map( function( b ) {
        return new BodyNode( b ).mutate( { scale: 0.5 } );
      } ).getArray();
      if ( goalNode.children.length > 0 ) {
        goalNode.right = visibleBoundsProperty.value.right - 10;
      }
    };
    this.model.goalBodies.addItemAddedListener( update );
    this.model.goalBodies.addItemRemovedListener( update );
    update();

    this.addChild( goalNode );

    model.levelStartedEmitter.addListener( function() {
      self.goalNode.bottom = layoutBounds.top;
    } );

    var homeButton = new RoundPushButton( { scale: 1.5, content: new FontAwesomeNode( 'home', { fill: 'black' } ) } );
    homeButton.addListener( showHomeScreen );
    this.addChild( homeButton );

    visibleBoundsProperty.link( function( visibleBounds ) {
      homeButton.top = visibleBounds.top + 10;
      homeButton.left = visibleBounds.left + 10;
    } );

    var self = this;
    visibleBoundsProperty.link( function( visibleBounds ) {
      self.buttonLayer.bottom = visibleBounds.bottom - 20;
    } );

    var levelDescriptionNode = new MultiLineText( 'default text', {
      align: 'left',
      font: new PhetFont( { size: 23 } )
    } );
    var quote = new Panel( levelDescriptionNode );
    var updateTextLocation = function() {
      var visibleBounds = self.visibleBoundsProperty.value;
      quote.top = visibleBounds.top + 10;
      quote.centerX = visibleBounds.centerX;
    };
    visibleBoundsProperty.link( updateTextLocation );

    this.addChild( quote );

    model.levelProperty.link( function( level ) {
      levelDescriptionNode.setText( 'Level: ' + (model.levels.indexOf( level ) + 1) );
      updateTextLocation();
    } );

    model.successEmitter.addListener( function( callback ) {
      var textPushButton = new TextPushButton( 'Continue', { scale: 4 } );
      var levelText = (model.levels.indexOf( model.level ) + 1) + '';
      var createSuccessPanelChildren = [
        new Text( 'Level ' + levelText + ' cleared!', { fontSize: 48 } ),
        textPushButton
      ];
      var panel = new Panel( new VBox( {
        children: createSuccessPanelChildren
      } ), {
        centerX: layoutBounds.centerX,
        bottom: layoutBounds.bottom - 10
      } );
      textPushButton.addListener( function() {
        self.removeChild( panel );
        callback();
      } );
      self.addChild( panel );
    } );

    model.levelProperty.link( function( level ) {
      self.clearOperations();
      for ( var i = 0; i < level.availableOperations.length; i++ ) {
        var obj = level.availableOperations[ i ];
        self.addOperation( obj );
      }
      self.goalNode.bottom = layoutBounds.top;
    } );
    this.speed = 1;

    var tryAgainButton = new TextPushButton( 'Try Again', {
      scale: 3
    } );
    tryAgainButton.addListener( function() {

      // blah
      var currentIndex = self.model.levels.indexOf( self.model.level );
      self.model.startLevel( self.model.levels[ currentIndex ] );

      self.goalNode.bottom = layoutBounds.top;
      self.gameOver = false;

      self.gameOverPanel.visible = false;
    } );
    var gameOverPanel = new Panel( new VBox( {
      spacing: 20,
      children: [
        new MultiLineText( 'Game Over', {
          font: new PhetFont( 48 )
        } ),
        tryAgainButton
      ],
      center: this.layoutBounds.center
    } ) );
    this.addChild( gameOverPanel );
    this.gameOverPanel = gameOverPanel;
    gameOverPanel.visible = false;
  }

  shapeshift.register( 'ArcadeGameNode', ArcadeGameNode );

  return inherit( Node, ArcadeGameNode, {
    clearOperations: function() {
      this.buttonLayer.children = [];
      this.operationButtons.length = 0;
    },
    addOperation: function( operation ) {
      var operationButton = new OperationButton( this.model, operation );
      this.buttonLayer.addChild( operationButton );
      this.operationButtons.push( operationButton );

      this.layoutOperationButtons();
    },

    layoutOperationButtons: function() {
      this.buttonLayer.centerX = this.layoutBounds.centerX;
    },

    addBody: function( body ) {
      var bodyNode = new BodyNode( body );
      this.shapeLayer.addChild( bodyNode );
      this.bodyNodeMap[ body.id ] = bodyNode;
    },

    removeBody: function( body ) {
      this.shapeLayer.removeChild( this.bodyNodeMap[ body.id ] );
      delete this.bodyNodeMap[ body.id ];
    },

    step: function( dt ) {
      if ( !this.gameOver ) {
        this.time += dt;
        this.model.step( dt );
        this.operationButtons.forEach( function( operationButton ) {
          operationButton.update();
        } );
        this.leftEyebrow.step( dt );
        this.rightEyebrow.step( dt );
        this.goalNode.translate( 0, this.speed );
        if ( this.goalNode.globalBounds.intersectsBounds( this.ground.globalBounds ) ) {
          this.gameOver = true;
          this.gameOverPanel.visible = true;
          this.gameOverPanel.center = this.layoutBounds.center;
        }
      }
    }
  } );
} );<|endoftext|>


<commit_before>import React from 'react/addons';
import {Navigation} from 'react-router';
import $ from 'jquery';

import bem from '../bem';
import ui from '../ui';
import stores from '../stores';
import {
  formatTime,
  anonUsername,
  t,
  assign,
} from '../utils';

var AssetTypeIcon = bem.create('asset-type-icon');

var AssetRow = React.createClass({
  mixins: [
    Navigation
  ],
  clickAsset (evt) {
    var clickedActionIcon = $(evt.target).closest('[data-action]').get(0);
    if (clickedActionIcon && this.props.isSelected) {
      this.props.onActionButtonClick(assign(evt, {
        actionIcon: clickedActionIcon,
      }));
    } else {
      // this click was not intended for a button
      evt.nativeEvent.preventDefault();
      evt.nativeEvent.stopImmediatePropagation();
      evt.preventDefault();

      // if no asset is selected, then this asset
      // otherwise, toggle selection (unselect if already selected)
      let forceSelect = (stores.selectedAsset.uid === false);
      stores.selectedAsset.toggleSelect(this.props.uid, forceSelect);
    }
  },
  preventDefault (evt) {
    evt.preventDefault();
  },
  render () {
    var selfowned = this.props.owner__username === this.props.currentUsername;
    // var perm = this.props.perm;
    var isPublic = this.props.owner__username === anonUsername;
    var _rc = this.props.summary && this.props.summary.row_count;
    var isCollection = this.props.kind === 'collection',
        hrefTo = isCollection ? 'collection-page' : 'form-landing',
        hrefKey = isCollection ? 'uid' : 'assetid',
        hrefParams = {},
        tags = this.props.tags || [];
    if (isCollection) {
      _rc = this.props.assets_count + this.props.children_count;
    }
    var isDeployable = !isCollection && this.props.asset_type && this.props.asset_type === 'survey';
    hrefParams[hrefKey] = this.props.uid;
    return (
        <bem.AssetRow m={{
                            'selected': this.props.isSelected,
                            'deleted': this.props.deleted,
                            'deleting': this.props.deleting,
                          }}
                        onClick={this.clickAsset}
                      >

          <bem.AssetRow__cell m={['icon']}>
            <AssetTypeIcon m={[this.props.asset_type, 'medium']}></AssetTypeIcon>
          </bem.AssetRow__cell>

          <bem.AssetRow__celllink m={['name', this.props.name ? 'titled' : 'untitled']}
                data-kind={this.props.kind}
                data-asset-type={this.props.kind}
                href={this.makeHref( hrefTo, hrefParams)}
              >
            <bem.AssetRow__name>
              <ui.AssetName {...this.props} />
            </bem.AssetRow__name>
          </bem.AssetRow__celllink>
          <bem.AssetRow__cellmeta>
            <bem.AssetRow__cell m={'userlink'}>
              <bem.AssetRow__sharingIcon
                  href="#"
                  m={{
                    'self-owned': selfowned,
                    'public-owned': isPublic,
                  }}>

                {
                  selfowned ?
                    t('me') :
                  <bem.AssetRow__sharingIcon__owner>
                    {this.props.owner__username}
                  </bem.AssetRow__sharingIcon__owner>
                }
              </bem.AssetRow__sharingIcon>
            </bem.AssetRow__cell>
            <bem.AssetRow__cell m={'date-modified'}>
              {t('Modified')} {formatTime(this.props.date_modified)}
            </bem.AssetRow__cell>
            <bem.AssetRow__cell m={'row-count'}>
              {()=>{
                if (this.props.kind === 'collection') {
                  return t('collection with ___ items').replace('___', _rc);
                } else if (this.props.asset_type === 'survey') {
                  return t('survey with ___ questions').replace('___', _rc);
                } else if (this.props.asset_type === 'block') {
                  return t('block with ___ questions').replace('___', _rc);
                }
              }()}
            </bem.AssetRow__cell>
          </bem.AssetRow__cellmeta>
          { this.props.isSelected &&
            <bem.AssetRow__cell m={'buttons'}>
              <bem.AssetRow__cell m={'action-icons'}>
                { this.props.kind === 'asset' &&
                  ['edit', 'view', 'download', 'clone'].map((actn)=>{
                    return (
                          <bem.AssetRow__actionIcon
                              m={actn}
                              data-action={actn}
                              data-asset-type={this.props.kind}
                              data-disabled={false}
                              >

                            {actn}
                          </bem.AssetRow__actionIcon>
                        );
                  })
                }
                { isDeployable &&
                  <bem.AssetRow__actionIcon
                        m={'deploy'}
                        data-action={'deploy'}
                        data-asset-type={this.props.kind}
                      >

                    {t('deploy')}
                  </bem.AssetRow__actionIcon>
                }
                { this.props.kind === 'collection' &&
                ['view', 'sharing'].map((actn)=>{
                    return (
                          <bem.AssetRow__actionIcon
                            m={actn === 'view' ? 'view-collection' : actn}
                              data-action={actn}
                              data-asset-type={this.props.kind}
                              data-disabled={false}
                              >

                            {actn}
                          </bem.AssetRow__actionIcon>
                        );
                  })
                }
              </bem.AssetRow__cell>
            </bem.AssetRow__cell>
          }
          { tags.length > 0 && this.props.isSelected &&
            <bem.AssetRow__cellmeta m={'tags'}>
              <bem.AssetRow__cell m={'tags'}>
                <bem.AssetRow__tags>

                  {tags.map((tag)=>{
                    return (
                          <bem.AssetRow__tags__tag>{tag}</bem.AssetRow__tags__tag>
                      );
                  })}
                </bem.AssetRow__tags>
              </bem.AssetRow__cell>
            </bem.AssetRow__cellmeta>
          }
          { this.props.isSelected &&
            <bem.AssetRow__cell m={'secondary-buttons'}>
              <bem.AssetRow__cell m={'action-icons'}>
                {
                  ['refresh', 'delete'].map((actn)=>{
                    return (
                          <bem.AssetRow__actionIcon
                              m={actn}
                              data-action={actn}
                              data-asset-type={this.props.kind}
                              data-disabled={false}
                              >

                            {actn}
                          </bem.AssetRow__actionIcon>
                        );
                  })
                }
              </bem.AssetRow__cell>
            </bem.AssetRow__cell>
          }
        </bem.AssetRow>
      );
  }
});

export default AssetRow;
<commit_msg>simplifying assetrow icons<commit_after>import React from 'react/addons';
import {Navigation} from 'react-router';
import $ from 'jquery';

import bem from '../bem';
import ui from '../ui';
import stores from '../stores';
import {
  formatTime,
  anonUsername,
  t,
  assign,
} from '../utils';

var AssetTypeIcon = bem.create('asset-type-icon');

var AssetRow = React.createClass({
  mixins: [
    Navigation
  ],
  clickAsset (evt) {
    var clickedActionIcon = $(evt.target).closest('[data-action]').get(0);
    if (clickedActionIcon && this.props.isSelected) {
      this.props.onActionButtonClick(assign(evt, {
        actionIcon: clickedActionIcon,
      }));
    } else {
      // this click was not intended for a button
      evt.nativeEvent.preventDefault();
      evt.nativeEvent.stopImmediatePropagation();
      evt.preventDefault();

      // if no asset is selected, then this asset
      // otherwise, toggle selection (unselect if already selected)
      let forceSelect = (stores.selectedAsset.uid === false);
      stores.selectedAsset.toggleSelect(this.props.uid, forceSelect);
    }
  },
  preventDefault (evt) {
    evt.preventDefault();
  },
  render () {
    var selfowned = this.props.owner__username === this.props.currentUsername;
    // var perm = this.props.perm;
    var isPublic = this.props.owner__username === anonUsername;
    var _rc = this.props.summary && this.props.summary.row_count;
    var isCollection = this.props.kind === 'collection',
        hrefTo = isCollection ? 'collection-page' : 'form-landing',
        hrefKey = isCollection ? 'uid' : 'assetid',
        hrefParams = {},
        tags = this.props.tags || [];
    if (isCollection) {
      _rc = this.props.assets_count + this.props.children_count;
    }
    var isDeployable = !isCollection && this.props.asset_type && this.props.asset_type === 'survey';
    hrefParams[hrefKey] = this.props.uid;
    return (
        <bem.AssetRow m={{
                            'selected': this.props.isSelected,
                            'active': this.props.isSelected,
                            'inactive': !this.props.isSelected,
                            'deleted': this.props.deleted,
                            'deleting': this.props.deleting,
                          }}
                        onClick={this.clickAsset}
                      >

          <bem.AssetRow__cell m={['icon']}>
            <AssetTypeIcon m={[this.props.asset_type, 'medium']}></AssetTypeIcon>
          </bem.AssetRow__cell>

          <bem.AssetRow__celllink m={['name', this.props.name ? 'titled' : 'untitled']}
                data-kind={this.props.kind}
                data-asset-type={this.props.kind}
                href={this.makeHref( hrefTo, hrefParams)}
              >
            <bem.AssetRow__name>
              <ui.AssetName {...this.props} />
            </bem.AssetRow__name>
          </bem.AssetRow__celllink>
          <bem.AssetRow__cellmeta>
            <bem.AssetRow__cell m={'userlink'}>
              {
                selfowned ?
                  t('me') :
                  this.props.owner__username
              }
            </bem.AssetRow__cell>
            <bem.AssetRow__cell m={'date-modified'}>
              {t('Modified')} {formatTime(this.props.date_modified)}
            </bem.AssetRow__cell>
            <bem.AssetRow__cell m={'row-count'}>
              {()=>{
                if (this.props.kind === 'collection') {
                  return t('collection with ___ items').replace('___', _rc);
                } else if (this.props.asset_type === 'survey') {
                  return t('survey with ___ questions').replace('___', _rc);
                } else if (this.props.asset_type === 'block') {
                  return t('block with ___ questions').replace('___', _rc);
                }
              }()}
            </bem.AssetRow__cell>
          </bem.AssetRow__cellmeta>
          { this.props.isSelected &&
            <bem.AssetRow__cell m={'buttons'}>
              <bem.AssetRow__cell m={'action-icons'}>
                { this.props.kind === 'asset' &&
                  ['edit', 'view', 'download', 'clone'].map((actn)=>{
                    return (
                          <bem.AssetRow__actionIcon
                              m={actn}
                              data-action={actn}
                              data-asset-type={this.props.kind}
                              data-disabled={false}
                              >

                            {actn}
                          </bem.AssetRow__actionIcon>
                        );
                  })
                }
                { isDeployable &&
                  <bem.AssetRow__actionIcon
                        m={'deploy'}
                        data-action={'deploy'}
                        data-asset-type={this.props.kind}
                      >

                    {t('deploy')}
                  </bem.AssetRow__actionIcon>
                }
                { this.props.kind === 'collection' &&
                ['view', 'sharing'].map((actn)=>{
                    return (
                          <bem.AssetRow__actionIcon
                            m={actn === 'view' ? 'view-collection' : actn}
                              data-action={actn}
                              data-asset-type={this.props.kind}
                              data-disabled={false}
                              >

                            {actn}
                          </bem.AssetRow__actionIcon>
                        );
                  })
                }
              </bem.AssetRow__cell>
            </bem.AssetRow__cell>
          }
          { tags.length > 0 && this.props.isSelected &&
            <bem.AssetRow__cellmeta m={'tags'}>
              <bem.AssetRow__cell m={'tags'}>
                <bem.AssetRow__tags>

                  {tags.map((tag)=>{
                    return (
                          <bem.AssetRow__tags__tag>{tag}</bem.AssetRow__tags__tag>
                      );
                  })}
                </bem.AssetRow__tags>
              </bem.AssetRow__cell>
            </bem.AssetRow__cellmeta>
          }
          { this.props.isSelected &&
            <bem.AssetRow__cell m={'secondary-buttons'}>
              <bem.AssetRow__cell m={'action-icons'}>
                  {['refresh', 'delete'].map((actn)=>{
                    return (
                          <bem.AssetRow__actionIcon
                              m={actn}
                              data-action={actn}
                              data-asset-type={this.props.kind}
                              data-disabled={false}
                              >

                            {actn}
                          </bem.AssetRow__actionIcon>
                        );
                  })}
              </bem.AssetRow__cell>
            </bem.AssetRow__cell>
          }
        </bem.AssetRow>
      );
  }
});

export default AssetRow;
<|endoftext|>


<commit_before>const knex = require('knex')
const config = require('server/services/config')

var defaults = {
  pool: {
    min: 2,
    max: 10
  },
  migrations: {
    tableName: 'schema_migrations',
    directory: '/'
  },
  seeds: {
    directory: '/'
  }
}

module.exports = knex({
  ...defaults,
  ...config.database
})
<commit_msg>Replace object spread operator with Object.assign<commit_after>const knex = require('knex')
const config = require('server/services/config')

var defaults = {
  pool: {
    min: 2,
    max: 10
  },
  migrations: {
    tableName: 'schema_migrations',
    directory: '/'
  },
  seeds: {
    directory: '/'
  }
}

module.exports = knex(Object.assign({}, defaults, config.database))
<|endoftext|>


<commit_before>var _ = require('lodash');
var log = require('winston');

/**
 * Create a function that will extract information, to properties on the tag or doc, from the tags
 * that were parsed from the doc.
 *
 * @param  {Array} tagDefs
 *           A collection of tagDefinitions to extract from the parsed tags.
 * @param  {function(doc, tag, value)|Array.<function(doc, tag, value)>} [defaultTransforms]
 *           A single transformation function (or collection of transformation functions) to apply
 *           to every tag that is extracted.
 */
module.exports = {
  name: 'tagExtractor',
  exports: {
    tagExtractor: ['factory', function tagExtractorFactory(tagDefinitions, defaultTransforms) {

      // Compute a default transformation function
      var defaultTransformFn = getTransformationFn(defaultTransforms);

      // Add some useful methods to the tagDefs
      var tagDefs = _.map(tagDefinitions, function(tagDef) {

        // Make a copy of the tagDef as we are going to modify it
        tagDef = _.clone(tagDef);

        // Compute this tagDefs specific transformation function
        var transformFn = getTransformationFn(tagDef.transforms);

        // Attach a transformation function to the cloned tagDef
        // running the specific transforms followed by the default transforms
        var tagProperty = tagDef.tagProperty || 'description';
        tagDef.getProperty = function(doc, tag) {
          var value = tag[tagProperty];
          value = transformFn(doc, tag, value);
          value = defaultTransformFn(doc, tag, value);
          return value;
        };

        return tagDef;
      });

      return function tagExtractor(doc) {

        // Try to extract each of the tags defined in the tagDefs collection
        _.forEach(tagDefs, function(tagDef) {

          log.silly('extracting tags for: ' + tagDef.name);

          var docProperty = tagDef.docProperty || tagDef.name;
          log.silly(' - to be attached to doc.' + docProperty);

          // Collect the tags for this tag def
          var tags = doc.tags.getTags(tagDef.name);

          // No tags found for this tag def
          if ( tags.length === 0 ) {

            // This tag is required so throw an error
            if ( tagDef.required ) {
              throw new Error('Missing tag "' + tagDef.name + '" in file "' + doc.file + '" at line ' + doc.startingLine);
            }

            // Apply the default function if there is one
            if ( tagDef.defaultFn ) {
              log.silly(' - tag not found, applying default value function');
              var defaultValue = tagDef.defaultFn(doc);
              if ( defaultValue !== undefined ) {
                // If the defaultFn returns a value then use this as the document property
                if ( tagDef.multi ) {
                  doc[docProperty] = (doc[docProperty] || []).concat(defaultValue);
                } else {
                  doc[docProperty] = defaultValue;
                }
              }
            }

          } else {

            // Does this tagDef expect multiple instances of the tag?
            if ( tagDef.multi ) {

              // We may have multiple tags for this tag def, so we put them into an array
              doc[docProperty] = doc[docProperty] || [];
              _.forEach(tags, function(tag) {
                // Transform and add the tag to the array
                doc[docProperty].push(tagDef.getProperty(doc, tag));
              });

            } else {

              // We only expect one tag for this tag def
              if ( tags.length > 1 ) {
                throw new Error('Only one of "' + tagDef.name + '" (or its aliases) allowed. There were ' + tags.length + ' in file "' + doc.file + '" at line ' + doc.startingLine);
              }

              // Transform and apply the tag to the document
              doc[docProperty] = tagDef.getProperty(doc, tags[0]);
            }
          }

        });

        if ( doc.tags.badTags.length > 0 ) {
          log.warn(formatBadTagErrorMessage(doc));
        }
      };
    }]
  }
};

/**
 * Create a function to transform from the tag to doc property
 * @param  {function(doc, tag, value)|Array.<function(doc, tag, value)>} transform
 *         The transformation to apply to the tag
 * @return {function(doc, tag, value)} A single function that will do the transformation
 */
function getTransformationFn(transforms) {

  if ( _.isFunction(transforms) ) {

    // transform is a single function so just use that
    return transforms;
  }

  if ( _.isArray(transforms) ) {

    // transform is an array then we will apply each in turn like a pipe-line
    return function(doc, tag, value) {

      _.forEach(transforms, function(transform) {
        value = transform(doc, tag, value);
      });

      return value;

    };
  }

  if ( !transforms ) {

    // No transform is specified so we just provide a default
    return function(doc, tag, value) { return value; };

  }

  throw new Error('Invalid transformFn in tag definition, ' + tagDef.name +
      ' - you must provide a function or an array of functions.');
}

function formatBadTagErrorMessage(doc) {
  var id = (doc.id || doc.name);
  id = id ? '"' + id + '" ' : '';
  var message = 'Invalid tags found in doc, starting at line ' + doc.startingLine + ', from file "' + doc.file + '"\n';

  _.forEach(doc.tags.badTags, function(badTag) {
    var description = (_.isString(badTag.description) && (badTag.description.substr(0, 20) + '...'));
    if ( badTag.name ) {
      description = badTag.name + ' ' + description;
    }
    if ( badTag.typeExpression ) {
      description = '{' + badTag.typeExpression + '} ' + description;
    }

    message += 'Line: ' + badTag.startingLine + ': @' + badTag.tagName + ' ' + description + '\n';
    _.forEach(badTag.errors, function(error) {
      message += '    * ' + error + '\n';
    });
  });

  return message + '\n';
}
<commit_msg>fix(tagExtractor): invalid injectable parameter name<commit_after>var _ = require('lodash');
var log = require('winston');

/**
 * Create a function that will extract information, to properties on the tag or doc, from the tags
 * that were parsed from the doc.
 *
 * @param  {Array} tagDefinitions
 *           A collection of tagDefinitions to extract from the parsed tags.
 * @param  {function(doc, tag, value)|Array.<function(doc, tag, value)>} [defaultTagTransforms]
 *           A single transformation function (or collection of transformation functions) to apply
 *           to every tag that is extracted.
 */
module.exports = {
  name: 'tagExtractor',
  exports: {
    tagExtractor: ['factory', function tagExtractorFactory(tagDefinitions, defaultTagTransforms) {

      // Compute a default transformation function
      var defaultTransformFn = getTransformationFn(defaultTagTransforms);

      // Add some useful methods to the tagDefs
      var tagDefs = _.map(tagDefinitions, function(tagDef) {

        // Make a copy of the tagDef as we are going to modify it
        tagDef = _.clone(tagDef);

        // Compute this tagDefs specific transformation function
        var transformFn = getTransformationFn(tagDef.transforms);

        // Attach a transformation function to the cloned tagDef
        // running the specific transforms followed by the default transforms
        var tagProperty = tagDef.tagProperty || 'description';
        tagDef.getProperty = function(doc, tag) {
          var value = tag[tagProperty];
          value = transformFn(doc, tag, value);
          value = defaultTransformFn(doc, tag, value);
          return value;
        };

        return tagDef;
      });

      return function tagExtractor(doc) {

        // Try to extract each of the tags defined in the tagDefs collection
        _.forEach(tagDefs, function(tagDef) {

          log.silly('extracting tags for: ' + tagDef.name);

          var docProperty = tagDef.docProperty || tagDef.name;
          log.silly(' - to be attached to doc.' + docProperty);

          // Collect the tags for this tag def
          var tags = doc.tags.getTags(tagDef.name);

          // No tags found for this tag def
          if ( tags.length === 0 ) {

            // This tag is required so throw an error
            if ( tagDef.required ) {
              throw new Error('Missing tag "' + tagDef.name + '" in file "' + doc.file + '" at line ' + doc.startingLine);
            }

            // Apply the default function if there is one
            if ( tagDef.defaultFn ) {
              log.silly(' - tag not found, applying default value function');
              var defaultValue = tagDef.defaultFn(doc);
              if ( defaultValue !== undefined ) {
                // If the defaultFn returns a value then use this as the document property
                if ( tagDef.multi ) {
                  doc[docProperty] = (doc[docProperty] || []).concat(defaultValue);
                } else {
                  doc[docProperty] = defaultValue;
                }
              }
            }

          } else {

            // Does this tagDef expect multiple instances of the tag?
            if ( tagDef.multi ) {

              // We may have multiple tags for this tag def, so we put them into an array
              doc[docProperty] = doc[docProperty] || [];
              _.forEach(tags, function(tag) {
                // Transform and add the tag to the array
                doc[docProperty].push(tagDef.getProperty(doc, tag));
              });

            } else {

              // We only expect one tag for this tag def
              if ( tags.length > 1 ) {
                throw new Error('Only one of "' + tagDef.name + '" (or its aliases) allowed. There were ' + tags.length + ' in file "' + doc.file + '" at line ' + doc.startingLine);
              }

              // Transform and apply the tag to the document
              doc[docProperty] = tagDef.getProperty(doc, tags[0]);
            }
          }

        });

        if ( doc.tags.badTags.length > 0 ) {
          log.warn(formatBadTagErrorMessage(doc));
        }
      };
    }]
  }
};

/**
 * Create a function to transform from the tag to doc property
 * @param  {function(doc, tag, value)|Array.<function(doc, tag, value)>} transform
 *         The transformation to apply to the tag
 * @return {function(doc, tag, value)} A single function that will do the transformation
 */
function getTransformationFn(transforms) {

  if ( _.isFunction(transforms) ) {

    // transform is a single function so just use that
    return transforms;
  }

  if ( _.isArray(transforms) ) {

    // transform is an array then we will apply each in turn like a pipe-line
    return function(doc, tag, value) {

      _.forEach(transforms, function(transform) {
        value = transform(doc, tag, value);
      });

      return value;

    };
  }

  if ( !transforms ) {

    // No transform is specified so we just provide a default
    return function(doc, tag, value) { return value; };

  }

  throw new Error('Invalid transformFn in tag definition, ' + tagDef.name +
      ' - you must provide a function or an array of functions.');
}

function formatBadTagErrorMessage(doc) {
  var id = (doc.id || doc.name);
  id = id ? '"' + id + '" ' : '';
  var message = 'Invalid tags found in doc, starting at line ' + doc.startingLine + ', from file "' + doc.file + '"\n';

  _.forEach(doc.tags.badTags, function(badTag) {
    var description = (_.isString(badTag.description) && (badTag.description.substr(0, 20) + '...'));
    if ( badTag.name ) {
      description = badTag.name + ' ' + description;
    }
    if ( badTag.typeExpression ) {
      description = '{' + badTag.typeExpression + '} ' + description;
    }

    message += 'Line: ' + badTag.startingLine + ': @' + badTag.tagName + ' ' + description + '\n';
    _.forEach(badTag.errors, function(error) {
      message += '    * ' + error + '\n';
    });
  });

  return message + '\n';
}
<|endoftext|>