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

/**
 * Grunt configuration file for PhET projects.
 * Requires a package.json file containing project settings.
 * Tasks share information via global.phet, see individual tasks for details.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 * @author Jon Olson
 * @author Sam Reid
 * @author John Blanco
 */

// built-in node APIs
var assert = require( 'assert' );
var fs = require( 'fs' );

// 3rd-party packages
/* jshint -W079 */
var _ = require( '../../../sherpa/lib/lodash-2.4.1.min' ); // allow _ to be redefined, contrary to jshintOptions.js
/* jshint +W079 */

// PhET custom grunt tasks
var afterRequirejsBuild = require( '../../../chipper/js/grunt/afterRequirejsBuild' );
var beforeRequirejsBuild = require( '../../../chipper/js/grunt/beforeRequirejsBuild' );
var checkoutShas = require( '../../../chipper/js/grunt/checkoutShas' );
var createSim = require( '../../../chipper/js/grunt/createSim' );
var deploySimulation = require( '../../../chipper/js/grunt/deploySimulation' );
var deployDev = require( '../../../chipper/js/grunt/deployDev' );
var generateREADME = require( '../../../chipper/js/grunt/generateREADME' );
var generateThumbnails = require( '../../../chipper/js/grunt/generateThumbnails' );
var pullAll = require( '../../../chipper/js/grunt/pullAll' );
var setPreload = require( '../../../chipper/js/grunt/setPreload' );
var stringReport = require( '../../../chipper/js/grunt/stringReport' );
var reportMedia = require( '../../../chipper/js/grunt/reportMedia' );
var reportThirdParty = require( '../../../chipper/js/grunt/reportThirdParty' );

//TODO look at why this is necessary
/*
 * In Node, global is the global namespace object.
 * Register fs as a global so it can be accessed through the requirejs build system. Text.js plugin
 * may have a superior way to handle this but I (SR) couldn't get it working after a small amount of effort.
 */
global.fs = fs;

module.exports = function( grunt ) {
  'use strict';

  var FALLBACK_LOCAL = 'en';

  // Read package.json, verify that it contains properties required by all PhET repositories
  assert( fs.existsSync( 'package.json' ), 'repository must have a package.json' );
  var pkg = grunt.file.readJSON( 'package.json' );
  assert( pkg.name, 'name missing from package.json' );
  assert( pkg.version, 'version missing from package.json' );
  assert( pkg.license, 'license missing from package.json' );

  // For sims, read common phetLibs from chipper/build.json. We'll do this here since several grunt tasks (including some utilities) need phetLibs.
  assert( fs.existsSync( '../chipper/build.json' ), 'missing build.json' );
  var buildInfo = grunt.file.readJSON( '../chipper/build.json' );
  pkg.phetLibs = pkg.phetLibs || [];
  pkg.phetLibs = _.uniq( pkg.phetLibs.concat( buildInfo.common.phetLibs ).sort() );
  grunt.log.debug( 'phetLibs = ' + pkg.phetLibs );

  // TODO: As a temporary means of keeping track of "together" versions, replace "-dev" with "-together" in the version
  // string. This approach has a lot of problems and should be replaced as soon as we work out a more all encompassing
  // way of tracking together-enhanced versions.  See https://github.com/phetsims/special-ops/issues/3 for more info.
  if ( grunt.option( 'together' ) && pkg.version.indexOf( '-dev' ) > -1 ) {
    pkg.version = pkg.version.replace( '-dev', '-together' );
  }

  var globalDefs = {
    // global assertions
    assert: false,
    assertSlow: false,
    // scenery logging
    sceneryLog: false,
    sceneryLayerLog: false,
    sceneryEventLog: false,
    sceneryAccessibilityLog: false,
    phetAllocation: false
  };

  // Enumerate the list of files to be linted for the jshint:allFiles task
  console.log( 'pkg.phetLibs=' + pkg.phetLibs );//XXX
  var allFilesToLint = _.map( pkg.phetLibs, function( repo ) {
    return '../' + repo + '/js/**/*.js';
  } );

  // The brand repo has a different structure, so add it explicitly
  allFilesToLint.push( '../brand/*/js/**/*.js' );

  // Don't try to lint the svgPath.js.  It was automatically generated and doesn't match convention
  allFilesToLint.push( '!../kite/js/parser/svgPath.js' );

  // Identify the repo files to lint for the single repo.
  // The brand repo is a special case since it has nested subdirectories instead of a top level js/ directory
  var repoFilesToLint = ( pkg.name === 'brand' ) ? [ '*/js/**/*.js' ] : [ 'js/**/*.js' ];

  console.log( 'allFilesToLint=' + allFilesToLint );
  console.log( 'repoFilesToLint=' + repoFilesToLint );

  grunt.initConfig( {
    /*
     * Read in the project settings from the package.json file into the pkg property.
     * This allows us to refer to project settings from within this config file.
     */
    pkg: pkg,

    // configure the RequireJS plugin
    requirejs: {

      // builds the minified script
      build: {
        options: {
          almond: true,
          mainConfigFile: 'js/<%= pkg.name %>-config.js',
          out: 'build/<%= pkg.name %>.min.js',
          name: '<%= pkg.name %>-config',

          // Minification strategy.  Put this to none if you want to debug a non-minified but compiled version
          optimize: 'uglify2',
          wrap: true,
//            generateSourceMaps: true, //#42 commented out this line until source maps are fixed
          preserveLicenseComments: false,
          uglify2: {
            output: {
              inline_script: true // escape </script
            },
            compress: {
              global_defs: globalDefs,
              dead_code: true
            }
          },

          //stub out the plugins so their source code won't be included in the minified file
          stubModules: [ 'string', 'audio', 'image' ]
        }
      }
    },

    // configure the JSHint plugin
    jshint: {

      // source files that are specific to this repository
      repoFiles: repoFilesToLint,

      // All source files for this repository (repository-specific and dependencies).
      // Excludes kite/js/parser/svgPath.js, which is auto-generated.
      allFiles: allFilesToLint,

      // reference external JSHint options in jshintOptions.js
      options: require( './jshintOptions' )
    }
  } );

  //---------------------------------------------------------------------------------------------------------------
  // Primary tasks
  //---------------------------------------------------------------------------------------------------------------

  // Default task ('grunt')

  grunt.registerTask( 'default', 'Builds the English HTML', [ 'build' ] );

  // Add the linting step as an pre-build step.  Can be skipped with --lint=false
  var optionalTasks = [];
  if ( grunt.option( 'lint' ) === false ) {
  }
  else {
    optionalTasks.push( 'lint-all' );
  }

  grunt.registerTask( 'build',
    'Builds the simulation:\n' +
    'with no options, builds HTML for English only\n' +
    '--locales=* : all locales in strings/ directory\n' +
    '--locales=fr : French\n' +
    '--locales=ar,fr,es : Arabic, French and Spanish (comma separated locales)\n' +
    '--localesRepo=$repo : all locales in another repository\'s strings/ directory, ignored if --locales is present\n' +
    '--together : adds additional preload files needed to support together.js\n' +
    '--lint=false : skip the lint sub-task',
    optionalTasks.concat( [
      'clean',
      'set-preload',
      'before-requirejs-build',
      'requirejs:build',
      'after-requirejs-build' ] )
  );

  grunt.registerTask( 'deploy-production',
    'Deploy a simulation. Should be run AFTER grunt build since it uses the shas from dependencies.json in the build directory.\n' +
    'with no options, deploys to phet-dev (since this is still being tested)\n' +
    '--devDeploy : deploys to spot',
    function() {
      deploySimulation( grunt, grunt.option( 'devDeploy' ) );
    }
  );

  grunt.registerTask( 'deploy-dev',
    'Deploy a dev version to spot, or optionally to the server in your preferences file\n' +
    '--buildServer : build the sim with the build server if true\n' +
    '--mkdir : set to true to create the sim dir and .htaccess file before copying the version directory\n' +
    '--test : set to true to disable commit and push, and SCP to a test directory on spot',
    function() {
      if ( grunt.option( 'buildServer' ) ) {
        deploySimulation( grunt, 'simian' );
      }
      else {
        deployDev( grunt, grunt.option( 'mkdir' ), grunt.option( 'test' ) );
      }
    }
  );

  grunt.registerTask( 'lint', 'lint js files that are specific to this repository', [ 'jshint:repoFiles' ] );

  grunt.registerTask( 'lint-all', 'lint all js files that are required to build this repository', [ 'jshint:allFiles' ] );

  grunt.registerTask( 'clean',
    'Erases the build/ directory and all its contents, and recreates the build/ directory',
    function() {
      if ( fs.existsSync( 'build' ) ) {
        grunt.file.delete( 'build' );
      }
      grunt.file.mkdir( 'build' );
    } );

  grunt.registerTask( 'set-preload',
    '(internal use only) Determines the set of files that will be preloaded in the HTML file',
    function() {
      setPreload( grunt, pkg );
    } );

  grunt.registerTask( 'before-requirejs-build',
    '(internal use only) Do things before the requirejs:build task',
    function() {
      assert( pkg.phetLibs, 'phetLibs missing from package.json' );
      assert( pkg.preload, 'preload missing from package.json' );
      beforeRequirejsBuild( grunt, pkg, FALLBACK_LOCAL );
    } );

  grunt.registerTask( 'after-requirejs-build',
    '(internal use only) Do things after the requirejs:build task',
    function() {
      afterRequirejsBuild( grunt, pkg, FALLBACK_LOCAL );
    } );

  //---------------------------------------------------------------------------------------------------------------
  // Utility tasks
  //---------------------------------------------------------------------------------------------------------------

  grunt.registerTask( 'checkout-shas',
    'Check out shas for a project, as specified in dependencies.json',
    function() {
      var buildServer = grunt.option( 'buildServer' ) ? true : false;
      checkoutShas( grunt, pkg.name, false, buildServer );
    } );

  grunt.registerTask( 'checkout-master',
    'Check out master branch for all dependencies, as specified in dependencies.json',
    function() {
      checkoutShas( grunt, pkg.name, true );
    } );

  grunt.registerTask( 'create-sim',
    'Creates a sim based on the simula-rasa template.\n' +
    '--name="string" : the repository name\n' +
    '--author="string" : the author name\n' +
    '--title="string" : (optional) the simulation title\n' +
    '--clean=true : (optional) deletes the repository directory if it exists',
    function() {
      createSim( grunt, grunt.option( 'name' ), grunt.option( 'author' ), grunt.option( 'title' ), grunt.option( 'clean' ) );
    } );

  // See reportMedia.js
  grunt.registerTask( 'report-media', '(project-wide) Report on license.json files throughout all working copies. ' +
                                      'Reports any media (such as images or audio) files that have any of the following problems:\n' +
                                      '(1) incompatible-license (resource license not approved)\n' +
                                      '(2) not-annotated (license.json missing or entry missing from license.json)\n' +
                                      '(3) missing-file (entry in the license.json but not on the file system)', function() {
    reportMedia( grunt );
  } );

  // see reportThirdParty.js
  grunt.registerTask( 'report-third-party', 'Given a directory of HTML files (required argument), report the ' +
                                            'third party code, images, audio, etc. used in the group ' +
                                            'and commit the changes to sherpa/third-party-licenses.json. ' +
                                            'If the "--copy-from-build" option is given, it will iterate over the active-runnables ' +
                                            'and copy all the files to the report HTML directory (required argument)', function( path ) {
    assert( path, 'The path is a required grunt argument (use taskname:argument)' );
    reportThirdParty( grunt, path );
  } );

  grunt.registerTask( 'published-README',
    'Generates README.md file for a published simulation.',
    function() {
      assert( pkg.phetLibs, 'phetLibs missing from package.json' );
      assert( pkg.simTitleStringKey, 'simTitleStringKey missing from package.json' );
      generateREADME( grunt, pkg.name, pkg.phetLibs, pkg.simTitleStringKey, true /* published */ );
    } );

  grunt.registerTask( 'unpublished-README',
    'Generates README.md file for an unpublished simulation.',
    function() {
      assert( pkg.phetLibs, 'phetLibs missing from package.json' );
      assert( pkg.simTitleStringKey, 'simTitleStringKey missing from package.json' );
      generateREADME( grunt, pkg.name, pkg.phetLibs, pkg.simTitleStringKey, false /* published */ );
    } );

  grunt.registerTask( 'pull-all',
    'Pull all sibling repositories',
    function() {
      pullAll( grunt );
    } );

  grunt.registerTask( 'string-report',
    'After doing a build, reports on which strings are missing for each locale that was built.',
    function() {
      stringReport( grunt, pkg.name, FALLBACK_LOCAL );
    } );

  grunt.registerTask( 'generate-thumbnails', 'Generate 128x84 and 600x394 thumbnails to be used on the website.', function() {
    var finished = _.after( 2, grunt.task.current.async() );
    generateThumbnails( grunt, pkg.name, 128, 84, finished );
    generateThumbnails( grunt, pkg.name, 600, 394, finished );
  } );

  /*
   * Load tasks from grunt plugins that have been installed locally using npm.
   * Put these in package.json and run 'npm install' before running grunt.
   */
  grunt.loadNpmTasks( 'grunt-requirejs' );
  grunt.loadNpmTasks( 'grunt-contrib-jshint' );
};
<commit_msg>#246 doc<commit_after>// Copyright 2002-2015, University of Colorado Boulder

