<commit_before>"use strict";

//Module dependencies
var bnetAPI = process.require("api/bnet.js");
var warcraftLogsAPI = process.require("api/warcraftLogs.js");
var logger = process.require("api/logger.js").get("logger");
var characterUpdateModel = process.require("models/characterUpdateModel.js");
var characterModel = process.require("models/characterModel.js");
var applicationStorage = process.require("api/applicationStorage.js");
var userService = process.require("services/userService.js");
var realmService = process.require("services/realmService.js")
var guildKillModel = process.require("models/guildKillModel.js");
var guildProgressUpdateModel = process.require("models/guildProgressUpdateModel.js");

var async = require("async");

//Configuration
var env = process.env.NODE_ENV || 'dev';
var config = process.require('config/config.'+env+'.json');

module.exports.updateNext = function(callback){
    var self=this;
    characterUpdateModel.getNextToUpdate(function(error,characterUpdate) {
        if (error) {
            logger.error(error.message);
            return callback(error);
        }
        if (characterUpdate) {
            //Get Character Update Result (json or key)
            if(characterUpdate.region && characterUpdate.realm && characterUpdate.name ) {
                logger.info("Update Character "+characterUpdate.region+"-"+characterUpdate.realm+"-"+characterUpdate.name);
                self.update(characterUpdate.region, characterUpdate.realm, characterUpdate.name, function (error) {
                    if(error && error.message == "BNET_API_ERROR_DENY") {
                        //Bnet API DENY reset the characterUpdateModel for after
                        characterUpdateModel.insertOrUpdate(characterUpdate.region,characterUpdate.realm,characterUpdate.name,characterUpdate.priority,function(error){
                            if(error) {
                                logger.error(error.message);
                                return callback();
                            }
                            logger.warn("Bnet Api Deny ... waiting 1 min");
                            return setTimeout(function () {
                                callback();
                            }, 60000);
                        });
                    }
                    else
                        callback();
                });

            }
            else{
                //Character Update is already parse before
                callback();
            }
        }
        else{
            //Character Update is empty
            logger.info("No CharacterUpdate ... waiting 3 sec");
            setTimeout(function() {
                callback();
            }, 3000);

        }
    });
};

module.exports.update = function(region,realm,name,callback) {
    var self = this;

    async.waterfall([
        function(callback){
            //GET Character from Bnet
            bnetAPI.getCharacter(region, realm, name, function (error, character) {
                return callback(error,character);
            });
        },
        function(character,callback) {
            async.series([
                function(callback){
                    //Insert bnet in database
                    characterModel.insertOrUpdateBnet(region, character.realm, character.name, character, function (error) {
                        logger.info('insert/update character: ' + region + "-" + character.realm + "-" + character.name);
                        self.emitCount();
                        callback(error);
                    });
                },
                function(callback){
                    //Insert character progress in database
                    if (character.guild && character.guild.name && character.guild.realm){
                        //Loop on talents
                        async.forEachSeries(character.talents,function(talent,callback){

                            if(!talent.selected || !talent.spec || talent.spec.name ==null ||talent.spec.role ==null )
                                return callback();

                            //Raid progression with kill
                            async.forEachSeries(character.progression.raids,function(raid,callback){
                                //Parse only raid in config
                                var raidConfig = null;
                                async.forEach(config.progress.raids,function(obj,callback){
                                    if(obj.name == raid.name)
                                        raidConfig = obj;
                                    callback();

                                });

                                if(raidConfig==null)
                                    return callback();

                                //Raid progression from character progress bnet
                                var bossWeight = 0;
                                async.forEachSeries(raid.bosses,function(boss,callback){

                                    var difficulties = ["normal","heroic","mythic"];
                                    async.forEachSeries(difficulties,function(difficulty,callback){
                                        if(boss[difficulty+'Timestamp']==0)
                                            return callback();

                                        //ADD PROGRESS
                                        var progress = {name:character.name, realm:character.realm, region:region,spec:talent.spec.name,role:talent.spec.role,level:character.level,faction:character.faction,class:character.class,averageItemLevelEquipped:character.items.averageItemLevelEquipped};
                                        guildKillModel.insertOrUpdate(region,character.guild.realm,character.guild.name,raid.name,boss.name,bossWeight,difficulty,boss[difficulty+'Timestamp'],"progress",progress,function(error) {
                                            callback(error);
                                        });
                                    },function(){
                                        bossWeight++;
                                        callback();
                                    });

                                },function(){
                                    callback();
                                });

                            },function(){
                                callback();
                            });

                        },function(){
                            callback();
                        });
                    }
                    else
                        callback();

                },
                function(callback) {
                    async.waterfall([
                        function(callback){
                            warcraftLogsAPI.getRankings(region, character.realm, character.name, function (error, warcraftLogs) {
                                callback(error,warcraftLogs)
                            });
                        },
                        function(warcraftLogs,callback) {
                            characterModel.insertOrUpdateWarcraftLogs(region, character.realm, character.name, warcraftLogs, function (error) {
                                logger.info('insert/update wlogs for character: ' + region + "-" + character.realm + "-" + character.name);
                                callback(error);
                            });
                        }
                    ],function(error){
                        callback(error);
                    });
                }
            ],function(error){
                callback(error);
            });
        }
    ],function(error){
        callback(error);
    });
};

module.exports.insertOrUpdateUpdate =  function(region,realm,name,callback) {
    characterUpdateModel.insertOrUpdate(region, realm, name, 5, function (error) {
        if (error){
            logger.error(error.message);
            callback(error);
            return;
        }
        characterUpdateModel.getPosition(5,function(error,position){
            if (error){
                logger.error(error.message);
            }
            callback(error,position);
        });
    });
};

module.exports.emitCount = function(){
    //Dispatch count to all users if new
    characterModel.getCount(function(error,count){
        if (error){
            logger.error(error.message);
            return;
        }
        var io = applicationStorage.getSocketIo();
        if(!io)
            var io = require('socket.io-emitter')();
        io.emit('get:charactersCount', count);
    });
};

module.exports.emitAdsCount = function(){
    //Dispatch count to all users if new
    characterModel.getAdsCount(function(error,count){
        if (error){
            logger.error(error.message);
            return;
        }
        var io = applicationStorage.getSocketIo();
        if(!io)
            var io = require('socket.io-emitter')();
        io.emit('get:characterAdsCount', count);
    });
};

module.exports.emitLastAds = function(){
    characterModel.getLastAds(function (error, characterAds) {
        if (error) {
            return;
        }
        var io = applicationStorage.getSocketIo();
        if(!io)
            var io = require('socket.io-emitter')();
        io.emit('get:lastCharacterAds', characterAds);
    });

};

module.exports.insertOrUpdateAd = function(region,realm,name,id,ad,callback){
    var self = this;
    userService.isOwner(id,region,realm,name,function(error,isMyCharacter){
        if(error){
            logger.error(error.message);
            callback(error);
            return;
        }
        if(isMyCharacter){
            bnetAPI.getCharacterWithParams(region,realm,name,[],function(error,character){
                if (error)
                    return callback(error);
                characterModel.insertOrUpdateAd(region,character.realm,character.name,id,ad,function(error){
                    if(error)
                        logger.error(error.message);

                    self.emitAdsCount();
                    self.emitCount();
                    self.emitLastAds();

                    characterUpdateModel.insertOrUpdate(region,realm,name,10,function(error){
                        if(error)
                            logger.error(error.message);
                    });
                    callback(error);
                });
            });

        }
        else {
            error = new Error("CHARACTER_NOT_MEMBER_ERROR");
            logger.error(error.message);
            callback(error);
        }
    });
};

module.exports.setId = function(region,realm,name,id,callback){
    characterModel.setId(region,realm,name,id,function(error){
        if(error)
            logger.error(error.message);
        callback(error);
    });
};

module.exports.getLastAds = function(callback) {
    characterModel.getLastAds(function (error, characters) {
        if (error)
            logger.error(error.message);
        callback(error,characters);

    });
};

module.exports.getAds = function(number,filters,callback) {
    filters.realmList = [];
    async.waterfall([
        function(callback){
            async.waterfall([
                function(callback){
                    if(filters.realmZones && filters.realmZones && filters.realmZones.length>0){
                        realmService.getFromRealmZones(filters.realmZones,function(error,realms){
                            filters.realmList = realms;
                            callback();
                        });
                    }
                    else
                        callback()
                },
                function(callback){
                    if(filters.realm && filters.realm.region && filters.realm.name ){
                        realmService.get(filters.realm.region,filters.realm.name,function(error,realm){
                            if(!realm)
                                return callback();

                            async.forEach(realm.connected_realms,function(name,callback){
                                filters.realmList =[{name:name,region:filters.realm.region}];
                                callback();

                            },function(){
                                callback();
                            })
                        });
                    }
                    else
                        callback();
                }
            ],function(){
                callback();
            });
        },
        function(callback){
            characterModel.getAds(number,filters,function (error, characters) {
                if (error)
                    logger.error(error.message);
                callback(error,characters);
            });
        }
    ],function(error,characters){
        callback(error,characters)
    });
};

module.exports.get = function(region,realm,name,callback){
    characterModel.get(region,realm,name,function(error,character){
        if (error)
            logger.error(error.message);
        callback(error,character);
    });
};

module.exports.getCount = function(callback){
    characterModel.getCount(function (error, count) {
        if (error)
            logger.error(error.message);
        callback(error,count);
    });
};

module.exports.getAdsCount = function(callback){
    characterModel.getAdsCount(function (error, count) {
        if (error)
            logger.error(error.message);
        callback(error,count);
    });
};

module.exports.deleteAd = function(region,realm,name,id,callback){
    var self=this;
    characterModel.deleteAd(region,realm,name,id,function(error){
        if (error)
            logger.error(error.message);

        self.emitAdsCount();
        self.emitCount();
        self.emitLastAds();

        callback(error);

    });
};

module.exports.getUserAds = function(id,callback){
    characterModel.getUserAds(id,function(error,ads){
        if (error)
            logger.error(error.message);

        callback(error,ads);
    });
};

module.exports.deleteOldAds = function(callback){
    var timestamp = new Date().getTime();
    var oldTimestamp = timestamp - (30 * 24 * 3600 * 1000);
    characterModel.deleteOldAds(oldTimestamp,function(error){
        if (error){
            logger.error(error.message);
        }
        callback(error);
    });
};

module.exports.setAdsToUpdate = function(callback){

    characterModel.getAds(0,null,function(error,guilds){
        if(error){
            logger.error(error.message);
            return callback(error);
        }
        async.eachSeries(guilds,function(guild,callback){
            characterUpdateModel.insertOrUpdate(guild.region,guild.realm,guild.name,3,function(error){
                if(error)
                    logger.error(error.message);
                logger.info("Insert character to update " + guild.region + "-" + guild.realm + "-" + guild.name + ' priority 3');
                callback(error);
            });
        });
    });

};<commit_msg>Guild Progress update<commit_after>"use strict";

