<commit_before>/* ----------------------------------
 * Ratchet's Gruntfile
 * Licensed under The MIT License
 * http://opensource.org/licenses/MIT
 * ---------------------------------- */

/* jshint node: true */
module.exports = function(grunt) {
  'use strict';

  // Force use of Unix newlines
  grunt.util.linefeed = '\n';

  RegExp.quote = function (string) {
    return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
  };

  var generateRatchiconsData = require('./grunt/ratchicons-data-generator.js');

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    // Metadata.
    meta: {
      distPath:       'dist/',
      docsPath:       'docs/dist/',
      docsAssetsPath: 'docs/assets/'
    },

    banner: '/*!\n' +
            ' * =====================================================\n' +
            ' * Ratchet v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
            ' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
            ' * Licensed under <%= pkg.license %>.\n' +
            ' *\n' +
            ' * v<%= pkg.version %> designed by @connors.\n' +
            ' * =====================================================\n' +
            ' */\n',

    clean: {
      dist: ['dist', 'docs/dist']
    },

    concat: {
      ratchet: {
        options: {
          banner: '<%= banner %>'
        },
        src: [
          'js/modals.js',
          'js/popovers.js',
          'js/push.js',
          'js/segmented-controllers.js',
          'js/sliders.js',
          'js/toggles.js'
        ],
        dest: '<%= meta.distPath %>js/<%= pkg.name %>.js'
      },
      docs: {
        src: '<%= meta.distPath %>js/<%= pkg.name %>.js',
        dest: '<%= meta.docsPath %>js/<%= pkg.name %>.js'
      }
    },

    sass: {
      options: {
        banner: '<%= banner %>',
        style: 'expanded',
        unixNewlines: true
      },
      dist: {
        files: {
          '<%= meta.distPath %>css/<%= pkg.name %>.css': 'sass/ratchet.scss',
          '<%= meta.distPath %>css/<%= pkg.name %>-theme-ios.css': 'sass/theme-ios.scss',
          '<%= meta.distPath %>css/<%= pkg.name %>-theme-android.css': 'sass/theme-android.scss',
          '<%= meta.docsAssetsPath %>css/docs.css': 'sass/docs.scss'
        }
      }
    },

    csscomb: {
      options: {
        config: 'sass/.csscomb.json'
      },
      dist: {
        files: {
          'dist/css/<%= pkg.name %>.css': 'dist/css/<%= pkg.name %>.css',
          'dist/css/<%= pkg.name %>-theme-android.css': 'dist/css/<%= pkg.name %>-theme-android.css',
          'dist/css/<%= pkg.name %>-theme-ios.css': 'dist/css/<%= pkg.name %>-theme-ios.css'
        }
      },
      docs: {
        files: {
          'docs/assets/css/docs.css': 'docs/assets/css/docs.css'
        }
      }
    },

    copy: {
      fonts: {
        expand: true,
        src: 'fonts/*',
        dest: 'dist/'
      },
      docs: {
        expand: true,
        cwd: 'dist',
        src: [
          '**/*'
        ],
        dest: 'docs/dist'
      }
    },

    cssmin: {
      options: {
        banner: '', // set to empty; see bellow
        keepSpecialComments: '*', // set to '*' because we already add the banner in sass
        noAdvanced: true, // disable advanced optimizations since it causes many issues
        report: 'min'
      },
      ratchet: {
        src: '<%= meta.distPath %>css/<%= pkg.name %>.css',
        dest: '<%= meta.distPath %>css/<%= pkg.name %>.min.css'
      },
      theme: {
        files: {
          '<%= meta.distPath %>css/<%= pkg.name %>-theme-ios.min.css': '<%= meta.distPath %>css/<%= pkg.name %>-theme-ios.css',
          '<%= meta.distPath %>css/<%= pkg.name %>-theme-android.min.css': '<%= meta.distPath %>css/<%= pkg.name %>-theme-android.css'
        }
      },
      docs: {
        src: [
          '<%= meta.docsAssetsPath %>css/docs.css',
          '<%= meta.docsAssetsPath %>css/pygments-manni.css'
        ],
        dest: '<%= meta.docsAssetsPath %>css/docs.min.css'
      }
    },

    uglify: {
      options: {
        banner: '<%= banner %>',
        compress: true,
        mangle: true,
        preserveComments: false,
        report: 'min'
      },
      ratchet: {
        src: '<%= meta.distPath %>js/<%= pkg.name %>.js',
        dest: '<%= meta.distPath %>js/<%= pkg.name %>.min.js'
      },
      docs: {
        src: [
          '<%= meta.docsAssetsPath %>js/docs.js',
          '<%= meta.docsAssetsPath %>js/fingerblast.js'
        ],
        dest: '<%= meta.docsAssetsPath %>js/docs.min.js'
      }
    },

    watch: {
      scripts: {
        files: [
          '<%= meta.srcPath %>/**/*.scss'
        ],
        tasks: ['sass']
      }
    },

    jekyll: {
      docs: {}
    },

    jshint: {
      options: {
        jshintrc: 'js/.jshintrc'
      },
      grunt: {
        src: ['Gruntfile.js', 'grunt/*.js']
      },
      src: {
        src: 'js/*.js'
      },
      docs: {
        src: ['docs/assets/js/docs.js', 'docs/assets/js/fingerblast.js']
      }
    },

    jscs: {
      options: {
        config: 'js/.jscsrc'
      },
      grunt: {
        src: '<%= jshint.grunt.src %>'
      },
      src: {
        src: '<%= jshint.src.src %>'
      },
      docs: {
        src: '<%= jshint.docs.src %>'
      }
    },

    csslint: {
      options: {
        csslintrc: 'sass/.csslintrc'
      },
      src: [
        'dist/css/<%= pkg.name %>.css',
        'dist/css/<%= pkg.name %>-theme-android.css',
        'dist/css/<%= pkg.name %>-theme-ios.css'
      ],
      docs: {
        options: {
          ids: false
        },
        src: ['docs/assets/css/docs.css']
      }
    },

    validation: {
      options: {
        charset: 'utf-8',
        doctype: 'HTML5',
        failHard: true,
        reset: true,
        relaxerror: [
          'Bad value apple-mobile-web-app-title for attribute name on element meta: Keyword apple-mobile-web-app-title is not registered.',
          'Bad value apple-mobile-web-app-status-bar-style for attribute name on element meta: Keyword apple-mobile-web-app-status-bar-style is not registered.',
          'Bad value X-UA-Compatible for attribute http-equiv on element meta.',
          'Attribute ontouchstart not allowed on element body at this point.'
        ]
      },
      files: {
        src: '_site/**/*.html'
      }
    },

    sed: {
      versionNumber: {
        pattern: (function () {
          var old = grunt.option('oldver');
          return old ? RegExp.quote(old) : old;
        })(),
        replacement: grunt.option('newver'),
        recursive: true
      }
    }
  });

  // Load the plugins
  require('load-grunt-tasks')(grunt, {scope: 'devDependencies'});
  require('time-grunt')(grunt);

  // Default task(s).
  grunt.registerTask('dist-css', ['sass', 'csscomb', 'cssmin']);
  grunt.registerTask('dist-js', ['concat', 'uglify']);
  grunt.registerTask('dist', ['clean', 'dist-css', 'dist-js', 'copy', 'build-ratchicons-data']);
  grunt.registerTask('validate-html', ['jekyll', 'validation']);
  grunt.registerTask('build', ['dist']);
  grunt.registerTask('default', ['dist']);
  grunt.registerTask('test', ['dist', 'csslint', 'jshint', 'jscs', 'validate-html']);

  grunt.registerTask('build-ratchicons-data', generateRatchiconsData);

  // Version numbering task.
  // grunt change-version-number --oldver=A.B.C --newver=X.Y.Z
  // This can be overzealous, so its changes should always be manually reviewed!
  grunt.registerTask('change-version-number', 'sed');
};
<commit_msg>Re-enable clean-css's advanced optimizations.<commit_after>/* ----------------------------------
 * Ratchet's Gruntfile
 * Licensed under The MIT License
 * http://opensource.org/licenses/MIT
 * ---------------------------------- */