/**
 * Grunt configuration file for PhET projects.
 * Requires a package.json file containing project settings.
 * Tasks share information via global.phet, see individual tasks for details.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 * @author Jon Olson
 * @author Sam Reid
 * @author John Blanco
 */

// built-in node APIs
var assert = require( 'assert' );
var fs = require( 'fs' );

// 3rd-party packages
/* jshint -W079 */
var _ = require( '../../../sherpa/lib/lodash-2.4.1.min' ); // allow _ to be redefined, contrary to jshintOptions.js
/* jshint +W079 */

// PhET custom grunt tasks
var afterRequirejsBuild = require( '../../../chipper/js/grunt/afterRequirejsBuild' );
var beforeRequirejsBuild = require( '../../../chipper/js/grunt/beforeRequirejsBuild' );
var checkoutShas = require( '../../../chipper/js/grunt/checkoutShas' );
var createSim = require( '../../../chipper/js/grunt/createSim' );
var deploySimulation = require( '../../../chipper/js/grunt/deploySimulation' );
var deployDev = require( '../../../chipper/js/grunt/deployDev' );
var generateREADME = require( '../../../chipper/js/grunt/generateREADME' );
var generateThumbnails = require( '../../../chipper/js/grunt/generateThumbnails' );
var pullAll = require( '../../../chipper/js/grunt/pullAll' );
var setPreload = require( '../../../chipper/js/grunt/setPreload' );
var stringReport = require( '../../../chipper/js/grunt/stringReport' );
var reportMedia = require( '../../../chipper/js/grunt/reportMedia' );
var reportThirdParty = require( '../../../chipper/js/grunt/reportThirdParty' );

//TODO look at why this is necessary
/*
 * In Node, global is the global namespace object.
 * Register fs as a global so it can be accessed through the requirejs build system. Text.js plugin
 * may have a superior way to handle this but I (SR) couldn't get it working after a small amount of effort.
 */
global.fs = fs;

module.exports = function( grunt ) {
  'use strict';

  var FALLBACK_LOCAL = 'en';

  // Read package.json, verify that it contains properties required by all PhET repositories
  assert( fs.existsSync( 'package.json' ), 'repository must have a package.json' );
  var pkg = grunt.file.readJSON( 'package.json' );
  assert( pkg.name, 'name missing from package.json' );
  assert( pkg.version, 'version missing from package.json' );
  assert( pkg.license, 'license missing from package.json' );

  // For sims, read common phetLibs from chipper/build.json. We'll do this here since several grunt tasks (including some utilities) need phetLibs.
  assert( fs.existsSync( '../chipper/build.json' ), 'missing build.json' );
  var buildInfo = grunt.file.readJSON( '../chipper/build.json' );

  // Add phetLibs from build-local.json
  pkg.phetLibs = pkg.phetLibs || [];
  pkg.phetLibs = _.uniq( pkg.phetLibs.concat( buildInfo.common.phetLibs ).sort() );
  grunt.log.debug( 'phetLibs = ' + pkg.phetLibs );

  // TODO: As a temporary means of keeping track of "together" versions, replace "-dev" with "-together" in the version
  // string. This approach has a lot of problems and should be replaced as soon as we work out a more all encompassing
  // way of tracking together-enhanced versions.  See https://github.com/phetsims/special-ops/issues/3 for more info.
  if ( grunt.option( 'together' ) && pkg.version.indexOf( '-dev' ) > -1 ) {
    pkg.version = pkg.version.replace( '-dev', '-together' );
  }

  var globalDefs = {
    // global assertions
    assert: false,
    assertSlow: false,
    // scenery logging
    sceneryLog: false,
    sceneryLayerLog: false,
    sceneryEventLog: false,
    sceneryAccessibilityLog: false,
    phetAllocation: false
  };

  // Enumerate the list of files to be linted for the jshint:allFiles task
  console.log( 'pkg.phetLibs=' + pkg.phetLibs );//XXX
  var allFilesToLint = _.map( pkg.phetLibs, function( repo ) {
    return '../' + repo + '/js/**/*.js';
  } );

  // The brand repo has a different structure, so add it explicitly
  allFilesToLint.push( '../brand/*/js/**/*.js' );

  // Don't try to lint the svgPath.js.  It was automatically generated and doesn't match convention
  allFilesToLint.push( '!../kite/js/parser/svgPath.js' );

  // Identify the repo files to lint for the single repo.
  // The brand repo is a special case since it has nested subdirectories instead of a top level js/ directory
  var repoFilesToLint = ( pkg.name === 'brand' ) ? [ '*/js/**/*.js' ] : [ 'js/**/*.js' ];

  console.log( 'allFilesToLint=' + allFilesToLint );
  console.log( 'repoFilesToLint=' + repoFilesToLint );

  grunt.initConfig( {
    /*
     * Read in the project settings from the package.json file into the pkg property.
     * This allows us to refer to project settings from within this config file.
     */
    pkg: pkg,

    // configure the RequireJS plugin
    requirejs: {

      // builds the minified script
      build: {
        options: {
          almond: true,
          mainConfigFile: 'js/<%= pkg.name %>-config.js',
          out: 'build/<%= pkg.name %>.min.js',
          name: '<%= pkg.name %>-config',

          // Minification strategy.  Put this to none if you want to debug a non-minified but compiled version
          optimize: 'uglify2',
          wrap: true,
//            generateSourceMaps: true, //#42 commented out this line until source maps are fixed
          preserveLicenseComments: false,
          uglify2: {
            output: {
              inline_script: true // escape </script
            },
            compress: {
              global_defs: globalDefs,
              dead_code: true
            }
          },

          //stub out the plugins so their source code won't be included in the minified file
          stubModules: [ 'string', 'audio', 'image' ]
        }
      }
    },

    // configure the JSHint plugin
    jshint: {

      // source files that are specific to this repository
      repoFiles: repoFilesToLint,

      // All source files for this repository (repository-specific and dependencies).
      // Excludes kite/js/parser/svgPath.js, which is auto-generated.
      allFiles: allFilesToLint,

      // reference external JSHint options in jshintOptions.js
      options: require( './jshintOptions' )
    }
  } );

  //---------------------------------------------------------------------------------------------------------------
  // Primary tasks
  //---------------------------------------------------------------------------------------------------------------

  // Default task ('grunt')

  grunt.registerTask( 'default', 'Builds the English HTML', [ 'build' ] );

  // Add the linting step as an pre-build step.  Can be skipped with --lint=false
  var optionalTasks = [];
  if ( grunt.option( 'lint' ) === false ) {
  }
  else {
    optionalTasks.push( 'lint-all' );
  }

  grunt.registerTask( 'build',
    'Builds the simulation:\n' +
    'with no options, builds HTML for English only\n' +
    '--locales=* : all locales in strings/ directory\n' +
    '--locales=fr : French\n' +
    '--locales=ar,fr,es : Arabic, French and Spanish (comma separated locales)\n' +
    '--localesRepo=$repo : all locales in another repository\'s strings/ directory, ignored if --locales is present\n' +
    '--together : adds additional preload files needed to support together.js\n' +
    '--lint=false : skip the lint sub-task',
    optionalTasks.concat( [
      'clean',
      'set-preload',
      'before-requirejs-build',
      'requirejs:build',
      'after-requirejs-build' ] )
  );

  grunt.registerTask( 'deploy-production',
    'Deploy a simulation. Should be run AFTER grunt build since it uses the shas from dependencies.json in the build directory.\n' +
    'with no options, deploys to phet-dev (since this is still being tested)\n' +
    '--devDeploy : deploys to spot',
    function() {
      deploySimulation( grunt, grunt.option( 'devDeploy' ) );
    }
  );

  grunt.registerTask( 'deploy-dev',
    'Deploy a dev version to spot, or optionally to the server in your preferences file\n' +
    '--buildServer : build the sim with the build server if true\n' +
    '--mkdir : set to true to create the sim dir and .htaccess file before copying the version directory\n' +
    '--test : set to true to disable commit and push, and SCP to a test directory on spot',
    function() {
      if ( grunt.option( 'buildServer' ) ) {
        deploySimulation( grunt, 'simian' );
      }
      else {
        deployDev( grunt, grunt.option( 'mkdir' ), grunt.option( 'test' ) );
      }
    }
  );

  grunt.registerTask( 'lint', 'lint js files that are specific to this repository', [ 'jshint:repoFiles' ] );

  grunt.registerTask( 'lint-all', 'lint all js files that are required to build this repository', [ 'jshint:allFiles' ] );

  grunt.registerTask( 'clean',
    'Erases the build/ directory and all its contents, and recreates the build/ directory',
    function() {
      if ( fs.existsSync( 'build' ) ) {
        grunt.file.delete( 'build' );
      }
      grunt.file.mkdir( 'build' );
    } );

  grunt.registerTask( 'set-preload',
    '(internal use only) Determines the set of files that will be preloaded in the HTML file',
    function() {
      setPreload( grunt, pkg );
    } );

  grunt.registerTask( 'before-requirejs-build',
    '(internal use only) Do things before the requirejs:build task',
    function() {
      assert( pkg.phetLibs, 'phetLibs missing from package.json' );
      assert( pkg.preload, 'preload missing from package.json' );
      beforeRequirejsBuild( grunt, pkg, FALLBACK_LOCAL );
    } );

  grunt.registerTask( 'after-requirejs-build',
    '(internal use only) Do things after the requirejs:build task',
    function() {
      afterRequirejsBuild( grunt, pkg, FALLBACK_LOCAL );
    } );

  //---------------------------------------------------------------------------------------------------------------
  // Utility tasks
  //---------------------------------------------------------------------------------------------------------------

  grunt.registerTask( 'checkout-shas',
    'Check out shas for a project, as specified in dependencies.json',
    function() {
      var buildServer = grunt.option( 'buildServer' ) ? true : false;
      checkoutShas( grunt, pkg.name, false, buildServer );
    } );

  grunt.registerTask( 'checkout-master',
    'Check out master branch for all dependencies, as specified in dependencies.json',
    function() {
      checkoutShas( grunt, pkg.name, true );
    } );

  grunt.registerTask( 'create-sim',
    'Creates a sim based on the simula-rasa template.\n' +
    '--name="string" : the repository name\n' +
    '--author="string" : the author name\n' +
    '--title="string" : (optional) the simulation title\n' +
    '--clean=true : (optional) deletes the repository directory if it exists',
    function() {
      createSim( grunt, grunt.option( 'name' ), grunt.option( 'author' ), grunt.option( 'title' ), grunt.option( 'clean' ) );
    } );

  // See reportMedia.js
  grunt.registerTask( 'report-media', '(project-wide) Report on license.json files throughout all working copies. ' +
                                      'Reports any media (such as images or audio) files that have any of the following problems:\n' +
                                      '(1) incompatible-license (resource license not approved)\n' +
                                      '(2) not-annotated (license.json missing or entry missing from license.json)\n' +
                                      '(3) missing-file (entry in the license.json but not on the file system)', function() {
    reportMedia( grunt );
  } );

  // see reportThirdParty.js
  grunt.registerTask( 'report-third-party', 'Given a directory of HTML files (required argument), report the ' +
                                            'third party code, images, audio, etc. used in the group ' +
                                            'and commit the changes to sherpa/third-party-licenses.json. ' +
                                            'If the "--copy-from-build" option is given, it will iterate over the active-runnables ' +
                                            'and copy all the files to the report HTML directory (required argument)', function( path ) {
    assert( path, 'The path is a required grunt argument (use taskname:argument)' );
    reportThirdParty( grunt, path );
  } );

  grunt.registerTask( 'published-README',
    'Generates README.md file for a published simulation.',
    function() {
      assert( pkg.phetLibs, 'phetLibs missing from package.json' );
      assert( pkg.simTitleStringKey, 'simTitleStringKey missing from package.json' );
      generateREADME( grunt, pkg.name, pkg.phetLibs, pkg.simTitleStringKey, true /* published */ );
    } );

  grunt.registerTask( 'unpublished-README',
    'Generates README.md file for an unpublished simulation.',
    function() {
      assert( pkg.phetLibs, 'phetLibs missing from package.json' );
      assert( pkg.simTitleStringKey, 'simTitleStringKey missing from package.json' );
      generateREADME( grunt, pkg.name, pkg.phetLibs, pkg.simTitleStringKey, false /* published */ );
    } );

  grunt.registerTask( 'pull-all',
    'Pull all sibling repositories',
    function() {
      pullAll( grunt );
    } );

  grunt.registerTask( 'string-report',
    'After doing a build, reports on which strings are missing for each locale that was built.',
    function() {
      stringReport( grunt, pkg.name, FALLBACK_LOCAL );
    } );

  grunt.registerTask( 'generate-thumbnails', 'Generate 128x84 and 600x394 thumbnails to be used on the website.', function() {
    var finished = _.after( 2, grunt.task.current.async() );
    generateThumbnails( grunt, pkg.name, 128, 84, finished );
    generateThumbnails( grunt, pkg.name, 600, 394, finished );
  } );

  /*
   * Load tasks from grunt plugins that have been installed locally using npm.
   * Put these in package.json and run 'npm install' before running grunt.
   */
  grunt.loadNpmTasks( 'grunt-requirejs' );
  grunt.loadNpmTasks( 'grunt-contrib-jshint' );
};
<|endoftext|>