//Module dependencies
var bnetAPI = process.require("api/bnet.js");
var warcraftLogsAPI = process.require("api/warcraftLogs.js");
var logger = process.require("api/logger.js").get("logger");
var characterUpdateModel = process.require("models/characterUpdateModel.js");
var characterModel = process.require("models/characterModel.js");
var applicationStorage = process.require("api/applicationStorage.js");
var userService = process.require("services/userService.js");
var realmService = process.require("services/realmService.js")
var guildKillModel = process.require("models/guildKillModel.js");
var guildProgressUpdateModel = process.require("models/guildProgressUpdateModel.js");

var async = require("async");

//Configuration
var env = process.env.NODE_ENV || 'dev';
var config = process.require('config/config.'+env+'.json');

module.exports.updateNext = function(callback){
    var self=this;
    characterUpdateModel.getNextToUpdate(function(error,characterUpdate) {
        if (error) {
            logger.error(error.message);
            return callback(error);
        }
        if (characterUpdate) {
            //Get Character Update Result (json or key)
            if(characterUpdate.region && characterUpdate.realm && characterUpdate.name ) {
                logger.info("Update Character "+characterUpdate.region+"-"+characterUpdate.realm+"-"+characterUpdate.name);
                self.update(characterUpdate.region, characterUpdate.realm, characterUpdate.name, function (error) {
                    if(error && error.message == "BNET_API_ERROR_DENY") {
                        //Bnet API DENY reset the characterUpdateModel for after
                        characterUpdateModel.insertOrUpdate(characterUpdate.region,characterUpdate.realm,characterUpdate.name,characterUpdate.priority,function(error){
                            if(error) {
                                logger.error(error.message);
                                return callback();
                            }
                            logger.warn("Bnet Api Deny ... waiting 1 min");
                            return setTimeout(function () {
                                callback();
                            }, 60000);
                        });
                    }
                    else
                        callback();
                });

            }
            else{
                //Character Update is already parse before
                callback();
            }
        }
        else{
            //Character Update is empty
            logger.info("No CharacterUpdate ... waiting 3 sec");
            setTimeout(function() {
                callback();
            }, 3000);

        }
    });
};

module.exports.update = function(region,realm,name,callback) {
    var self = this;

    async.waterfall([
        function(callback){
            //GET Character from Bnet
            bnetAPI.getCharacter(region, realm, name, function (error, character) {
                return callback(error,character);
            });
        },
        function(character,callback) {
            async.series([
                function(callback){
                    //Insert bnet in database
                    characterModel.insertOrUpdateBnet(region, character.realm, character.name, character, function (error) {
                        logger.info('insert/update character: ' + region + "-" + character.realm + "-" + character.name);
                        self.emitCount();
                        callback(error);
                    });
                },
                function(callback){
                    //Insert character progress in database
                    if (character.guild && character.guild.name && character.guild.realm){
                        //Loop on talents
                        async.forEachSeries(character.talents,function(talent,callback){

                            if(!talent.selected || !talent.spec || talent.spec.name ==null ||talent.spec.role ==null )
                                return callback();

                            //Raid progression with kill
                            async.forEachSeries(character.progression.raids,function(raid,callback){
                                //Parse only raid in config
                                var raidConfig = null;
                                async.forEach(config.progress.raids,function(obj,callback){
                                    if(obj.name == raid.name)
                                        raidConfig = obj;
                                    callback();

                                });

                                if(raidConfig==null)
                                    return callback();

                                //Raid progression from character progress bnet
                                var bossWeight = 0;
                                async.forEachSeries(raid.bosses,function(boss,callback){

                                    var difficulties = ["normal","heroic","mythic"];
                                    async.forEachSeries(difficulties,function(difficulty,callback){
                                        if(boss[difficulty+'Timestamp']==0)
                                            return callback();

                                        async.series([
                                            function(callback){
                                                //ADD PROGRESS
                                                var progress = {name:character.name, realm:character.realm, region:region,spec:talent.spec.name,role:talent.spec.role,level:character.level,faction:character.faction,class:character.class,averageItemLevelEquipped:character.items.averageItemLevelEquipped};
                                                guildKillModel.insertOrUpdate(region,character.guild.realm,character.guild.name,raid.name,boss.name,bossWeight,difficulty,boss[difficulty+'Timestamp'],"progress",progress,function(error) {
                                                    callback(error);
                                                });
                                            },
                                            function(callback){
                                                guildProgressUpdateModel.insertOrUpdate(region, character.guild.realm, character.guild.name, 0, function (error) {
                                                    callback(error);
                                                });
                                            }
                                        ],function(error){
                                            callback(error);
                                        });
                                    },function(){
                                        bossWeight++;
                                        callback();
                                    });

                                },function(){
                                    callback();
                                });

                            },function(){
                                callback();
                            });

                        },function(){
                            callback();
                        });
                    }
                    else
                        callback();

                },
                function(callback) {
                    async.waterfall([
                        function(callback){
                            warcraftLogsAPI.getRankings(region, character.realm, character.name, function (error, warcraftLogs) {
                                callback(error,warcraftLogs)
                            });
                        },
                        function(warcraftLogs,callback) {
                            characterModel.insertOrUpdateWarcraftLogs(region, character.realm, character.name, warcraftLogs, function (error) {
                                logger.info('insert/update wlogs for character: ' + region + "-" + character.realm + "-" + character.name);
                                callback(error);
                            });
                        }
                    ],function(error){
                        callback(error);
                    });
                }
            ],function(error){
                callback(error);
            });
        }
    ],function(error){
        callback(error);
    });
};

module.exports.insertOrUpdateUpdate =  function(region,realm,name,callback) {
    characterUpdateModel.insertOrUpdate(region, realm, name, 5, function (error) {
        if (error){
            logger.error(error.message);
            callback(error);
            return;
        }
        characterUpdateModel.getPosition(5,function(error,position){
            if (error){
                logger.error(error.message);
            }
            callback(error,position);
        });
    });
};

module.exports.emitCount = function(){
    //Dispatch count to all users if new
    characterModel.getCount(function(error,count){
        if (error){
            logger.error(error.message);
            return;
        }
        var io = applicationStorage.getSocketIo();
        if(!io)
            var io = require('socket.io-emitter')();
        io.emit('get:charactersCount', count);
    });
};

module.exports.emitAdsCount = function(){
    //Dispatch count to all users if new
    characterModel.getAdsCount(function(error,count){
        if (error){
            logger.error(error.message);
            return;
        }
        var io = applicationStorage.getSocketIo();
        if(!io)
            var io = require('socket.io-emitter')();
        io.emit('get:characterAdsCount', count);
    });
};

module.exports.emitLastAds = function(){
    characterModel.getLastAds(function (error, characterAds) {
        if (error) {
            return;
        }
        var io = applicationStorage.getSocketIo();
        if(!io)
            var io = require('socket.io-emitter')();
        io.emit('get:lastCharacterAds', characterAds);
    });

};

module.exports.insertOrUpdateAd = function(region,realm,name,id,ad,callback){
    var self = this;
    userService.isOwner(id,region,realm,name,function(error,isMyCharacter){
        if(error){
            logger.error(error.message);
            callback(error);
            return;
        }
        if(isMyCharacter){
            bnetAPI.getCharacterWithParams(region,realm,name,[],function(error,character){
                if (error)
                    return callback(error);
                characterModel.insertOrUpdateAd(region,character.realm,character.name,id,ad,function(error){
                    if(error)
                        logger.error(error.message);

                    self.emitAdsCount();
                    self.emitCount();
                    self.emitLastAds();

                    characterUpdateModel.insertOrUpdate(region,realm,name,10,function(error){
                        if(error)
                            logger.error(error.message);
                    });
                    callback(error);
                });
            });

        }
        else {
            error = new Error("CHARACTER_NOT_MEMBER_ERROR");
            logger.error(error.message);
            callback(error);
        }
    });
};

module.exports.setId = function(region,realm,name,id,callback){
    characterModel.setId(region,realm,name,id,function(error){
        if(error)
            logger.error(error.message);
        callback(error);
    });
};

module.exports.getLastAds = function(callback) {
    characterModel.getLastAds(function (error, characters) {
        if (error)
            logger.error(error.message);
        callback(error,characters);

    });
};

module.exports.getAds = function(number,filters,callback) {
    filters.realmList = [];
    async.waterfall([
        function(callback){
            async.waterfall([
                function(callback){
                    if(filters.realmZones && filters.realmZones && filters.realmZones.length>0){
                        realmService.getFromRealmZones(filters.realmZones,function(error,realms){
                            filters.realmList = realms;
                            callback();
                        });
                    }
                    else
                        callback()
                },
                function(callback){
                    if(filters.realm && filters.realm.region && filters.realm.name ){
                        realmService.get(filters.realm.region,filters.realm.name,function(error,realm){
                            if(!realm)
                                return callback();

                            async.forEach(realm.connected_realms,function(name,callback){
                                filters.realmList =[{name:name,region:filters.realm.region}];
                                callback();

                            },function(){
                                callback();
                            })
                        });
                    }
                    else
                        callback();
                }
            ],function(){
                callback();
            });
        },
        function(callback){
            characterModel.getAds(number,filters,function (error, characters) {
                if (error)
                    logger.error(error.message);
                callback(error,characters);
            });
        }
    ],function(error,characters){
        callback(error,characters)
    });
};

module.exports.get = function(region,realm,name,callback){
    characterModel.get(region,realm,name,function(error,character){
        if (error)
            logger.error(error.message);
        callback(error,character);
    });
};

module.exports.getCount = function(callback){
    characterModel.getCount(function (error, count) {
        if (error)
            logger.error(error.message);
        callback(error,count);
    });
};

module.exports.getAdsCount = function(callback){
    characterModel.getAdsCount(function (error, count) {
        if (error)
            logger.error(error.message);
        callback(error,count);
    });
};

module.exports.deleteAd = function(region,realm,name,id,callback){
    var self=this;
    characterModel.deleteAd(region,realm,name,id,function(error){
        if (error)
            logger.error(error.message);

        self.emitAdsCount();
        self.emitCount();
        self.emitLastAds();

        callback(error);

    });
};

module.exports.getUserAds = function(id,callback){
    characterModel.getUserAds(id,function(error,ads){
        if (error)
            logger.error(error.message);

        callback(error,ads);
    });
};

module.exports.deleteOldAds = function(callback){
    var timestamp = new Date().getTime();
    var oldTimestamp = timestamp - (30 * 24 * 3600 * 1000);
    characterModel.deleteOldAds(oldTimestamp,function(error){
        if (error){
            logger.error(error.message);
        }
        callback(error);
    });
};

module.exports.setAdsToUpdate = function(callback){

    characterModel.getAds(0,null,function(error,guilds){
        if(error){
            logger.error(error.message);
            return callback(error);
        }
        async.eachSeries(guilds,function(guild,callback){
            characterUpdateModel.insertOrUpdate(guild.region,guild.realm,guild.name,3,function(error){
                if(error)
                    logger.error(error.message);
                logger.info("Insert character to update " + guild.region + "-" + guild.realm + "-" + guild.name + ' priority 3');
                callback(error);
            });
        });
    });

};<|endoftext|>


