var gulp = require('gulp');
var addsrc = require('gulp-add-src');
var filter = require('gulp-filter');
var print = require('gulp-print');
var taskListing = require('gulp-task-listing');
var del = require('del');
var bower = require('gulp-bower');
var tsd = require('gulp-tsd');
var typescript = require('gulp-typescript');
var sass = require('gulp-sass');
var electron = require('electron-connect').server.create();
var mocha = require('gulp-mocha');
var fs = require('fs');
var path = require('path');

function outputFile(input) {
  var origin = input;
  if (input.match(__dirname) != null) {
    [
      [path.join(__dirname, 'src'), path.join(__dirname, 'build')],
      [path.join(__dirname, 'test'), path.join(__dirname, 'test-build')]
    ].forEach(function(ptn) {
      input = input.replace(ptn[0], ptn[1]);
    });
  } else {
    [
      [/src\//, 'build/'],
      [/test\//, 'test-build/']
    ].forEach(function(ptn) {
      input = input.replace(ptn[0], ptn[1]);
    });
  }
  [
    [/\.ts/, '.js'],
    [/\.scss/, '.css']
  ].forEach(function(ptn) {
    input = input.replace(ptn[0], ptn[1]);
  });
  return input;
}

function needToCompile(input) {
  input = input.path;
  var output = outputFile(input);
  try {
    fs.accessSync(output);
  } catch(e) {
    return true;
  }
  var input_mtime = fs.statSync(input).mtime;
  var output_mtime = fs.statSync(output).mtime;
  return input_mtime > output_mtime;
}

function showBuild(compile) {
  return function(input) {
    return "[BUILD] " + compile +
           " " + input.replace(__dirname, '') +
           " => " + outputFile(input).replace(__dirname, '');
  }
}

gulp.task('help', taskListing);

gulp.task('build', ['build:src', 'build:test']);

gulp.task('build:src', function(){
  gulp.src('src/**/*.ts')
  .pipe(filter(needToCompile))
  .pipe(print(showBuild('tsc')))
  .pipe(addsrc('./typings/tsd.d.ts'))
  .pipe(typescript({ target: 'es5',
                     module: 'commonjs',
                     sourceMap: true }))
  .js
  .pipe(gulp.dest('build'));

  gulp.src('src/**/*.{sass,scss}')
  .pipe(filter(needToCompile))
  .pipe(print(showBuild('sass')))
  .pipe(sass().on('error', sass.logError))
  .pipe(gulp.dest('build'));

  gulp.src('src/**/*.{html,css,js}', { base: 'src' })
  .pipe(filter(needToCompile))
  .pipe(print(showBuild('clone')))
  .pipe(gulp.dest('build'));
});

gulp.task('watch', function(){
  gulp.watch('{test,src}/**/*', ['build']);
});

gulp.task('clean', function(cb) {
  del(['build', 'test-build'], cb);
});


gulp.task('build:test', function() {
  gulp.src('test/**/*.ts')
    .pipe(filter(needToCompile))
    .pipe(print(showBuild('tsc')))
    .pipe(addsrc('./typings/tsd.d.ts'))
    .pipe(typescript({ target: 'es5',
                       module: 'commonjs',
                       sourceMap: true }))
    .js
    .pipe(gulp.dest('test-build'));

  gulp.src(['test/**/*.js', 'test/testdata/**/*'], { base: 'test' })
  .pipe(filter(needToCompile))
  .pipe(print(showBuild('clone')))
  .pipe(gulp.dest('test-build'));
});

gulp.task('test', function() {
  return gulp.src(['test-build/**/*_test.js'])
    .pipe(mocha({ reporter: 'dot'}));
});

gulp.task('serve', ['watch'], function () {
  electron.start();

  // Restart electron when resources loaded from BrowserProcess updates
  gulp.watch('build/browser/**/*.js', electron.restart);

  // Reload a page when resources loaded from RendererProcess updates
  gulp.watch('build/renderer/**/*.{html,js,css}', electron.reload);
});

gulp.task('install', ['install:bower', 'install:tsd']);

gulp.task('install:bower', function() {
  return bower();
});

gulp.task('install:tsd', function(callback) {
  tsd({ command: 'reinstall',
        config: 'tsd.json'
      }, callback);
});

@@ -135,56 +135,8 @@
 ');%0A
-var taskListing = require('gulp-task-listing');%0A
 var 
@@ -1593,103 +1593,34 @@
 sk('
-help', taskListing);%0A%0Agulp.task('build', %5B'build:src', 'build:test'%5D);%0A%0Agulp.task('build:src', 
+build:src', gulp.parallel(
 func
@@ -1621,28 +1621,36 @@
 l(function()
+ 
 %7B%0A  
+return 
 gulp.src('sr
@@ -1908,34 +1908,56 @@
 dest('build'));%0A
-%0A 
+%7D, function() %7B%0A  return
  gulp.src('src/*
@@ -2103,34 +2103,56 @@
 dest('build'));%0A
-%0A 
+%7D, function() %7B%0A  return
  gulp.src('src/*
@@ -2277,32 +2277,33 @@
 st('build'));%0A%7D)
+)
 ;%0A%0Agulp.task('wa
@@ -2304,96 +2304,35 @@
 sk('
-watch', function()%7B%0A  gulp.watch('%7Btest,src%7D/**/*', %5B'build'%5D);%0A%7D);%0A%0Agulp.task('clean', 
+build:test', gulp.parallel(
 func
@@ -2340,94 +2340,20 @@
 ion(
-cb
 ) %7B%0A  
-del(%5B'build', 'test-build'%5D, cb);%0A%7D);%0A%0A%0Agulp.task('build:test', function() %7B%0A 
+return
  gul
@@ -2650,18 +2650,40 @@
 ild'));%0A
-%0A 
+%7D, function() %7B%0A  return
  gulp.sr
@@ -2838,24 +2838,256 @@
 t-build'));%0A
+%7D));%0A%0Agulp.task('build', gulp.parallel('build:src', 'build:test'));%0A%0Agulp.task('watch', function() %7B%0A  gulp.watch('%7Btest,src%7D/**/*', gulp.series('build'));%0A%7D);%0A%0Agulp.task('clean', function() %7B%0A  return del(%5B'build', 'test-build'%5D);%0A
 %7D);%0A%0Agulp.ta
@@ -3222,19 +3222,8 @@
 ve',
- %5B'watch'%5D,
  fun
@@ -3531,65 +3531,8 @@
 );%0A%0A
-gulp.task('install', %5B'install:bower', 'install:tsd'%5D);%0A%0A
 gulp
@@ -3713,12 +3713,80 @@
 lback);%0A%7D);%0A
+%0Agulp.task('install', gulp.series('install:bower', 'install:tsd'));%0A

Fix gulpfile.js for v4.0