<commit_before>var tempo = 120;

var time = !!performance ? performance : Date;

function getNow () {
  return time.now() | 0;
}

var timing = {
  startTime: getNow(),
  pattern: function (beat, noteValue) {
    return (beat / noteValue * this.note(1)) | 0;
  },
  note: function (noteValue) {
    return (60 / tempo * 4000 / noteValue) | 0;
  },
  current: function (){
    return getNow() - this.startTime;
  },
};
<commit_msg>fix ios compat<commit_after>var tempo = 120;

console.log(!!performance);

var time = !!performance ? performance : Date;

function getNow () {
  return time.now() | 0;
}

var timing = {
  startTime: getNow(),
  pattern: function (beat, noteValue) {
    return (beat / noteValue * this.note(1)) | 0;
  },
  note: function (noteValue) {
    return (60 / tempo * 4000 / noteValue) | 0;
  },
  current: function (){
    return getNow() - this.startTime;
  },
};
<|endoftext|>


<commit_before>/* --------------------
 * Sequelize hierarchy
 * Hooks on all models
 * ------------------*/

'use strict';

// Modules
const _ = require('lodash');

// Exports

module.exports = (Sequelize, patches) => {
	const {HierarchyError} = Sequelize,
		{attributes, isModelInstance, uppercaseFirst} = patches;

	return {
		afterDefine,
		beforeFindAfterExpandIncludeAll,
		afterFind
	};

	function afterDefine(model) {
		// Get hierarchy option
		let {hierarchy} = model.options;

		// Check for hierarchy set on a field
		_.forIn(attributes(model), (field, fieldName) => {
			if (!field.hierarchy) return;

			if (hierarchy) {
				throw new HierarchyError(`You cannot define hierarchy on two attributes, or an attribute and the model options, in '${model.name}'`);
			}

			hierarchy = field.hierarchy;
			if (hierarchy === true) hierarchy = {};

			// Deduce foreignKey and as for the hierarchy from field name
			hierarchy.foreignKey = fieldName;
			const primaryKey = hierarchy.primaryKey || model.primaryKeyAttribute;
			if (!hierarchy.as) {
				if (_.endsWith(fieldName, uppercaseFirst(primaryKey))) {
					hierarchy.as = fieldName.slice(0, -primaryKey.length);
				} else if (_.endsWith(fieldName, `_${primaryKey}`)) {
					hierarchy.as = fieldName.slice(0, -primaryKey.length - 1);
				} else {
					hierarchy.as = fieldName;
				}
			}

			model.options.hierarchy = hierarchy;
			field.hierarchy = true;
		});

		// If hierarchy set, init hierarchy
		if (hierarchy) model.isHierarchy(hierarchy);
	}

	function beforeFindAfterExpandIncludeAll(options) {
		const model = this; // eslint-disable-line no-invalid-this

		// Check options do not include illegal hierarchies
		let hierarchyExists = false;
		if (options.hierarchy) {
			if (!model.hierarchy) {
				throw new HierarchyError(`You cannot get hierarchy of '${model.name}' - it is not hierarchical`);
			}
			hierarchyExists = true;
		}

		// Record whether `hierarchy` is set anywhere in includes, so expansion of
		// hierarchies can be skipped if their are none
		options.hierarchyExists = hierarchyExists || checkHierarchy(options, model);
	}

	function afterFind(result, options) {
		// If no results, return
		if (!result) return;

		// If no hierarchies to expand anywhere in tree of includes, return
		if (!options.hierarchyExists) return;

		const model = this, // eslint-disable-line no-invalid-this
			{hierarchy} = model;

		let parent;

		// Where called from getDescendents, find id of parent
		if (options.hierarchy && options.includeMap) {
			const include = options.includeMap[hierarchy.through.name];

			if (include && include.where) {
				const parentId = include.where[hierarchy.throughForeignKey];
				if (parentId) parent = {[hierarchy.primaryKey]: parentId};
			}
		}

		// Convert hierarchies into trees
		convertHierarchies(result, options, model, parent);

		// Where called from getDescendents, retrieve result from parent.children
		if (parent) {
			result.length = 0;
			result.push(...parent[hierarchy.childrenAs]);
		}
	}

	function checkHierarchy(options, model) {
		// Check options do not include illegal hierarchies - throw error if so
		if (!options.include) return undefined;

		let hierarchyExists = false;
		for (const include of options.include) {
			const includeModel = include.model;

			// If hierarchy set, check is legal
			if (include.hierarchy) {
				if (!includeModel.hierarchy) {
					throw new HierarchyError(`You cannot get hierarchy of '${includeModel.name}' - it is not hierarchical`);
				}
				// Use model names rather than model references to compare,
				// as Model.scope() results in a new model object.
				if (includeModel.name.singular !== model.name.singular) {
					throw new HierarchyError(`You cannot get a hierarchy of '${includeModel.name}' without including it from a parent`);
				}
				if (include.as !== model.hierarchy.descendentsAs) {
					throw new HierarchyError(`You cannot set hierarchy on '${model.name}' without using the '${model.hierarchy.descendentsAs}' accessor`);
				}

				hierarchyExists = true;
			}

			// Check includes
			hierarchyExists = hierarchyExists || checkHierarchy(include, includeModel);
		}

		return hierarchyExists;
	}

	function convertHierarchies(results, options, model, parent) {
		if (!results) return;

		// Convert hierarchies into trees
		if (options.include) {
			for (const include of options.include) {
				const includeModel = include.model,
					accessor = include.as;

				if (!Array.isArray(results)) results = [results];

				for (const result of results) {
					convertHierarchies(result[accessor], include, includeModel, result);
				}
			}
		}

		if (options.hierarchy) convertHierarchy(results, model, parent);
	}

	function convertHierarchy(results, model, parent) {
		const {hierarchy} = model,
			{primaryKey, foreignKey} = hierarchy,
			childrenAccessor = hierarchy.childrenAs,
			descendentsAccessor = hierarchy.descendentsAs,
			throughAccessor = hierarchy.through.name;

		// Get parent ID and create output array
		let parentId, output;
		if (parent) {
			parentId = parent[primaryKey];

			// Remove parent.descendents and create empty parent.children array
			output = [];
			setValue(parent, childrenAccessor, output);
			deleteValue(parent, descendentsAccessor);
		} else {
			parentId = null;

			// Duplicate results array and empty output array
			output = results;
			results = results.slice();
			output.length = 0;
		}

		// Run through all results, turning into tree

		// Create references object keyed by id
		const references = {};
		for (const item of results) {
			// TODO Make keys strings for faster lookup
			references[item[primaryKey]] = item;
		}

		// Run through results, transferring to output array or nesting within parent
		for (const item of results) {
			// Remove reference to through table
			deleteValue(item, throughAccessor);

			// If top-level item, add to output array
			const thisParentId = item[foreignKey];
			if (thisParentId === parentId) {
				output.push(item);
				continue;
			}

			// Not top-level item - nest inside parent
			const thisParent = references[thisParentId];
			if (!thisParent) {
				throw new HierarchyError(`Parent ID ${thisParentId} not found in result set`);
			}

			let parentChildren = thisParent[childrenAccessor];
			if (!parentChildren) {
				parentChildren = [];
				setValue(thisParent, childrenAccessor, parentChildren);
			}

			parentChildren.push(item);
		}
	}

	function setValue(item, key, value) {
		item[key] = value;
		if (isModelInstance(item)) item.dataValues[key] = value;
	}

	function deleteValue(item, key) {
		delete item[key];
		if (isModelInstance(item)) delete item.dataValues[key];
	}
};
<commit_msg>`afterFind` hook building hierarchy faster [perf]<commit_after>/* --------------------
 * Sequelize hierarchy
 * Hooks on all models
 * ------------------*/

'use strict';

// Modules
const _ = require('lodash');

// Exports