<commit_before>/**
 *
 *  Web Starter Kit
 *  Copyright 2015 Google Inc. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 */

'use strict';

// This gulpfile makes use of new JavaScript features.
// Babel handles this without us having to do anything. It just works.
// You can read more about the new JavaScript features here:
// https://babeljs.io/docs/learn-es2015/

import path from 'path';
import gulp from 'gulp';
import del from 'del';
import runSequence from 'run-sequence';
import browserSync from 'browser-sync';
import moment from 'moment';
import gulpLoadPlugins from 'gulp-load-plugins';
import { output as pagespeed } from 'psi';
import pkg from './package.json';

const $ = gulpLoadPlugins();
const reload = browserSync.reload;

// File paths to various assets are defined here.
var PATHS = {
    phpcs: [
        '**/*.php',
        '!wpcs',
        '!wpcs/**'
    ]
};

// Lint JavaScript
gulp.task('lint', () =>
    gulp.src(['src/js/**/*.js', '!node_modules/**'])
    .pipe($.eslint())
    .pipe($.eslint.format())
    .pipe($.if(!browserSync.active, $.eslint.failAfterError()))
);

// Optimize images
gulp.task('images', () =>
    gulp.src('src/images/**/*')
        .pipe($.if('*.svg', $.svgo({ plugins: [
            {removeTitle: true},
            {removeDimensions: true}
        ]})))
        .pipe($.cache($.imagemin({
            plugins: [$.imagemin.gifsicle(), $.imagemin.jpegtran(), $.imagemin.svgo()],
            progressive: true,
            interlaced: true
        })))
        .pipe(gulp.dest('dist/images'))
    .pipe($.size({ title: 'images' }))
);

// Compile styles
gulp.task('styles', () => {
    const AUTOPREFIXER_BROWSERS = [
        'ie >= 10',
        'ie_mob >= 10',
        'ff >= 30',
        'chrome >= 34',
        'safari >= 7',
        'opera >= 23',
        'ios >= 7',
        'android >= 4.4',
        'bb >= 10'
    ];
    const neat = require('node-neat').includePaths;

    // For best performance, don't add Sass partials to `gulp.src`
    return gulp.src('src/sass/style.scss')
        .pipe($.sourcemaps.init())
        .pipe($.sass({
            precision: 10,
            includePaths: ['src/sass/**/*.scss'].concat(neat)
        }).on('error', $.sass.logError))
        .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
        // Concatenate and minify styles
        .pipe($.if('*.css', $.cssnano({ discardComments: true, zindex: false })))
        .pipe($.size({ title: 'styles' }))
        .pipe($.sourcemaps.write('./'))
        .pipe(gulp.dest('src/'));
});

// Generate & Inline Critical-path CSS
const critical = require('critical').stream;
gulp.task('critical', ['styles'], ()=> {
    return gulp.src('src/html/*.html')
        .pipe(critical({
            base: './',
            dest: 'src/critical.css',
            inline: false,
            minify: true,
            css: ['src/style.css'],
            width: 640,
            height: 360
        }))
        .on('error', function(err) { $.util.log($.util.colors.red(err.message)); })
        .pipe(gulp.dest('dist/assets/css'));
});

// Concatenate and minify JavaScript. Optionally transpiles ES2015 code to ES5.
// to enable ES2015 support remove the line `"only": "gulpfile.babel.js",` in the
// `.babelrc` file.
gulp.task('scripts', () =>
    gulp.src([
        // Note: Since we are not using useref in the scripts build pipeline,
        //       you need to explicitly list your scripts here in the right order
        //       to be correctly concatenated
        './src/js/main.js',
        './src/js/navigation.js',
        './src/js/skip-link-focus-fix.js',
        './node_modules/headroom.js/dist/headroom.js',
        './src/js/socialshare-slide.js',
        './src/js/scrollhandler.js',
        './src/js/comments.js',
    ])
    .pipe($.newer('.tmp/scripts'))
    .pipe($.sourcemaps.init())
    .pipe($.babel())
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('.tmp/scripts'))
    .pipe($.concat('main.min.js'))
    .pipe($.uglify({ preserveComments: 'some' }))
    // Output files
    .pipe($.size({ title: 'scripts' }))
    .pipe($.sourcemaps.write('.'))
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(gulp.dest('.tmp/scripts'))
);

gulp.task('scripts:loadcss', ()=> {
    gulp.src('./node_modules/fg-loadcss/src/*.js')
    .pipe($.uglify({ preserveComments: 'none' }))
    .pipe(gulp.dest('dist/assets/js'));
});

// Clean output directory
gulp.task('clean', () => del(['.tmp', 'dist/*', '!dist/.git'], { dot: true }));

gulp.task('copy:styles', () => {
    return gulp.src(['src/style.css', 'src/style.css.map', 'src/critical.css']).pipe(gulp.dest('dist/'));
});

gulp.task('copy:images', () => {
    return gulp.src('src/images/**/*').pipe(gulp.dest('dist/assets/images/'));
});

gulp.task('copy:php', () => {
    return gulp.src('src/**/*.php').pipe(gulp.dest('dist/'));
});

gulp.task('build', ['clean'], cb => {
    runSequence(['scripts', 'scripts:loadcss', 'styles', 'copy:styles', 'copy:images', 'copy:php'], cb);
});

// PHP Code Sniffer task
gulp.task('phpcs', function() {
    return gulp.src(PATHS.phpcs)
        .pipe($.phpcs({
            bin: 'wpcs/vendor/bin/phpcs',
            standard: './codesniffer.ruleset.xml',
            showSniffCode: true,
        }))
        .on('error', $.util.log)
        .pipe($.phpcs.reporter('log'));
});

// PHP Code Beautifier task
gulp.task('phpcbf', function() {
    return gulp.src(PATHS.phpcs)
        .pipe($.phpcbf({
            bin: 'wpcs/vendor/bin/phpcbf',
            standard: './codesniffer.ruleset.xml',
            warningSeverity: 0
        }))
        .on('error', $.util.log)
        .pipe(gulp.dest('.'));
});

// Package task
gulp.task('package', ['build'], function() {
    var title = 'presson-theme' + '_' + moment().format("YYYY-MM-DD_HH-mm") + '.zip';

    return gulp.src('dist/**/*')
        .pipe($.zip(title))
        .pipe(gulp.dest('packaged'));
});

gulp.task('serve:wordpress', ['build'], function() {
    browserSync({
        notify: false,
        // Customize the Browsersync console logging prefix
        proxy: 'http://localhost:8080'
    });

    gulp.watch(['src/sass/**/*.scss'], ['styles', 'copy:styles', reload]);
    gulp.watch(['src/**/*.php'], ['copy:php', reload]);
    gulp.watch(['src/images/**/*'], ['copy:images', reload]);
    gulp.watch(['src/js/**/*'], ['lint', 'scripts', reload]);
});

// Build production files, the default task
gulp.task('default', ['clean'], cb =>
    runSequence(
        'lint', 'styles', ['build'],
        cb
    )
);

// Run PageSpeed Insights
gulp.task('pagespeed', cb =>
    // Update the below URL to the public URL of your site
    pagespeed('', {
        strategy: 'mobile'
            // By default we use the PageSpeed Insights free (no API key) tier.
            // Use a Google Developer API key if you have one: http://goo.gl/RkN0vE
            // key: 'YOUR_API_KEY'
    }, cb)
);

// Load custom tasks from the `tasks` directory
// Run: `npm install --save-dev require-dir` from the command-line
// try { require('require-dir')('tasks'); } catch (err) { console.error(err); }
<commit_msg>[sett] fix race condition in `gulp build`<commit_after>/**
 *
 *  Web Starter Kit
 *  Copyright 2015 Google Inc. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 */

'use strict';

// This gulpfile makes use of new JavaScript features.
// Babel handles this without us having to do anything. It just works.
// You can read more about the new JavaScript features here:
// https://babeljs.io/docs/learn-es2015/

import path from 'path';
import gulp from 'gulp';
import del from 'del';
import runSequence from 'run-sequence';
import browserSync from 'browser-sync';
import moment from 'moment';
import gulpLoadPlugins from 'gulp-load-plugins';
import { output as pagespeed } from 'psi';
import pkg from './package.json';

const $ = gulpLoadPlugins();
const reload = browserSync.reload;

// File paths to various assets are defined here.
var PATHS = {
    phpcs: [
        '**/*.php',
        '!wpcs',
        '!wpcs/**'
    ]
};

// Lint JavaScript
gulp.task('lint', () =>
    gulp.src(['src/js/**/*.js', '!node_modules/**'])
    .pipe($.eslint())
    .pipe($.eslint.format())
    .pipe($.if(!browserSync.active, $.eslint.failAfterError()))
);

// Optimize images
gulp.task('images', () =>
    gulp.src('src/images/**/*')
        .pipe($.if('*.svg', $.svgo({ plugins: [
            {removeTitle: true},
            {removeDimensions: true}
        ]})))
        .pipe($.cache($.imagemin({
            plugins: [$.imagemin.gifsicle(), $.imagemin.jpegtran(), $.imagemin.svgo()],
            progressive: true,
            interlaced: true
        })))
        .pipe(gulp.dest('dist/images'))
    .pipe($.size({ title: 'images' }))
);

// Compile styles
gulp.task('styles', () => {
    const AUTOPREFIXER_BROWSERS = [
        'ie >= 10',
        'ie_mob >= 10',
        'ff >= 30',
        'chrome >= 34',
        'safari >= 7',
        'opera >= 23',
        'ios >= 7',
        'android >= 4.4',
        'bb >= 10'
    ];
    const neat = require('node-neat').includePaths;

    // For best performance, don't add Sass partials to `gulp.src`
    return gulp.src('src/sass/style.scss')
        .pipe($.sourcemaps.init())
        .pipe($.sass({
            precision: 10,
            includePaths: ['src/sass/**/*.scss'].concat(neat)
        }).on('error', $.sass.logError))
        .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
        // Concatenate and minify styles
        .pipe($.if('*.css', $.cssnano({ discardComments: true, zindex: false })))
        .pipe($.size({ title: 'styles' }))
        .pipe($.sourcemaps.write('./'))
        .pipe(gulp.dest('src/'));
});

// Generate & Inline Critical-path CSS
const critical = require('critical').stream;
gulp.task('critical', ['styles'], ()=> {
    return gulp.src('src/html/*.html')
        .pipe(critical({
            base: './',
            dest: 'src/critical.css',
            inline: false,
            minify: true,
            css: ['src/style.css'],
            width: 640,
            height: 360
        }))
        .on('error', function(err) { $.util.log($.util.colors.red(err.message)); })
        .pipe(gulp.dest('dist/assets/css'));
});