/* jshint node: true */
module.exports = function(grunt) {
  'use strict';

  // Force use of Unix newlines
  grunt.util.linefeed = '\n';

  RegExp.quote = function (string) {
    return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
  };

  var generateRatchiconsData = require('./grunt/ratchicons-data-generator.js');

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    // Metadata.
    meta: {
      distPath:       'dist/',
      docsPath:       'docs/dist/',
      docsAssetsPath: 'docs/assets/'
    },

    banner: '/*!\n' +
            ' * =====================================================\n' +
            ' * Ratchet v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
            ' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
            ' * Licensed under <%= pkg.license %>.\n' +
            ' *\n' +
            ' * v<%= pkg.version %> designed by @connors.\n' +
            ' * =====================================================\n' +
            ' */\n',

    clean: {
      dist: ['dist', 'docs/dist']
    },

    concat: {
      ratchet: {
        options: {
          banner: '<%= banner %>'
        },
        src: [
          'js/modals.js',
          'js/popovers.js',
          'js/push.js',
          'js/segmented-controllers.js',
          'js/sliders.js',
          'js/toggles.js'
        ],
        dest: '<%= meta.distPath %>js/<%= pkg.name %>.js'
      },
      docs: {
        src: '<%= meta.distPath %>js/<%= pkg.name %>.js',
        dest: '<%= meta.docsPath %>js/<%= pkg.name %>.js'
      }
    },

    sass: {
      options: {
        banner: '<%= banner %>',
        style: 'expanded',
        unixNewlines: true
      },
      dist: {
        files: {
          '<%= meta.distPath %>css/<%= pkg.name %>.css': 'sass/ratchet.scss',
          '<%= meta.distPath %>css/<%= pkg.name %>-theme-ios.css': 'sass/theme-ios.scss',
          '<%= meta.distPath %>css/<%= pkg.name %>-theme-android.css': 'sass/theme-android.scss',
          '<%= meta.docsAssetsPath %>css/docs.css': 'sass/docs.scss'
        }
      }
    },

    csscomb: {
      options: {
        config: 'sass/.csscomb.json'
      },
      dist: {
        files: {
          'dist/css/<%= pkg.name %>.css': 'dist/css/<%= pkg.name %>.css',
          'dist/css/<%= pkg.name %>-theme-android.css': 'dist/css/<%= pkg.name %>-theme-android.css',
          'dist/css/<%= pkg.name %>-theme-ios.css': 'dist/css/<%= pkg.name %>-theme-ios.css'
        }
      },
      docs: {
        files: {
          'docs/assets/css/docs.css': 'docs/assets/css/docs.css'
        }
      }
    },

    copy: {
      fonts: {
        expand: true,
        src: 'fonts/*',
        dest: 'dist/'
      },
      docs: {
        expand: true,
        cwd: 'dist',
        src: [
          '**/*'
        ],
        dest: 'docs/dist'
      }
    },

    cssmin: {
      options: {
        banner: '', // set to empty; see bellow
        keepSpecialComments: '*', // set to '*' because we already add the banner in sass
        report: 'min'
      },
      ratchet: {
        src: '<%= meta.distPath %>css/<%= pkg.name %>.css',
        dest: '<%= meta.distPath %>css/<%= pkg.name %>.min.css'
      },
      theme: {
        files: {
          '<%= meta.distPath %>css/<%= pkg.name %>-theme-ios.min.css': '<%= meta.distPath %>css/<%= pkg.name %>-theme-ios.css',
          '<%= meta.distPath %>css/<%= pkg.name %>-theme-android.min.css': '<%= meta.distPath %>css/<%= pkg.name %>-theme-android.css'
        }
      },
      docs: {
        src: [
          '<%= meta.docsAssetsPath %>css/docs.css',
          '<%= meta.docsAssetsPath %>css/pygments-manni.css'
        ],
        dest: '<%= meta.docsAssetsPath %>css/docs.min.css'
      }
    },

    uglify: {
      options: {
        banner: '<%= banner %>',
        compress: true,
        mangle: true,
        preserveComments: false,
        report: 'min'
      },
      ratchet: {
        src: '<%= meta.distPath %>js/<%= pkg.name %>.js',
        dest: '<%= meta.distPath %>js/<%= pkg.name %>.min.js'
      },
      docs: {
        src: [
          '<%= meta.docsAssetsPath %>js/docs.js',
          '<%= meta.docsAssetsPath %>js/fingerblast.js'
        ],
        dest: '<%= meta.docsAssetsPath %>js/docs.min.js'
      }
    },

    watch: {
      scripts: {
        files: [
          '<%= meta.srcPath %>/**/*.scss'
        ],
        tasks: ['sass']
      }
    },

    jekyll: {
      docs: {}
    },

    jshint: {
      options: {
        jshintrc: 'js/.jshintrc'
      },
      grunt: {
        src: ['Gruntfile.js', 'grunt/*.js']
      },
      src: {
        src: 'js/*.js'
      },
      docs: {
        src: ['docs/assets/js/docs.js', 'docs/assets/js/fingerblast.js']
      }
    },

    jscs: {
      options: {
        config: 'js/.jscsrc'
      },
      grunt: {
        src: '<%= jshint.grunt.src %>'
      },
      src: {
        src: '<%= jshint.src.src %>'
      },
      docs: {
        src: '<%= jshint.docs.src %>'
      }
    },

    csslint: {
      options: {
        csslintrc: 'sass/.csslintrc'
      },
      src: [
        'dist/css/<%= pkg.name %>.css',
        'dist/css/<%= pkg.name %>-theme-android.css',
        'dist/css/<%= pkg.name %>-theme-ios.css'
      ],
      docs: {
        options: {
          ids: false
        },
        src: ['docs/assets/css/docs.css']
      }
    },

    validation: {
      options: {
        charset: 'utf-8',
        doctype: 'HTML5',
        failHard: true,
        reset: true,
        relaxerror: [
          'Bad value apple-mobile-web-app-title for attribute name on element meta: Keyword apple-mobile-web-app-title is not registered.',
          'Bad value apple-mobile-web-app-status-bar-style for attribute name on element meta: Keyword apple-mobile-web-app-status-bar-style is not registered.',
          'Bad value X-UA-Compatible for attribute http-equiv on element meta.',
          'Attribute ontouchstart not allowed on element body at this point.'
        ]
      },
      files: {
        src: '_site/**/*.html'
      }
    },

    sed: {
      versionNumber: {
        pattern: (function () {
          var old = grunt.option('oldver');
          return old ? RegExp.quote(old) : old;
        })(),
        replacement: grunt.option('newver'),
        recursive: true
      }
    }
  });

  // Load the plugins
  require('load-grunt-tasks')(grunt, {scope: 'devDependencies'});
  require('time-grunt')(grunt);

  // Default task(s).
  grunt.registerTask('dist-css', ['sass', 'csscomb', 'cssmin']);
  grunt.registerTask('dist-js', ['concat', 'uglify']);
  grunt.registerTask('dist', ['clean', 'dist-css', 'dist-js', 'copy', 'build-ratchicons-data']);
  grunt.registerTask('validate-html', ['jekyll', 'validation']);
  grunt.registerTask('build', ['dist']);
  grunt.registerTask('default', ['dist']);
  grunt.registerTask('test', ['dist', 'csslint', 'jshint', 'jscs', 'validate-html']);

  grunt.registerTask('build-ratchicons-data', generateRatchiconsData);

  // Version numbering task.
  // grunt change-version-number --oldver=A.B.C --newver=X.Y.Z
  // This can be overzealous, so its changes should always be manually reviewed!
  grunt.registerTask('change-version-number', 'sed');
};
<|endoftext|>


<commit_before>var version = require('./build/version'),
    setup = require('./build/setup'),
    path = require('path'),
    connect_livereload = require('connect-livereload'),
    gunify = require('grunt-fayde-unify');

module.exports = function (grunt) {
    grunt.loadNpmTasks('grunt-typescript');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-symlink');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-open');
    var unify = gunify(grunt);

    var meta = {
        name: 'Fayde'
    };
    var ports = {
        testsite: 7001,
        stress: 7002,
        livereload: 34343
    };
    var dirs = {
        test: {
            root: 'test',
            build: 'test/.build',
            lib: 'test/lib'
        },
        testsite: {
            root: 'testsite',
            build: 'testsite/.build',
            lib: 'testsite/lib'
        },
        stress: {
            root: 'stress',
            build: 'stress/.build',
            lib: 'stress/lib'
        }
    };
    var libs = ["requirejs", "requirejs-text", "minerva", "nullstone"];

    function linksTo(blibs, dest) {
        return blibs.map(function (libName) {
            return {src: './lib/' + libName, dest: dest + '/' + libName};
        });
    }

    function mount(connect, dir) {
        return connect.static(path.resolve(dir));
    }

    grunt.initConfig({
        ports: ports,
        meta: meta,
        dirs: dirs,
        pkg: grunt.file.readJSON('./package.json'),
        clean: {
            bower: ['./lib'],
            test: [dirs.test.lib],
            testsite: [dirs.testsite.lib],
            stress: [dirs.stress.lib]
        },
        setup: {
            fayde: {
                cwd: '.'
            }
        },
        symlink: {
            options: {
                overwrite: true
            },
            test: {
                files: [
                    {src: './themes', dest: dirs.test.lib + '/fayde/themes'},
                    {src: './dist', dest: dirs.test.lib + '/fayde/dist'},
                    {src: './src', dest: dirs.test.lib + '/fayde/src'},
                    {src: './lib/qunit', dest: dirs.test.lib + '/qunit'}
                ].concat(linksTo(libs, dirs.test.lib))
            },
            testsite: {
                files: [
                    {src: './themes', dest: dirs.testsite.lib + '/fayde/themes'},
                    {src: './dist', dest: dirs.testsite.lib + '/fayde/dist'},
                    {src: './src', dest: dirs.testsite.lib + '/fayde/src'}
                ].concat(linksTo(libs, dirs.testsite.lib))
            },
            stress: {
                files: [
                    {src: './themes', dest: dirs.stress.lib + '/fayde/themes'},
                    {src: './dist', dest: dirs.stress.lib + '/fayde/dist'},
                    {src: './src', dest: dirs.stress.lib + '/fayde/src'}
                ].concat(linksTo(libs, dirs.stress.lib))
            },
            localnullstone: {
                files: [
                    {src: '../nullstone', dest: './lib/nullstone'}
                ]
            },
            localminerva: {
                files: [
                    {src: '../minerva', dest: './lib/minerva'}
                ]
            }
        },
        typescript: {
            build: {
                src: [
                    'typings/*.d.ts',
                    'src/_Version.ts',
                    'src/polyfill/**/*.ts',
                    'src/_Types.ts',
                    'src/**/*.ts'
                ].concat(unify.typings({includeSelf: false})),
                dest: 'dist/Fayde.js',
                options: {
                    target: 'es5',
                    declaration: true,
                    sourceMap: true
                }
            },
            test: {
                src: [
                    'typings/*.d.ts',
                    '<%= dirs.test.root %>/**/*.ts',
                    '!<%= dirs.test.root %>/lib/**/*.ts'
                ].concat(unify.typings()),
                dest: dirs.test.build,
                options: {
                    target: 'es5',
                    basePath: dirs.test.root,
                    module: 'amd',
                    sourceMap: true
                }
            },
            testsite: {
                src: [
                    'typings/*.d.ts',
                    '<%= dirs.testsite.root %>/**/*.ts',
                    '!<%= dirs.testsite.root %>/lib/**/*.ts'
                ].concat(unify.typings()),
                dest: dirs.testsite.build,
                options: {
                    basePath: dirs.testsite.root,
                    target: 'es5',
                    module: 'amd'
                }
            },
            stress: {
                src: [
                    'typings/*.d.ts',
                    '<%= dirs.stress.root %>/**/*.ts',
                    '!<%= dirs.stress.lib %>/**/*.ts'
                ].concat(unify.typings()),
                dest: '<%= dirs.stress.build %>',
                options: {
                    target: 'es5',
                    basePath: '<%= dirs.stress.root %>',
                    module: 'amd',
                    sourceMap: true
                }
            }
        },
        qunit: {
            all: ['<%= dirs.test.root %>/*.html']
        },
        connect: {
            testsite: {
                options: {
                    port: ports.testsite,
                    base: dirs.testsite.root,
                    middleware: function (connect) {
                        return [
                            connect_livereload({port: ports.livereload}),
                            mount(connect, dirs.testsite.build),
                            mount(connect, dirs.testsite.root)
                        ];
                    }
                }
            },
            stress: {
                options: {
                    port: ports.stress,
                    base: dirs.stress.root,
                    middleware: function (connect) {
                        return [
                            connect_livereload({port: ports.livereload}),
                            mount(connect, dirs.stress.build),
                            mount(connect, dirs.stress.root)
                        ];
                    }
                }
            }
        },
        watch: {
            src: {
                files: ['src/**/*.ts'],
                tasks: ['typescript:build']
            },
            testsitets: {
                files: ['testsite/**/*.ts', '!testsite/lib/**/*.ts'],
                tasks: ['typescript:testsite']
            },
            testsitejs: {
                files: ['testsite/**/*.js', '!testsite/lib/**/*.js'],
                options: {
                    livereload: ports.livereload
                }
            },
            testsitefay: {
                files: ['testsite/**/*.fap', 'testsite/**/*.fayde'],
                options: {
                    livereload: ports.livereload
                }
            },
            stressts: {
                files: ['stress/**/*.ts', '!stress/lib/**/*.ts'],
                tasks: ['typescript:stress']
            },
            stressjs: {
                files: ['stress/**/*.js', '!stress/lib/**/*.js'],
                options: {
                    liverelaod: ports.livereload
                }
            }
        },
        open: {
            testsite: {
                path: 'http://localhost:<%= ports.testsite %>/index.html'
            },
            stress: {
                path: 'http://localhost:<%= ports.stress %>/index.html'
            }
        },
        version: {
            bump: {},
            apply: {
                src: './build/_VersionTemplate._ts',
                dest: './src/_Version.ts'
            }
        }
    });

    grunt.registerTask('default', ['typescript:build']);
    grunt.registerTask('test', ['typescript:build', 'typescript:test', 'qunit']);
    grunt.registerTask('testsite', ['typescript:build', 'typescript:testsite', 'connect:testsite', 'open:testsite', 'watch']);
    grunt.registerTask('stress', ['typescript:build', 'typescript:stress', 'connect:stress', 'open:stress', 'watch']);
    setup(grunt);
    version(grunt);
    grunt.registerTask('lib:reset', ['clean', 'setup', 'symlink:test', 'symlink:testsite', 'symlink:stress']);
    grunt.registerTask('link:nullstone', ['symlink:localnullstone']);
    grunt.registerTask('link:minerva', ['symlink:localminerva']);
    grunt.registerTask('dist:upbuild', ['version:bump', 'version:apply', 'typescript:build']);
    grunt.registerTask('dist:upminor', ['version:bump:minor', 'version:apply', 'typescript:build']);
    grunt.registerTask('dist:upmajor', ['version:bump:major', 'version:apply', 'typescript:build']);

};<commit_msg>Dynamic expansion of symlink dirs.<commit_after>var version = require('./build/version'),
    setup = require('./build/setup'),
    path = require('path'),
    connect_livereload = require('connect-livereload'),
    gunify = require('grunt-fayde-unify');

