text: var args = require('yargs').argv,
      path = require('path'),
      gulp = require('gulp'),
      $ = require('gulp-load-plugins')(),
      gulpsync = $.sync(gulp),
      browserSync = require('browser-sync'),
      reload = browserSync.reload,
      PluginError = $.util.PluginError,
      del = require('del');
  
  // production mode (see build task)
  var isProduction = false;
  // styles sourcemaps
  var useSourceMaps = false;
  
  // Switch to sass mode.
  // Example:
  //    gulp --usesass
  var useSass = args.usesass;
  
  // ignore everything that begins with underscore
  var hidden_files = '**/_*.*';
  var ignored_files = '!' + hidden_files;
  
  // MAIN PATHS
  var paths = {
      app: '../app/',
      styles: 'less/',
      scripts: 'js/'
  }
  
  // if sass -> switch to sass folder
  if (useSass) {
      log('Using SASS stylesheets...');
      paths.styles = 'sass/';
  }
  
  
  // VENDOR CONFIG
  var vendor = {
      // vendor scripts required to start the app
      base: {
          source: require('./vendor.base.json'),
          js: 'base.js',
          css: 'base.css'
      },
      // vendor scripts to make the app work. Usually via lazy loading
      app: {
          source: require('./vendor.json'),
          dest: '../vendor'
      }
  };
  
  
  // SOURCES CONFIG
  var source = {
      scripts: [
          //paths.scripts + 'utils.js',
          paths.scripts + 'app.module.js',
          // template modules
          paths.scripts + 'modules/**/*.module.js',
          paths.scripts + 'modules/**/*.js',
          // custom modules
          paths.scripts + 'custom/**/*.module.js',
          paths.scripts + 'custom/**/*.js'
      ],
      styles: {
          app: [paths.styles + '*.*'],
          themes: [paths.styles + 'themes/*'],
          watch: [paths.styles + '**/*', '!' + paths.styles + 'themes/*']
      }
  };
  
  // BUILD TARGET CONFIG
  var build = {
      scripts: paths.app + 'js',
      styles: paths.app + 'css'
  };
  
  // PLUGINS OPTIONS
  
  var prettifyOpts = {
      indent_char: ' ',
      indent_size: 3,
      unformatted: ['a', 'sub', 'sup', 'b', 'i', 'u', 'pre', 'code']
  };
  
  var vendorUglifyOpts = {
      mangle: {
          except: ['$super'] // rickshaw requires this
      }
  };
  
  var compassOpts = {
      project: path.join(__dirname, '../'),
      css: 'app/css',
      sass: 'master/sass/',
      image: 'app/img'
  };
  
  var compassOptsThemes = {
      project: path.join(__dirname, '../'),
      css: 'app/css',
      sass: 'master/sass/themes/', // themes in a subfolders
      image: 'app/img'
  };
  
  var cssnanoOpts = {
      safe: true,
      discardUnused: false, // no remove @font-face
      reduceIdents: false // no change on @keyframes names
  }
  
  //---------------
  // TASKS
  //---------------
  
  
  // JS APP
  gulp.task('scripts:app', function() {
      log('Building scripts..');
      // Minify and copy all JavaScript (except vendor scripts)
      return gulp.src(source.scripts)
          .pipe($.jsvalidate())
          .on('error', handleError)
          .pipe($.if(useSourceMaps, $.sourcemaps.init()))
          .pipe($.concat('app.js'))
          .pipe($.ngAnnotate())
          .on('error', handleError)
          .pipe($.if(isProduction, $.uglify({
              preserveComments: 'some'
          })))
          .on('error', handleError)
          .pipe($.if(useSourceMaps, $.sourcemaps.write()))
          .pipe(gulp.dest(build.scripts))
          .pipe(reload({
              stream: true
          }));
  });
  
  
  // VENDOR BUILD
  gulp.task('vendor', gulpsync.sync(['vendor:base', 'vendor:app']));
  
  // Build the base script to start the application from vendor assets
  gulp.task('vendor:base', function() {
      log('Copying base vendor assets..');
  
      var jsFilter = $.filter('**/*.js', {
          restore: true
      });
      var cssFilter = $.filter('**/*.css', {
          restore: true
      });
  
      return gulp.src(vendor.base.source)
          .pipe($.expectFile(vendor.base.source))
          .pipe(jsFilter)
              .pipe($.concat(vendor.base.js))
              .pipe($.if(isProduction, $.uglify()))
              .pipe(gulp.dest(build.scripts))
          .pipe(jsFilter.restore())
          .pipe(cssFilter)
              .pipe($.concat(vendor.base.css))
              .pipe($.if(isProduction, $.cssnano(cssnanoOpts)))
              .pipe(gulp.dest(build.styles))
          .pipe(cssFilter.restore())
          ;
  });
  
  // copy file from bower folder into the app vendor folder
  gulp.task('vendor:app', function() {
      log('Copying vendor assets..');
  
      var jsFilter = $.filter('**/*.js', {
          restore: true
      });
      var cssFilter = $.filter('**/*.css', {
          restore: true
      });
  
      return gulp.src(vendor.app.source, {
              base: 'bower_components'
          })
          .pipe($.expectFile(vendor.app.source))
          .pipe(jsFilter)
          .pipe($.if(isProduction, $.uglify(vendorUglifyOpts)))
          .pipe(jsFilter.restore())
          .pipe(cssFilter)
          .pipe($.if(isProduction, $.cssnano(cssnanoOpts)))
          .pipe(cssFilter.restore())
          .pipe(gulp.dest(vendor.app.dest));
  
  });
  
  // APP LESS
  gulp.task('styles:app', function() {
      log('Building application styles..');
      return gulp.src(source.styles.app)
          .pipe($.if(useSourceMaps, $.sourcemaps.init()))
          .pipe(useSass ? $.compass(compassOpts) : $.less())
          .on('error', handleError)
          .pipe($.if(isProduction, $.cssnano(cssnanoOpts)))
          .pipe($.if(useSourceMaps, $.sourcemaps.write()))
          .pipe(gulp.dest(build.styles))
          .pipe(reload({
              stream: true
          }));
  });
  
  // APP RTL
  gulp.task('styles:app:rtl', function() {
      log('Building application RTL styles..');
      return gulp.src(source.styles.app)
          .pipe($.if(useSourceMaps, $.sourcemaps.init()))
          .pipe(useSass ? $.compass(compassOpts) : $.less())
          .on('error', handleError)
          .pipe($.rtlcss()) /* RTL Magic ! */
          .pipe($.if(isProduction, $.cssnano(cssnanoOpts)))
          .pipe($.if(useSourceMaps, $.sourcemaps.write()))
          .pipe($.rename(function(path) {
              path.basename += "-rtl";
              return path;
          }))
          .pipe(gulp.dest(build.styles))
          .pipe(reload({
              stream: true
          }));
  });
  
  // LESS THEMES
  gulp.task('styles:themes', function() {
      log('Building application theme styles..');
      return gulp.src(source.styles.themes)
          .pipe(useSass ? $.compass(compassOptsThemes) : $.less())
          .on('error', handleError)
          .pipe(gulp.dest(build.styles))
          .pipe(reload({
              stream: true
          }));
  });
  
  //---------------
  // WATCH
  //---------------
  
  // Rerun the task when a file changes
  gulp.task('watch', function() {
      log('Watching source files..');
  
      gulp.watch(source.scripts, ['scripts:app']);
      gulp.watch(source.styles.watch, ['styles:app', 'styles:app:rtl']);
      gulp.watch(source.styles.themes, ['styles:themes']);
  
  });
  
  // Serve files with auto reaload
  gulp.task('browsersync', function() {
      log('Starting BrowserSync..');
  
      browserSync({
          notify: false,
          server: {
              baseDir: '..'
          }
      });
  
  });
  
  // lint javascript
  gulp.task('lint', function() {
      return gulp
          .src(source.scripts)
          .pipe($.jshint())
          .pipe($.jshint.reporter('jshint-stylish', {
              verbose: true
          }))
          .pipe($.jshint.reporter('fail'));
  });
  
  // Remove all files from the build paths
  gulp.task('clean', function(done) {
      var delconfig = [].concat(
          build.styles,
          build.scripts,
          vendor.app.dest
      );
  
      log('Cleaning: ' + $.util.colors.blue(delconfig));
      // force: clean files outside current directory
      del(delconfig, {
          force: true
      }, done);
  });
  
  //---------------
  // MAIN TASKS
  //---------------
  
  // build for production (minify)
  gulp.task('build', gulpsync.sync([
      'prod',
      'vendor',
      'assets'
  ]));
  
  gulp.task('prod', function() {
      log('Starting production build...');
      isProduction = true;
  });
  
  // Server for development
  gulp.task('serve', gulpsync.sync([
      'default',
      'browsersync'
  ]), done);
  
  // Server for production
  gulp.task('serve-prod', gulpsync.sync([
      'build',
      'browsersync'
  ]), done);
  
  // build with sourcemaps (no minify)
  gulp.task('sourcemaps', ['usesources', 'default']);
  gulp.task('usesources', function() {
      useSourceMaps = true;
  });
  
  // default (no minify)
  gulp.task('default', gulpsync.sync([
      'vendor',
      'assets',
      'watch'
  ]));
  
  gulp.task('assets', [
      'scripts:app',
      'styles:app',
      'styles:app:rtl',
      'styles:themes'
  ]);
  
  
  /////////////////////
  
  function done() {
      log('************');
      log('* All Done * You can start editing your code, BrowserSync will update your browser after any change..');
      log('************');
  }
  
  // Error handler
  function handleError(err) {
      log(err.toString());
      this.emit('end');
  }
  
  // log to console using
  function log(msg) {
      $.util.log($.util.colors.blue(msg));
  }
  