// Concatenate and minify JavaScript. Optionally transpiles ES2015 code to ES5.
// to enable ES2015 support remove the line `"only": "gulpfile.babel.js",` in the
// `.babelrc` file.
gulp.task('scripts', () =>
    gulp.src([
        // Note: Since we are not using useref in the scripts build pipeline,
        //       you need to explicitly list your scripts here in the right order
        //       to be correctly concatenated
        './src/js/main.js',
        './src/js/navigation.js',
        './src/js/skip-link-focus-fix.js',
        './node_modules/headroom.js/dist/headroom.js',
        './src/js/socialshare-slide.js',
        './src/js/scrollhandler.js',
        './src/js/comments.js',
    ])
    .pipe($.newer('.tmp/scripts'))
    .pipe($.sourcemaps.init())
    .pipe($.babel())
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('.tmp/scripts'))
    .pipe($.concat('main.min.js'))
    .pipe($.uglify({ preserveComments: 'some' }))
    // Output files
    .pipe($.size({ title: 'scripts' }))
    .pipe($.sourcemaps.write('.'))
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(gulp.dest('.tmp/scripts'))
);

gulp.task('scripts:loadcss', ()=> {
    gulp.src('./node_modules/fg-loadcss/src/*.js')
    .pipe($.uglify({ preserveComments: 'none' }))
    .pipe(gulp.dest('dist/assets/js'));
});

// Clean output directory
gulp.task('clean', () => del(['.tmp', 'dist/*', '!dist/.git'], { dot: true }));

gulp.task('copy:styles', () => {
    return gulp.src(['src/style.css', 'src/style.css.map', 'src/critical.css']).pipe(gulp.dest('dist/'));
});

gulp.task('copy:images', () => {
    return gulp.src('src/images/**/*').pipe(gulp.dest('dist/assets/images/'));
});

gulp.task('copy:php', () => {
    return gulp.src('src/**/*.php').pipe(gulp.dest('dist/'));
});

gulp.task('build', ['clean'], cb => {
    runSequence(['scripts', 'scripts:loadcss', 'styles'], ['copy:styles', 'copy:images', 'copy:php'], cb);
});

// PHP Code Sniffer task
gulp.task('phpcs', function() {
    return gulp.src(PATHS.phpcs)
        .pipe($.phpcs({
            bin: 'wpcs/vendor/bin/phpcs',
            standard: './codesniffer.ruleset.xml',
            showSniffCode: true,
        }))
        .on('error', $.util.log)
        .pipe($.phpcs.reporter('log'));
});

// PHP Code Beautifier task
gulp.task('phpcbf', function() {
    return gulp.src(PATHS.phpcs)
        .pipe($.phpcbf({
            bin: 'wpcs/vendor/bin/phpcbf',
            standard: './codesniffer.ruleset.xml',
            warningSeverity: 0
        }))
        .on('error', $.util.log)
        .pipe(gulp.dest('.'));
});

// Package task
gulp.task('package', ['build'], function() {
    var title = 'presson-theme' + '_' + moment().format("YYYY-MM-DD_HH-mm") + '.zip';

    return gulp.src('dist/**/*')
        .pipe($.zip(title))
        .pipe(gulp.dest('packaged'));
});

gulp.task('serve:wordpress', ['build'], function() {
    browserSync({
        notify: false,
        // Customize the Browsersync console logging prefix
        proxy: 'http://localhost:8080'
    });

    gulp.watch(['src/sass/**/*.scss'], ['styles', 'copy:styles', reload]);
    gulp.watch(['src/**/*.php'], ['copy:php', reload]);
    gulp.watch(['src/images/**/*'], ['copy:images', reload]);
    gulp.watch(['src/js/**/*'], ['lint', 'scripts', reload]);
});

// Build production files, the default task
gulp.task('default', ['clean'], cb =>
    runSequence(
        'lint', 'styles', ['build'],
        cb
    )
);

// Run PageSpeed Insights
gulp.task('pagespeed', cb =>
    // Update the below URL to the public URL of your site
    pagespeed('', {
        strategy: 'mobile'
            // By default we use the PageSpeed Insights free (no API key) tier.
            // Use a Google Developer API key if you have one: http://goo.gl/RkN0vE
            // key: 'YOUR_API_KEY'
    }, cb)
);

// Load custom tasks from the `tasks` directory
// Run: `npm install --save-dev require-dir` from the command-line
// try { require('require-dir')('tasks'); } catch (err) { console.error(err); }
<|endoftext|>


<commit_before>const DrawCard = require('../../drawcard.js');

class Kamayari extends DrawCard {
    setupCardAbilities(ability) {
        this.reaction({
            title: 'Bow character who triggered ability',
            when: {
                // TODO: Need to check for immunity and cannot restrictions - requires TriggeredAbility to pass context to this function
                onCardAbilityInitiated: event => event.card.type === 'character' && this.parent.isParticipating() && !event.card.bowed
            },
            handler: context => {
                this.game.addMessage('{0} uses {1} to bow {2}', this.controller, this, context.event.card);
                this.controller.bowCard(context.event.card, context.source);
            }
        });
    }
}

Kamayari.id = 'kamayari';

module.exports = Kamayari;
<commit_msg>attachment restriction<commit_after>const DrawCard = require('../../drawcard.js');

class Kamayari extends DrawCard {
    setupCardAbilities(ability) {
        this.reaction({
            title: 'Bow character who triggered ability',
            when: {
                // TODO: Need to check for immunity and cannot restrictions - requires TriggeredAbility to pass context to this function
                onCardAbilityInitiated: event => event.card.type === 'character' && this.parent.isParticipating() && !event.card.bowed
            },
            handler: context => {
                this.game.addMessage('{0} uses {1} to bow {2}', this.controller, this, context.event.card);
                this.controller.bowCard(context.event.card, context.source);
            }
        });
    }

    canAttach(card) {
        if(card.hasTrait('bushi')) {
            return super.canAttach(card);
        }
        return false;
    }
}

Kamayari.id = 'kamayari';

module.exports = Kamayari;
<|endoftext|>


<commit_before>/* jshint esnext: true */
var data;

var margin = {top: 0, right: 0, bottom: 0, left: 100};
var width = 960 - margin.left - margin.right;
var height = 600 - margin.top - margin.bottom;

var dataMargin = {top: 10, right: 6, bottom: 50, left: 0};
var dataWidth = width - dataMargin.left - dataMargin.right;
var dataHeight = height - dataMargin.top - dataMargin.bottom;

var x_min = 0;
var x_max = 10;
var current_x_min = x_min;

var discrete_mode = false; // this is a kludge to fix centerOn bug
var pinned = false;

var x = d3.scaleLinear()
  .domain([x_min, x_max])
  .range([dataMargin.left, dataWidth]);

var y = d3.scaleLinear()
  .domain([1, 30])
  .range([dataMargin.top, dataHeight]);

var line = d3.line()
  .curve(d3.curveMonotoneX)
  .x(d => x(d.week))
  .y(d => y(d.rank));

var voronoi = d3.voronoi()
  .x(d => d.x)
  .y(d => d.y)
  .size([3200, height]);

var format = d3.format(".01f");

window.onload = function() {
  d3.json('api/rankings/2016', function(error, json) {
    if (error) {
      return console.warn(error);
    }
    data = json.results;
    $('#spinner-container').css('display', 'none');

    // find initial rankings for greensock
    var start_rankings = new Array(30);
    data.forEach(function(team) {
      let rank = team.rankings[0].rank;
      start_rankings[rank - 1] = '.' + team.slug;
    });
    start_rankings.reverse();

    /*
     * D3.js Code
     */
    var outer = d3.select(".chart").append("svg")
        .attr("style", "border: 1px solid black;")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom);

    var inner = outer
      .append("g")
        .attr("transform", `translate(${margin.left}, ${margin.top})`)
      .append("svg")
        .attr("width", dataWidth + dataMargin.left + dataMargin.right)
        .attr("height", dataHeight + dataMargin.top + dataMargin.bottom)
      .append('g')
        .attr("transform", `translate(${dataMargin.left}, ${dataMargin.top})`);

    var xAxis = d3.axisBottom(x);

    var gX = outer.append('g')
      .attr('transform', `translate(${margin.left + dataMargin.left}, ${height - margin.bottom - dataMargin.bottom + 5})`)
      .call(xAxis);

    var gY = outer.append('g')
        .attr('transform', `translate(${margin.left}, ${margin.top + dataMargin.top})`);

    var labels = gY.selectAll('.team-label')
      .data(data)
      .enter().append('text')
        .attr('class', d => `${d.slug} team-label`)
        .attr('text-anchor', 'end')
        .attr('transform', d => `translate(0, ${y(d.rankings[current_x_min].rank)})`)
        .text(d => d.name);

    var team = inner.selectAll('.team')
      .data(data)
      .enter().append('g')
        .attr('class', d => `${d.slug} team`)
      .append('path')
        .attr('d', d => line(d.rankings))
        .style('fill', 'none')
        .style('stroke-width', 1.5)
        .style('stroke', d => d.color)
        .attr('team', d => d.slug);

    var zoom = d3.zoom()
      .on('zoom', zoomed)
      .on('end', centerOnNearestBase)
      .translateExtent([[0,0], [3200, height + margin.top + margin.bottom]])
      .scaleExtent([1,1]);

    var zoomHandle = inner.append('rect')
      .attr('width', width)
      .attr('height', height)
      .attr('class', 'zoom-handle')
      .call(zoom);

    var allPoints = generateVoronoiPoints($('.team path'));

    var voronoiData = voronoi.polygons(allPoints);

    var voronoiPoly = inner.selectAll('.voronoi')
      .data(voronoiData)
      .enter().append('g')
        .attr('class', d => 'voronoi')
      .append('path')
        .attr('d', d => d ? "M" + d.join("L") + "Z" : null)
        .on('click', pin(team))
        .on('mouseover', highlight(team))
        .on('mouseout', highlightAll);

    function zoomed() {
      team.attr('transform', d3.event.transform);
      voronoiPoly.attr('transform', d3.event.transform);
      gX.call(xAxis.scale(d3.event.transform.rescaleX(x)));

      var x_min = format(x.invert(-d3.event.transform.x));
      var xFloor = Math.floor(x_min);
      var xCeil = Math.ceil(x_min);
      var percent = d3.easeCubic(x_min % 1);

      labels.attr('transform', function(d) {
        var floor = y(d.rankings[xFloor].rank);
        var ceil = y(d.rankings[xCeil].rank);
        var travel = ceil - floor;
        var newY = floor + ( travel * percent );
        return `translate(0, ${newY})`;
      });
    }

    /*
     * Panning Logic
     */
    function centerOnNearestBase() {
      if (discrete_mode) {
        // there's a bug here where if you hit the pan buttons too fast
        // we get into an infinite loop trying to center while another
        // zoom event is happening
        return;
      }
      var base = format(x.invert(-d3.event.transform.x)); // where the left hand of the axis lies
      var roundedBase = format(Math.round(base));
      if (Math.abs(x(roundedBase - base)) > 1)  {
        // if we're more than 1 pixel off
        centerOn(roundedBase);
      }
    }

    function centerOn(base) {
      var mX = x(base);
      var t = d3.zoomIdentity.translate(-mX, 0);
      zoomHandle
        .transition()
        .duration(200)
        .call(zoom.transform, t);
    }

    // Desktop Panning Controls
    var leftButton = d3.select('#left')
      .on('click', function() {
        discrete_mode = true;
        if (current_x_min > 0) {
          current_x_min--;
          centerOn(current_x_min);
        }
      });
    var rightButton = d3.select('#right')
      .on('click', function() {
        discrete_mode = true;
        current_x_min++;
        centerOn(current_x_min);
      });

    // Animate all this garbage in
    TweenMax.staggerFrom(start_rankings, 1, {opacity: 0}, 0.025);

  });

  function pin(team) {
    pinned = true;
  }

  function highlight(team) {
    return function(team) {
      if (team) {
        var slug = team.data.slug;
        console.log();
        d3.selectAll('.team path')
          .transition()
          .duration(15)
          .ease(d3.easeLinear)
          .style('stroke-width', d => (slug === d.slug) ? '3px' : '1px')
          .style('stroke', d => (slug === d.slug) ? d.color : 'gray');
      }
    };
  }

  function highlightAll() {
    d3.selectAll('.team path')
      .transition()
      .duration(15)
      .ease(d3.easeLinear)
      .style('stroke', d => d.color)
      .style('stroke-width', '1.5px');
  }

  function samplePath(pathNode, precision) {
    var pathLength = pathNode.getTotalLength();
    var samples = [];
    for (let sample, sampleLength = 0; sampleLength <= pathLength; sampleLength += precision) {
      sample = pathNode.getPointAtLength(sampleLength);
      samples.push({
        x: sample.x,
        y: sample.y,
        slug: pathNode.__data__.slug // there is surely a better way to get this
      });
    }
    return samples;
  }

  function generateVoronoiPoints(paths) {
    var allPoints = [];
    for (var path of paths) {
      allPoints = allPoints.concat( samplePath(path, 15) );
    }
    return allPoints;
  }

};
<commit_msg>added pinning<commit_after>/* jshint esnext: true */
var data;