module.exports = function (grunt) {
    grunt.loadNpmTasks('grunt-typescript');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-symlink');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-open');
    var unify = gunify(grunt);

    var meta = {
        name: 'Fayde'
    };
    var ports = {
        testsite: 7001,
        stress: 7002,
        livereload: 34343
    };
    var dirs = {
        test: {
            root: 'test',
            build: 'test/.build',
            lib: 'test/lib'
        },
        testsite: {
            root: 'testsite',
            build: 'testsite/.build',
            lib: 'testsite/lib'
        },
        stress: {
            root: 'stress',
            build: 'stress/.build',
            lib: 'stress/lib'
        }
    };

    function mount(connect, dir) {
        return connect.static(path.resolve(dir));
    }

    grunt.initConfig({
        ports: ports,
        meta: meta,
        dirs: dirs,
        pkg: grunt.file.readJSON('./package.json'),
        clean: {
            bower: ['./lib'],
            test: [dirs.test.lib],
            testsite: [dirs.testsite.lib],
            stress: [dirs.stress.lib]
        },
        setup: {
            fayde: {
                cwd: '.'
            }
        },
        symlink: {
            options: {
                overwrite: true
            },
            test: {
                files: [
                    {src: './themes', dest: dirs.test.lib + '/fayde/themes'},
                    {src: './dist', dest: dirs.test.lib + '/fayde/dist'},
                    {src: './src', dest: dirs.test.lib + '/fayde/src'},
                    {src: './lib/qunit', dest: dirs.test.lib + '/qunit'},
                    {
                        expand: true,
                        cwd: 'lib/',
                        src: ['*'],
                        dest: dirs.test.lib,
                        filter: 'isDirectory'
                    }
                ]
            },
            testsite: {
                files: [
                    {src: './themes', dest: dirs.testsite.lib + '/fayde/themes'},
                    {src: './dist', dest: dirs.testsite.lib + '/fayde/dist'},
                    {src: './src', dest: dirs.testsite.lib + '/fayde/src'},
                    {
                        expand: true,
                        cwd: 'lib/',
                        src: ['*', '!qunit'],
                        dest: dirs.testsite.lib,
                        filter: 'isDirectory'
                    }
                ]
            },
            stress: {
                files: [
                    {src: './themes', dest: dirs.stress.lib + '/fayde/themes'},
                    {src: './dist', dest: dirs.stress.lib + '/fayde/dist'},
                    {src: './src', dest: dirs.stress.lib + '/fayde/src'},
                    {
                        expand: true,
                        cwd: 'lib/',
                        src: ['*', '!qunit'],
                        dest: dirs.stress.lib,
                        filter: 'isDirectory'
                    }
                ]
            },
            localnullstone: {
                files: [
                    {src: '../nullstone', dest: './lib/nullstone'}
                ]
            },
            localminerva: {
                files: [
                    {src: '../minerva', dest: './lib/minerva'}
                ]
            }
        },
        typescript: {
            build: {
                src: [
                    'typings/*.d.ts',
                    'src/_Version.ts',
                    'src/polyfill/**/*.ts',
                    'src/_Types.ts',
                    'src/**/*.ts'
                ].concat(unify.typings({includeSelf: false})),
                dest: 'dist/Fayde.js',
                options: {
                    target: 'es5',
                    declaration: true,
                    sourceMap: true
                }
            },
            test: {
                src: [
                    'typings/*.d.ts',
                    '<%= dirs.test.root %>/**/*.ts',
                    '!<%= dirs.test.root %>/lib/**/*.ts'
                ].concat(unify.typings()),
                dest: dirs.test.build,
                options: {
                    target: 'es5',
                    basePath: dirs.test.root,
                    module: 'amd',
                    sourceMap: true
                }
            },
            testsite: {
                src: [
                    'typings/*.d.ts',
                    '<%= dirs.testsite.root %>/**/*.ts',
                    '!<%= dirs.testsite.root %>/lib/**/*.ts'
                ].concat(unify.typings()),
                dest: dirs.testsite.build,
                options: {
                    basePath: dirs.testsite.root,
                    target: 'es5',
                    module: 'amd'
                }
            },
            stress: {
                src: [
                    'typings/*.d.ts',
                    '<%= dirs.stress.root %>/**/*.ts',
                    '!<%= dirs.stress.lib %>/**/*.ts'
                ].concat(unify.typings()),
                dest: '<%= dirs.stress.build %>',
                options: {
                    target: 'es5',
                    basePath: '<%= dirs.stress.root %>',
                    module: 'amd',
                    sourceMap: true
                }
            }
        },
        qunit: {
            all: ['<%= dirs.test.root %>/*.html']
        },
        connect: {
            testsite: {
                options: {
                    port: ports.testsite,
                    base: dirs.testsite.root,
                    middleware: function (connect) {
                        return [
                            connect_livereload({port: ports.livereload}),
                            mount(connect, dirs.testsite.build),
                            mount(connect, dirs.testsite.root)
                        ];
                    }
                }
            },
            stress: {
                options: {
                    port: ports.stress,
                    base: dirs.stress.root,
                    middleware: function (connect) {
                        return [
                            connect_livereload({port: ports.livereload}),
                            mount(connect, dirs.stress.build),
                            mount(connect, dirs.stress.root)
                        ];
                    }
                }
            }
        },
        watch: {
            src: {
                files: ['src/**/*.ts'],
                tasks: ['typescript:build']
            },
            testsitets: {
                files: ['testsite/**/*.ts', '!testsite/lib/**/*.ts'],
                tasks: ['typescript:testsite']
            },
            testsitejs: {
                files: ['testsite/**/*.js', '!testsite/lib/**/*.js'],
                options: {
                    livereload: ports.livereload
                }
            },
            testsitefay: {
                files: ['testsite/**/*.fap', 'testsite/**/*.fayde'],
                options: {
                    livereload: ports.livereload
                }
            },
            stressts: {
                files: ['stress/**/*.ts', '!stress/lib/**/*.ts'],
                tasks: ['typescript:stress']
            },
            stressjs: {
                files: ['stress/**/*.js', '!stress/lib/**/*.js'],
                options: {
                    liverelaod: ports.livereload
                }
            }
        },
        open: {
            testsite: {
                path: 'http://localhost:<%= ports.testsite %>/index.html'
            },
            stress: {
                path: 'http://localhost:<%= ports.stress %>/index.html'
            }
        },
        version: {
            bump: {},
            apply: {
                src: './build/_VersionTemplate._ts',
                dest: './src/_Version.ts'
            }
        }
    });

    grunt.registerTask('default', ['typescript:build']);
    grunt.registerTask('test', ['typescript:build', 'typescript:test', 'qunit']);
    grunt.registerTask('testsite', ['typescript:build', 'typescript:testsite', 'connect:testsite', 'open:testsite', 'watch']);
    grunt.registerTask('stress', ['typescript:build', 'typescript:stress', 'connect:stress', 'open:stress', 'watch']);
    setup(grunt);
    version(grunt);
    grunt.registerTask('lib:reset', ['clean', 'setup', 'symlink:test', 'symlink:testsite', 'symlink:stress']);
    grunt.registerTask('link:nullstone', ['symlink:localnullstone']);
    grunt.registerTask('link:minerva', ['symlink:localminerva']);
    grunt.registerTask('dist:upbuild', ['version:bump', 'version:apply', 'typescript:build']);
    grunt.registerTask('dist:upminor', ['version:bump:minor', 'version:apply', 'typescript:build']);
    grunt.registerTask('dist:upmajor', ['version:bump:major', 'version:apply', 'typescript:build']);

};<|endoftext|>