module.exports = (Sequelize, patches) => {
	const {HierarchyError} = Sequelize,
		{attributes, isModelInstance, uppercaseFirst} = patches;

	return {
		afterDefine,
		beforeFindAfterExpandIncludeAll,
		afterFind
	};

	function afterDefine(model) {
		// Get hierarchy option
		let {hierarchy} = model.options;

		// Check for hierarchy set on a field
		_.forIn(attributes(model), (field, fieldName) => {
			if (!field.hierarchy) return;

			if (hierarchy) {
				throw new HierarchyError(`You cannot define hierarchy on two attributes, or an attribute and the model options, in '${model.name}'`);
			}

			hierarchy = field.hierarchy;
			if (hierarchy === true) hierarchy = {};

			// Deduce foreignKey and as for the hierarchy from field name
			hierarchy.foreignKey = fieldName;
			const primaryKey = hierarchy.primaryKey || model.primaryKeyAttribute;
			if (!hierarchy.as) {
				if (_.endsWith(fieldName, uppercaseFirst(primaryKey))) {
					hierarchy.as = fieldName.slice(0, -primaryKey.length);
				} else if (_.endsWith(fieldName, `_${primaryKey}`)) {
					hierarchy.as = fieldName.slice(0, -primaryKey.length - 1);
				} else {
					hierarchy.as = fieldName;
				}
			}

			model.options.hierarchy = hierarchy;
			field.hierarchy = true;
		});

		// If hierarchy set, init hierarchy
		if (hierarchy) model.isHierarchy(hierarchy);
	}

	function beforeFindAfterExpandIncludeAll(options) {
		const model = this; // eslint-disable-line no-invalid-this

		// Check options do not include illegal hierarchies
		let hierarchyExists = false;
		if (options.hierarchy) {
			if (!model.hierarchy) {
				throw new HierarchyError(`You cannot get hierarchy of '${model.name}' - it is not hierarchical`);
			}
			hierarchyExists = true;
		}

		// Record whether `hierarchy` is set anywhere in includes, so expansion of
		// hierarchies can be skipped if their are none
		options.hierarchyExists = hierarchyExists || checkHierarchy(options, model);
	}

	function afterFind(result, options) {
		// If no results, return
		if (!result) return;

		// If no hierarchies to expand anywhere in tree of includes, return
		if (!options.hierarchyExists) return;

		const model = this, // eslint-disable-line no-invalid-this
			{hierarchy} = model;

		let parent;

		// Where called from getDescendents, find id of parent
		if (options.hierarchy && options.includeMap) {
			const include = options.includeMap[hierarchy.through.name];

			if (include && include.where) {
				const parentId = include.where[hierarchy.throughForeignKey];
				if (parentId) parent = {[hierarchy.primaryKey]: parentId};
			}
		}

		// Convert hierarchies into trees
		convertHierarchies(result, options, model, parent);

		// Where called from getDescendents, retrieve result from parent.children
		if (parent) {
			result.length = 0;
			result.push(...parent[hierarchy.childrenAs]);
		}
	}

	function checkHierarchy(options, model) {
		// Check options do not include illegal hierarchies - throw error if so
		if (!options.include) return undefined;

		let hierarchyExists = false;
		for (const include of options.include) {
			const includeModel = include.model;

			// If hierarchy set, check is legal
			if (include.hierarchy) {
				if (!includeModel.hierarchy) {
					throw new HierarchyError(`You cannot get hierarchy of '${includeModel.name}' - it is not hierarchical`);
				}
				// Use model names rather than model references to compare,
				// as Model.scope() results in a new model object.
				if (includeModel.name.singular !== model.name.singular) {
					throw new HierarchyError(`You cannot get a hierarchy of '${includeModel.name}' without including it from a parent`);
				}
				if (include.as !== model.hierarchy.descendentsAs) {
					throw new HierarchyError(`You cannot set hierarchy on '${model.name}' without using the '${model.hierarchy.descendentsAs}' accessor`);
				}

				hierarchyExists = true;
			}

			// Check includes
			hierarchyExists = hierarchyExists || checkHierarchy(include, includeModel);
		}

		return hierarchyExists;
	}

	function convertHierarchies(results, options, model, parent) {
		if (!results) return;

		// Convert hierarchies into trees
		if (options.include) {
			for (const include of options.include) {
				const includeModel = include.model,
					accessor = include.as;

				if (!Array.isArray(results)) results = [results];

				for (const result of results) {
					convertHierarchies(result[accessor], include, includeModel, result);
				}
			}
		}

		if (options.hierarchy) convertHierarchy(results, model, parent);
	}

	function convertHierarchy(results, model, parent) {
		const {hierarchy} = model,
			{primaryKey, foreignKey} = hierarchy,
			childrenAccessor = hierarchy.childrenAs,
			descendentsAccessor = hierarchy.descendentsAs,
			throughAccessor = hierarchy.through.name;

		// Get parent ID and create output array
		let parentId, output;
		if (parent) {
			parentId = parent[primaryKey];

			// Remove parent.descendents and create empty parent.children array
			output = [];
			setValue(parent, childrenAccessor, output);
			deleteValue(parent, descendentsAccessor);
		} else {
			parentId = null;

			// Duplicate results array and empty output array
			output = results;
			results = results.slice();
			output.length = 0;
		}

		// Run through all results, turning into tree

		// Create references object keyed by id
		// NB IDs prepended with '_' to ensure keys are non-numerical for fast hash lookup
		const references = {};
		for (const item of results) {
			references[`_${item[primaryKey]}`] = item;
		}

		// Run through results, transferring to output array or nesting within parent
		for (const item of results) {
			// Remove reference to through table
			deleteValue(item, throughAccessor);

			// If top-level item, add to output array
			const thisParentId = item[foreignKey];
			if (thisParentId === parentId) {
				output.push(item);
				continue;
			}

			// Not top-level item - nest inside parent
			const thisParent = references[`_${thisParentId}`];
			if (!thisParent) {
				throw new HierarchyError(`Parent ID ${thisParentId} not found in result set`);
			}

			let parentChildren = thisParent[childrenAccessor];
			if (!parentChildren) {
				parentChildren = [];
				setValue(thisParent, childrenAccessor, parentChildren);
			}

			parentChildren.push(item);
		}
	}

	function setValue(item, key, value) {
		item[key] = value;
		if (isModelInstance(item)) item.dataValues[key] = value;
	}

	function deleteValue(item, key) {
		delete item[key];
		if (isModelInstance(item)) delete item.dataValues[key];
	}
};
<|endoftext|>


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

/**
 * This grunt task creates a simulation based on the simula-rasa template.
 * Run from any repository directory that is a sibling of simula-rasa.
 *
 * Example usage:
 * grunt create-sim --name=cannon-blaster --author="Sam Reid (PhET Interactive Simulations)"
 *
 * This task will attempt to coerce a sim title from the repository name. For example,
 * 'cannon-blaster' becomes 'Cannon Blaster'.  If this is not suitable, then use --title
 * to specify a title.  For example:
 * grunt create-sim --name=fractions-basics --title="Fractions: Basics" --author="Sam Reid (PhET Interactive Simulations)"
 *
 * For development and debugging, add --clean=true to delete the repository directory.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Chris Malley (PixelZoom, Inc.)
 */

'use strict';

const assert = require( 'assert' );
const execute = require( '../common/execute' );
const grunt = require( 'grunt' );
const gruntCommand = require( '../common/gruntCommand' );
const npmUpdate = require( '../common/npmUpdate' );

/**
 * @param {string} repo
 * @param {string} author
 * @param {Object} options
 */
module.exports = async function( repo, author, options ) {
  const {
    title = toTitle( repo ),
    clean = false
  } = options || {};

  assert( typeof repo === 'string' );
  assert( typeof author === 'string' );
  assert( typeof title === 'string' );
  assert( typeof clean === 'boolean' );

  /**
   * Coerces a repository name to a sim title, eg, 'simula-rasa' -> 'Simula Rasa'
   * @param {string} simName - the input string like 'build-an-atom'
   * @returns {string}
   */
  function toTitle( simName ) {
    const tmpString = simName.replace( /-(.)/g, function( match, group1 ) {
      return ' ' + group1.toUpperCase();
    } );
    return tmpString.substring( 0, 1 ).toUpperCase() + tmpString.substring( 1 );
  }

  /**
   * Converts a string to camel case, eg: 'simula-rasa' -> 'simulaRasa'
   * See http://stackoverflow.com/questions/10425287/convert-string-to-camelcase-with-regular-expression
   *
   * @param {string} str - the input string
   * @returns {string} a new string
   */
  function toCamelCase( str ) {
    return str.toLowerCase().replace( /-(.)/g, function( match, group1 ) {
      return group1.toUpperCase();
    } );
  }

  grunt.log.writeln( `Greetings ${author}!` );
  grunt.log.writeln( `creating sim with repository name ${repo}` );

  // initialize the directory
  const destinationPath = `../${repo}`;
  if ( grunt.file.exists( destinationPath ) ) {
    if ( clean ) {
      grunt.log.writeln( 'Cleaning ' + destinationPath );
      grunt.file.delete( destinationPath, { force: true } ); // delete won't operate outside of current working dir unless forced
    }
    else {
      grunt.log.writeln( 'WARNING:' + destinationPath + ' already exists, overwriting' );
    }
  }
  grunt.file.mkdir( destinationPath );

  // Create variations of the repository name
  const configPath = repo.toUpperCase().replace( /-/g, '_' ); // eg, 'simula-rasa' -> 'SIMULA_RASA'
  const lowerCamelCase = toCamelCase( repo ); // eg, 'simula-rasa' -> 'simulaRasa'
  const upperCamelCase = lowerCamelCase.substring( 0, 1 ).toUpperCase() + lowerCamelCase.substring( 1 ); // eg, 'simula-rasa' -> 'SimulaRasa'

  const yearToday = grunt.template.today( 'yyyy' );

  // Iterate over the file system and copy files, changing filenames and contents as we go.
  grunt.file.recurse( '../simula-rasa', function( abspath, rootdir, subdir, filename ) {

    // skip these files
    if ( abspath.indexOf( '../simula-rasa/README.md' ) === 0 ||
         abspath.indexOf( '../simula-rasa/node_modules/' ) === 0 ||
         abspath.indexOf( '../simula-rasa/.git/' ) === 0 ||
         abspath.indexOf( '../simula-rasa/build/' ) === 0 ) {

      // do nothing
    }
    else {
      let contents = grunt.file.read( abspath );

      // Replace variations of the repository name
      contents = contents.replace( /simula-rasa/g, repo );
      contents = contents.replace( /SIMULA_RASA/g, configPath );
      contents = contents.replace( /simulaRasa/g, lowerCamelCase );
      contents = contents.replace( /SimulaRasa/g, upperCamelCase );

      // Replace the title
      contents = contents.replace( /{{TITLE}}/g, title );

      // Replace author
      contents = contents.replace( /{{AUTHOR}}/g, author );

      // Fix copyright comments
      contents = contents.replace( /\/\/ Copyright \d\d\d\d.*/g, `// Copyright ${yearToday}, University of Colorado Boulder` );

      // Replace names in the path where the contents will be written
      let contentsPath = subdir ? ( destinationPath + '/' + subdir + '/' + filename ) : ( destinationPath + '/' + filename );
      contentsPath = contentsPath.replace( /simula-rasa/, repo );
      contentsPath = contentsPath.replace( /simulaRasa/, lowerCamelCase );
      contentsPath = contentsPath.replace( /SimulaRasa/, upperCamelCase );

      // Write the file
      grunt.file.write( contentsPath, contents );
      grunt.log.writeln( 'wrote', contentsPath );
    }
  } );

  await npmUpdate( repo );
  await execute( gruntCommand, [ 'unpublished-README' ], `../${repo}` );
  await execute( gruntCommand, [ 'generate-config' ], `../${repo}` );
};
<commit_msg>replace name with repo flag and mention that task must be run from perennial<commit_after>// Copyright 2014-2015, University of Colorado Boulder

/**
 * This grunt task creates a simulation based on the simula-rasa template.
 * This task must be run from perennial directory.
 *
 * Example usage:
 * grunt create-sim --repo=cannon-blaster --author="Sam Reid (PhET Interactive Simulations)"
 *
 * This task will attempt to coerce a sim title from the repository name. For example,
 * 'cannon-blaster' becomes 'Cannon Blaster'.  If this is not suitable, then use --title
 * to specify a title.  For example:
 * grunt create-sim --repo=fractions-basics --title="Fractions: Basics" --author="Sam Reid (PhET Interactive Simulations)"
 *
 * For development and debugging, add --clean=true to delete the repository directory.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Chris Malley (PixelZoom, Inc.)
 */

'use strict';

const assert = require( 'assert' );
const execute = require( '../common/execute' );
const grunt = require( 'grunt' );
const gruntCommand = require( '../common/gruntCommand' );
const npmUpdate = require( '../common/npmUpdate' );

/**
 * @param {string} repo
 * @param {string} author
 * @param {Object} options
 */