var margin = {top: 0, right: 0, bottom: 0, left: 100};
var width = 960 - margin.left - margin.right;
var height = 600 - margin.top - margin.bottom;

var dataMargin = {top: 10, right: 6, bottom: 50, left: 0};
var dataWidth = width - dataMargin.left - dataMargin.right;
var dataHeight = height - dataMargin.top - dataMargin.bottom;

var x_min = 0;
var x_max = 10;
var current_x_min = x_min;

var discrete_mode = false; // this is a kludge to fix centerOn bug
var pinned = false;

var x = d3.scaleLinear()
  .domain([x_min, x_max])
  .range([dataMargin.left, dataWidth]);

var y = d3.scaleLinear()
  .domain([1, 30])
  .range([dataMargin.top, dataHeight]);

var line = d3.line()
  .curve(d3.curveMonotoneX)
  .x(d => x(d.week))
  .y(d => y(d.rank));

var voronoi = d3.voronoi()
  .x(d => d.x)
  .y(d => d.y)
  .size([3200, height]);

var format = d3.format(".01f");

window.onload = function() {
  d3.json('api/rankings/2016', function(error, json) {
    if (error) {
      return console.warn(error);
    }
    data = json.results;
    $('#spinner-container').css('display', 'none');

    // find initial rankings for greensock
    var start_rankings = new Array(30);
    data.forEach(function(team) {
      let rank = team.rankings[0].rank;
      start_rankings[rank - 1] = '.' + team.slug;
    });
    start_rankings.reverse();

    /*
     * D3.js Code
     */
    var outer = d3.select(".chart").append("svg")
        .attr("style", "border: 1px solid black;")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom);

    var inner = outer
      .append("g")
        .attr("transform", `translate(${margin.left}, ${margin.top})`)
      .append("svg")
        .attr("width", dataWidth + dataMargin.left + dataMargin.right)
        .attr("height", dataHeight + dataMargin.top + dataMargin.bottom)
      .append('g')
        .attr("transform", `translate(${dataMargin.left}, ${dataMargin.top})`);

    var xAxis = d3.axisBottom(x);

    var gX = outer.append('g')
      .attr('transform', `translate(${margin.left + dataMargin.left}, ${height - margin.bottom - dataMargin.bottom + 5})`)
      .call(xAxis);

    var gY = outer.append('g')
        .attr('transform', `translate(${margin.left}, ${margin.top + dataMargin.top})`);

    var labels = gY.selectAll('.team-label')
      .data(data)
      .enter().append('text')
        .attr('class', d => `${d.slug} team-label`)
        .attr('text-anchor', 'end')
        .attr('transform', d => `translate(0, ${y(d.rankings[current_x_min].rank)})`)
        .text(d => d.name);

    var team = inner.selectAll('.team')
      .data(data)
      .enter().append('g')
        .attr('class', d => `${d.slug} team`)
      .append('path')
        .attr('d', d => line(d.rankings))
        .style('fill', 'none')
        .style('stroke-width', 1.5)
        .style('stroke', d => d.color)
        .attr('team', d => d.slug);

    var zoom = d3.zoom()
      .on('zoom', zoomed)
      .on('end', centerOnNearestBase)
      .translateExtent([[0,0], [3200, height + margin.top + margin.bottom]])
      .scaleExtent([1,1]);

    var zoomHandle = inner.append('rect')
      .attr('width', width)
      .attr('height', height)
      .attr('class', 'zoom-handle')
      .call(zoom);

    var allPoints = generateVoronoiPoints($('.team path'));

    var voronoiData = voronoi.polygons(allPoints);

    var voronoiPoly = inner.selectAll('.voronoi')
      .data(voronoiData)
      .enter().append('g')
        .attr('class', d => 'voronoi')
      .append('path')
        .attr('d', d => d ? "M" + d.join("L") + "Z" : null)
        .on('click', pin(team))
        .on('mouseover', highlight(team))
        .on('mouseout', highlightAll);

    function zoomed() {
      team.attr('transform', d3.event.transform);
      voronoiPoly.attr('transform', d3.event.transform);
      gX.call(xAxis.scale(d3.event.transform.rescaleX(x)));

      var x_min = format(x.invert(-d3.event.transform.x));
      var xFloor = Math.floor(x_min);
      var xCeil = Math.ceil(x_min);
      var percent = d3.easeCubic(x_min % 1);

      labels.attr('transform', function(d) {
        var floor = y(d.rankings[xFloor].rank);
        var ceil = y(d.rankings[xCeil].rank);
        var travel = ceil - floor;
        var newY = floor + ( travel * percent );
        return `translate(0, ${newY})`;
      });
    }

    /*
     * Panning Logic
     */
    function centerOnNearestBase() {
      if (discrete_mode) {
        // there's a bug here where if you hit the pan buttons too fast
        // we get into an infinite loop trying to center while another
        // zoom event is happening
        return;
      }
      var base = format(x.invert(-d3.event.transform.x)); // where the left hand of the axis lies
      var roundedBase = format(Math.round(base));
      if (Math.abs(x(roundedBase - base)) > 1)  {
        // if we're more than 1 pixel off
        centerOn(roundedBase);
      }
    }

    function centerOn(base) {
      var mX = x(base);
      var t = d3.zoomIdentity.translate(-mX, 0);
      zoomHandle
        .transition()
        .duration(200)
        .call(zoom.transform, t);
    }

    // Desktop Panning Controls
    var leftButton = d3.select('#left')
      .on('click', function() {
        discrete_mode = true;
        if (current_x_min > 0) {
          current_x_min--;
          centerOn(current_x_min);
        }
      });
    var rightButton = d3.select('#right')
      .on('click', function() {
        discrete_mode = true;
        current_x_min++;
        centerOn(current_x_min);
      });

    // Animate all this garbage in
    TweenMax.staggerFrom(start_rankings, 1, {opacity: 0}, 0.025);

  });

  function pin(team) {
    return function(team) {
      highlightTeam(team.data.slug);
      pinned = true;
    };
  }

  function highlightTeam(slug) {
    d3.selectAll('.team path')
      .transition()
      .duration(15)
      .ease(d3.easeLinear)
      .style('stroke-width', d => (slug === d.slug) ? '3px' : '1px')
      .style('stroke', d => (slug === d.slug) ? d.color : 'gray');
  }

  function highlight(team) {
    return function(team) {
      if (team && !pinned) {
        highlightTeam(team.data.slug);
      }
    };
  }

  function highlightAll() {
    if (!pinned) {
      d3.selectAll('.team path')
        .transition()
        .duration(15)
        .ease(d3.easeLinear)
        .style('stroke', d => d.color)
        .style('stroke-width', '1.5px');
    }
  }

  function samplePath(pathNode, precision) {
    var pathLength = pathNode.getTotalLength();
    var samples = [];
    for (let sample, sampleLength = 0; sampleLength <= pathLength; sampleLength += precision) {
      sample = pathNode.getPointAtLength(sampleLength);
      samples.push({
        x: sample.x,
        y: sample.y,
        slug: pathNode.__data__.slug // there is surely a better way to get this
      });
    }
    return samples;
  }

  function generateVoronoiPoints(paths) {
    var allPoints = [];
    for (var path of paths) {
      allPoints = allPoints.concat( samplePath(path, 15) );
    }
    return allPoints;
  }

};
<|endoftext|>


<commit_before>---
---

'use strict';

import gulp from 'gulp';
import gulpLoadPlugins from 'gulp-load-plugins';
import runSequence from 'run-sequence';
import browserSync from 'browser-sync';
import access from 'gulp-accessibility';
import swPrecache from 'sw-precache';
import rename from 'gulp-rename';

const $ = gulpLoadPlugins();

// Test our website accessibility
gulp.task('accessibility', function() {
  return gulp.src('./_site/**/*.html')
    .pipe(access({
      force: true,
      verbose: false, // true: to output error to console; false: output report files only
      options: {
          accessibilityLevel: 'WCAG2AA',
          reportLocation: 'accessibility-reports',
          reportLevels: {
              notice: true,
              warning: true,
              error: true
          }
      }
    }))
    .on('error', console.log)
    .pipe(access.report({reportType: 'txt'}))
    .pipe(rename({extname: '.txt'}))
    .pipe(gulp.dest('reports/json'));
});

// Minify the HTML.
gulp.task('minify-html', () => {
  return gulp.src('_site/**/*.html')
    .pipe($.htmlmin({
      removeComments: true,
      collapseWhitespace: true,
      collapseBooleanAttributes: true,
      removeAttributeQuotes: true,
      removeRedundantAttributes: true,
      removeEmptyAttributes: true,
      removeScriptTypeAttributes: true,
      removeStyleLinkTypeAttributes: true,
      removeOptionalTags: true
    }))
    .pipe(gulp.dest('_site'));
});

// Optimize images.
gulp.task('minify-images', () => {
  gulp.src('images/**/*')
    .pipe($.imagemin({
      progressive: true,
      interlaced: true
    }))
    .pipe(gulp.dest('_site/images'));
});