<commit_before>module.exports = function(grunt) {

	grunt.task.loadNpmTasks("grunt-contrib-watch");
	grunt.task.loadNpmTasks("grunt-contrib-uglify");
	grunt.task.loadNpmTasks("grunt-contrib-cssmin");
	grunt.task.loadNpmTasks("grunt-contrib-jshint");
	grunt.task.loadNpmTasks("grunt-contrib-connect");
	grunt.task.loadNpmTasks("grunt-remove-logging");
	grunt.task.loadNpmTasks("grunt-mocha-test");
	grunt.task.loadNpmTasks("grunt-reload");
	grunt.task.loadNpmTasks("grunt-open");

	grunt.initConfig({

		pkg: grunt.file.readJSON("package.json"),

		jshint: {
			default: ["src/**/*.js"],
			options: {
				'-W014': true
			}
		},

		watch: {
			deploy: {
				files: ["src/**/*"],
				tasks: ["jshint","uglify","mochaTest"]
			}
		},

		mochaTest: {
			default: {
				options: {
					ui: 'bdd',
					reporter: 'nyan'
				},
				src: "test/**/*.js"
			}
		},

		uglify: {
			bar: {
				options: {
					compress: false,
					beautify: true,
					mangle: false
				},
				files: {
					"dist/development/bar.js": ["src/merge.js","src/bar/**/*.js"]
				}
			},
			combine: {

			},
			deploy: {
				options: {
					sourceMap: 'dist/production/d3ca.map.js'
				},
				files: {
					'dist/production/d3ca.min.js': ['dist/development/**/*.js']
				}
			}
		},

		cssmin: {
			bar: {
				files: {
					"dist/development/bar.css": ["src/bar/**/*.css"]
				}
			},
			combine: {

			},
			deploy: {
				files: {
					"dist/production/d3ca.min.css": ["dist/development/**/*.css"]
				}
			}
		},

		reload: {
			port: 6001,
			proxy: {
				host: 'localhost',
				port: 9000
			}
		},

		connect: {
			bar: {
				options: {
					port: "9000"
				}
			}
		},

		open: {
			bar: {
				path: "http://localhost:9000/bar.html"
			}
		}

	});

	grunt.registerTask("clean", ["jshint"]);
	grunt.registerTask("minify", ["uglify:bar"]);

	grunt.registerTask("test", ["clean", "minify", "mochaTest"]);
	grunt.registerTask("bar", ["connect:bar","open:bar", "reload", "watch"]);
	grunt.registerTask("deploy", ["uglify:deploy", "cssmin:deploy"]);

}<commit_msg>grunt changed again<commit_after>module.exports = function(grunt) {

	grunt.task.loadNpmTasks("grunt-contrib-watch");
	grunt.task.loadNpmTasks("grunt-contrib-uglify");
	grunt.task.loadNpmTasks("grunt-contrib-cssmin");
	grunt.task.loadNpmTasks("grunt-contrib-jshint");
	grunt.task.loadNpmTasks("grunt-contrib-connect");
	grunt.task.loadNpmTasks("grunt-remove-logging");
	grunt.task.loadNpmTasks("grunt-mocha-test");
	grunt.task.loadNpmTasks("grunt-reload");
	grunt.task.loadNpmTasks("grunt-open");

	grunt.initConfig({

		pkg: grunt.file.readJSON("package.json"),

		jshint: {
			default: ["src/**/*.js"],
			options: {
				'-W014': true
			}
		},

		watch: {
			deploy: {
				files: ["src/**/*", "test/**/*"],
				tasks: ["jshint","uglify","mochaTest"]
			}
		},

		mochaTest: {
			default: {
				options: {
					ui: 'bdd',
					reporter: 'nyan'
				},
				src: "test/**/*.js"
			}
		},

		uglify: {
			bar: {
				options: {
					compress: false,
					beautify: true,
					mangle: false
				},
				files: {
					"dist/development/bar.js": ["src/merge.js","src/bar/**/*.js"]
				}
			},
			combine: {

			},
			deploy: {
				options: {
					sourceMap: 'dist/production/d3ca.map.js'
				},
				files: {
					'dist/production/d3ca.min.js': ['dist/development/**/*.js']
				}
			}
		},

		cssmin: {
			bar: {
				files: {
					"dist/development/bar.css": ["src/bar/**/*.css"]
				}
			},
			combine: {

			},
			deploy: {
				files: {
					"dist/production/d3ca.min.css": ["dist/development/**/*.css"]
				}
			}
		},

		reload: {
			port: 6001,
			proxy: {
				host: 'localhost',
				port: 9000
			}
		},

		connect: {
			bar: {
				options: {
					port: "9000"
				}
			}
		},

		open: {
			bar: {
				path: "http://localhost:9000/bar.html"
			}
		}

	});

	grunt.registerTask("clean", ["jshint"]);
	grunt.registerTask("minify", ["uglify:bar"]);

	grunt.registerTask("test", ["clean", "minify", "mochaTest"]);
	grunt.registerTask("bar", ["connect:bar","open:bar", "reload", "watch"]);
	grunt.registerTask("deploy", ["uglify:deploy", "cssmin:deploy"]);

}<|endoftext|>


<commit_before>module.exports = function(grunt) {
    grunt.initConfig({
        srcPath: '.',
        buildPath: 'build',

        browserify: {
          production: {
            src: ['jsx/index.js'],
            dest: 'build/cw-ui.js',
            options: {
                alias: ['jsx/cc-eng-model.js:models'],
                transform:  [ require('grunt-react').browserify ]
            }
          },
          demo: {
            src: ['jsx/index.js'],
            dest: 'build/cw-ui-demo.js',
            options: {
                alias: ['jsx/models-mock.js:models'],
                transform:  [ require('grunt-react').browserify ]
            }
          }
        },
        react: {
            jsx: {
                files: [{
                    expand: true,
                    cwd: 'jsx',
                    src: [ '**/*.js' ],
                    dest: 'build/',
                    ext: '.js'
                }]
            }
        },
        connect: {
            server: {
                options: {
                    port: 9001,
                    base: '.'
                }
            }
        },
        compass: {
            dist: {
                options: {
                    sassDir: 'sass',
                    cssDir: 'css',
                    environment: 'production'

                    // raw: "\
                    //     require 'modular-scale'\n\
                    //     project_path = '.'\n\
                    //     preferred_syntax = :scss\n\
                    //     css_dir = './css'\n\
                    //     sass_dir = './sass'\n\
                    //     images_dir = './images'\n\
                    //     relative_assets = true\n\
                    //     line_comments = false\n\
                    // "
                }
            }
        },
        cacheBust: {
          options: {
            algorithm: 'sha1',
            length: 32
            //dir: '.'
          },
          assets: {
              files: [{
                  expand: true,
                  src: ['build/demo-ui.html', 'build/demo-eng.html'],
                  dest: 'dist/'
              }]
          }
        },

        copy: {
            build_to_dist: {
                expand: true,
                cwd:'build',
                src:'**',
                dest: 'dist/'
            },
            bower_to_dist: {
                expand: true,
                src:'bower_components/**',
                dest: 'dist/'
            },
            css_to_dist: {
                expand: true,
                src:'css/**',
                dest: 'dist/'
            },
            img_to_dist: {
                expand: true,
                src:'img/**',
                dest: 'dist/'
            },
            fonts_to_dist: {
                expand: true,
                src:'fonts/**',
                dest: 'dist/'
            },
            demo_ui: {
                src: 'html/demo-ui.html',
                dest: 'build/demo-ui.html'
            },
            demo_eng: {
                src: 'html/demo-ui.html',
                dest: 'build/demo-eng.html',
                options: {
                    process: function (content, srcpath) {
                        content = content.replace("cw-ui-demo.js", "cw-ui.js");
                        content = content.replace("<!-- load engines here -->",
                                                  '<script src="cc-wallet-engine.js"></script>');
                        return content;
                    }
                }
            },
            cc_wallet_eng: {
                src: "node_modules/cc-wallet-engine/cc-wallet-engine.js",
                dest: "build/cc-wallet-engine.js"
            }
        },
        subgrunt: {
            cc_wallet_eng: {
                projects: {
                    "node_modules/cc-wallet-engine": "compile"
                }
            }
        },
        watch: {
          scripts: {
            files: ['jsx/*.js', '!jsx/*_*.js', '!jsx/\.#*'],
            //Second is to exclude flymake files, third auto-save emacs files
            tasks: ['build'],
            options: {
              spawn: false
            }
          },
          sass: {
            files: ['sass/*.scss','sass/var/*.scss'],
            tasks: ['compass'],
            options: {
              spawn: false
            }
          }
        }
    });

    grunt.loadNpmTasks('grunt-browserify');
    grunt.loadNpmTasks('grunt-react');
    grunt.loadNpmTasks('grunt-subgrunt');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-compass');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-cache-bust');

    grunt.registerTask('build-eng', [
                         'subgrunt:cc_wallet_eng',
                         'copy:cc_wallet_eng'
                       ]);

    grunt.registerTask('dist', [
        'copy:build_to_dist', 'copy:bower_to_dist',
        'copy:css_to_dist', 'copy:img_to_dist','copy:fonts_to_dist']);

    grunt.registerTask('build', [
                           'react',
                           'browserify:production',
                           'browserify:demo',
                           'copy:demo_ui',
                           'copy:demo_eng',
                           'dist',
                           'cacheBust'
                       ]);

    grunt.registerTask('default', [
                           'build',
                           'connect',
                           'watch'
                       ]);

};
<commit_msg>cachebust on dist instead of build<commit_after>module.exports = function(grunt) {
    grunt.initConfig({
        srcPath: '.',
        buildPath: 'build',

        browserify: {
          production: {
            src: ['jsx/index.js'],
            dest: 'build/cw-ui.js',
            options: {
                alias: ['jsx/cc-eng-model.js:models'],
                transform:  [ require('grunt-react').browserify ]
            }
          },
          demo: {
            src: ['jsx/index.js'],
            dest: 'build/cw-ui-demo.js',
            options: {
                alias: ['jsx/models-mock.js:models'],
                transform:  [ require('grunt-react').browserify ]
            }
          }
        },
        react: {
            jsx: {
                files: [{
                    expand: true,
                    cwd: 'jsx',
                    src: [ '**/*.js' ],
                    dest: 'build/',
                    ext: '.js'
                }]
            }
        },
        connect: {
            server: {
                options: {
                    port: 9001,
                    base: '.'
                }
            }
        },
        compass: {
            dist: {
                options: {
                    sassDir: 'sass',
                    cssDir: 'css',
                    environment: 'production'

                    // raw: "\
                    //     require 'modular-scale'\n\
                    //     project_path = '.'\n\
                    //     preferred_syntax = :scss\n\
                    //     css_dir = './css'\n\
                    //     sass_dir = './sass'\n\
                    //     images_dir = './images'\n\
                    //     relative_assets = true\n\
                    //     line_comments = false\n\
                    // "
                }
            }
        },
        cacheBust: {
          options: {
            algorithm: 'sha1',
            length: 32
            //dir: '.'
          },
          assets: {
              files: [{
                  expand: true,
                  src: ['dist/demo-ui.html', 'dist/demo-eng.html'],
                  dest: 'dist/'
              }]
          }
        },

        copy: {
            build_to_dist: {
                expand: true,
                cwd:'build',
                src:'**',
                dest: 'dist/'
            },
            bower_to_dist: {
                expand: true,
                src:'bower_components/**',
                dest: 'dist/'
            },
            css_to_dist: {
                expand: true,
                src:'css/**',
                dest: 'dist/'
            },
            img_to_dist: {
                expand: true,
                src:'img/**',
                dest: 'dist/'
            },
            fonts_to_dist: {
                expand: true,
                src:'fonts/**',
                dest: 'dist/'
            },
            demo_ui: {
                src: 'html/demo-ui.html',
                dest: 'build/demo-ui.html'
            },
            demo_eng: {
                src: 'html/demo-ui.html',
                dest: 'build/demo-eng.html',
                options: {
                    process: function (content, srcpath) {
                        content = content.replace("cw-ui-demo.js", "cw-ui.js");
                        content = content.replace("<!-- load engines here -->",
                                                  '<script src="cc-wallet-engine.js"></script>');
                        return content;
                    }
                }
            },
            cc_wallet_eng: {
                src: "node_modules/cc-wallet-engine/cc-wallet-engine.js",
                dest: "build/cc-wallet-engine.js"
            }
        },
        subgrunt: {
            cc_wallet_eng: {
                projects: {
                    "node_modules/cc-wallet-engine": "compile"
                }
            }
        },
        watch: {
          scripts: {
            files: ['jsx/*.js', '!jsx/*_*.js', '!jsx/\.#*'],
            //Second is to exclude flymake files, third auto-save emacs files
            tasks: ['build'],
            options: {
              spawn: false
            }
          },
          sass: {
            files: ['sass/*.scss','sass/var/*.scss'],
            tasks: ['compass'],
            options: {
              spawn: false
            }
          }
        }
    });

    grunt.loadNpmTasks('grunt-browserify');
    grunt.loadNpmTasks('grunt-react');
    grunt.loadNpmTasks('grunt-subgrunt');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-compass');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-cache-bust');

    grunt.registerTask('build-eng', [
                         'subgrunt:cc_wallet_eng',
                         'copy:cc_wallet_eng'
                       ]);

    grunt.registerTask('dist', [
        'copy:build_to_dist', 'copy:bower_to_dist',
        'copy:css_to_dist', 'copy:img_to_dist','copy:fonts_to_dist']);

    grunt.registerTask('build', [
                           'react',
                           'browserify:production',
                           'browserify:demo',
                           'copy:demo_ui',
                           'copy:demo_eng',
                           'dist',
                           'cacheBust'
                       ]);

    grunt.registerTask('default', [
                           'build',
                           'connect',
                           'watch'
                       ]);

};
<|endoftext|>