module.exports = async function( repo, author, options ) {
  const {
    title = toTitle( repo ),
    clean = false
  } = options || {};

  assert( typeof repo === 'string' );
  assert( typeof author === 'string' );
  assert( typeof title === 'string' );
  assert( typeof clean === 'boolean' );

  /**
   * Coerces a repository name to a sim title, eg, 'simula-rasa' -> 'Simula Rasa'
   * @param {string} simName - the input string like 'build-an-atom'
   * @returns {string}
   */
  function toTitle( simName ) {
    const tmpString = simName.replace( /-(.)/g, function( match, group1 ) {
      return ' ' + group1.toUpperCase();
    } );
    return tmpString.substring( 0, 1 ).toUpperCase() + tmpString.substring( 1 );
  }

  /**
   * Converts a string to camel case, eg: 'simula-rasa' -> 'simulaRasa'
   * See http://stackoverflow.com/questions/10425287/convert-string-to-camelcase-with-regular-expression
   *
   * @param {string} str - the input string
   * @returns {string} a new string
   */
  function toCamelCase( str ) {
    return str.toLowerCase().replace( /-(.)/g, function( match, group1 ) {
      return group1.toUpperCase();
    } );
  }

  grunt.log.writeln( `Greetings ${author}!` );
  grunt.log.writeln( `creating sim with repository name ${repo}` );

  // initialize the directory
  const destinationPath = `../${repo}`;
  if ( grunt.file.exists( destinationPath ) ) {
    if ( clean ) {
      grunt.log.writeln( 'Cleaning ' + destinationPath );
      grunt.file.delete( destinationPath, { force: true } ); // delete won't operate outside of current working dir unless forced
    }
    else {
      grunt.log.writeln( 'WARNING:' + destinationPath + ' already exists, overwriting' );
    }
  }
  grunt.file.mkdir( destinationPath );

  // Create variations of the repository name
  const configPath = repo.toUpperCase().replace( /-/g, '_' ); // eg, 'simula-rasa' -> 'SIMULA_RASA'
  const lowerCamelCase = toCamelCase( repo ); // eg, 'simula-rasa' -> 'simulaRasa'
  const upperCamelCase = lowerCamelCase.substring( 0, 1 ).toUpperCase() + lowerCamelCase.substring( 1 ); // eg, 'simula-rasa' -> 'SimulaRasa'

  const yearToday = grunt.template.today( 'yyyy' );

  // Iterate over the file system and copy files, changing filenames and contents as we go.
  grunt.file.recurse( '../simula-rasa', function( abspath, rootdir, subdir, filename ) {

    // skip these files
    if ( abspath.indexOf( '../simula-rasa/README.md' ) === 0 ||
         abspath.indexOf( '../simula-rasa/node_modules/' ) === 0 ||
         abspath.indexOf( '../simula-rasa/.git/' ) === 0 ||
         abspath.indexOf( '../simula-rasa/build/' ) === 0 ) {

      // do nothing
    }
    else {
      let contents = grunt.file.read( abspath );

      // Replace variations of the repository name
      contents = contents.replace( /simula-rasa/g, repo );
      contents = contents.replace( /SIMULA_RASA/g, configPath );
      contents = contents.replace( /simulaRasa/g, lowerCamelCase );
      contents = contents.replace( /SimulaRasa/g, upperCamelCase );

      // Replace the title
      contents = contents.replace( /{{TITLE}}/g, title );

      // Replace author
      contents = contents.replace( /{{AUTHOR}}/g, author );

      // Fix copyright comments
      contents = contents.replace( /\/\/ Copyright \d\d\d\d.*/g, `// Copyright ${yearToday}, University of Colorado Boulder` );

      // Replace names in the path where the contents will be written
      let contentsPath = subdir ? ( destinationPath + '/' + subdir + '/' + filename ) : ( destinationPath + '/' + filename );
      contentsPath = contentsPath.replace( /simula-rasa/, repo );
      contentsPath = contentsPath.replace( /simulaRasa/, lowerCamelCase );
      contentsPath = contentsPath.replace( /SimulaRasa/, upperCamelCase );

      // Write the file
      grunt.file.write( contentsPath, contents );
      grunt.log.writeln( 'wrote', contentsPath );
    }
  } );

  await npmUpdate( repo );
  await execute( gruntCommand, [ 'unpublished-README' ], `../${repo}` );
  await execute( gruntCommand, [ 'generate-config' ], `../${repo}` );
};
<|endoftext|>


<commit_before>import {vector} from "./entities.js";
import {objects} from "./entities/objects.js";

var nests = [], generation = 0, clearGame;
const targetNbrLinks = {min: 10, max: 50}, nbrNests = 1;

function R2one(n) {
	return 2*Math.atan(n)/Math.PI;
}
function one2R(n) {
	if(n>1) n = 1;
	else if(n<-1) n = -1;
	return Math.tan(n*1.5);	//tan(pi/2) : illegal
}
function randomInputCombo(inputNames) {
	var rv = [];
	while(.3>Math.random())
		rv.push(inputNames[Math.floor(Math.random()*inputNames.length)]);
	return rv.join('*');
}
function randomItem(arr) {
	return arr[Math.floor(Math.random()*arr.length)];
}
export var intelligence = {
	get raw() {
		return {neurons: this.neurons, defaults: this.defaults};
	},
	set raw(v) {
		this.neurons = v.neurons;
		this.defaults = v.defaults;
	},
	defaults: {},
	neurons: {},
	random() {
		var i;
		this.defaults = $.extend(true, {}, this.defaults);
		this.neurons = $.extend(true, {}, this.neurons);
		for(i in this.defaults) this.defaults[i] = one2R(2*Math.random()-1);
		for(i in io.output) {
			this.neurons[i] = {};
			while(.7>Math.random())
				this.neurons[i][randomInputCombo(inputNames)] = one2R(2*Math.random()-1);
		}
	},
	mutationAddOne() {
		var itm = randomItem(Object.keys(this.neurons)),
			combo = randomInputCombo(inputNames);
		this.neurons[itm][combo] = Math.random()-0.5;
	},
	mutationDefaultOne() {
		this.defaults[randomItem(Object.keys(this.defaults))] += Math.random()-.5;
	},
	neuronCount() {
		var nCnt = {}, i, total = 0;
		for(i in this.neurons) {
			nCnt[i] = Object.keys(this.neurons[i]);
			total += nCnt[i].length;
		}
		nCnt.total = total;
		return nCnt;
	},
	mutationPick(nCnt) {
		var i, tIndex;
		tIndex = Math.floor(Math.random()*nCnt.total);
		for(i in this.neurons) {
			if(tIndex< nCnt[i].length)
				return {output: i, input: nCnt[i][tIndex]};
			else
				tIndex -= nCnt[i].length;
		}
	},
	mutationChangeOne(nCnt) {
		var {input, output} = this.mutationPick(nCnt);
		this.neurons[output][input] += Math.random()-.5;
	},
	mutationDeleteOne(nCnt) {
		var {input, output} = this.mutationPick(nCnt);
		delete this.neurons[output][input];
		--nCnt.total;
		nCnt[output].splice(nCnt[output].indexOf(input), 1);
	},
	mutate() {
		var nCnt = this.neuronCount();
		while(.5> Math.random())
			this.mutationDefaultOne();
		while(nCnt.total/targetNbrLinks.max> Math.random())
			this.mutationDeleteOne(nCnt);
		while(nCnt.total && 1-(targetNbrLinks.min/nCnt.total)> Math.random())
			this.mutationChangeOne(nCnt);
		while(targetNbrLinks.min/nCnt.total> Math.random()) {
			this.mutationAddOne();
			++nCnt.total;
		}
	},
	layers(ant, interractions) {
		var input = {}, output = {}, me = this;
		function base(type) {
			return 0;/*
			if(undefined=== me.base[type])
				me.base[type] = 0;
			return me.base[type];*/
		}
		function defaults(type) {
			if(undefined=== me.defaults[type])
				me.defaults[type] = 0;
			return R2one(me.defaults[type]);
		}
		function inputLoaded(type) {
			input['loaded.'+type] = (ant.loaded && ant.loaded[type]) || defaults('loaded.'+type);
		}
		function inputObjects(type) {
			input['object.'+type+'.qtt'] = R2one(interractions[type] && interractions[type].qtt) || defaults('object.'+type+'.qtt');
			input['object.'+type+'.distance'] = (interractions[type] && interractions[type].proximity) || defaults('object.'+type+'.distance');
			input['object.'+type+'.proximity'] = (interractions[type] && (1-interractions[type].proximity)) || defaults('object.'+type+'.proximity');
			output['object.'+type+'.direction'] = base('object.'+type);
		}
		function inputPheromon(type) {
			input['pheromon.'+type+'.qtt'] = R2one(interractions.pheromons[type] && interractions.pheromons[type].qtt) || defaults('pheromon.'+type+'.qtt');
			input['pheromon.'+type+'.distance'] = (interractions.pheromons[type] && interractions.pheromons[type].proximity) || defaults('pheromon.'+type+'.distance');
			input['pheromon.'+type+'.proximity'] = (interractions.pheromons[type] && (1-interractions.pheromons[type].proximity)) || defaults('pheromon.'+type+'.proximity');
			output['pheromon.'+type+'.direction'] = base('pheromon.'+type+'.direction');
			output['pheromon.'+type+'.radius'] = base('pheromon.'+type+'.radius');
			output['pheromon.'+type+'.strength'] = base('pheromon.'+type+'.strength');
			output['pheromon.'+type+'.degeneration'] = base('pheromon.'+type+'.degeneration');
		}
		inputLoaded('grass');
		//inputLoaded('poison');
		inputObjects('lava');
		inputObjects('grass');
		inputObjects('queen');
		//inputObjects('poison');
		output['action.grab'] = base('action.grab');
		output['action.eat'] = base('action.eat');
		output['velocity'] = base('velocity');
		input['ant.strength'] = ant.strength*2-1;
		input['ant.loaded'] = ant.loaded?1:-1;
		input['random'] = Math.random()*2-1;
		//output['action.drop'] = base('action.drop');
		for(let i = 0; i < 5; ++i)
			inputPheromon('p'+i);
		return {input, output};
	},
	step(ant, interractions) {
		var direction = new vector(0, 0), pheromons = {},
			{input, output} = this.layers(ant, interractions);
		for(let o in output) {
			let neurons = this.neurons[o];
			if(neurons) {
				for(let n in neurons) {
					let tv = neurons[n], comps = n.split('*');
					if(''!== n) for(let i in comps)
						tv *= input[comps[i]];
					output[o] += /*R2one*/(tv);
				}
				let dst = o.split('.'), tDirection = false;
				if('direction'=== dst[2]) {
					if('pheromon'=== dst[0])
						tDirection = interractions.pheromons;
					else if('object'=== dst[0])
						tDirection = interractions;
					tDirection = tDirection[dst[1]];
					if(tDirection) {
						tDirection = tDirection.direction;
						if(!tDirection.isZero())
							direction.add(tDirection.clone().multiply(output[o]));
					}
				} else if('pheromon'=== dst[0]) {
					if(!pheromons[dst[1]])
						pheromons[dst[1]] = {};
					pheromons[dst[1]][dst[2]] =
						'radius'=== dst[2]? 5*(1+R2one(output[o])):
						'strength'=== dst[2]? R2one(output[o]):
						/*'degeneration'=== dst[2]?*/ Math.pow(.01, 1+R2one(output[o])/2);
				}
			}
		}

		return {
			direction: direction.isZero()?ant.direction:direction.angle(),
			velocity: (1+R2one(output.velocity))/2,
			action: {
				grab: 0<output['action.grab'],
				eat: 0<output['action.eat']/*,
				drop: 0*/
			},
			pheromons
		};
	}
}
var io = intelligence.layers({}, {pheromons:{}}),
	inputNames = Object.keys(io.input);

export function initIntelligence(clear) {
	clearGame = clear;
	return {
		pheromons: {
			p0: new objects('pheromons', 250),
			p1: new objects('pheromons', 25),
			p2: new objects('pheromons', 75),
			p3: new objects('pheromons', 150),
			p4: new objects('pheromons', 175)
		}
	}
}