// Concatenate, transpiles ES2015 code to ES5 and minify JavaScript.
gulp.task('scripts', () => {
  gulp.src([
    // Note: You need to explicitly list your scripts here in the right order
    // to be correctly concatenated
    './_scripts/vendor/medium-lightbox.js',
    './_scripts/vendor/anime.js',
    './_scripts/vendor/headroom.js',
    './_scripts/main.js'
  ])
    // .pipe($.babel())
    .pipe($.concat('main.min.js'))
    .pipe($.uglify({preserveComments: 'some'}))
    .pipe(gulp.dest('scripts'));
});

// Minify and add prefix to css.
gulp.task('css', () => {
  const AUTOPREFIXER_BROWSERS = [
    'ie >= 10',
    'ie_mob >= 10',
    'ff >= 30',
    'chrome >= 34',
    'safari >= 7',
    'opera >= 23',
    'ios >= 7',
    'android >= 4.4',
    'bb >= 10'
  ];

  return gulp.src('css/main.css')
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe($.cssnano())
    .pipe(gulp.dest('_site/css'));
});

// Compile scss to css.
gulp.task('scss', () => {
    return gulp.src('scss/main.scss')
        .pipe($.sass({
            includePaths: ['css'],
            onError: browserSync.notify
        }))
        .pipe(gulp.dest('css'));
});

// Watch change in files.
gulp.task('serve', ['jekyll-build-dev'], () => {
  browserSync.init({
    notify: false,
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: '_site',
    port: 3000
  });

  // Watch html changes.
  gulp.watch([
    'css/**/*.css',
    'scripts/**/*.js',
    '_includes/**/*.html',
    '_layouts/**/*.html',
    '_posts/**/*.md',
    '*.md',
    '*.html',
    '_config.yml'
  ], ['jekyll-build-dev', browserSync.reload]);

  // Watch scss changes.
  gulp.watch('scss/**/*.scss', ['scss']);

  // Watch JavaScript changes.
  gulp.watch('_scripts/**/*.js', ['scripts']);
});

gulp.task('generate-service-worker', function(callback) {
  var path = require('path');
  var rootDir = '_site';

  swPrecache.write(path.join(rootDir, 'sw.js'), {
    staticFileGlobs: [rootDir + '/**/*.{js,html,css,png,jpg,gif,json}'],
    stripPrefix: rootDir,
    replacePrefix: '{{ site | baseurl }}'
  }, callback);
});

gulp.task('jekyll-build-prod', ['scripts', 'scss'], $.shell.task([ 'jekyll build' ]));
gulp.task('jekyll-build-dev', ['scripts', 'scss'], $.shell.task([ 'jekyll build --config _config.yml,_config-dev.yml' ]));

// Default task.
gulp.task('default', () =>
  runSequence(
    'scss',
    'jekyll-build-dev',
    'minify-html',
    'css',
    'generate-service-worker',
    'minify-images'
  )
);

// Depoly website to gh-pages.
gulp.task('gh-pages', () => {
  return gulp.src('./_site/**/*')
    .pipe($.ghPages());
});

gulp.task('deploy', () => {
  runSequence(
    'scss',
    'jekyll-build-prod',
    'minify-html',
    'css',
    'generate-service-worker',
    'minify-images',
    'gh-pages',
    'jekyll-build-dev' // reset local back to development config after deploy
  )
});

<commit_msg>edit url in babel file<commit_after>'use strict';

import gulp from 'gulp';
import gulpLoadPlugins from 'gulp-load-plugins';
import runSequence from 'run-sequence';
import browserSync from 'browser-sync';
import access from 'gulp-accessibility';
import swPrecache from 'sw-precache';
import rename from 'gulp-rename';

const $ = gulpLoadPlugins();

// Test our website accessibility
gulp.task('accessibility', function() {
  return gulp.src('./_site/**/*.html')
    .pipe(access({
      force: true,
      verbose: false, // true: to output error to console; false: output report files only
      options: {
          accessibilityLevel: 'WCAG2AA',
          reportLocation: 'accessibility-reports',
          reportLevels: {
              notice: true,
              warning: true,
              error: true
          }
      }
    }))
    .on('error', console.log)
    .pipe(access.report({reportType: 'txt'}))
    .pipe(rename({extname: '.txt'}))
    .pipe(gulp.dest('reports/json'));
});

// Minify the HTML.
gulp.task('minify-html', () => {
  return gulp.src('_site/**/*.html')
    .pipe($.htmlmin({
      removeComments: true,
      collapseWhitespace: true,
      collapseBooleanAttributes: true,
      removeAttributeQuotes: true,
      removeRedundantAttributes: true,
      removeEmptyAttributes: true,
      removeScriptTypeAttributes: true,
      removeStyleLinkTypeAttributes: true,
      removeOptionalTags: true
    }))
    .pipe(gulp.dest('_site'));
});

// Optimize images.
gulp.task('minify-images', () => {
  gulp.src('images/**/*')
    .pipe($.imagemin({
      progressive: true,
      interlaced: true
    }))
    .pipe(gulp.dest('_site/images'));
});

// Concatenate, transpiles ES2015 code to ES5 and minify JavaScript.
gulp.task('scripts', () => {
  gulp.src([
    // Note: You need to explicitly list your scripts here in the right order
    // to be correctly concatenated
    './_scripts/vendor/medium-lightbox.js',
    './_scripts/vendor/anime.js',
    './_scripts/vendor/headroom.js',
    './_scripts/main.js'
  ])
    // .pipe($.babel())
    .pipe($.concat('main.min.js'))
    .pipe($.uglify({preserveComments: 'some'}))
    .pipe(gulp.dest('scripts'));
});

// Minify and add prefix to css.
gulp.task('css', () => {
  const AUTOPREFIXER_BROWSERS = [
    'ie >= 10',
    'ie_mob >= 10',
    'ff >= 30',
    'chrome >= 34',
    'safari >= 7',
    'opera >= 23',
    'ios >= 7',
    'android >= 4.4',
    'bb >= 10'
  ];

  return gulp.src('css/main.css')
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe($.cssnano())
    .pipe(gulp.dest('_site/css'));
});

// Compile scss to css.
gulp.task('scss', () => {
    return gulp.src('scss/main.scss')
        .pipe($.sass({
            includePaths: ['css'],
            onError: browserSync.notify
        }))
        .pipe(gulp.dest('css'));
});

// Watch change in files.
gulp.task('serve', ['jekyll-build-dev'], () => {
  browserSync.init({
    notify: false,
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: '_site',
    port: 3000
  });

  // Watch html changes.
  gulp.watch([
    'css/**/*.css',
    'scripts/**/*.js',
    '_includes/**/*.html',
    '_layouts/**/*.html',
    '_posts/**/*.md',
    '*.md',
    '*.html',
    '_config.yml'
  ], ['jekyll-build-dev', browserSync.reload]);

  // Watch scss changes.
  gulp.watch('scss/**/*.scss', ['scss']);

  // Watch JavaScript changes.
  gulp.watch('_scripts/**/*.js', ['scripts']);
});

gulp.task('generate-service-worker', function(callback) {
  var path = require('path');
  var rootDir = '_site';

  swPrecache.write(path.join(rootDir, 'sw.js'), {
    staticFileGlobs: [rootDir + '/**/*.{js,html,css,png,jpg,gif,json}'],
    stripPrefix: rootDir,
    replacePrefix: './'
  }, callback);
});

gulp.task('jekyll-build-prod', ['scripts', 'scss'], $.shell.task([ 'jekyll build' ]));
gulp.task('jekyll-build-dev', ['scripts', 'scss'], $.shell.task([ 'jekyll build --config _config.yml,_config-dev.yml' ]));

// Default task.
gulp.task('default', () =>
  runSequence(
    'scss',
    'jekyll-build-dev',
    'minify-html',
    'css',
    'generate-service-worker',
    'minify-images'
  )
);

// Depoly website to gh-pages.
gulp.task('gh-pages', () => {
  return gulp.src('./_site/**/*')
    .pipe($.ghPages());
});

gulp.task('deploy', () => {
  runSequence(
    'scss',
    'jekyll-build-prod',
    'minify-html',
    'css',
    'generate-service-worker',
    'minify-images',
    'gh-pages',
    'jekyll-build-dev' // reset local back to development config after deploy
  )
});

<|endoftext|>


<commit_before>'use strict'

// Load global config and gulp
import config from './foley.json'
import gulp from 'gulp'

// Load modules to run tasks from files
import requireDir from 'require-dir'
import runSequence from 'run-sequence'
const tasks = requireDir(__dirname + '/tasks') // eslint-disable-line

// Watch task
gulp.task('watch', () => {
  gulp.watch(config.paths.scss + '**/*.scss', ['scss'])
  gulp.watch(config.paths.spec + '**/*[Ss]pec.js', ['jasmine'])
  gulp.watch(config.paths.js + '**/*.js', ['jasmine', 'jslint', 'webpack'])
  gulp.watch(config.paths.img + '{,**/}*.{png,jpg,gif,svg}', ['img'])
  gulp.watch(config.paths.icons + '**/*.svg', ['svgsprite'])
  gulp.watch([config.paths.fonts + '**/*', config.paths.files + '**/*'], ['copy'])
  gulp.watch([config.paths.layouts + '**/*.hbs', config.paths.pages + '**/*.hbs', config.paths.partials + '**/*.hbs'], ['metalsmith'])
})

// jsdev Watch task
gulp.task('jsdevwatch', () => {
  gulp.watch(config.paths.spec + '**/*[Ss]pec.js', ['jasmine', 'specsjslint'])
  gulp.watch(config.paths.js + '**/*.js', ['jasmine'])
})

// Build website, either with development or minified assets and run server with live reloading
gulp.task('default', callback => {
  runSequence(
    'jasmine',
    'jslint',
    'clean',
    'metalsmith',
    ['htmlmin', 'svgsprite', 'scss', 'webpack', 'img', 'copy'],
    ['browsersync', 'watch'],
    callback
  )
})

// Build website, either with development or minified assets depending on flag
gulp.task('deploy', callback => {
  runSequence(
    'jasmine',
    'jslint',
    'clean',
    'metalsmith',
    ['htmlmin', 'svgsprite', 'scss', 'webpack', 'img', 'copy'],
    'crticalcss',
    callback
  )
})

// Run tests and watch js/spec files
gulp.task('jsdev', callback => {
  runSequence(
    'jasmine',
    'specsjslint',
    'jsdevwatch',
    callback
  )
})

// Run the audit task to check code standards
gulp.task('auditcode', callback => {
  runSequence(
    'scsslint',
    'jslint',
    callback
  )
})
<commit_msg>lint all the things in jsdev task<commit_after>'use strict'

// Load global config and gulp
import config from './foley.json'
import gulp from 'gulp'

// Load modules to run tasks from files
import requireDir from 'require-dir'
import runSequence from 'run-sequence'
const tasks = requireDir(__dirname + '/tasks') // eslint-disable-line