<commit_before>module.exports = function (grunt)
{
	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-jshint');

	grunt.initConfig({
		pkg : grunt.file.readJSON('package.json'),
		uglify :
		{
			options :
			{
				banner : '/*! <%= pkg.name %> | Copyright (C) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> | <%= pkg.homepage %> | Released under the MIT License */\n'
			},
			dist :
			{
				files :
				{
					'dist/jquery.thar.min.js': ['jquery.thar.js']
				}
			}
		},

		copy :
		{
			main :
			{
				files :
				[
					{
						src  : ['dist/jquery.thar.min.js'],
						dest : 'dist/jquery.thar.v<%= pkg.version %>.min.js'
					}
				]
			}
		},

		jshint :
		{
			files : ['Gruntfile.js', 'jquery.thar.js'],
			options :
			{
				globals :
				{
					jQuery : true
				}
			}
		}
	});

	grunt.registerTask('default', ['jshint', 'uglify', 'copy']);
	grunt.registerTask('debug', ['jshint']);
};<commit_msg>Turn reporting back on.<commit_after>module.exports = function (grunt)
{
	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-jshint');

	grunt.initConfig({
		pkg : grunt.file.readJSON('package.json'),
		uglify :
		{
			options :
			{
				banner : '/*! <%= pkg.name %> | Copyright (C) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> | <%= pkg.homepage %> | Released under the MIT License */\n',
				report : "gzip"
			},
			dist :
			{
				files :
				{
					'dist/jquery.thar.min.js': ['jquery.thar.js']
				}
			}
		},

		copy :
		{
			main :
			{
				files :
				[
					{
						src  : ['dist/jquery.thar.min.js'],
						dest : 'dist/jquery.thar.v<%= pkg.version %>.min.js'
					}
				]
			}
		},

		jshint :
		{
			files : ['Gruntfile.js', 'jquery.thar.js'],
			options :
			{
				globals :
				{
					jQuery : true
				}
			}
		}
	});

	grunt.registerTask('default', ['jshint', 'uglify', 'copy']);
	grunt.registerTask('debug', ['jshint']);
};<|endoftext|>


<commit_before>/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Task configuration.
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        unused: true,
        boss: true,
        eqnull: true,
        browser: true,
        globals: {
          jQuery: true
        }
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      lib_test: {
        src: ['lib/**/*.js', 'test/**/*.js']
      }
    },
    qunit: {
      files: ['test/**/*.html']
    },
    watch: {
      gruntfile: {
        files: '<%= jshint.gruntfile.src %>',
        tasks: ['jshint:gruntfile']
      },
      lib_test: {
        files: '<%= jshint.lib_test.src %>',
        tasks: ['jshint:lib_test', 'qunit']
      }
    },
    copy: {
      main: {
        files: [
          {
            expand: true,
            flatten: true,
            src: [
              'bower_components/zepto/zepto.js',
              'bower_components/otr/build/dep/**',
              'bower_components/otr/lib/otr.js'
            ],
            dest: 'src/common/lib/',
            filter: 'isFile'
          }
        ]
      }
    },
    shell: {
      build: {
        command: 'G:\\Dev\\JS\\kango-framework-latest\\kango.py build "G:\\Dev\\OTR for Facebook"'
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-shell');

  // Default task.
  grunt.registerTask('default', ['jshint', 'qunit']);
  grunt.registerTask('build', ['copy', 'shell']);

};
<commit_msg>Added cleaning to build process.<commit_after>/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Task configuration.
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        unused: true,
        boss: true,
        eqnull: true,
        browser: true,
        globals: {
          jQuery: true
        }
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      lib_test: {
        src: ['lib/**/*.js', 'test/**/*.js']
      }
    },
    qunit: {
      files: ['test/**/*.html']
    },
    watch: {
      gruntfile: {
        files: '<%= jshint.gruntfile.src %>',
        tasks: ['jshint:gruntfile']
      },
      lib_test: {
        files: '<%= jshint.lib_test.src %>',
        tasks: ['jshint:lib_test', 'qunit']
      }
    },
    copy: {
      main: {
        files: [
          {
            expand: true,
            flatten: true,
            src: [
              'bower_components/zepto/zepto.js',
              'bower_components/otr/build/dep/**',
              'bower_components/otr/lib/otr.js'
            ],
            dest: 'src/common/lib/',
            filter: 'isFile'
          }
        ]
      }
    },
    shell: {
      build: {
        command: 'G:\\Dev\\JS\\kango-framework-latest\\kango.py build "G:\\Dev\\OTR for Facebook"'
      }
    },
    clean: {
      build: ["src/common/lib/"],
      release: ["output/"]
    },
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-shell');

  // Default task.
  grunt.registerTask('default', ['jshint', 'qunit']);
  grunt.registerTask('build', ['copy', 'shell', 'clean:build']);

};
<|endoftext|>


<commit_before>module.exports = function(grunt) {
	grunt.initConfig({
		bowerPkg: grunt.file.readJSON('bower.json'),
		karma: {
			unit: {
				configFile: 'karma.conf.js',
				singleRun: true,
				browsers: ['PhantomJS']
			}
		},
		cssmin: {
			build: {
				options: {
					banner: '/* <%= bowerPkg.name %> v<%= bowerPkg.version %> (<%= bowerPkg.homepage %>) */'
				},
				src: 'src/progress-button.css',
				dest: 'dist/progress-button.min.css'
			}
		},
		uglify: {
			options: {
				banner: '/* <%= bowerPkg.name %> v<%= bowerPkg.version %> (<%= bowerPkg.homepage %>) */\n'
			},
			build: {
				src: 'src/progress-button.js',
				dest: 'dist/progress-button.min.js'
			}
		}
	})

	grunt.loadNpmTasks('grunt-contrib-cssmin');
	grunt.loadNpmTasks('grunt-contrib-uglify')
	grunt.loadNpmTasks('grunt-karma')

	grunt.registerTask('build', ['cssmin', 'uglify'])
	grunt.registerTask('test', ['karma'])
	grunt.registerTask('default', [])
}
<commit_msg>Set ‘build’ as the default Grunt task<commit_after>module.exports = function(grunt) {
	grunt.initConfig({
		bowerPkg: grunt.file.readJSON('bower.json'),
		karma: {
			unit: {
				configFile: 'karma.conf.js',
				singleRun: true,
				browsers: ['PhantomJS']
			}
		},
		cssmin: {
			build: {
				options: {
					banner: '/* <%= bowerPkg.name %> v<%= bowerPkg.version %> (<%= bowerPkg.homepage %>) */'
				},
				src: 'src/progress-button.css',
				dest: 'dist/progress-button.min.css'
			}
		},
		uglify: {
			options: {
				banner: '/* <%= bowerPkg.name %> v<%= bowerPkg.version %> (<%= bowerPkg.homepage %>) */\n'
			},
			build: {
				src: 'src/progress-button.js',
				dest: 'dist/progress-button.min.js'
			}
		}
	})

	grunt.loadNpmTasks('grunt-contrib-cssmin');
	grunt.loadNpmTasks('grunt-contrib-uglify')
	grunt.loadNpmTasks('grunt-karma')

	grunt.registerTask('build', ['cssmin', 'uglify'])
	grunt.registerTask('test', ['karma'])
	grunt.registerTask('default', ['build'])
}
<|endoftext|>