export function endGame(score) {
	//if(score < -10) score = undefined;
	if(undefined!== score)
		nests.push($.extend(true, {score}, intelligence.raw));
	nests.sort(function(a, b) { return b.score-a.score; });
	if(nbrNests < nests.length || (nbrNests == nests.length && undefined=== score)) {
		if(undefined!== score)
			nests.pop();	//removes the "loser"
		var index = Math.random();
		if(document.getElementById('checkBest').checked)
			index = 0;
		else
			index *= index * nests.length;	//[0..1[ square to chose more probably best ones
		index = Math.floor(index);
		intelligence.raw = $.extend(true, {}, nests[index]);
		nests[index].score -= /*(maxS-minS)*/1;	//kill the father, 5 offsprings for the best
		intelligence.mutate();
	} else {
		intelligence.random();
	}
	var average = 0;
	for(let i in nests)
		average += nests[i].score;
	$('#scoreAverage').text(average / nests.length);
	$('#scoreMin').text(nests[nests.length-1].score);
	$('#scoreMax').text(nests[0].score);
	$('#population').text(nests.length);
	$('#generation').text(++generation);
	clearGame();
}

$("#infos").append(`

Generation:

population:

Max:

Average:

Min:

		<button id="saveCmd">Save</button>
		<input type="file" accept="json" id="loadFile" />
		<button id="loadCmd">Load</button>

		<input type="checkbox" id="checkBest" /> See the best

`);

$('#saveCmd').click(function() {
	var blob = new Blob([JSON.stringify({nests, generation})], {type: "application/json;charset=utf-8"});
	saveAs(blob, "nests.json");
});

var fr;
function receivedText() {
	var vals = JSON.parse(fr.result);
	nests = vals.nests;
	generation = vals.generation-1;
	endGame();
}
$('#loadCmd').click(function() {
	var input = $('#loadFile')[0];
	fr = new FileReader();
	fr.onload = receivedText;
	fr.readAsText(input.files[0]);
	//fr.readAsDataURL(input.files[0]);
});
<commit_msg>test vals<commit_after>import {vector} from "./entities.js";
import {objects} from "./entities/objects.js";

var nests = [], generation = 0, clearGame;
const targetNbrLinks = {min: 10, max: 50}, nbrNests = 100;

function R2one(n) {
	return 2*Math.atan(n)/Math.PI;
}
function one2R(n) {
	if(n>1) n = 1;
	else if(n<-1) n = -1;
	return Math.tan(n*1.5);	//tan(pi/2) : illegal
}
function randomInputCombo(inputNames) {
	var rv = [];
	while(.3>Math.random())
		rv.push(inputNames[Math.floor(Math.random()*inputNames.length)]);
	return rv.join('*');
}
function randomItem(arr) {
	return arr[Math.floor(Math.random()*arr.length)];
}
export var intelligence = {
	get raw() {
		return {neurons: this.neurons, defaults: this.defaults};
	},
	set raw(v) {
		this.neurons = v.neurons;
		this.defaults = v.defaults;
	},
	defaults: {},
	neurons: {},
	random() {
		var i;
		this.defaults = $.extend(true, {}, this.defaults);
		this.neurons = $.extend(true, {}, this.neurons);
		for(i in this.defaults) this.defaults[i] = one2R(2*Math.random()-1);
		for(i in io.output) {
			this.neurons[i] = {};
			while(.7>Math.random())
				this.neurons[i][randomInputCombo(inputNames)] = one2R(2*Math.random()-1);
		}
	},
	mutationAddOne() {
		var itm = randomItem(Object.keys(this.neurons)),
			combo = randomInputCombo(inputNames);
		this.neurons[itm][combo] = Math.random()-0.5;
	},
	mutationDefaultOne() {
		this.defaults[randomItem(Object.keys(this.defaults))] += Math.random()-.5;
	},
	neuronCount() {
		var nCnt = {}, i, total = 0;
		for(i in this.neurons) {
			nCnt[i] = Object.keys(this.neurons[i]);
			total += nCnt[i].length;
		}
		nCnt.total = total;
		return nCnt;
	},
	mutationPick(nCnt) {
		var i, tIndex;
		tIndex = Math.floor(Math.random()*nCnt.total);
		for(i in this.neurons) {
			if(tIndex< nCnt[i].length)
				return {output: i, input: nCnt[i][tIndex]};
			else
				tIndex -= nCnt[i].length;
		}
	},
	mutationChangeOne(nCnt) {
		var {input, output} = this.mutationPick(nCnt);
		this.neurons[output][input] += Math.random()-.5;
	},
	mutationDeleteOne(nCnt) {
		var {input, output} = this.mutationPick(nCnt);
		delete this.neurons[output][input];
		--nCnt.total;
		nCnt[output].splice(nCnt[output].indexOf(input), 1);
	},
	mutate() {
		var nCnt = this.neuronCount();
		while(.5> Math.random())
			this.mutationDefaultOne();
		while(nCnt.total/targetNbrLinks.max> Math.random())
			this.mutationDeleteOne(nCnt);
		while(nCnt.total && 1-(targetNbrLinks.min/nCnt.total)> Math.random())
			this.mutationChangeOne(nCnt);
		while(targetNbrLinks.min/nCnt.total> Math.random()) {
			this.mutationAddOne();
			++nCnt.total;
		}
	},
	layers(ant, interractions) {
		var input = {}, output = {}, me = this;
		function base(type) {
			return 0;/*
			if(undefined=== me.base[type])
				me.base[type] = 0;
			return me.base[type];*/
		}
		function defaults(type) {
			if(undefined=== me.defaults[type])
				me.defaults[type] = 0;
			return R2one(me.defaults[type]);
		}
		function inputLoaded(type) {
			input['loaded.'+type] = (ant.loaded && ant.loaded[type]) || defaults('loaded.'+type);
		}
		function inputObjects(type) {
			input['object.'+type+'.qtt'] = R2one(interractions[type] && interractions[type].qtt) || defaults('object.'+type+'.qtt');
			input['object.'+type+'.distance'] = (interractions[type] && interractions[type].proximity) || defaults('object.'+type+'.distance');
			input['object.'+type+'.proximity'] = (interractions[type] && (1-interractions[type].proximity)) || defaults('object.'+type+'.proximity');
			output['object.'+type+'.direction'] = base('object.'+type);
		}
		function inputPheromon(type) {
			input['pheromon.'+type+'.qtt'] = R2one(interractions.pheromons[type] && interractions.pheromons[type].qtt) || defaults('pheromon.'+type+'.qtt');
			input['pheromon.'+type+'.distance'] = (interractions.pheromons[type] && interractions.pheromons[type].proximity) || defaults('pheromon.'+type+'.distance');
			input['pheromon.'+type+'.proximity'] = (interractions.pheromons[type] && (1-interractions.pheromons[type].proximity)) || defaults('pheromon.'+type+'.proximity');
			output['pheromon.'+type+'.direction'] = base('pheromon.'+type+'.direction');
			output['pheromon.'+type+'.radius'] = base('pheromon.'+type+'.radius');
			output['pheromon.'+type+'.strength'] = base('pheromon.'+type+'.strength');
			output['pheromon.'+type+'.degeneration'] = base('pheromon.'+type+'.degeneration');
		}
		inputLoaded('grass');
		//inputLoaded('poison');
		inputObjects('lava');
		inputObjects('grass');
		inputObjects('queen');
		//inputObjects('poison');
		output['action.grab'] = base('action.grab');
		output['action.eat'] = base('action.eat');
		output['velocity'] = base('velocity');
		input['ant.strength'] = ant.strength*2-1;
		input['ant.loaded'] = ant.loaded?1:-1;
		input['random'] = Math.random()*2-1;
		//output['action.drop'] = base('action.drop');
		for(let i = 0; i < 5; ++i)
			inputPheromon('p'+i);
		return {input, output};
	},
	step(ant, interractions) {
		var direction = new vector(0, 0), pheromons = {},
			{input, output} = this.layers(ant, interractions);
		for(let o in output) {
			let neurons = this.neurons[o];
			if(neurons) {
				for(let n in neurons) {
					let tv = neurons[n], comps = n.split('*');
					if(''!== n) for(let i in comps)
						tv *= input[comps[i]];
					output[o] += /*R2one*/(tv);
				}
				let dst = o.split('.'), tDirection = false;
				if('direction'=== dst[2]) {
					if('pheromon'=== dst[0])
						tDirection = interractions.pheromons;
					else if('object'=== dst[0])
						tDirection = interractions;
					tDirection = tDirection[dst[1]];
					if(tDirection) {
						tDirection = tDirection.direction;
						if(!tDirection.isZero())
							direction.add(tDirection.clone().multiply(output[o]));
					}
				} else if('pheromon'=== dst[0]) {
					if(!pheromons[dst[1]])
						pheromons[dst[1]] = {};
					pheromons[dst[1]][dst[2]] =
						'radius'=== dst[2]? 5*(1+R2one(output[o])):
						'strength'=== dst[2]? R2one(output[o]):
						/*'degeneration'=== dst[2]?*/ Math.pow(.01, 1+R2one(output[o])/2);
				}
			}
		}

		return {
			direction: direction.isZero()?ant.direction:direction.angle(),
			velocity: (1+R2one(output.velocity))/2,
			action: {
				grab: 0<output['action.grab'],
				eat: 0<output['action.eat']/*,
				drop: 0*/
			},
			pheromons
		};
	}
}
var io = intelligence.layers({}, {pheromons:{}}),
	inputNames = Object.keys(io.input);

export function initIntelligence(clear) {
	clearGame = clear;
	return {
		pheromons: {
			p0: new objects('pheromons', 250),
			p1: new objects('pheromons', 25),
			p2: new objects('pheromons', 75),
			p3: new objects('pheromons', 150),
			p4: new objects('pheromons', 175)
		}
	}
}

export function endGame(score) {
	//if(score < -10) score = undefined;
	if(undefined!== score)
		nests.push($.extend(true, {score}, intelligence.raw));
	nests.sort(function(a, b) { return b.score-a.score; });
	if(nbrNests < nests.length || (nbrNests == nests.length && undefined=== score)) {
		if(undefined!== score)
			nests.pop();	//removes the "loser"
		var index = Math.random();
		if(document.getElementById('checkBest').checked)
			index = 0;
		else
			index *= index * nests.length;	//[0..1[ square to chose more probably best ones
		index = Math.floor(index);
		intelligence.raw = $.extend(true, {}, nests[index]);
		nests[index].score -= /*(maxS-minS)*/1;	//kill the father, 5 offsprings for the best
		intelligence.mutate();
	} else {
		intelligence.random();
	}
	var average = 0;
	for(let i in nests)
		average += nests[i].score;
	$('#scoreAverage').text(average / nests.length);
	$('#scoreMin').text(nests[nests.length-1].score);
	$('#scoreMax').text(nests[0].score);
	$('#population').text(nests.length);
	$('#generation').text(++generation);
	clearGame();
}

$("#infos").append(`

Generation:

population:

Max:

Average:

Min:

		<button id="saveCmd">Save</button>
		<input type="file" accept="json" id="loadFile" />
		<button id="loadCmd">Load</button>

		<input type="checkbox" id="checkBest" /> See the best

`);

$('#saveCmd').click(function() {
	var blob = new Blob([JSON.stringify({nests, generation})], {type: "application/json;charset=utf-8"});
	saveAs(blob, "nests.json");
});

var fr;
function receivedText() {
	var vals = JSON.parse(fr.result);
	nests = vals.nests;
	generation = vals.generation-1;
	endGame();
}
$('#loadCmd').click(function() {
	var input = $('#loadFile')[0];
	fr = new FileReader();
	fr.onload = receivedText;
	fr.readAsText(input.files[0]);
	//fr.readAsDataURL(input.files[0]);
});
<|endoftext|>


<commit_before>/**
 [lang:ja]
 * @scope enchant.Entity.prototype
 [/lang]
 [lang:en]
 * @scope enchant.Entity.prototype
 [/lang]
 */