// Watch task
gulp.task('watch', () => {
  gulp.watch(config.paths.scss + '**/*.scss', ['scss'])
  gulp.watch(config.paths.spec + '**/*[Ss]pec.js', ['jasmine'])
  gulp.watch(config.paths.js + '**/*.js', ['jasmine', 'jslint', 'webpack'])
  gulp.watch(config.paths.img + '{,**/}*.{png,jpg,gif,svg}', ['img'])
  gulp.watch(config.paths.icons + '**/*.svg', ['svgsprite'])
  gulp.watch([config.paths.fonts + '**/*', config.paths.files + '**/*'], ['copy'])
  gulp.watch([config.paths.layouts + '**/*.hbs', config.paths.pages + '**/*.hbs', config.paths.partials + '**/*.hbs'], ['metalsmith'])
})

// jsdev Watch task
gulp.task('jsdevwatch', () => {
  gulp.watch(config.paths.spec + '**/*[Ss]pec.js', ['jasmine', 'specsjslint'])
  gulp.watch(config.paths.js + '**/*.js', ['jasmine', 'jslint'])
})

// Build website, either with development or minified assets and run server with live reloading
gulp.task('default', callback => {
  runSequence(
    'jasmine',
    'jslint',
    'clean',
    'metalsmith',
    ['htmlmin', 'svgsprite', 'scss', 'webpack', 'img', 'copy'],
    ['browsersync', 'watch'],
    callback
  )
})

// Build website, either with development or minified assets depending on flag
gulp.task('deploy', callback => {
  runSequence(
    'jasmine',
    'jslint',
    'clean',
    'metalsmith',
    ['htmlmin', 'svgsprite', 'scss', 'webpack', 'img', 'copy'],
    'crticalcss',
    callback
  )
})

// Run tests and watch js/spec files
gulp.task('jsdev', callback => {
  runSequence(
    'jasmine',
    'jslint',
    'specsjslint',
    'jsdevwatch',
    callback
  )
})

// Run the audit task to check code standards
gulp.task('auditcode', callback => {
  runSequence(
    'scsslint',
    'jslint',
    callback
  )
})
<|endoftext|>


<commit_before>var auth = require('../auth');
var consts = require('../../../shared/constants');
var service = require('./service');

var init = function(io) {
    io.of(consts.socket.playerSync.NAMESPACE).use(auth.authorize);

    io.of(consts.socket.playerSync.NAMESPACE).on('connection', function(socket) {
        // console.log(socket.id + ' connected (controller)');
        socket.on(consts.socket.playerSync.REGISTER, function(data) {
            auth.getProfile(socket).then(function(profile) {
                if (!socket.connected) {
                    // console.log(socket.id + ' got disconnected before completing registration');
                    return;
                }

                var broadcastConnect = function(player) {
                    socket.broadcast.emit(consts.socket.playerSync.OTHER_CONNECT, player);
                };

                var emitConnect = function(player) {
                    socket.emit(consts.socket.playerSync.OTHER_CONNECT, player);
                };

                service.register(socket.id, profile, data, broadcastConnect, emitConnect);
            });
        });

        socket.on(consts.socket.playerSync.CHANGE, function(data) {
            var broadcastChange = function(player) {
                socket.broadcast.emit(consts.socket.playerSync.OTHER_CHANGE, player);
            };

            service.update(socket.id, data, broadcastChange);
        });

        socket.on('disconnect', function() {
            // console.log(socket.id + ' disconnected (controller)');
            var broadcastDisconnect = function(playerId) {
                socket.broadcast.emit(consts.socket.playerSync.OTHER_DISCONNECT, playerId);
            };

            service.disconnect(socket.id, broadcastDisconnect);
        });
    });
};

module.exports = {
    init: init
};
<commit_msg>using volatile to transmit position changes<commit_after>var auth = require('../auth');
var consts = require('../../../shared/constants');
var service = require('./service');

var init = function(io) {
    io.of(consts.socket.playerSync.NAMESPACE).use(auth.authorize);

    io.of(consts.socket.playerSync.NAMESPACE).on('connection', function(socket) {
        // console.log(socket.id + ' connected (controller)');
        socket.on(consts.socket.playerSync.REGISTER, function(data) {
            auth.getProfile(socket).then(function(profile) {
                if (!socket.connected) {
                    // console.log(socket.id + ' got disconnected before completing registration');
                    return;
                }

                var broadcastConnect = function(player) {
                    socket.broadcast.emit(consts.socket.playerSync.OTHER_CONNECT, player);
                };

                var emitConnect = function(player) {
                    socket.emit(consts.socket.playerSync.OTHER_CONNECT, player);
                };

                service.register(socket.id, profile, data, broadcastConnect, emitConnect);
            });
        });

        socket.on(consts.socket.playerSync.CHANGE, function(data) {
            var broadcastChange = function(player) {
                socket.broadcast.volatile.emit(consts.socket.playerSync.OTHER_CHANGE, player);
            };

            service.update(socket.id, data, broadcastChange);
        });

        socket.on('disconnect', function() {
            // console.log(socket.id + ' disconnected (controller)');
            var broadcastDisconnect = function(playerId) {
                socket.broadcast.emit(consts.socket.playerSync.OTHER_DISCONNECT, playerId);
            };

            service.disconnect(socket.id, broadcastDisconnect);
        });
    });
};

module.exports = {
    init: init
};
<|endoftext|>


<commit_before>import gulp from 'gulp'
import browserify from 'browserify'
import watchify from 'watchify'
import coffeeify from 'coffeeify'
import rimraf from 'rimraf'
import source from 'vinyl-source-stream'
import sass from 'gulp-sass'
import browserSyncModule from 'browser-sync'
import autoprefixer from 'gulp-autoprefixer'
import gutil from 'gulp-util'
import coffee from 'gulp-coffee'
import symlink from 'gulp-symlink'
import plumber from 'gulp-plumber'
import notify from 'gulp-notify'
import uglify from 'gulp-uglify'
import minifyCss from 'gulp-minify-css'
import pug from 'gulp-pug'
import haml from 'gulp-haml'
import rename from 'gulp-rename'
import buffer from 'vinyl-buffer'

let browserSync = browserSyncModule.create()

const config = {
  inFiles: {
    html: 'src/*.html',
    pug: 'src/*.pug',
    haml: 'src/*.haml',
    js:   ['src/coffeescript/application.coffee'],
    css:  'src/sass/style.{sass,scss,css}'
  },
  out_development: 'development/',
  out_production: 'production/',
  outFiles: {
    js:   'app.js',
    css:  'style.css',
  },
}

let out_directory = config.out_development

gutil.log('- - - - - - - - - - - - - - -')
gutil.log('          Starting!          ')
gutil.log('')
gutil.log(' _._     _,-\'""`-._')
gutil.log('(,-.`._,\'(       |\`-/|')
gutil.log('    `-.-\' \ )-`( , o o)')
gutil.log('-bf-      `-    \`_`"\'-')
gutil.log('')
gutil.log('- - - - - - - - - - - - - - -')

function getBundler() {
  if (!global.bundler) {
    let conf = {
      entries: config.inFiles.js,
      paths: ['./node_modules', './src'],
      debug: true,
    }
    Object.assign(conf, watchify.args)

    global.bundler = watchify(browserify(conf)).transform(coffeeify)
  }
  return global.bundler
}

// -------------------------------------------------------
// Set development directory
gulp.task('set-development', function () {
  out_directory = config.out_development
})

// -------------------------------------------------------
// Set production directory
gulp.task('set-production', function () {
  out_directory = config.out_production
})

// -------------------------------------------------------
//
// DEVELOPMENT TASK
//
// -------------------------------------------------------

// -------------------------------------------------------
// Utility: A `rm -rf` util for nodejs
gulp.task('clean', function (cb) {
  return rimraf(out_directory, cb)
})

// -------------------------------------------------------
// Development: Open server
gulp.task('server', function () {
  return browserSync.init({
    server: {baseDir: out_directory},
    ui: false,
    notify: false
  })
})

// -------------------------------------------------------
// Development: Create Symlink
gulp.task('symlink', function () {
  return gulp.src(['src/images/', 'src/fonts/', 'src/icons/'])
  .pipe( symlink( [
      out_directory + 'images',
      out_directory + 'fonts',
      out_directory + 'icons'
    ], {force: true} )
  )
})