<commit_before>/* jshint node: true */
module.exports = function(grunt) {
    "use strict";

    // Project configuration.
    grunt.initConfig({
        // Metadata.
        pkg: grunt.file.readJSON('package.json'),
        banner: '/**\n' +
                '* <%= pkg.name %>.js v<%= pkg.version %> by @fat and @mdo\n' +
                '* Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
                '* <%= _.pluck(pkg.licenses, "url").join(", ") %>\n' +
                '*/\n',
        jqueryCheck: 'if (!jQuery) { throw new Error(\"Bootstrap requires jQuery\") }\n\n',
        // Task configuration.
        clean: {
            dist: ['dist']
        },
        concat: {
            options: {
                banner: '<%= banner %><%= jqueryCheck %>',
                stripBanners: false
            },
            bootstrap: {
                src: ['js/transition.js', 'js/alert.js', 'js/button.js', 'js/carousel.js', 'js/collapse.js', 'js/dropdown.js', 'js/modal.js', 'js/tooltip.js', 'js/popover.js', 'js/scrollspy.js', 'js/tab.js', 'js/affix.js'],
                dest: 'dist/js/<%= pkg.name %>.js'
            }
        },
        jshint: {
            options: {
                jshintrc: 'js/.jshintrc'
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            src: {
                src: ['js/*.js']
            },
            test: {
                src: ['js/tests/unit/*.js']
            }
        },
        recess: {
            options: {
                compile: true
            },
            bootstrap: {
                files: {
                    'dist/css/bootstrap.css': ['less/bootstrap.less']
                }
            },
            min: {
                options: {
                    compress: true
                },
                files: {
                    'dist/css/bootstrap.min.css': ['less/bootstrap.less']
                }
            }
        },
        uglify: {
            options: {
                banner: '<%= banner %>'
            },
            bootstrap: {
                files: {
                    'dist/js/<%= pkg.name %>.min.js': ['<%= concat.bootstrap.dest %>']
                }
            }
        },
        qunit: {
            options: {
                inject: 'js/tests/unit/phantom.js'
            },
            files: ['js/tests/*.html']
        },
        connect: {
            server: {
                options: {
                    port: 3000,
                    base: '.'
                }
            }
        },
        watch: {
            src: {
                files: '<%= jshint.src.src %>',
                tasks: ['jshint:src', 'qunit']
            },
            test: {
                files: '<%= jshint.test.src %>',
                tasks: ['jshint:test', 'qunit']
            },
            recess: {
                files: 'less/*.less',
                tasks: ['recess']
            }
        }
    });

    // These plugins provide necessary tasks.
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-recess');

    // Test task.
    grunt.registerTask('test', ['jshint', 'qunit']);

    // JS distribution task.
    grunt.registerTask('dist-js', ['concat', 'uglify']);

    // CSS distribution task.
    grunt.registerTask('dist-css', ['recess']);

    // Full distribution task.
    grunt.registerTask('dist', ['clean', 'dist-css', 'dist-js']);

    // Default task.
    grunt.registerTask('default', ['test', 'dist']);
};
<commit_msg>This pull request organizes the Gruntfile, makes better use of Grunt conventions and placates my OCD.<commit_after>/* jshint node: true */

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

  // Project configuration.
  grunt.initConfig({

    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    banner: '/**\n' +
              '* <%= pkg.name %>.js v<%= pkg.version %> by @fat and @mdo\n' +
              '* Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
              '* <%= _.pluck(pkg.licenses, "url").join(", ") %>\n' +
              '*/\n',
    jqueryCheck: 'if (!jQuery) { throw new Error(\"Bootstrap requires jQuery\") }\n\n',

    // Task configuration.
    clean: {
      dist: ['dist']
    },

    jshint: {
      options: {
        jshintrc: 'js/.jshintrc'
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      src: {
        src: ['js/*.js']
      },
      test: {
        src: ['js/tests/unit/*.js']
      }
    },
    concat: {
      options: {
        banner: '<%= banner %><%= jqueryCheck %>',
        stripBanners: false
      },
      bootstrap: {
        src: [
          'js/transition.js',
          'js/alert.js',
          'js/button.js',
          'js/carousel.js',
          'js/collapse.js',
          'js/dropdown.js',
          'js/modal.js',
          'js/tooltip.js',
          'js/popover.js',
          'js/scrollspy.js',
          'js/tab.js',
          'js/affix.js'
        ],
        dest: 'dist/js/<%= pkg.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      bootstrap: {
        src: ['<%= concat.bootstrap.dest %>'],
        dest: 'dist/js/<%= pkg.name %>.min.js'
      }
    },

    recess: {
      options: {
        compile: true
      },
      bootstrap: {
        src: ['less/bootstrap.less'],
        dest: 'dist/css/<%= pkg.name %>.css'
      },
      min: {
        options: {
          compress: true
        },
        src: ['less/bootstrap.less'],
        dest: 'dist/css/<%= pkg.name %>.min.css'
      }
    },

    qunit: {
      options: {
        inject: 'js/tests/unit/phantom.js'
      },
      files: ['js/tests/*.html']
    },
    connect: {
      server: {
        options: {
          port: 3000,
          base: '.'
        }
      }
    },

    watch: {
      src: {
        files: '<%= jshint.src.src %>',
        tasks: ['jshint:src', 'qunit']
      },
      test: {
        files: '<%= jshint.test.src %>',
        tasks: ['jshint:test', 'qunit']
      },
      recess: {
        files: 'less/*.less',
        tasks: ['recess']
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-recess');

  // Test task.
  grunt.registerTask('test', ['jshint', 'qunit']);

  // JS distribution task.
  grunt.registerTask('dist-js', ['concat', 'uglify']);

  // CSS distribution task.
  grunt.registerTask('dist-css', ['recess']);

  // Full distribution task.
  grunt.registerTask('dist', ['clean', 'dist-css', 'dist-js']);

  // Default task.
  grunt.registerTask('default', ['test', 'dist']);
};
<|endoftext|>


<commit_before>"use strict";
var GameMusic;

/**
 * GameMusic is a music daemon playing game background music of various
 * intensity. The daemon mantains multiple music playlists, each marked by the
 * target game play intensity (a number from 0 to 1 inclusive) and fades the
 * another music playlist whenever the game play intensity changes enough.
 *
 *
The changes between playlists and songs within playlist happen with
 * cross-fading. The change of playlist makes the playlist start at random
 * song.

 *
 *
The daemon loads all its configuration and playlists from the global
 * Settings class.

 *
 *
Note that the daemon starts loading the game music the moment its
 * instance is constructed.

 */
GameMusic = function () {
    // -------------------- private field definitions -------------------------

    /**
     * The playlists of game music organized as object. Each property name is
     * the playlist's target game play intensity - a number from the range
     * [0, 1]. Each playlist is an Array of Audio instances.
     *
     * @type Object
     */
    var playlists,

    /**
     * The duration of cross-fading between songs and playlists in
     * milliseconds.
     *
     * @type Number
     */
    fadeDuration,

    /**
     * The current game play intensity. Specifies also the approximate
     * intensity of the currently played music. The intensity is specified as a
     * number from range [0, 1].
     *
     * @type Number
     */
    intensity,

    /**
     * The number of the currently played song the of current playlist. The
     * songs of a playlist are numbered from 0.
     *
     * @type Number
     */
    song,

    /**
     * The volume of the played music, specified as a number within the range
     * [0, 1]
     *
     * @type Number
     */
    volume,

    /**
     * An object representing map of songs' durations. Each property name is a
     * playlist intensity. Each property is an array of numbers. Each number
     * is duration of the song in milliseconds (the song is identified by the
     * playlist intesity and index of the song in the playlist array).
     *
     *
Note: the specified duration does not have to be accurate with
     * millisecond precision becouse slight errors will be hidden by song
     * cross-fading.

     *
     * @type Object
     */
    songDurations,

    /**
     * An object representing map of loaded songs. Each property name is a
     * playlist intensity. Each property is an array of Booleans. Each boolean
     * is set to true if the song has been loaded already, or false if the song
     * is still being loaded.
     *
     * @type Object
     */
    loadedSongs,

    /**
     * A boolean flag signalling whether all songs has been loaded yet. The
     * flag is set to true if all songs have been already loaded. The flag is
     * set to false otherwise.
     *
     * @type Boolean
     */
    loaded,

    /**
     * An array of registered loading process observers. Each registered
     * observer is executed every time a song has finished loading itself. Each
     * observer is a single-parameter function. The parameter is set to the
     * current loading progress represented as a number withing [0, 1].
     *
     * @type Array
     */
    loadingObservers,

    /**
     * A Boolean flag signifying whether the daemon is playing any music. This
     * flag is used to prevent multiple songs playing at the same time by
     * repeatedly invoking the public play() method.
     *
     * @type Boolean
     */
    playing,

    /**
     * Identifier of the currently registered timeout callback for performing
     * the cross-fade efect between songs.
     *
     * @type Number
     */
    crossFadeTimeout,

    /**
     * Boolean flag used for synchronization of cross-fade timeout callback
     * registrations. This flag prevents registering a cross-fade effect while
     * another cross-fade effect is active.
     *
     * @type Boolean
     */
    crossFading;

    // -------------------------- private methods -----------------------------

    /**
     * Finds the closest intensity (a number within range [0, 1]) to the
     * specified intensity for which exists a playlist of songs.
     *
     * @param {Number} wantedIntensity
     * @return {Number} The closes intensity to the wantedIntesity for which
     *         exists a playlist.
     */
    function findIntensity(wantedIntensity) {
        var playlistIntensity, bestIntensity;
        bestIntensity = 0;
        for (playlistIntensity in playlists) {
            if (playlists.hasOwnProperty(playlistIntensity)) {
                continue;
            }
            if (Math.abs(wantedIntensity - playlistIntensity) <
                    Math.abs(wantedIntensity - bestIntensity)) {
                bestIntensity = playlistIntensity;
            }
        }
        return bestIntensity;
    }

    /**
     * Prepares intervals and timeouts performing the song cross-fade effect.
     *
     * @param {Number} nextIntensity The intensity of the next playlist to use.
     * @param {Number} nextSong The number of the song to play from the new
     *        playlist.
     * @param {Boolean} now Set to true if the cross-fade effect should take
     *        place right now. Set to false to perform the cross-fade during
     *        the last seconds of the current song (the continious parameter
     *        has to be true).
     * @param {Boolean} continious Set to true if the method is being called
     *        when another song is already playing. This is neccessary for
     *        correct timing of the cross-fade effect. Only this method sets
     *        this parameter to true.
     */
    function prepareSongCrossFade(nextIntensity, nextSong, now, continious) {
        var interval;
        // aren't we already cross-fading to another song?
        if (crossFading) {
            // wait for the current cross-fading to finish
            interval = setInterval(function () {
                if (crossFading) {
                    return;
                }
                prepareSongCrossFade(nextIntensity, nextSong, now, continious);
                clearInterval(interval);
            }, 17); // prime number - to prevent timing collisions
            return; // we will return here later
        }

        // cancel the upcoming cross-fade to another song
        crossFadeTimeout && clearTimeout(crossFadeTimeout);

        // set up cross-fading
        crossFadeTimeout = setTimeout(function () {
            var start;
            crossFading = true; // think of this as of synchronization lock
            start = (new Date()).getTime();
            playlists[nextIntensity][nextSong].setVolume(0);
            playlists[nextIntensity][nextSong].play();

            interval = setInterval(function () {
                var current, progress;
                current = (new Date()).getTime();
                progress = (current - start) / fadeDuration;
                if (progress <= 1) {
                    playlists[intensity][song].
                            setVolume((1 - progress) * volume);
                    playlists[nextIntensity][nextSong].
                            setVolume(progress * volume);
                } else {
                    clearInterval(interval);
                    playlists[intensity][song].stop();
                    intensity = nextIntensity;
                    song = nextSong;
                    crossFading = false; // release the lock

                    // prepare fade to next song
                    prepareSongCrossFade(intensity,
                            (song + 1) % playlists[intensity].length, false,
                            true);
                }
            }, 10);
        }, now ? 1 : (songDurations[intensity][song] -
            (continious ? (2 * fadeDuration) : fadeDuration)));
    }

    // ----------------------------- public API -------------------------------

    this.play = function () {
        var interval, startTime;
        if (playing) {
            throw new Error('Already playing music');
        }
        // select random song
        song = Math.floor(Math.random() * playlists[intensity].length);
        // start playback with a fade-in
        playlists[intensity][song].setVolume(0);
        playlists[intensity][song].play();
        startTime = (new Date()).getTime();
        interval = setInterval(function () {
            var now;
            now = (new Date()).getTime();
            if (now - startTime < fadeDuration) {
                playlists[intensity][song].
                        setVolume((now - startTime) / fadeDuration * volume);
            } else {
                playlists[intensity][song].setVolume(volume);
                clearInterval(interval);
            }
        }, 10);
        prepareSongCrossFade(intensity,
                (song + 1) % playlists[intensity].length, false, false);
    };

    this.stop = function () {
        if (!playing) {
            throw new Error('The music is not playing');
        }
        // TODO
    };

    this.setIntensity = function (newIntensity) {
        if ((newIntensity < 0) || (newIntensity > 1)) {
            throw new Error(
                    'GameMusic: The intensity must be within range [0, 1]');
        }
        newIntensity = findIntensity(newIntensity);
        if (newIntensity == intensity) {
            return;
        }
        if (playing) {
            prepareSongCrossFade(newIntensity, Math.floor(
                    Math.random() * playlists[newIntensity].length), true,
                    false);
        }
    };

    /**
     * Registers an observer of the loading process. An observer is a function
     * with a single Number parameter. The game music daemon invokes the
     * observer every time a song finishes its loading process. The loading
     * progress is passed to the observer as a Number from range [0, 1].
     *
     *
Note that the observer is not registered but invoked immediately if
     * all songs have been already loaded.

     *
     * @param {Function} observer The loading progress observer function. The
     *        function should have a single Number parameter. The parameter is
     *        set to a value from range [0, 1] every time a song is loaded.
     */
    this.registerLoadingObserver = function (observer) {
        if (loaded) {
            observer(1);
            return;
        }
        loadingObservers.push(observer);
    };

    // ----------------------------- constructor ------------------------------

    // Initialize private fields
    playlists        = Settings.gameMusic.playlists;
    fadeDuration     = Settings.gameMusic.fadeDuration;
    volume           = Settings.gameMusic.volume;
    intensity        = findIntensity(0);
    loadedSongs      = {};
    songDurations    = {};
    loaded           = false;
    loadingObservers = [];
    playing          = false;

    // Constructor body. The constructor is within a closure so that the
    // instance will not contain any unneccessary fields.
    (function () {
        var playlistIntensity, playlist, i;

        function loadingCallback() {
            var songCount, loadedCount, playlistIntensity;
            songCount = 0;
            loadedCount = 0;
            for (playlistIntensity in playlists) {
                if (!playlists.hasOwnProperty(playlistIntensity)) {
                    continue;
                }
                songCount += playlists[playlistIntensity].length;
                playlists[playlistIntensity].forEach(function (loaded) {
                    loaded && loadedCount++;
                });
            }

            loadingObservers.forEach(function (observer) {
                observer(loadedCount / songCount);
            });

            loaded = loadedCount == songCount;
        }

        for (playlistIntensity in playlists) {
            if (!playlists.hasOwnProperty(playlistIntensity)) {
                continue;
            }
            playlist = playlists[playlistIntensity];
            loadedSongs[playlistIntensity] = [];
            songDurations[playlistIntensity] = [];
            for (i = playlist.length; i--;) {
                loadedSongs[playlistIntensity][i] = false;
                songDurations[playlistIntensity][i] = playlist[i].duration;
                (function (intensityIndex, songIndex) {
                    playlist[i] = new Audio(playlist[i].src, {
                        volume: volume,
                        onload: function () {
                            loadedSongs[intensityIndex][songIndex] = true;
                            loadingCallback();
                        }
                    });
                }(playlistIntensity, i));
            }
        }
    }());
};
<commit_msg>game music daemon: implemented the stop() method, disabled crossfader for now becaused it doesn't work yet<commit_after>"use strict";
var GameMusic;

/**
 * GameMusic is a music daemon playing game background music of various
 * intensity. The daemon mantains multiple music playlists, each marked by the
 * target game play intensity (a number from 0 to 1 inclusive) and fades the
 * another music playlist whenever the game play intensity changes enough.
 *
 *
The changes between playlists and songs within playlist happen with
 * cross-fading. The change of playlist makes the playlist start at random
 * song.

 *
 *
The daemon loads all its configuration and playlists from the global
 * Settings class.

 *
 *
Note that the daemon starts loading the game music the moment its
 * instance is constructed.

 */
GameMusic = function () {
    // -------------------- private field definitions -------------------------

    /**
     * The playlists of game music organized as object. Each property name is
     * the playlist's target game play intensity - a number from the range
     * [0, 1]. Each playlist is an Array of Audio instances.
     *
     * @type Object
     */
    var playlists,

    /**
     * The duration of cross-fading between songs and playlists in
     * milliseconds.
     *
     * @type Number
     */
    fadeDuration,

    /**
     * The current game play intensity. Specifies also the approximate
     * intensity of the currently played music. The intensity is specified as a
     * number from range [0, 1].
     *
     * @type Number
     */
    intensity,

    /**
     * The number of the currently played song the of current playlist. The
     * songs of a playlist are numbered from 0.
     *
     * @type Number
     */
    song,

    /**
     * The volume of the played music, specified as a number within the range
     * [0, 1]
     *
     * @type Number
     */
    volume,

    /**
     * An object representing map of songs' durations. Each property name is a
     * playlist intensity. Each property is an array of numbers. Each number
     * is duration of the song in milliseconds (the song is identified by the
     * playlist intesity and index of the song in the playlist array).
     *
     *
Note: the specified duration does not have to be accurate with
     * millisecond precision becouse slight errors will be hidden by song
     * cross-fading.

     *
     * @type Object
     */
    songDurations,

    /**
     * An object representing map of loaded songs. Each property name is a
     * playlist intensity. Each property is an array of Booleans. Each boolean
     * is set to true if the song has been loaded already, or false if the song
     * is still being loaded.
     *
     * @type Object
     */
    loadedSongs,

    /**
     * A boolean flag signalling whether all songs has been loaded yet. The
     * flag is set to true if all songs have been already loaded. The flag is
     * set to false otherwise.
     *
     * @type Boolean
     */
    loaded,

    /**
     * An array of registered loading process observers. Each registered
     * observer is executed every time a song has finished loading itself. Each
     * observer is a single-parameter function. The parameter is set to the
     * current loading progress represented as a number withing [0, 1].
     *
     * @type Array
     */
    loadingObservers,

    /**
     * A Boolean flag signifying whether the daemon is playing any music. This
     * flag is used to prevent multiple songs playing at the same time by
     * repeatedly invoking the public play() method.
     *
     * @type Boolean
     */
    playing,

    /**
     * Identifier of the currently registered timeout callback for performing
     * the cross-fade efect between songs.
     *
     * @type Number
     */
    crossFadeTimeout,

    /**
     * Boolean flag used for synchronization of cross-fade timeout callback
     * registrations. This flag prevents registering a cross-fade effect while
     * another cross-fade effect is active.
     *
     * @type Boolean
     */
    crossFading;

    // -------------------------- private methods -----------------------------

    /**
     * Finds the closest intensity (a number within range [0, 1]) to the
     * specified intensity for which exists a playlist of songs.
     *
     * @param {Number} wantedIntensity
     * @return {Number} The closes intensity to the wantedIntesity for which
     *         exists a playlist.
     */
    function findIntensity(wantedIntensity) {
        var playlistIntensity, bestIntensity;
        bestIntensity = 0;
        for (playlistIntensity in playlists) {
            if (playlists.hasOwnProperty(playlistIntensity)) {
                continue;
            }
            if (Math.abs(wantedIntensity - playlistIntensity) <
                    Math.abs(wantedIntensity - bestIntensity)) {
                bestIntensity = playlistIntensity;
            }
        }
        return bestIntensity;
    }

    /**
     * Prepares intervals and timeouts performing the song cross-fade effect.
     *
     * @param {Number} nextIntensity The intensity of the next playlist to use.
     * @param {Number} nextSong The number of the song to play from the new
     *        playlist.
     * @param {Boolean} now Set to true if the cross-fade effect should take
     *        place right now. Set to false to perform the cross-fade during
     *        the last seconds of the current song (the continious parameter
     *        has to be true).
     * @param {Boolean} continious Set to true if the method is being called
     *        when another song is already playing. This is neccessary for
     *        correct timing of the cross-fade effect. Only this method sets
     *        this parameter to true.
     */
    function prepareSongCrossFade(nextIntensity, nextSong, now, continious) {
        var interval;
        // aren't we already cross-fading to another song?
        if (crossFading) {
            // wait for the current cross-fading to finish
            interval = setInterval(function () {
                if (crossFading) {
                    return;
                }
                prepareSongCrossFade(nextIntensity, nextSong, now, continious);
                clearInterval(interval);
            }, 17); // prime number - to prevent timing collisions
            return; // we will return here later
        }

        // cancel the upcoming cross-fade to another song
        crossFadeTimeout && clearTimeout(crossFadeTimeout);

        // set up cross-fading
        crossFadeTimeout = setTimeout(function () {
            var start;
            crossFading = true; // think of this as of synchronization lock
            start = (new Date()).getTime();
            playlists[nextIntensity][nextSong].setVolume(0);
            playlists[nextIntensity][nextSong].play();

            interval = setInterval(function () {
                var current, progress;
                current = (new Date()).getTime();
                progress = (current - start) / fadeDuration;
                if (progress <= 1) {
                    playlists[intensity][song].
                            setVolume((1 - progress) * volume);
                    playlists[nextIntensity][nextSong].
                            setVolume(progress * volume);
                } else {
                    clearInterval(interval);
                    playlists[intensity][song].stop();
                    intensity = nextIntensity;
                    song = nextSong;
                    crossFading = false; // release the lock

                    // prepare fade to next song
                    prepareSongCrossFade(intensity,
                            (song + 1) % playlists[intensity].length, false,
                            true);
                }
            }, 10);
        }, now ? 1 : (songDurations[intensity][song] -
            (continious ? (2 * fadeDuration) : fadeDuration)));
    }

    // ----------------------------- public API -------------------------------

    this.play = function () {
        var interval, startTime;
        if (playing) {
            throw new Error('GameMusic: Already playing music');
        }
        // select random song
        song = Math.floor(Math.random() * playlists[intensity].length);
        // start playback with a fade-in
        playlists[intensity][song].setVolume(0);
        playlists[intensity][song].play();
        startTime = (new Date()).getTime();
        interval = setInterval(function () {
            var now;
            now = (new Date()).getTime();
            if (now - startTime < fadeDuration) {
                playlists[intensity][song].
                        setVolume((now - startTime) / fadeDuration * volume);
            } else {
                playlists[intensity][song].setVolume(volume);
                clearInterval(interval);
            }
        }, 10);
        playing = true;
        //prepareSongCrossFade(intensity,
        //        (song + 1) % playlists[intensity].length, false, false);
    };

    this.stop = function () {
        var interval, startTime;
        if (!playing) {
            throw new Error('GameMusic: The music is not playing');
        }
        startTime = (new Date()).getTime();
        interval = setInterval(function () {
            var now;
            now = (new Date()).getTime();
            if (now - startTime < fadeDuration) {
                playlists[intensity][song].setVolume(
                        (1 - (now - startTime) / fadeDuration) * volume);
            } else {
                playlists[intensity][song].stop();
                clearInterval(interval);
                playing = false;
            }
        }, 10);
    };

    this.setIntensity = function (newIntensity) {
        if ((newIntensity < 0) || (newIntensity > 1)) {
            throw new Error(
                    'GameMusic: The intensity must be within range [0, 1]');
        }
        newIntensity = findIntensity(newIntensity);
        if (newIntensity == intensity) {
            return;
        }
        if (playing) {
            prepareSongCrossFade(newIntensity, Math.floor(
                    Math.random() * playlists[newIntensity].length), true,
                    false);
        }
    };

    /**
     * Registers an observer of the loading process. An observer is a function
     * with a single Number parameter. The game music daemon invokes the
     * observer every time a song finishes its loading process. The loading
     * progress is passed to the observer as a Number from range [0, 1].
     *
     *
Note that the observer is not registered but invoked immediately if
     * all songs have been already loaded.

     *
     * @param {Function} observer The loading progress observer function. The
     *        function should have a single Number parameter. The parameter is
     *        set to a value from range [0, 1] every time a song is loaded.
     */
    this.registerLoadingObserver = function (observer) {
        if (loaded) {
            observer(1);
            return;
        }
        loadingObservers.push(observer);
    };

    // ----------------------------- constructor ------------------------------

    // Initialize private fields
    playlists        = Settings.gameMusic.playlists;
    fadeDuration     = Settings.gameMusic.fadeDuration;
    volume           = Settings.gameMusic.volume;
    intensity        = findIntensity(0);
    loadedSongs      = {};
    songDurations    = {};
    loaded           = false;
    loadingObservers = [];
    playing          = false;

    // Constructor body. The constructor is within a closure so that the
    // instance will not contain any unneccessary fields.
    (function () {
        var playlistIntensity, playlist, i;

        function loadingCallback() {
            var songCount, loadedCount, playlistIntensity;
            songCount = 0;
            loadedCount = 0;
            for (playlistIntensity in playlists) {
                if (!playlists.hasOwnProperty(playlistIntensity)) {
                    continue;
                }
                songCount += playlists[playlistIntensity].length;
                playlists[playlistIntensity].forEach(function (loaded) {
                    loaded && loadedCount++;
                });
            }

            loadingObservers.forEach(function (observer) {
                observer(loadedCount / songCount);
            });

            loaded = loadedCount == songCount;
        }

        for (playlistIntensity in playlists) {
            if (!playlists.hasOwnProperty(playlistIntensity)) {
                continue;
            }
            playlist = playlists[playlistIntensity];
            loadedSongs[playlistIntensity] = [];
            songDurations[playlistIntensity] = [];
            for (i = playlist.length; i--;) {
                loadedSongs[playlistIntensity][i] = false;
                songDurations[playlistIntensity][i] = playlist[i].duration;
                (function (intensityIndex, songIndex) {
                    playlist[i] = new Audio(playlist[i].src, {
                        volume: volume,
                        onload: function () {
                            loadedSongs[intensityIndex][songIndex] = true;
                            loadingCallback();
                        }
                    });
                }(playlistIntensity, i));
            }
        }
    }());
};
<|endoftext|>


<commit_before>module.exports = function (grunt) {

    /* Task configuration */

    grunt.initConfig({

        pkg: grunt.file.readJSON('package.json'),

        watch: {

            src: {

                files: ['Gruntfile.js', 'src/**/*.js'],
                tasks: ['jshint:src', 'build'],

            },

            spec: {

                files: 'spec/**/*.js',
                tasks: 'jshint:spec',

            }
        },

        concat: {

            dist: {

                src: 'src/**/*.js',
                dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js',
                options: {

                    separator: ';'

                }
            }
        },

        uglify: {

            dist: {

                files: {

                    'dist/<%= pkg.name %>-<%= pkg.version %>-min.js': 'dist/<%= pkg.name %>-<%= pkg.version %>.js'

                },

                options: {

                    report: 'min'

                }
            }
        },

        jshint: {

            src: {

                src: ['Gruntfile.js', 'src/**/*.js'],
                options: {

                    jshintrc: 'jshint.json'

                }
            },

            spec: {

                src: 'spec/**/*.js',
                options: {

                    jshintrc: 'spec/jshint.json'

                }
            }
        },

        jasmine: {

            src: 'src/**/*.js',
            options: {

                specs: 'spec/**/*-spec.js',
                template: require('grunt-template-jasmine-istanbul'),
                templateOptions: {

                    coverage: 'coverage/coverage.json',
                    report: 'coverage/'

                }
            }
        }
    });

    /* Load tasks */

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-jasmine');

    /* Register tasks */

    grunt.registerTask('test', ['jshint', 'jasmine']);
    grunt.registerTask('build', ['concat', 'uglify']);
    grunt.registerTask('default', ['test', 'build']);
}
<commit_msg>Array style<commit_after>module.exports = function (grunt) {

    /* Task configuration */

    grunt.initConfig({

        pkg: grunt.file.readJSON('package.json'),

        watch: {

            src: {

                files: [ 'Gruntfile.js', 'src/**/*.js' ],
                tasks: [ 'jshint:src', 'build' ],

            },

            spec: {

                files: 'spec/**/*.js',
                tasks: 'jshint:spec',

            }
        },

        concat: {

            dist: {

                src: 'src/**/*.js',
                dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js',
                options: {

                    separator: ';'

                }
            }
        },

        uglify: {

            dist: {

                files: {

                    'dist/<%= pkg.name %>-<%= pkg.version %>-min.js': 'dist/<%= pkg.name %>-<%= pkg.version %>.js'

                },

                options: {

                    report: 'min'

                }
            }
        },

        jshint: {

            src: {

                src: [ 'Gruntfile.js', 'src/**/*.js' ],
                options: {

                    jshintrc: 'jshint.json'

                }
            },

            spec: {

                src: 'spec/**/*.js',
                options: {

                    jshintrc: 'spec/jshint.json'

                }
            }
        },

        jasmine: {

            src: 'src/**/*.js',
            options: {

                specs: 'spec/**/*-spec.js',
                template: require('grunt-template-jasmine-istanbul'),
                templateOptions: {

                    coverage: 'coverage/coverage.json',
                    report: 'coverage/'

                }
            }
        }
    });

    /* Load tasks */

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-jasmine');

    /* Register tasks */

    grunt.registerTask('test', [ 'jshint', 'jasmine' ]);
    grunt.registerTask('build', [ 'concat', 'uglify' ]);
    grunt.registerTask('default', [ 'test', 'build' ]);
}
<|endoftext|>