text: /*******************************
             Watch Task
  *******************************/
  
  var
    gulp         = require('gulp'),
  
    // node dependencies
    console      = require('better-console'),
    fs           = require('fs'),
  
    // gulp dependencies
    autoprefixer = require('gulp-autoprefixer'),
    chmod        = require('gulp-chmod'),
    clone        = require('gulp-clone'),
    gulpif       = require('gulp-if'),
    less         = require('gulp-less'),
    minifyCSS    = require('gulp-minify-css'),
    plumber      = require('gulp-plumber'),
    print        = require('gulp-print'),
    rename       = require('gulp-rename'),
    replace      = require('gulp-replace'),
    uglify       = require('gulp-uglify'),
    util         = require('gulp-util'),
    watch        = require('gulp-watch'),
  
    // user config
    config       = require('./config/user'),
  
    // task config
    tasks        = require('./config/tasks'),
    install      = require('./config/project/install'),
  
    // shorthand
    globs        = config.globs,
    assets       = config.paths.assets,
    output       = config.paths.output,
    source       = config.paths.source,
  
    banner       = tasks.banner,
    comments     = tasks.regExp.comments,
    log          = tasks.log,
    settings     = tasks.settings
  
  ;
  
  // add tasks referenced using gulp.run (sub-tasks)
  if(config.rtl) {
    require('./collections/rtl')(gulp);
  }
  require('./collections/internal')(gulp);
  
  
  // export task
  module.exports = function(callback) {
  
    if( !install.isSetup() ) {
      console.error('Cannot watch files. Run "gulp install" to set-up Semantic');
      return;
    }
  
    // check for right-to-left (RTL) language
    if(config.rtl == 'both') {
      gulp.start('watch-rtl');
    }
    if(config.rtl === true || config.rtl === 'Yes') {
      gulp.start('watch-rtl');
      return;
    }
  
    //console.clear();
    console.log('Watching source files for changes');
  
    /*--------------
        Watch CSS
    ---------------*/
  
    gulp
      .watch([
        source.config,
        source.definitions   + '/**/*.less',
        source.site          + '/**/*.{overrides,variables}',
        source.themes        + '/**/*.{overrides,variables}'
      ], function(file) {
  
        var
          lessPath,
  
          stream,
          compressedStream,
          uncompressedStream,
  
          isDefinition,
          isPackagedTheme,
          isSiteTheme,
          isConfig
        ;
  
        // log modified file
        gulp.src(file.path)
          .pipe(print(log.modified))
        ;
  
        /*--------------
           Find Source
        ---------------*/
  
        // recompile on *.override , *.variable change
        isConfig        = (file.path.indexOf('theme.config') !== -1 || file.path.indexOf('site.variables') !== -1);
        isPackagedTheme = (file.path.indexOf(source.themes) !== -1);
        isSiteTheme     = (file.path.indexOf(source.site) !== -1);
        isDefinition    = (file.path.indexOf(source.definitions) !== -1);
  
        if(isConfig) {
          console.info('Rebuilding all UI');
          // impossible to tell which file was updated in theme.config, rebuild all
          gulp.start('build-css');
          return;
        }
        else if(isPackagedTheme) {
          console.log('Change detected in packaged theme');
          lessPath = util.replaceExtension(file.path, '.less');
          lessPath = lessPath.replace(tasks.regExp.theme, source.definitions);
        }
        else if(isSiteTheme) {
          console.log('Change detected in site theme');
          lessPath = util.replaceExtension(file.path, '.less');
          lessPath = lessPath.replace(source.site, source.definitions);
        }
        else {
          console.log('Change detected in definition');
          lessPath = file.path;
        }
  
        /*--------------
           Create CSS
        ---------------*/
  
        if( fs.existsSync(lessPath) ) {
  
          // unified css stream
          stream = gulp.src(lessPath)
            .pipe(plumber(settings.plumber.less))
            .pipe(less(settings.less))
            .pipe(print(log.created))
            .pipe(replace(comments.variables.in, comments.variables.out))
            .pipe(replace(comments.license.in, comments.license.out))
            .pipe(replace(comments.large.in, comments.large.out))
            .pipe(replace(comments.small.in, comments.small.out))
            .pipe(replace(comments.tiny.in, comments.tiny.out))
            .pipe(autoprefixer(settings.prefix))
            .pipe(gulpif(config.hasPermission, chmod(config.permission)))
          ;
  
          // use 2 concurrent streams from same pipe
          uncompressedStream = stream.pipe(clone());
          compressedStream   = stream.pipe(clone());
  
          uncompressedStream
            .pipe(plumber())
            .pipe(replace(assets.source, assets.uncompressed))
            .pipe(gulp.dest(output.uncompressed))
            .pipe(print(log.created))
            .on('end', function() {
              gulp.start('package uncompressed css');
            })
          ;
  
          compressedStream = stream
            .pipe(plumber())
            .pipe(replace(assets.source, assets.compressed))
            .pipe(minifyCSS(settings.minify))
            .pipe(rename(settings.rename.minCSS))
            .pipe(gulp.dest(output.compressed))
            .pipe(print(log.created))
            .on('end', function() {
              gulp.start('package compressed css');
            })
          ;
        }
        else {
          console.log('Cannot find UI definition at path', lessPath);
        }
      })
    ;
  
    /*--------------
        Watch JS
    ---------------*/
  
    gulp
      .watch([
        source.definitions   + '/**/*.js'
      ], function(file) {
        gulp.src(file.path)
          .pipe(plumber())
          .pipe(replace(comments.license.in, comments.license.out))
          .pipe(gulpif(config.hasPermission, chmod(config.permission)))
          .pipe(gulp.dest(output.uncompressed))
          .pipe(print(log.created))
          .pipe(uglify(settings.uglify))
          .pipe(rename(settings.rename.minJS))
          .pipe(gulp.dest(output.compressed))
          .pipe(print(log.created))
          .on('end', function() {
            gulp.start('package compressed js');
            gulp.start('package uncompressed js');
          })
        ;
      })
    ;
  
    /*--------------
      Watch Assets
    ---------------*/
  
    // only copy assets that match component names (or their plural)
    gulp
      .watch([
        source.themes   + '/**/assets/**/*.*'
      ], function(file) {
        // copy assets
        gulp.src(file.path, { base: source.themes })
          .pipe(gulpif(config.hasPermission, chmod(config.permission)))
          .pipe(gulp.dest(output.themes))
          .pipe(print(log.created))
        ;
      })
    ;
  
  };