enchant.Entity = enchant.Class.create(enchant.Node, {
    /**
     [lang:ja]
     * DOM上で表示する実体を持ったクラス.直接使用することはない.
     [/lang]
     [lang:en]
     * A class with objects displayed on DOM. Not used directly.
     [/lang]
     * @constructs
     * @extends enchant.Node
     */
    initialize: function() {
        var game = enchant.Game.instance;
        enchant.Node.call(this);

        this._originX = null;
        this._originY = null;

        this._width = 0;
        this._height = 0;
        this._backgroundColor = null;
        this._opacity = 1;
        this._visible = true;
        this._buttonMode = null;

        this._style = {};

        /**
         [lang:ja]
         * Entityにボタンの機能を設定する.
         * Entityに対するタッチ, クリックをleft, right, up, down, a, bいずれかの
         * ボタン入力として割り当てる.
         * @type {String}
         [/lang]
         [lang:en]
         * Set button function to Entity.
         * Apply touch, click to left, right, up, down, a, b
         * for button input for Entity.
         * @type {String}
         [/lang]
         */
        this.buttonMode = null;
        /**
         [lang:ja]
         * Entityが押されているかどうか.
         * buttonModeが設定されているときだけ機能する.
         * @type {Boolean}
         [/lang]
         [lang:en]
         * Checks if Entity is being pushed.
         * Only functions when buttonMode is set.
         * @type {Boolean}
         [/lang]
         */
        this.buttonPressed = false;
        this.addEventListener('touchstart', function() {
            if (!this.buttonMode) {
                return;
            }
            this.buttonPressed = true;
            var e = new enchant.Event(this.buttonMode + 'buttondown');
            this.dispatchEvent(e);
            game.dispatchEvent(e);
        });
        this.addEventListener('touchend', function() {
            if (!this.buttonMode) {
                return;
            }
            this.buttonPressed = false;
            var e = new enchant.Event(this.buttonMode + 'buttonup');
            this.dispatchEvent(e);
            game.dispatchEvent(e);
        });

        var that = this;
        var render = function() {
            that.dispatchEvent(new enchant.Event('render'));
        };
        this.addEventListener('addedtoscene', function() {
            render();
            game.addEventListener('exitframe', render);
        });
        this.addEventListener('removedfromscene', function() {
            game.removeEventListener('exitframe', render);
        });

    },
    /**
     [lang:ja]
     * DOMのID.
     * @type {String}
     [/lang]
     [lang:en]
     * DOM ID.
     * @type {String}
     [/lang]
     */
    id: {
        get: function() {
            return this._element.id;
        },
        set: function(id) {
            this._element.id = id;
        }
    },
    /**
     [lang:ja]
     * DOMのclass.
     * @type {String}
     [/lang]
     [lang:en]
     * DOM class.
     * @type {String}
     [/lang]
     */
    className: {
        get: function() {
            return this._element.className;
        },
        set: function(className) {
            this._element.className = className;
        }
    },
    /**
     [lang:ja]
     * Entityの横幅.
     * @type {Number}
     [/lang]
     [lang:en]
     * Entity width.
     * @type {Number}
     [/lang]
     */
    width: {
        get: function() {
            return this._width;
        },
        set: function(width) {
            this._width = width;
        }
    },
    /**
     [lang:ja]
     * Entityの高さ.
     * @type {Number}
     [/lang]
     [lang:en]
     * Entity height.
     * @type {Number}
     [/lang]
     */
    height: {
        get: function() {
            return this._height;
        },
        set: function(height) {
            this._height = height;
        }
    },
    /**
     [lang:ja]
     * Entityの背景色.
     * CSSの'color'プロパティと同様の形式で指定できる.
     * @type {String}
     [/lang]
     [lang:en]
     * Entity background color.
     * Designates as same format as CSS 'color' properties.
     * @type {String}
     [/lang]
     */
    backgroundColor: {
        get: function() {
            return this._backgroundColor;
        },
        set: function(color) {
            this._backgroundColor = color;
        }
    },
    /**
     [lang:ja]
     * Entityの透明度.
     * 0から1までの値を設定する(0が完全な透明, 1が完全な不透明).
     * @type {Number}
     [/lang]
     [lang:en]
     * Entity transparency.
     * Sets level from 0 to 1 (0 is completely transparent, 1 is completely opaque).
     * @type {Number}
     [/lang]
     */
    opacity: {
        get: function() {
            return this._opacity;
        },
        set: function(opacity) {
            this._opacity = opacity;
        }
    },
    /**
     [lang:ja]
     * Entityを表示するかどうかを指定する.
     * @type {Boolean}
     [/lang]
     [lang:en]
     * Indicates whether or not to display Entity.
     * @type {Boolean}
     [/lang]
     */
    visible: {
        get: function() {
            return this._visible;
        },
        set: function(visible) {
            this._visible = visible;
        }
    },
    /**
     [lang:ja]
     * Entityのタッチを有効にするかどうかを指定する.
     * @type {Boolean}
     [/lang]
     [lang:en]
     * Designates whether or not to make Entity touch valid.
     * @type {Boolean}
     [/lang]
     */
    touchEnabled: {
        get: function() {
            return this._touchEnabled;
        },
        set: function(enabled) {
            if (this._touchEnabled = enabled) {
                this._style.pointerEvents = 'all';
            } else {
                this._style.pointerEvents = 'none';
            }
        }
    },
    /**
     [lang:ja]
     * Entityの矩形が交差しているかどうかにより衝突判定を行う.
     * @param {*} other 衝突判定を行うEntityなどx, y, width, heightプロパティを持ったObject.
     * @return {Boolean} 衝突判定の結果.
     [/lang]
     [lang:en]
     * Operates collision detection based on whether or not rectangle angles are intersecting.
     * @param {*} other Object with properties of x, y, width, height that operate Entity collision detection.
     * @return {Boolean} Collision detection results.
     [/lang]
     */
    intersect: function(other) {
        return this._offsetX < other._offsetX + other.width && other._offsetX < this._offsetX + this.width &&
            this._offsetY < other._offsetY + other.height && other._offsetY < this._offsetY + this.height;
    },
    /**
     [lang:ja]
     * Entityの中心点どうしの距離により衝突判定を行う.
     * @param {*} other 衝突判定を行うEntityなどx, y, width, heightプロパティを持ったObject.
     * @param {Number} [distance] 衝突したと見なす最大の距離. デフォルト値は二つのEntityの横幅と高さの平均.
     * @return {Boolean} 衝突判定の結果.
     [/lang]
     [lang:en]
     * Operates collision detection based on distance from Entity's central point.
     * @param {*} other Object with properties of x, y, width, height that operate Entity collision detection.
     * @param {Number} [distance] Greatest distance considered in collision. Default level is average of Entity width and height.
     * @return {Boolean} Collision detection result.
     [/lang]
     */
    within: function(other, distance) {
        if (distance == null) {
            distance = (this.width + this.height + other.width + other.height) / 4;
        }
        var _;
        return (_ = this._offsetX - other._offsetX + (this.width - other.width) / 2) * _ +
            (_ = this._offsetY - other._offsetY + (this.height - other.height) / 2) * _ < distance * distance;
    }, /**
     [lang:ja]
     * Spriteを拡大縮小する.
     * @param {Number} x 拡大するx軸方向の倍率.
     * @param {Number} [y] 拡大するy軸方向の倍率.
     [/lang]
     [lang:en]
     * Expand or contract Sprite.
     * @param {Number} x Scaling for x axis to be expanded.
     * @param {Number} [y] Scaling for y axis to be expanded.
     [/lang]
     */
    scale: function(x, y) {
        if (y == null) {
            y = x;
        }
        this._scaleX *= x;
        this._scaleY *= y;
        this._dirty = true;
    },
    /**
     [lang:ja]
     * Spriteを回転する.
     * @param {Number} deg 回転する角度 (度数法).
     [/lang]
     [lang:en]
     * Rotate Sprite.
     * @param {Number} deg Rotation angle (frequency).
     [/lang]
     */
    rotate: function(deg) {
        this._rotation += deg;
        this._dirty = true;
    },
    /**
     [lang:ja]
     * Spriteのx軸方向の倍率.
     * @type {Number}
     [/lang]
     [lang:en]
     * Scaling for Sprite's x axis direction.
     * @type {Number}
     [/lang]
     */
    scaleX: {
        get: function() {
            return this._scaleX;
        },
        set: function(scaleX) {
            this._scaleX = scaleX;
            this._dirty = true;
        }
    },
    /**
     [lang:ja]
     * Spriteのy軸方向の倍率.
     * @type {Number}
     [/lang]
     [lang:en]
     * Scaling for Sprite's y axis direction.
     * @type {Number}
     [/lang]
     */
    scaleY: {
        get: function() {
            return this._scaleY;
        },
        set: function(scaleY) {
            this._scaleY = scaleY;
            this._dirty = true;
        }
    },
    /**
     [lang:ja]
     * Spriteの回転角 (度数法).
     [/lang]
     [lang:en]
     * Sprite rotation angle (frequency).
     [/lang]
     * @type {Number}
     */
    rotation: {
        get: function() {
            return this._rotation;
        },
        set: function(rotation) {
            this._rotation = rotation;
            this._dirty = true;
        }
    },
    /**
     [lang:ja]
     * 回転・拡大縮小の基準点のX座標
     [/lang]
     [lang:en]
     * origin point of rotation, scaling
     [/lang]
     * @type {Number}
     */
    originX: {
        get: function() {
            return this._originX;
        },
        set: function(originX) {
            this._originX = originX;
        }
    },
    /**
     [lang:ja]
     * 回転・拡大縮小の基準点のY座標
     [/lang]
     [lang:en]
     * origin point of rotation, scaling
     [/lang]
     * @type {Number}
     */
    originY: {
        get: function() {
            return this._originY;
        },
        set: function(originY) {
            this._originY = originY;
        }
    }
});
<commit_msg>remove functions that depends on CSS or DOM from enchant.Entity<commit_after>/**
 [lang:ja]
 * @scope enchant.Entity.prototype
 [/lang]
 [lang:en]
 * @scope enchant.Entity.prototype
 [/lang]
 */
