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

    var _ = grunt.util._;
    var path = require('path');

    var coreFiles = [
        'vendor/**/*.js',
        'template/_header.js',
        'src/**/*.js',
        'template/_footer.js'
    ];

    var plugins = grunt.option('plugins');
    // Create plugin paths and verify hey exist
    plugins = _.map(plugins ? plugins.split(',') : [], function (plugin) {
        var path = 'plugins/' + plugin + '.js';

        if(!grunt.file.exists(path))
            throw new Error("Plugin '" + plugin + "' not found in plugins directory.");

        return path;
    });

    // Taken from http://dzone.com/snippets/calculate-all-combinations
    var combine = function (a) {
        var fn = function (n, src, got, all) {
            if (n === 0) {
                all.push(got);
                return;
            }

            for (var j = 0; j < src.length; j++) {
                fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all);
            }
        };

        var all = [a];

        for (var i = 0; i < a.length; i++) {
            fn(i, a, [], all);
        }

        return all;
    };

    var pluginCombinations = combine(grunt.file.expand('plugins/*.js'));
    var pluginConcatFiles = _.reduce(pluginCombinations, function (dict, comb) {
        var key = _.map(comb, function (plugin) {
            return path.basename(plugin, '.js');
        });
        key.sort();

        var dest = path.join('build/', key.join(','), '/<%= pkg.name %>.js');
        dict[dest] = coreFiles.concat(comb);

        return dict;
    }, {});

    var gruntConfig = {
        pkg: grunt.file.readJSON('package.json'),
        aws: grunt.file.exists('aws.json') ? grunt.file.readJSON('aws.json'): {},

        clean: ['build'],
        concat: {
            options: {
                separator: '\n',
                banner: grunt.file.read('template/_copyright.js'),
                process: true
            },
            core: {
                src: coreFiles.concat(plugins),
                dest: 'build/<%= pkg.name %>.js'
            },
            all: {
                files: pluginConcatFiles
            }
        },

        uglify: {
            options: {
                sourceMap: function (dest) {
                    return path.join(path.dirname(dest),
                                     path.basename(dest, '.js')) +
                           '.map';
                },
                sourceMappingURL: function (dest) {
                    return path.basename(dest, '.js') + '.map';
                },
                preserveComments: 'some'
            },
            dist: {
                src: ['build/**/*.js'],
                ext: '.min.js',
                expand: true
            }
        },

        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            all: ['Gruntfile.js', 'src/**/*.js', 'plugins/**/*.js']
        },

        mocha: {
            all: {
                options: {
                    mocha: {
                        ignoreLeaks: true,
                        grep:        grunt.option('grep')
                    },
                    log:      true,
                    reporter: 'Dot',
                    run:      true
                },
                src: ['test/index.html'],
                nonull: true
            }
        },

        release: {
            options: {
                npm:           false,
                commitMessage: 'Release <%= version %>'
            }
        },

        s3: {
            options: {
                key: '<%= aws.key %>',
                secret: '<%= aws.secret %>',
                bucket: '<%= aws.bucket %>',
                access: 'public-read'
            },
            all: {
                upload: [{
                    src: 'build/**/*',
                    dest: 'build/<%= pkg.version %>/',
                    rel: 'build/'
                }]
            }
        }
    };

    grunt.initConfig(gruntConfig);

    // Grunt contrib tasks
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-jshint');

    // 3rd party Grunt tasks
    grunt.loadNpmTasks('grunt-mocha');
    grunt.loadNpmTasks('grunt-release');
    grunt.loadNpmTasks('grunt-s3');

    // Build tasks
    grunt.registerTask('build.core', ['clean', 'concat:core', 'uglify']);
    grunt.registerTask('build.all', ['clean', 'concat:all', 'uglify']);

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

    grunt.registerTask('publish', ['test', 'build.all', 'release', 's3']);
    grunt.registerTask('default', ['build.all']);
};

@@ -2778,32 +2778,211 @@
   %7D%0A        %7D,%0A%0A
+        fixSourceMaps: %7B%0A            options: %7B%0A                srcBase: 'build',%0A                destBase: 'build'%0A            %7D,%0A            all: %5B'build/**/*.map'%5D%0A        %7D,%0A%0A
         jshint: 
@@ -2979,24 +2979,24 @@
   jshint: %7B%0A
-
             
@@ -4217,24 +4217,1066 @@
 ntConfig);%0A%0A
+    // Custom Grunt tasks%0A    grunt.registerMultiTask('fixSourceMaps', function () %7B%0A        var options = this.options(%7B%0A            destBase: '',%0A            srcBase: ''%0A        %7D);%0A%0A        this.files.forEach(function (f) %7B%0A            var result;%0A            var sources = f.src.filter(function (filepath) %7B%0A                if (!grunt.file.exists(filepath)) %7B%0A                    grunt.log.warn('Source file %22' + filepath + '%22 not found.');%0A                    return false;%0A                %7D else %7B%0A                    return true;%0A                %7D%0A            %7D).forEach(function (filepath) %7B%0A                var sMap = grunt.file.readJSON(filepath);%0A                sMap.file = path.relative(options.destBase, sMap.file);%0A                sMap.sources = _.map(sMap.sources, path.relative.bind(path, options.srcBase));%0A%0A                grunt.file.write(filepath, JSON.stringify(sMap));%0A                // Print a success message.%0A                grunt.log.writeln('File %22' + filepath + '%22 fixed.');%0A            %7D);%0A        %7D);%0A    %7D);%0A%0A
     // Grunt
@@ -5713,24 +5713,41 @@
 e', 'uglify'
+, 'fixSourceMaps'
 %5D);%0A    grun
@@ -5806,16 +5806,33 @@
 'uglify'
+, 'fixSourceMaps'
 %5D);%0A%0A   

Fix file paths in source maps