// -------------------------------------------------------
// Development: Compile Js and stream to browser
gulp.task('js', function () {
    return getBundler().bundle()
    .pipe(plumber({errorHandler: (err) => {
        notify.onError({ title: "Gulp", subtitle: "Failure!", message: "Error: <%= error.message %>", sound: "Beep" })(err)
        this.emit("end")
      }
    }))
    .pipe(source(config.outFiles.js))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Js compiled' }))
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
// Development: Compile Sass and stream to browser
gulp.task('sass', function () {
  return gulp.src(config.inFiles.css)
    .pipe(plumber({errorHandler: (err) => {
        notify.onError({ title: "Gulp", subtitle: "Failure!", message: "Error: <%= error.message %>", sound: "Beep" })(err)
        this.emit("end")
      }
    }))
    .pipe(sass({includePaths: 'node_modules/'}))
    .pipe(autoprefixer({ browsers: ['> 5% in IT', 'ie >= 8'] }))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Sass compiled' }))
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
// Development: Copy HTML files
gulp.task('html', function () {
  return gulp.src(config.inFiles.html)
    .pipe(gulp.dest(out_directory)) // Just copy.
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
// Development: Compile Pug files
gulp.task('pug', function () {
  return gulp.src(config.inFiles.pug)
    .pipe(pug())
    .pipe(gulp.dest(out_directory)) // Just copy.
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
// Development: Compile Pug files
gulp.task('haml', function () {
  return gulp.src(config.inFiles.haml)
    .pipe(haml())
    .pipe(gulp.dest(out_directory)) // Just copy.
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
gulp.task('watch', ['symlink', 'js', 'sass', 'pug', 'html', 'server'], function () {
  // FIXME: initial development is done twice
  getBundler().on('update', () => gulp.start('js'))
  gulp.watch('**/*.pug', ['pug'])
  gulp.watch('**/*.coffee', ['js'])
  gulp.watch('**/*.{sass,scss,css}', ['sass'])
  gulp.watch(config.inFiles.html, ['html'])
})

// -------------------------------------------------------
//
// PRODUCTION TASK
//
// -------------------------------------------------------

// -------------------------------------------------------
// Production: Compile JS
gulp.task('compile-js', function () {
  browserify({
      entries: ['src/coffeescript/application.coffee'],
      debug: true,
      extensions: [".coffee"],
      transform: ["coffeeify"]
    })
    .bundle()
    .pipe(source(config.outFiles.js))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Compile JS task complete' }))
});

// -------------------------------------------------------
// Production: Copy And Compress JS
gulp.task('uglify-js', function() {
  browserify({
      entries: ['src/coffeescript/application.coffee'],
      debug: true,
      extensions: [".coffee"],
      transform: ["coffeeify"]
    })
    .bundle()
    .pipe(source(config.outFiles.js))
    .pipe(buffer())
    .pipe(uglify())
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Compile JS task complete' }))
});

// -------------------------------------------------------
// Production: Compile SASS
gulp.task('compile-sass', function () {
  return gulp.src(config.inFiles.css)
    .pipe(sass({includePaths: 'node_modules/'}))
    .pipe(autoprefixer({ browsers: ['> 5% in IT', 'ie >= 8'] }))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'SASS compiled' }))
})

// -------------------------------------------------------
// Production: Copy And Compress CSS
gulp.task('minify-css', function() {
  return gulp.src(config.inFiles.css)
    .pipe(sass({includePaths: 'node_modules/'}))
    .pipe(autoprefixer({ browsers: ['> 5% in IT', 'ie >= 8'] }))
    .pipe(minifyCss({keepSpecialComments: 0}))
    .pipe(rename(config.outFiles.css))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Minify CSS task complete' }))
});

// -------------------------------------------------------
// Production: Copy HTML files
gulp.task('copy:html', ['pug', 'haml'], function () {
  return gulp.src(['src/*.html'])
  .pipe(gulp.dest(out_directory))
  .pipe(notify({ message: 'Copy HTML task complete' }))
});

// -------------------------------------------------------
// Production: Copy Images files
gulp.task('copy:images', function () {
  return gulp.src(['src/images/**/*'])
  .pipe(gulp.dest(out_directory + 'images'))
  .pipe(notify({ message: 'Copy images task complete' }))
});

// -------------------------------------------------------
// Production: Copy Fonts files
gulp.task('copy:fonts', function () {
  return gulp.src(['src/fonts/**/*'])
  .pipe(gulp.dest(out_directory + 'fonts'))
  .pipe(notify({ message: 'Copy fonts task complete' }))
});

// -------------------------------------------------------
// Production: Copy Icons files
gulp.task('copy:icons', function () {
  return gulp.src(['src/icons/**/*'])
  .pipe(gulp.dest(out_directory + 'icons'))
  .pipe(notify({ message: 'Copy icons task complete' }))
});
// -------------------------------------------------------

gulp.task('build:unminified', ['copy:html', 'copy:images', 'copy:fonts', 'copy:icons', 'compile-sass', 'compile-js'], function () {})
gulp.task('build:minified', ['copy:html', 'copy:images', 'copy:fonts', 'copy:icons', 'minify-css', 'uglify-js'], function () {})

gulp.task('production', ['set-production', 'build:minified'], function () {})
gulp.task('production:minified', ['set-production', 'build:minified'], function () {})
gulp.task('production:unminified', ['set-production', 'build:unminified'], function () {})

<commit_msg>Minor fixes to Gulpfile<commit_after>import gulp from 'gulp'
import browserify from 'browserify'
import watchify from 'watchify'
import coffeeify from 'coffeeify'
import rimraf from 'rimraf'
import source from 'vinyl-source-stream'
import sass from 'gulp-sass'
import browserSyncModule from 'browser-sync'
import autoprefixer from 'gulp-autoprefixer'
import gutil from 'gulp-util'
import coffee from 'gulp-coffee'
import symlink from 'gulp-symlink'
import plumber from 'gulp-plumber'
import notify from 'gulp-notify'
import uglify from 'gulp-uglify'
import minifyCss from 'gulp-minify-css'
import pug from 'gulp-pug'
import haml from 'gulp-haml'
import rename from 'gulp-rename'
import buffer from 'vinyl-buffer'

let browserSync = browserSyncModule.create()

const config = {
  inFiles: {
    html: 'src/*.html',
    pug: 'src/*.pug',
    haml: 'src/*.haml',
    js:   ['src/coffeescript/application.coffee'],
    css:  'src/sass/style.{sass,scss,css}'
  },
  out_development: 'development/',
  out_production: 'production/',
  outFiles: {
    js:   'app.js',
    css:  'style.css',
  },
}

let out_directory = config.out_development

gutil.log('- - - - - - - - - - - - - - -')
gutil.log('          Starting!          ')
gutil.log('')
gutil.log(' _._     _,-\'""`-._')
gutil.log('(,-.`._,\'(       |\`-/|')
gutil.log('    `-.-\' \ )-`( , o o)')
gutil.log('-bf-      `-    \`_`"\'-')
gutil.log('')
gutil.log('- - - - - - - - - - - - - - -')

function getBundler() {
  if (!global.bundler) {
    let conf = {
      entries: config.inFiles.js,
      paths: ['./node_modules', './src'],
      debug: true,
    }
    Object.assign(conf, watchify.args)

    global.bundler = watchify(browserify(conf)).transform(coffeeify)
  }
  return global.bundler
}

// -------------------------------------------------------
// Set development directory
gulp.task('set-development', function () {
  out_directory = config.out_development
})

// -------------------------------------------------------
// Set production directory
gulp.task('set-production', function () {
  out_directory = config.out_production
})

// -------------------------------------------------------
//
// DEVELOPMENT TASK
//
// -------------------------------------------------------

// -------------------------------------------------------
// Utility: A `rm -rf` util for nodejs
gulp.task('clean', function (cb) {
  return rimraf(out_directory, cb)
})

// -------------------------------------------------------
// Development: Open server
gulp.task('server', function () {
  return browserSync.init({
    server: {baseDir: out_directory},
    ui: false,
    notify: false
  })
})

// -------------------------------------------------------
// Development: Create Symlink
gulp.task('symlink', function () {
  return gulp.src(['src/images/', 'src/fonts/', 'src/icons/'])
  .pipe( symlink( [
      out_directory + 'images',
      out_directory + 'fonts',
      out_directory + 'icons'
    ], {force: true} )
  )
})

// -------------------------------------------------------
// Development: Compile Js and stream to browser
gulp.task('js', function () {
    return getBundler().bundle()
    .pipe(plumber({errorHandler: (err) => {
        notify.onError({ title: "Gulp", subtitle: "Failure!", message: "Error: <%= error.message %>", sound: "Beep" })(err)
        this.emit("end")
      }
    }))
    .pipe(source(config.outFiles.js))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Js compiled' }))
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
// Development: Compile Sass and stream to browser
gulp.task('sass', function () {
  return gulp.src(config.inFiles.css)
    .pipe(plumber({errorHandler: (err) => {
        notify.onError({ title: "Gulp", subtitle: "Failure!", message: "Error: <%= error.message %>", sound: "Beep" })(err)
        this.emit("end")
      }
    }))
    .pipe(sass({includePaths: 'node_modules/'}))
    .pipe(autoprefixer({ browsers: ['> 5% in IT', 'ie >= 8'] }))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Sass compiled' }))
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
// Development: Copy HTML files
gulp.task('html', function () {
  return gulp.src(config.inFiles.html)
    .pipe(gulp.dest(out_directory)) // Just copy.
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
// Development: Compile Pug files
gulp.task('pug', function () {
  return gulp.src(config.inFiles.pug)
    .pipe(pug())
    .pipe(gulp.dest(out_directory)) // Just copy.
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
// Development: Compile Haml files
gulp.task('haml', function () {
  return gulp.src(config.inFiles.haml)
    .pipe(haml())
    .pipe(gulp.dest(out_directory)) // Just copy.
    .pipe(browserSync.stream())
})

// -------------------------------------------------------
gulp.task('watch', ['symlink', 'js', 'sass', 'pug', 'haml', 'html', 'server'], function () {
  // FIXME: initial development is done twice
  getBundler().on('update', () => gulp.start('js', 'sass', 'pug', 'haml', 'html'))
  gulp.watch(config.inFiles.pug, ['pug'])
  gulp.watch(config.inFiles.haml, ['haml'])
  gulp.watch(config.inFiles.html, ['html'])
  gulp.watch('**/*.coffee', ['js'])
  gulp.watch('**/*.{sass,scss,css}', ['sass'])
})

// -------------------------------------------------------
//
// PRODUCTION TASK
//
// -------------------------------------------------------

// -------------------------------------------------------
// Production: Compile JS
gulp.task('compile-js', function () {
  browserify({
      entries: ['src/coffeescript/application.coffee'],
      debug: true,
      extensions: [".coffee"],
      transform: ["coffeeify"]
    })
    .bundle()
    .pipe(source(config.outFiles.js))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Compile JS task complete' }))
});

// -------------------------------------------------------
// Production: Copy And Compress JS
gulp.task('uglify-js', function() {
  browserify({
      entries: ['src/coffeescript/application.coffee'],
      debug: true,
      extensions: [".coffee"],
      transform: ["coffeeify"]
    })
    .bundle()
    .pipe(source(config.outFiles.js))
    .pipe(buffer())
    .pipe(uglify())
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Compile JS task complete' }))
});

// -------------------------------------------------------
// Production: Compile SASS
gulp.task('compile-sass', function () {
  return gulp.src(config.inFiles.css)
    .pipe(sass({includePaths: 'node_modules/'}))
    .pipe(autoprefixer({ browsers: ['> 5% in IT', 'ie >= 8'] }))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'SASS compiled' }))
})

// -------------------------------------------------------
// Production: Copy And Compress CSS
gulp.task('minify-css', function() {
  return gulp.src(config.inFiles.css)
    .pipe(sass({includePaths: 'node_modules/'}))
    .pipe(autoprefixer({ browsers: ['> 5% in IT', 'ie >= 8'] }))
    .pipe(minifyCss({keepSpecialComments: 0}))
    .pipe(rename(config.outFiles.css))
    .pipe(gulp.dest(out_directory))
    .pipe(notify({ message: 'Minify CSS task complete' }))
});

// -------------------------------------------------------
// Production: Copy HTML files
gulp.task('copy:html', ['pug', 'haml'], function () {
  return gulp.src(['src/*.html'])
  .pipe(gulp.dest(out_directory))
  .pipe(notify({ message: 'Copy HTML task complete' }))
});

// -------------------------------------------------------
// Production: Copy Images files
gulp.task('copy:images', function () {
  return gulp.src(['src/images/**/*'])
  .pipe(gulp.dest(out_directory + 'images'))
  .pipe(notify({ message: 'Copy images task complete' }))
});

// -------------------------------------------------------
// Production: Copy Fonts files
gulp.task('copy:fonts', function () {
  return gulp.src(['src/fonts/**/*'])
  .pipe(gulp.dest(out_directory + 'fonts'))
  .pipe(notify({ message: 'Copy fonts task complete' }))
});

// -------------------------------------------------------
// Production: Copy Icons files
gulp.task('copy:icons', function () {
  return gulp.src(['src/icons/**/*'])
  .pipe(gulp.dest(out_directory + 'icons'))
  .pipe(notify({ message: 'Copy icons task complete' }))
});
// -------------------------------------------------------

gulp.task('build:unminified', ['copy:html', 'copy:images', 'copy:fonts', 'copy:icons', 'compile-sass', 'compile-js'], function () {})
gulp.task('build:minified', ['copy:html', 'copy:images', 'copy:fonts', 'copy:icons', 'minify-css', 'uglify-js'], function () {})

gulp.task('production', ['set-production', 'build:minified'], function () {})
gulp.task('production:minified', ['set-production', 'build:minified'], function () {})
gulp.task('production:unminified', ['set-production', 'build:unminified'], function () {})

<|endoftext|>