enchant.Entity = enchant.Class.create(enchant.Node, {
    /**
     [lang:ja]
     * DOM上で表示する実体を持ったクラス.直接使用することはない.
     [/lang]
     [lang:en]
     * A class with objects displayed on DOM. Not used directly.
     [/lang]
     * @constructs
     * @extends enchant.Node
     */
    initialize: function() {
        var game = enchant.Game.instance;
        enchant.Node.call(this);

        this._originX = null;
        this._originY = null;

        this._width = 0;
        this._height = 0;
        this._backgroundColor = null;
        this._opacity = 1;
        this._visible = true;
        this._buttonMode = null;

        this._style = {};

        /**
         [lang:ja]
         * Entityにボタンの機能を設定する.
         * Entityに対するタッチ, クリックをleft, right, up, down, a, bいずれかの
         * ボタン入力として割り当てる.
         * @type {String}
         [/lang]
         [lang:en]
         * Set button function to Entity.
         * Apply touch, click to left, right, up, down, a, b
         * for button input for Entity.
         * @type {String}
         [/lang]
         */
        this.buttonMode = null;
        /**
         [lang:ja]
         * Entityが押されているかどうか.
         * buttonModeが設定されているときだけ機能する.
         * @type {Boolean}
         [/lang]
         [lang:en]
         * Checks if Entity is being pushed.
         * Only functions when buttonMode is set.
         * @type {Boolean}
         [/lang]
         */
        this.buttonPressed = false;
        this.addEventListener('touchstart', function() {
            if (!this.buttonMode) {
                return;
            }
            this.buttonPressed = true;
            var e = new enchant.Event(this.buttonMode + 'buttondown');
            this.dispatchEvent(e);
            game.dispatchEvent(e);
        });
        this.addEventListener('touchend', function() {
            if (!this.buttonMode) {
                return;
            }
            this.buttonPressed = false;
            var e = new enchant.Event(this.buttonMode + 'buttonup');
            this.dispatchEvent(e);
            game.dispatchEvent(e);
        });

        var that = this;
        var render = function() {
            that.dispatchEvent(new enchant.Event('render'));
        };
        this.addEventListener('addedtoscene', function() {
            render();
            game.addEventListener('exitframe', render);
        });
        this.addEventListener('removedfromscene', function() {
            game.removeEventListener('exitframe', render);
        });

    },
    /**
     [lang:ja]
     * Entityの横幅.
     * @type {Number}
     [/lang]
     [lang:en]
     * Entity width.
     * @type {Number}
     [/lang]
     */
    width: {
        get: function() {
            return this._width;
        },
        set: function(width) {
            this._width = width;
        }
    },
    /**
     [lang:ja]
     * Entityの高さ.
     * @type {Number}
     [/lang]
     [lang:en]
     * Entity height.
     * @type {Number}
     [/lang]
     */
    height: {
        get: function() {
            return this._height;
        },
        set: function(height) {
            this._height = height;
        }
    },
    /**
     [lang:ja]
     * Entityの背景色.
     * CSSの'color'プロパティと同様の形式で指定できる.
     * @type {String}
     [/lang]
     [lang:en]
     * Entity background color.
     * Designates as same format as CSS 'color' properties.
     * @type {String}
     [/lang]
     */
    backgroundColor: {
        get: function() {
            return this._backgroundColor;
        },
        set: function(color) {
            this._backgroundColor = color;
        }
    },
    /**
     [lang:ja]
     * Entityの透明度.
     * 0から1までの値を設定する(0が完全な透明, 1が完全な不透明).
     * @type {Number}
     [/lang]
     [lang:en]
     * Entity transparency.
     * Sets level from 0 to 1 (0 is completely transparent, 1 is completely opaque).
     * @type {Number}
     [/lang]
     */
    opacity: {
        get: function() {
            return this._opacity;
        },
        set: function(opacity) {
            this._opacity = opacity;
        }
    },
    /**
     [lang:ja]
     * Entityを表示するかどうかを指定する.
     * @type {Boolean}
     [/lang]
     [lang:en]
     * Indicates whether or not to display Entity.
     * @type {Boolean}
     [/lang]
     */
    visible: {
        get: function() {
            return this._visible;
        },
        set: function(visible) {
            this._visible = visible;
        }
    },
    /**
     [lang:ja]
     * Entityのタッチを有効にするかどうかを指定する.
     * @type {Boolean}
     [/lang]
     [lang:en]
     * Designates whether or not to make Entity touch valid.
     * @type {Boolean}
     [/lang]
     */
    touchEnabled: {
        get: function() {
            return this._touchEnabled;
        },
        set: function(enabled) {
            this._touchEnabled = enabled;
            /*
            if (this._touchEnabled = enabled) {
                this._style.pointerEvents = 'all';
            } else {
                this._style.pointerEvents = 'none';
            }
            */
        }
    },
    /**
     [lang:ja]
     * Entityの矩形が交差しているかどうかにより衝突判定を行う.
     * @param {*} other 衝突判定を行うEntityなどx, y, width, heightプロパティを持ったObject.
     * @return {Boolean} 衝突判定の結果.
     [/lang]
     [lang:en]
     * Operates collision detection based on whether or not rectangle angles are intersecting.
     * @param {*} other Object with properties of x, y, width, height that operate Entity collision detection.
     * @return {Boolean} Collision detection results.
     [/lang]
     */
    intersect: function(other) {
        return this._offsetX < other._offsetX + other.width && other._offsetX < this._offsetX + this.width &&
            this._offsetY < other._offsetY + other.height && other._offsetY < this._offsetY + this.height;
    },
    /**
     [lang:ja]
     * Entityの中心点どうしの距離により衝突判定を行う.
     * @param {*} other 衝突判定を行うEntityなどx, y, width, heightプロパティを持ったObject.
     * @param {Number} [distance] 衝突したと見なす最大の距離. デフォルト値は二つのEntityの横幅と高さの平均.
     * @return {Boolean} 衝突判定の結果.
     [/lang]
     [lang:en]
     * Operates collision detection based on distance from Entity's central point.
     * @param {*} other Object with properties of x, y, width, height that operate Entity collision detection.
     * @param {Number} [distance] Greatest distance considered in collision. Default level is average of Entity width and height.
     * @return {Boolean} Collision detection result.
     [/lang]
     */
    within: function(other, distance) {
        if (distance == null) {
            distance = (this.width + this.height + other.width + other.height) / 4;
        }
        var _;
        return (_ = this._offsetX - other._offsetX + (this.width - other.width) / 2) * _ +
            (_ = this._offsetY - other._offsetY + (this.height - other.height) / 2) * _ < distance * distance;
    }, /**
     [lang:ja]
     * Spriteを拡大縮小する.
     * @param {Number} x 拡大するx軸方向の倍率.
     * @param {Number} [y] 拡大するy軸方向の倍率.
     [/lang]
     [lang:en]
     * Expand or contract Sprite.
     * @param {Number} x Scaling for x axis to be expanded.
     * @param {Number} [y] Scaling for y axis to be expanded.
     [/lang]
     */
    scale: function(x, y) {
        if (y == null) {
            y = x;
        }
        this._scaleX *= x;
        this._scaleY *= y;
        this._dirty = true;
    },
    /**
     [lang:ja]
     * Spriteを回転する.
     * @param {Number} deg 回転する角度 (度数法).
     [/lang]
     [lang:en]
     * Rotate Sprite.
     * @param {Number} deg Rotation angle (frequency).
     [/lang]
     */
    rotate: function(deg) {
        this._rotation += deg;
        this._dirty = true;
    },
    /**
     [lang:ja]
     * Spriteのx軸方向の倍率.
     * @type {Number}
     [/lang]
     [lang:en]
     * Scaling for Sprite's x axis direction.
     * @type {Number}
     [/lang]
     */
    scaleX: {
        get: function() {
            return this._scaleX;
        },
        set: function(scaleX) {
            this._scaleX = scaleX;
            this._dirty = true;
        }
    },
    /**
     [lang:ja]
     * Spriteのy軸方向の倍率.
     * @type {Number}
     [/lang]
     [lang:en]
     * Scaling for Sprite's y axis direction.
     * @type {Number}
     [/lang]
     */
    scaleY: {
        get: function() {
            return this._scaleY;
        },
        set: function(scaleY) {
            this._scaleY = scaleY;
            this._dirty = true;
        }
    },
    /**
     [lang:ja]
     * Spriteの回転角 (度数法).
     [/lang]
     [lang:en]
     * Sprite rotation angle (frequency).
     [/lang]
     * @type {Number}
     */
    rotation: {
        get: function() {
            return this._rotation;
        },
        set: function(rotation) {
            this._rotation = rotation;
            this._dirty = true;
        }
    },
    /**
     [lang:ja]
     * 回転・拡大縮小の基準点のX座標
     [/lang]
     [lang:en]
     * origin point of rotation, scaling
     [/lang]
     * @type {Number}
     */
    originX: {
        get: function() {
            return this._originX;
        },
        set: function(originX) {
            this._originX = originX;
        }
    },
    /**
     [lang:ja]
     * 回転・拡大縮小の基準点のY座標
     [/lang]
     [lang:en]
     * origin point of rotation, scaling
     [/lang]
     * @type {Number}
     */
    originY: {
        get: function() {
            return this._originY;
        },
        set: function(originY) {
            this._originY = originY;
        }
    }
});
<|endoftext|>


<commit_before>exports.sigfoxHttpsGet = function (apipath, username, password, callback) {
	var https = require('https');

	var options = {
		hostname: "backend.sigfox.com",
		auth: username + ":" + password,
		port: 443,
		path: apipath,
		method: 'GET'
	};

	var req = https.request(options, function(res) {
		var body='';
		console.log("statusCode: ", res.statusCode);
		console.log("headers: ", res.headers);
		res.on('data', function(d) {
			body+=d;
		});
		res.on('end', function() {
			var json = {};
			if (res.statusCode === 200){
				var headers = res.headers;
				if (headers['content-type'] !== undefined){
					if (headers['content-type'].indexOf("application/json") >= 0){
						try {
							json = JSON.parse(body);
						} catch (e) {
							console.error("Parsing error:", e);
						}
					}
				}
			}
			if (callback && typeof(callback) === "function") {
				json.statusCode = res.statusCode;
				callback(json);
			}
		});
	});
	req.end();

	req.on('error', function(e) {
	  console.error(e);
	});

};

exports.sigfoxHttpsPost = function (apipath,  username, password, data, callback) {
	var https = require('https');

	var dataString;
	if (data == null){
		dataString = "";
	}else{
		dataString = JSON.stringify(data);
	}
	console.log(dataString);
	console.log(apipath);

	var options = {
		hostname: 'backend.sigfox.com',
		auth: username + ":" + password,
		port: 443,
		path: apipath,
		method: 'POST',
		headers: {
          'Content-Type': 'application/json; charset=utf8',
          'Content-Length': dataString.length
		}

	};

	var req = https.request(options, function(res) {
		var body='';
		console.log("statusCode: ", res.statusCode);
		console.log("headers: ", res.headers);
		res.on('data', function(d) {
			body+=d;
		});
		res.on('end', function() {
			var json = {};
			if (res.statusCode === 200){
				var headers = res.headers;
				if (headers['content-type'] !== undefined){
					if (headers['content-type'].indexOf("application/json") >= 0){
						try {
							json = JSON.parse(body);
						} catch (e) {
							console.error("Parsing error:", e);
						}
					}
				}
			}
			json.statusCode = res.statusCode;
			if (callback && typeof(callback) === "function") {
				callback(json);
			}

		});
	});
	//req.write(dataString);
	req.end(dataString);
	req.on('error', function(e) {
	  console.error(e);
	});

};
<commit_msg>change result formatting<commit_after>exports.sigfoxHttpsGet = function (apipath, username, password, callback) {
	var https = require('https');

	var options = {
		hostname: "backend.sigfox.com",
		auth: username + ":" + password,
		port: 443,
		path: apipath,
		method: 'GET'
	};

	var req = https.request(options, function(res) {
		var body='';
		console.log("statusCode: ", res.statusCode);
		console.log("headers: ", res.headers);
		res.on('data', function(d) {
			body+=d;
		});
		res.on('end', function() {
			var json = {};
			if (res.statusCode === 200){
				var headers = res.headers;
				if (headers['content-type'] !== undefined){
					if (headers['content-type'].indexOf("application/json") >= 0){
						try {
							json.message = JSON.parse(body);
						} catch (e) {
							console.error("Parsing error:", e);
						}
					}
				}
			}
			if (callback && typeof(callback) === "function") {
				json.statusCode = res.statusCode;
				callback(json);
			}
		});
	});
	req.end();

	req.on('error', function(e) {
	  console.error(e);
	});

};

exports.sigfoxHttpsPost = function (apipath,  username, password, data, callback) {
	var https = require('https');

	var dataString;
	if (data == null){
		dataString = "";
	}else{
		dataString = JSON.stringify(data);
	}

	var options = {
		hostname: 'backend.sigfox.com',
		auth: username + ":" + password,
		port: 443,
		path: apipath,
		method: 'POST',
		headers: {
          'Content-Type': 'application/json; charset=utf8',
          'Content-Length': dataString.length
		}

	};

	var req = https.request(options, function(res) {
		var body='';
		console.log("statusCode: ", res.statusCode);
		console.log("headers: ", res.headers);
		res.on('data', function(d) {
			body+=d;
		});
		res.on('end', function() {
			var json = {};
			if (res.statusCode === 200){
				var headers = res.headers;
				if (headers['content-type'] !== undefined){
					if (headers['content-type'].indexOf("application/json") >= 0){
						try {
							json.message = JSON.parse(body);
						} catch (e) {
							console.error("Parsing error:", e);
						}
					}
				}
			}
			json.statusCode = res.statusCode;
			if (callback && typeof(callback) === "function") {
				callback(json);
			}

		});
	});
	//req.write(dataString);
	req.end(dataString);
	req.on('error', function(e) {
	  console.error(e);
	});

};
<|endoftext|>