<commit_before>const gulp = require('gulp');
const browserSync = require('browser-sync').create();
//const jasmine = require('gulp-jasmine');
//const browserify = require('gulp-browserify');

// Static server
gulp.task('browser-sync', () => {
  browserSync.init({
    server: {
      baseDir: './src'
    },
    port: process.env.PORT || 8000
  });
});

// gulp.task('build:scripts', () => {
//   return gulp.src(['src/js/inverted-index.js', 'jasmine/spec/inverted-index-test.js'])
//     .pipe(browserify())
//     .pipe(gulp.dest('build'));
// });

gulp.task('watch', () => {
  gulp.watch(['./**/*.html', './**/**/*.css', './**/**/*.js'])
    .on('change', browserSync.reload);
});

gulp.task('default', ['browser-sync', 'watch'], () => {});
<commit_msg>chore(gulp): activate gulp and browser-sync<commit_after>const gulp = require('gulp');
const browserSync = require('browser-sync').create();
//const jasmine = require('gulp-jasmine');
//const browserify = require('gulp-browserify');

// Static server
gulp.task('browser-sync', () => {
  browserSync.init({
    server: {
      baseDir: './src'
    },
    port: process.env.PORT || 8000
  });
});

gulp.task('watch', () => {
  gulp.watch(['./**/*.html', 'src/css/*.css', 'src/js/*.js'])
    .on('change', browserSync.reload);
});

// gulp.task('build:scripts', () => {
//   return gulp.src(['src/js/inverted-index.js', 'jasmine/spec/inverted-index-test.js'])
//     .pipe(browserify())
//     .pipe(gulp.dest('build'));
// });
gulp.task('default', ['browser-sync', 'watch']);
<|endoftext|>


<commit_before>var gulp = require('gulp');
var postcss = require('gulp-postcss');
var layout = require('./index.js');
var shell = require('gulp-shell');

var files = ['index.js', './test/*.js', './example/src/css/main.css', 'gulpfile.js'];

gulp.task('example', function() {
  var processors = [
    layout()
  ];

  return gulp.src('./example/src/css/main.css')
    .pipe(postcss(processors))
    .pipe(gulp.dest('./example/bld/css/'));
});

gulp.task('test', shell.task([
  'node test/test.js',
]));

gulp.task('default', ['test']);

gulp.task('watch-example', function () {
    gulp.watch(files, ['example']);
});

gulp.task('watch', function () {
    gulp.watch(files, ['test']);
});
<commit_msg>Gulp test updated.<commit_after>var gulp = require('gulp');
var postcss = require('gulp-postcss');
var ifm = require('./index.js');
// var shell = require('gulp-shell');
var tape = require('gulp-tape');
var tapDiff = require('tap-diff');

var files = ['index.js', './test/*.js', 'gulpfile.js'];

// gulp.task('test', shell.task([
//   'node test/test.js',
// ]));

gulp.task('test', function() {
  return gulp.src('test/*.js')
    .pipe(tape({
      reporter: tapDiff()
    }));
});

gulp.task('default', ['test']);

gulp.task('watch', function () {
    gulp.watch(files, ['test']);
});
<|endoftext|>


<commit_before>//plugins
var gulp = require('gulp'),
  nodemon = require('gulp-nodemon'),
  rimraf = require('rimraf'),
  concat = require('gulp-concat'),
  cssmin = require('gulp-cssmin'),
  uglify = require('gulp-uglify'),
  rev = require('gulp-rev'),
  revCollector = require('gulp-rev-collector'),
  browserSync = require('browser-sync');

//production files
var min = {
  'js': './public/dist/min-*.js',
  'css': './public/dist/min-*.css'
};

//source files
var srcJS = [
  'node_modules/jquery/dist/jquery.min.js',
  'node_modules/bootstrap/dist/js/bootstrap.min.js',
  'node_modules/angular/angular.min.js',
  'node_modules/angular-route/angular-route.min.js',
  'node_modules/angular-animate/angular-animate.min.js',
  'public/scripts/common/*.js',
  'public/scripts/modules/*.js',
  'public/scripts/controllers/*.js',
  'public/scripts/directives/*.js',
  'public/scripts/effects/*.js',
  'public/scripts/filters/*.js',
  'public/scripts/services/*.js'
];

var srcCSS = [
  './node_modules/bootstrap/dist/css/bootstrap.min.css',
  './public/styles/animate.css',
  './public/styles/fonts.css',
  './public/styles/style.css',
];

/*--------------------Tasks-------------------*/
gulp.task('debug', function () { process.env.ENV = 'debug' });

gulp.task('release', function () { process.env.ENV = 'release' });

gulp.task('clean:minjs', function (cb) { rimraf(min['js'], cb); })

gulp.task('clean:mincss', function (cb) { rimraf(min['css'], cb); });

gulp.task('min:js', function () {
  if (process.env.ENV === 'debug') {
    gulp.src(srcJS, { base: '.' })
      .pipe(concat('min.js'))
      .pipe(rev())
      .pipe(gulp.dest('./public/dist/'))
      .pipe(rev.manifest())
      .pipe(gulp.dest('rev/js'));
  } else {
    gulp.src(srcJS, { base: '.' })
      .pipe(concat('min.js'))
      .pipe(uglify())
      .pipe(rev())
      .pipe(gulp.dest('./public/dist/'))
      .pipe(rev.manifest())
      .pipe(gulp.dest('rev/js'));
  }
});

gulp.task('min:css', function () {
  if (process.env.ENV === 'debug') {
    gulp.src(srcCSS, { base: '.' })
      .pipe(concat('min.css'))
      .pipe(rev())
      .pipe(gulp.dest('./public/dist/'))
      .pipe(rev.manifest())
      .pipe(gulp.dest('rev/css'));
  } else {
    gulp.src(srcCSS, { base: '.' })
      .pipe(concat('min.css'))
      .pipe(cssmin())
      .pipe(rev())
      .pipe(gulp.dest('./public/dist/'))
      .pipe(rev.manifest())
      .pipe(gulp.dest('rev/css'));
  }
});

gulp.task('clean', [
  'clean:minjs',
  'clean:mincss'
]);

gulp.task('min', [
  'min:js',
  'min:css'
]);

//support rewrite url in html
gulp.task('rev', function () {
  gulp.src(['./rev/**/*.json', './public/index.html'])
    .pipe(revCollector({
      replaceReved: true
    }))
    .pipe(gulp.dest('./public/'));
});

//start local server by nodemon
gulp.task('serve', function () {
  nodemon({
    script: 'server',
    ext: 'js',
    stdout: false
  }).on('readable', function () {
    this.stdout.pipe(process.stdout);
    this.stderr.pipe(process.stderr);
  });
});

//add browser refresh
gulp.task('browser-sync', ['serve'], function () {
  browserSync.init(null, {
    proxy: 'http://localhost:3000',
    browser: 'google chrome',
    notify: false,
    port: 5000
  });

  gulp.watch(["public/scripts/**/*.js",], ['min:js']);
  gulp.watch("public/styles/**/*.css", ['min:css']);
  gulp.watch("public/dist/**/*.*", ['rev']);
  gulp.watch("public/*.html").on('change', browserSync.reload);
});

//for npm release
gulp.task('deploy', [
  'release',
  'clean',
  'min',
  'rev'
]);

//final task
gulp.task('default', [
  'release',
  'clean',
  'min',
  'browser-sync'
]);

gulp.task('dev', [
  'debug',
  'clean',
  'min',
  'browser-sync'
]);<commit_msg>modified gulp task<commit_after>//plugins
var gulp = require('gulp'),
  nodemon = require('gulp-nodemon'),
  rimraf = require('rimraf'),
  concat = require('gulp-concat'),
  cssmin = require('gulp-cssmin'),
  uglify = require('gulp-uglify'),
  rev = require('gulp-rev'),
  revCollector = require('gulp-rev-collector'),
  browserSync = require('browser-sync');

//production files
var min = {
  'js': './public/dist/min-*.js',
  'css': './public/dist/min-*.css'
};

//source files
var srcJS = [
  'node_modules/jquery/dist/jquery.min.js',
  'node_modules/bootstrap/dist/js/bootstrap.min.js',
  'node_modules/angular/angular.min.js',
  'node_modules/angular-route/angular-route.min.js',
  'node_modules/angular-animate/angular-animate.min.js',
  'public/scripts/common/*.js',
  'public/scripts/modules/*.js',
  'public/scripts/controllers/*.js',
  'public/scripts/directives/*.js',
  'public/scripts/effects/*.js',
  'public/scripts/filters/*.js',
  'public/scripts/services/*.js'
];

var srcCSS = [
  './node_modules/bootstrap/dist/css/bootstrap.min.css',
  './public/styles/animate.css',
  './public/styles/fonts.css',
  './public/styles/style.css',
];

/*--------------------Tasks-------------------*/
gulp.task('clean:minjs', function (cb) { rimraf(min['js'], cb); })

gulp.task('clean:mincss', function (cb) { rimraf(min['css'], cb); });

gulp.task('min:js', function () {
  gulp.src(srcJS, { base: '.' })
    .pipe(concat('min.js'))
    .pipe(uglify())
    .pipe(rev())
    .pipe(gulp.dest('./public/dist/'))
    .pipe(rev.manifest())
    .pipe(gulp.dest('rev/js'));
});

gulp.task('min:css', function () {
  gulp.src(srcCSS, { base: '.' })
    .pipe(concat('min.css'))
    .pipe(cssmin())
    .pipe(rev())
    .pipe(gulp.dest('./public/dist/'))
    .pipe(rev.manifest())
    .pipe(gulp.dest('rev/css'));
});

gulp.task('clean', [
  'clean:minjs',
  'clean:mincss'
]);

gulp.task('min', [
  'min:js',
  'min:css'
]);

//support rewrite url in html
gulp.task('rev', function () {
  gulp.src(['./rev/**/*.json', './public/index.html'])
    .pipe(revCollector({
      replaceReved: true
    }))
    .pipe(gulp.dest('./public/'));
});

//start local server by nodemon
gulp.task('serve', function () {
  nodemon({
    script: 'server',
    ext: 'js',
    stdout: false
  }).on('readable', function () {
    this.stdout.pipe(process.stdout);
    this.stderr.pipe(process.stderr);
  });
});

//add browser refresh
gulp.task('browser-sync', ['serve'], function () {
  browserSync.init(null, {
    proxy: 'http://localhost:3000',
    browser: 'google chrome',
    notify: false,
    port: 5000
  });

  gulp.watch(["public/scripts/**/*.js",], ['min:js']);
  gulp.watch("public/styles/**/*.css", ['min:css']);
  gulp.watch("public/dist/**/*.*", ['rev']);
  gulp.watch("public/*.html").on('change', browserSync.reload);
});

//for npm release
gulp.task('deploy', [
  'clean',
  'min',
  'rev'
]);

//final task
gulp.task('default', [
  'clean',
  'min',
  'browser-sync'
]);

gulp.task('dev', [
  'clean',
  'min',
  'browser-sync'
]);<|endoftext|>


<commit_before>const { gulp, series, parallel, dest, src, watch } = require('gulp');
const babel = require('gulp-babel');
const beeper = require('beeper');
const browserSync = require('browser-sync');
const concat = require('gulp-concat');
const del = require('del');
const log = require('fancy-log');
const fs = require('fs');
const imagemin = require('gulp-imagemin');
const partialimport = require('postcss-easy-import');
const plumber = require('gulp-plumber');
const postcss = require('gulp-postcss');
const postCSSMixins = require('postcss-mixins');
const postcssPresetEnv = require('postcss-preset-env');
const sourcemaps = require('gulp-sourcemaps');
const uglify = require('gulp-uglify');
const zip = require('gulp-vinyl-zip');
const dotenv = require('dotenv');
const path = require('path');
const { execSync } = require('child_process');

dotenv.config();

/* -------------------------------------------------------------------------------------------------
Theme Name
-------------------------------------------------------------------------------------------------- */
const themeName = 'wordpressify';

/* -------------------------------------------------------------------------------------------------
PostCSS Plugins
-------------------------------------------------------------------------------------------------- */
const pluginsListDev = [
	partialimport,
	postCSSMixins,
	postcssPresetEnv({
		stage: 0,
		features: {
			'nesting-rules': true,
			'color-mod-function': true,
			'custom-media': true,
		},
	}),
];

const pluginsListProd = [
	partialimport,
	postCSSMixins,
	postcssPresetEnv({
		stage: 0,
		features: {
			'nesting-rules': true,
			'color-mod-function': true,
			'custom-media': true,
		},
	}),
	require('cssnano')({
		preset: [
			'default',
			{
				discardComments: false,
			},
		],
	}),
];

/* -------------------------------------------------------------------------------------------------
Header & Footer JavaScript Boundles
-------------------------------------------------------------------------------------------------- */
const headerJS = ['./node_modules/jquery/dist/jquery.js'];

const footerJS = ['./src/assets/js/**'];

/* -------------------------------------------------------------------------------------------------
Environment Tasks
-------------------------------------------------------------------------------------------------- */
function setupEnvironment(done) {
	if (!fs.existsSync('./build')) {
		fs.mkdirSync('./build');
		fs.mkdirSync('./build/wordpress');
	}
	if (!fs.existsSync('./xdebug')) {
		fs.mkdirSync('./xdebug');
	}
	if (!fs.existsSync('./Dockerfile')) {
		let contents = fs.readFileSync('./Dockerfile.in', { encoding: 'utf8' });
		contents = contents.replace(/\{\{UID\}\}/g, process.getuid());
		contents = contents.replace(/\{\{GID\}\}/g, process.getgid());
		fs.writeFileSync('./Dockerfile', contents);
	}
	if (!fs.existsSync('./config/php.ini')) {
		let contents = fs.readFileSync('./config/php.ini.in', { encoding: 'utf8' });
		// If you're on Linux, you might have to modify the IP address 172.29.0.1 - See README
		let replacement =
			process.platform === 'win32' || process.platform === 'darwin'
				? 'host.docker.internal'
				: '172.29.0.1';
		contents = contents.replace(/\{\{XDEBUG_CLIENT_HOST\}\}/g, replacement);
		fs.writeFileSync('./config/php.ini', contents);
	}
	if (!fs.existsSync('./.env')) {
		let contents = fs.readFileSync('./.env.in', { encoding: 'utf8' });
		contents = contents.replace(/\{\{WPFY_UID\}\}/g, process.getuid());
		contents = contents.replace(/\{\{WPFY_GID\}\}/g, process.getgid());
		fs.writeFileSync('./.env', contents);
	}
	done();
}

function startContainers(done) {
	execSync('docker-compose up -d', { stdio: 'inherit' });
	done();
}

function stopContainers(done) {
	execSync('docker-compose down', { stdio: 'inherit' });
	if (typeof done === 'function') {
		done();
	}
}

async function cleanEnvironment(done) {
	execSync('docker-compose down', { stdio: 'inherit' });
	await del(['build', 'Dockerfile', 'xdebug', 'config/php.ini', '.env']);
	done();
}

function rebuildContainers(done) {
	execSync('docker-compose up -d --build --force-recreate', {
		stdio: 'inherit',
	});
	done();
}

function restartWordPress(done) {
	execSync('docker-compose restart wordpress');
	done();
}

exports['env:start'] = series(setupEnvironment, startContainers);
exports['env:stop'] = stopContainers;
exports['env:rebuild'] = series(
	cleanEnvironment,
	setupEnvironment,
	rebuildContainers
);
exports['env:restart'] = restartWordPress;

/* -------------------------------------------------------------------------------------------------
Development Tasks
-------------------------------------------------------------------------------------------------- */
function devServer() {
	browserSync({
		logPrefix: '🎈 WordPressify',
		proxy: `127.0.0.1:${process.env.SERVER_PORT}`,
		host: '127.0.0.1',
		port: `${process.env.PROXY_PORT}`,
		open: 'external',
	});

	watch('./src/assets/css/**/*.css', stylesDev);
	watch('./src/assets/js/**', series(footerScriptsDev, Reload));
	watch('./src/assets/img/**', series(copyImagesDev, Reload));
	watch('./src/assets/fonts/**', series(copyFontsDev, Reload));
	watch('./src/theme/**', series(copyThemeDev, Reload));
	watch('./src/plugins/**', series(pluginsDev, Reload));
}

function Reload(done) {
	browserSync.reload();
	done();
}

function copyThemeDev() {
	if (!fs.existsSync('./build')) {
		log(buildNotFound);
		process.exit(1);
	} else {
		return src('./src/theme/**').pipe(
			dest('./build/wordpress/wp-content/themes/' + themeName)
		);
	}
}

function copyImagesDev() {
	return src('./src/assets/img/**').pipe(
		dest('./build/wordpress/wp-content/themes/' + themeName + '/img')
	);
}

function copyFontsDev() {
	return src('./src/assets/fonts/**').pipe(
		dest('./build/wordpress/wp-content/themes/' + themeName + '/fonts')
	);
}

function stylesDev() {
	return src('./src/assets/css/style.css')
		.pipe(plumber({ errorHandler: onError }))
		.pipe(sourcemaps.init())
		.pipe(postcss(pluginsListDev))
		.pipe(sourcemaps.write('.'))
		.pipe(dest('./build/wordpress/wp-content/themes/' + themeName))
		.pipe(browserSync.stream({ match: '**/*.css' }));
}

function headerScriptsDev() {
	return src(headerJS)
		.pipe(plumber({ errorHandler: onError }))
		.pipe(sourcemaps.init())
		.pipe(concat('header-bundle.js'))
		.pipe(sourcemaps.write('.'))
		.pipe(dest('./build/wordpress/wp-content/themes/' + themeName + '/js'));
}

function footerScriptsDev() {
	return src(footerJS)
		.pipe(plumber({ errorHandler: onError }))
		.pipe(sourcemaps.init())
		.pipe(
			babel({
				presets: ['@babel/preset-env'],
			})
		)
		.pipe(concat('footer-bundle.js'))
		.pipe(sourcemaps.write('.'))
		.pipe(dest('./build/wordpress/wp-content/themes/' + themeName + '/js'));
}

function pluginsDev() {
	return src(['./src/plugins/**', '!./src/plugins/README.md']).pipe(
		dest('./build/wordpress/wp-content/plugins')
	);
}

exports.dev = series(
	startContainers,
	copyThemeDev,
	copyImagesDev,
	copyFontsDev,
	stylesDev,
	headerScriptsDev,
	footerScriptsDev,
	pluginsDev,
	devServer
);

/* -------------------------------------------------------------------------------------------------
Production Tasks
-------------------------------------------------------------------------------------------------- */
async function cleanProd() {
	await del(['./dist']);
}

function copyThemeProd() {
	return src(['./src/theme/**', '!./src/theme/**/node_modules/**']).pipe(
		dest('./dist/themes/' + themeName)
	);
}

function copyFontsProd() {
	return src('./src/assets/fonts/**').pipe(
		dest('./dist/themes/' + themeName + '/fonts')
	);
}

function stylesProd() {
	return src('./src/assets/css/style.css')
		.pipe(plumber({ errorHandler: onError }))
		.pipe(postcss(pluginsListProd))
		.pipe(dest('./dist/themes/' + themeName));
}

function headerScriptsProd() {
	return src(headerJS)
		.pipe(plumber({ errorHandler: onError }))
		.pipe(concat('header-bundle.js'))
		.pipe(uglify())
		.pipe(dest('./dist/themes/' + themeName + '/js'));
}

function footerScriptsProd() {
	return src(footerJS)
		.pipe(plumber({ errorHandler: onError }))
		.pipe(
			babel({
				presets: ['@babel/preset-env'],
			})
		)
		.pipe(concat('footer-bundle.js'))
		.pipe(uglify())
		.pipe(dest('./dist/themes/' + themeName + '/js'));
}

function pluginsProd() {
	return src(['./src/plugins/**', '!./src/plugins/**/*.md']).pipe(
		dest('./dist/plugins')
	);
}

function processImages() {
	return src('./src/assets/img/**')
		.pipe(plumber({ errorHandler: onError }))
		.pipe(
			imagemin([imagemin.svgo({ plugins: [{ removeViewBox: true }] })], {
				verbose: true,
			})
		)
		.pipe(dest('./dist/themes/' + themeName + '/img'));
}

function zipProd() {
	return src('./dist/themes/' + themeName + '/**/*')
		.pipe(zip.dest('./dist/' + themeName + '.zip'))
		.on('end', () => {
			beeper();
			log(pluginsGenerated);
			log(filesGenerated);
			log(thankYou);
		});
}

exports.prod = series(
	cleanProd,
	copyThemeProd,
	copyFontsProd,
	stylesProd,
	headerScriptsProd,
	footerScriptsProd,
	pluginsProd,
	processImages,
	zipProd
);

/* -------------------------------------------------------------------------------------------------
Utility Tasks
-------------------------------------------------------------------------------------------------- */
const onError = (err) => {
	beeper();
	log(wpFy + ' - ' + errorMsg + ' ' + err.toString());
	this.emit('end');
};

function Backup() {
	if (!fs.existsSync('./build')) {
		log(buildNotFound);
		process.exit(1);
	} else {
		return src('./build/**/*')
			.pipe(zip.dest('./backups/' + date + '.zip'))
			.on('end', () => {
				beeper();
				log(backupsGenerated);
				log(thankYou);
			});
	}
}

exports.backup = Backup;

/* -------------------------------------------------------------------------------------------------
Messages
-------------------------------------------------------------------------------------------------- */
const date = new Date().toLocaleDateString('en-GB').replace(/\//g, '.');
const errorMsg = '\x1b[41mError\x1b[0m';
const warning = '\x1b[43mWarning\x1b[0m';
const devServerReady =
	'Your development server is ready, start the workflow with the command: $ \x1b[1mnpm run dev\x1b[0m';
const buildNotFound =
	errorMsg +
	' ⚠　- You need to build the project first. Run the command: $ \x1b[1mnpm run env:start\x1b[0m';
const filesGenerated =
	'Your ZIP template file was generated in: \x1b[1m' +
	__dirname +
	'/dist/' +
	themeName +
	'.zip\x1b[0m - ✅';
const pluginsGenerated =
	'Plugins are generated in: \x1b[1m' + __dirname + '/dist/plugins/\x1b[0m - ✅';
const backupsGenerated =
	'Your backup was generated in: \x1b[1m' +
	__dirname +
	'/backups/' +
	date +
	'.zip\x1b[0m - ✅';
const wpFy = '\x1b[42m\x1b[1mWordPressify\x1b[0m';
const wpFyUrl = '\x1b[2m - http://www.wordpressify.co/\x1b[0m';
const thankYou = 'Thank you for using ' + wpFy + wpFyUrl;

/* -------------------------------------------------------------------------------------------------
End of all Tasks
-------------------------------------------------------------------------------------------------- */
<commit_msg>✅ TEST: Stop all docker containers before starting dev command<commit_after>const { gulp, series, parallel, dest, src, watch } = require('gulp');
const babel = require('gulp-babel');
const beeper = require('beeper');
const browserSync = require('browser-sync');
const concat = require('gulp-concat');
const del = require('del');
const log = require('fancy-log');
const fs = require('fs');
const imagemin = require('gulp-imagemin');
const partialimport = require('postcss-easy-import');
const plumber = require('gulp-plumber');
const postcss = require('gulp-postcss');
const postCSSMixins = require('postcss-mixins');
const postcssPresetEnv = require('postcss-preset-env');
const sourcemaps = require('gulp-sourcemaps');
const uglify = require('gulp-uglify');
const zip = require('gulp-vinyl-zip');
const dotenv = require('dotenv');
const path = require('path');
const { execSync } = require('child_process');

dotenv.config();

/* -------------------------------------------------------------------------------------------------
Theme Name
-------------------------------------------------------------------------------------------------- */
const themeName = 'wordpressify';

/* -------------------------------------------------------------------------------------------------
PostCSS Plugins
-------------------------------------------------------------------------------------------------- */
const pluginsListDev = [
	partialimport,
	postCSSMixins,
	postcssPresetEnv({
		stage: 0,
		features: {
			'nesting-rules': true,
			'color-mod-function': true,
			'custom-media': true,
		},
	}),
];

const pluginsListProd = [
	partialimport,
	postCSSMixins,
	postcssPresetEnv({
		stage: 0,
		features: {
			'nesting-rules': true,
			'color-mod-function': true,
			'custom-media': true,
		},
	}),
	require('cssnano')({
		preset: [
			'default',
			{
				discardComments: false,
			},
		],
	}),
];

/* -------------------------------------------------------------------------------------------------
Header & Footer JavaScript Boundles
-------------------------------------------------------------------------------------------------- */
const headerJS = ['./node_modules/jquery/dist/jquery.js'];

const footerJS = ['./src/assets/js/**'];

/* -------------------------------------------------------------------------------------------------
Environment Tasks
-------------------------------------------------------------------------------------------------- */
function setupEnvironment(done) {
	if (!fs.existsSync('./build')) {
		fs.mkdirSync('./build');
		fs.mkdirSync('./build/wordpress');
	}
	if (!fs.existsSync('./xdebug')) {
		fs.mkdirSync('./xdebug');
	}
	if (!fs.existsSync('./Dockerfile')) {
		let contents = fs.readFileSync('./Dockerfile.in', { encoding: 'utf8' });
		contents = contents.replace(/\{\{UID\}\}/g, process.getuid());
		contents = contents.replace(/\{\{GID\}\}/g, process.getgid());
		fs.writeFileSync('./Dockerfile', contents);
	}
	if (!fs.existsSync('./config/php.ini')) {
		let contents = fs.readFileSync('./config/php.ini.in', { encoding: 'utf8' });
		// If you're on Linux, you might have to modify the IP address 172.29.0.1 - See README
		let replacement =
			process.platform === 'win32' || process.platform === 'darwin'
				? 'host.docker.internal'
				: '172.29.0.1';
		contents = contents.replace(/\{\{XDEBUG_CLIENT_HOST\}\}/g, replacement);
		fs.writeFileSync('./config/php.ini', contents);
	}
	if (!fs.existsSync('./.env')) {
		let contents = fs.readFileSync('./.env.in', { encoding: 'utf8' });
		contents = contents.replace(/\{\{WPFY_UID\}\}/g, process.getuid());
		contents = contents.replace(/\{\{WPFY_GID\}\}/g, process.getgid());
		fs.writeFileSync('./.env', contents);
	}
	done();
}

function startContainers(done) {
	execSync('docker stop $(docker ps -a -q)', { stdio: 'inherit' });
	execSync('docker-compose up -d', { stdio: 'inherit' });
	done();
}

function stopContainers(done) {
	execSync('docker-compose down', { stdio: 'inherit' });
	if (typeof done === 'function') {
		done();
	}
}

async function cleanEnvironment(done) {
	execSync('docker-compose down', { stdio: 'inherit' });
	await del(['build', 'Dockerfile', 'xdebug', 'config/php.ini', '.env']);
	done();
}

function rebuildContainers(done) {
	execSync('docker-compose up -d --build --force-recreate', {
		stdio: 'inherit',
	});
	done();
}

function restartWordPress(done) {
	execSync('docker-compose restart wordpress');
	done();
}

exports['env:start'] = series(setupEnvironment, startContainers);
exports['env:stop'] = stopContainers;
exports['env:rebuild'] = series(
	cleanEnvironment,
	setupEnvironment,
	rebuildContainers
);
exports['env:restart'] = restartWordPress;

/* -------------------------------------------------------------------------------------------------
Development Tasks
-------------------------------------------------------------------------------------------------- */
function devServer() {
	browserSync({
		logPrefix: '🎈 WordPressify',
		proxy: `127.0.0.1:${process.env.SERVER_PORT}`,
		host: '127.0.0.1',
		port: `${process.env.PROXY_PORT}`,
		open: 'external',
	});

	watch('./src/assets/css/**/*.css', stylesDev);
	watch('./src/assets/js/**', series(footerScriptsDev, Reload));
	watch('./src/assets/img/**', series(copyImagesDev, Reload));
	watch('./src/assets/fonts/**', series(copyFontsDev, Reload));
	watch('./src/theme/**', series(copyThemeDev, Reload));
	watch('./src/plugins/**', series(pluginsDev, Reload));
}

function Reload(done) {
	browserSync.reload();
	done();
}

function copyThemeDev() {
	if (!fs.existsSync('./build')) {
		log(buildNotFound);
		process.exit(1);
	} else {
		return src('./src/theme/**').pipe(
			dest('./build/wordpress/wp-content/themes/' + themeName)
		);
	}
}

function copyImagesDev() {
	return src('./src/assets/img/**').pipe(
		dest('./build/wordpress/wp-content/themes/' + themeName + '/img')
	);
}

function copyFontsDev() {
	return src('./src/assets/fonts/**').pipe(
		dest('./build/wordpress/wp-content/themes/' + themeName + '/fonts')
	);
}

function stylesDev() {
	return src('./src/assets/css/style.css')
		.pipe(plumber({ errorHandler: onError }))
		.pipe(sourcemaps.init())
		.pipe(postcss(pluginsListDev))
		.pipe(sourcemaps.write('.'))
		.pipe(dest('./build/wordpress/wp-content/themes/' + themeName))
		.pipe(browserSync.stream({ match: '**/*.css' }));
}

function headerScriptsDev() {
	return src(headerJS)
		.pipe(plumber({ errorHandler: onError }))
		.pipe(sourcemaps.init())
		.pipe(concat('header-bundle.js'))
		.pipe(sourcemaps.write('.'))
		.pipe(dest('./build/wordpress/wp-content/themes/' + themeName + '/js'));
}

function footerScriptsDev() {
	return src(footerJS)
		.pipe(plumber({ errorHandler: onError }))
		.pipe(sourcemaps.init())
		.pipe(
			babel({
				presets: ['@babel/preset-env'],
			})
		)
		.pipe(concat('footer-bundle.js'))
		.pipe(sourcemaps.write('.'))
		.pipe(dest('./build/wordpress/wp-content/themes/' + themeName + '/js'));
}

function pluginsDev() {
	return src(['./src/plugins/**', '!./src/plugins/README.md']).pipe(
		dest('./build/wordpress/wp-content/plugins')
	);
}

exports.dev = series(
	startContainers,
	copyThemeDev,
	copyImagesDev,
	copyFontsDev,
	stylesDev,
	headerScriptsDev,
	footerScriptsDev,
	pluginsDev,
	devServer
);

/* -------------------------------------------------------------------------------------------------
Production Tasks
-------------------------------------------------------------------------------------------------- */
async function cleanProd() {
	await del(['./dist']);
}

function copyThemeProd() {
	return src(['./src/theme/**', '!./src/theme/**/node_modules/**']).pipe(
		dest('./dist/themes/' + themeName)
	);
}

function copyFontsProd() {
	return src('./src/assets/fonts/**').pipe(
		dest('./dist/themes/' + themeName + '/fonts')
	);
}

function stylesProd() {
	return src('./src/assets/css/style.css')
		.pipe(plumber({ errorHandler: onError }))
		.pipe(postcss(pluginsListProd))
		.pipe(dest('./dist/themes/' + themeName));
}

function headerScriptsProd() {
	return src(headerJS)
		.pipe(plumber({ errorHandler: onError }))
		.pipe(concat('header-bundle.js'))
		.pipe(uglify())
		.pipe(dest('./dist/themes/' + themeName + '/js'));
}

function footerScriptsProd() {
	return src(footerJS)
		.pipe(plumber({ errorHandler: onError }))
		.pipe(
			babel({
				presets: ['@babel/preset-env'],
			})
		)
		.pipe(concat('footer-bundle.js'))
		.pipe(uglify())
		.pipe(dest('./dist/themes/' + themeName + '/js'));
}

function pluginsProd() {
	return src(['./src/plugins/**', '!./src/plugins/**/*.md']).pipe(
		dest('./dist/plugins')
	);
}

function processImages() {
	return src('./src/assets/img/**')
		.pipe(plumber({ errorHandler: onError }))
		.pipe(
			imagemin([imagemin.svgo({ plugins: [{ removeViewBox: true }] })], {
				verbose: true,
			})
		)
		.pipe(dest('./dist/themes/' + themeName + '/img'));
}

function zipProd() {
	return src('./dist/themes/' + themeName + '/**/*')
		.pipe(zip.dest('./dist/' + themeName + '.zip'))
		.on('end', () => {
			beeper();
			log(pluginsGenerated);
			log(filesGenerated);
			log(thankYou);
		});
}

exports.prod = series(
	cleanProd,
	copyThemeProd,
	copyFontsProd,
	stylesProd,
	headerScriptsProd,
	footerScriptsProd,
	pluginsProd,
	processImages,
	zipProd
);

/* -------------------------------------------------------------------------------------------------
Utility Tasks
-------------------------------------------------------------------------------------------------- */
const onError = (err) => {
	beeper();
	log(wpFy + ' - ' + errorMsg + ' ' + err.toString());
	this.emit('end');
};

function Backup() {
	if (!fs.existsSync('./build')) {
		log(buildNotFound);
		process.exit(1);
	} else {
		return src('./build/**/*')
			.pipe(zip.dest('./backups/' + date + '.zip'))
			.on('end', () => {
				beeper();
				log(backupsGenerated);
				log(thankYou);
			});
	}
}

exports.backup = Backup;

/* -------------------------------------------------------------------------------------------------
Messages
-------------------------------------------------------------------------------------------------- */
const date = new Date().toLocaleDateString('en-GB').replace(/\//g, '.');
const errorMsg = '\x1b[41mError\x1b[0m';
const warning = '\x1b[43mWarning\x1b[0m';
const devServerReady =
	'Your development server is ready, start the workflow with the command: $ \x1b[1mnpm run dev\x1b[0m';
const buildNotFound =
	errorMsg +
	' ⚠　- You need to build the project first. Run the command: $ \x1b[1mnpm run env:start\x1b[0m';
const filesGenerated =
	'Your ZIP template file was generated in: \x1b[1m' +
	__dirname +
	'/dist/' +
	themeName +
	'.zip\x1b[0m - ✅';
const pluginsGenerated =
	'Plugins are generated in: \x1b[1m' + __dirname + '/dist/plugins/\x1b[0m - ✅';
const backupsGenerated =
	'Your backup was generated in: \x1b[1m' +
	__dirname +
	'/backups/' +
	date +
	'.zip\x1b[0m - ✅';
const wpFy = '\x1b[42m\x1b[1mWordPressify\x1b[0m';
const wpFyUrl = '\x1b[2m - http://www.wordpressify.co/\x1b[0m';
const thankYou = 'Thank you for using ' + wpFy + wpFyUrl;

/* -------------------------------------------------------------------------------------------------
End of all Tasks
-------------------------------------------------------------------------------------------------- */
<|endoftext|>


<commit_before>var gulp = require("gulp");
var concat = require('gulp-concat');
var babel = require("gulp-babel");

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

gulp.task("minifycss", function () {
    gulp.src("src/css/*.css")
        .pipe(concat("machete.css"))
        .pipe(gulp.dest("build/css/"));
});

gulp.task("minifyjs", function () {
    return gulp.src("src/js/**/*.js")
        .pipe(concat("machete.js"))
        .pipe(gulp.dest("build/js/"));
});

gulp.task("default", ["minifycss", "minifyjs"], function () {});

gulp.watch("./src/**", ["default"]);
<commit_msg>Fix gulp build<commit_after>var gulp = require("gulp");
var concat = require('gulp-concat');

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

gulp.task("minifycss", function () {
    gulp.src("src/css/*.css")
        .pipe(concat("machete.css"))
        .pipe(gulp.dest("build/css/"));
});

gulp.task("minifyjs", function () {
    return gulp.src("src/js/**/*.js")
        .pipe(concat("machete.js"))
        .pipe(gulp.dest("build/js/"));
});

gulp.task("default", ["minifycss", "minifyjs"], function () {});

gulp.watch("./src/**", ["default"]);
<|endoftext|>


<commit_before>import cornerstone from 'cornerstone-core';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
import debounce from 'lodash.debounce';

import StackManager from '../utils/StackManager';
import { StudyPrefetcher } from './StudyPrefetcher';

class BaseLoadingListener {
  constructor(stack, options = {}) {
    this.id = BaseLoadingListener.getNewId();
    this.stack = stack;
    this.statsItemsLimit = options.statsItemsLimit || 2;
    this.stats = {
      items: [],
      total: 0,
      elapsedTime: 0,
      speed: 0,
    };

    this._setProgressData = options._setProgressData;
    this._clearProgressById = options._clearProgressById;

    // Register the start point to make it possible to calculate
    // bytes/s or frames/s when the first byte or frame is received
    this._addStatsData(0);

    // Update the progress before starting the download
    // to make it possible to update the UI
    this._updateProgress();
  }

  _addStatsData(value) {
    const date = new Date();
    const stats = this.stats;
    const items = stats.items;
    const newItem = {
      value,
      date,
    };

    items.push(newItem);
    stats.total += newItem.value;

    // Remove items until it gets below the limit
    while (items.length > this.statsItemsLimit) {
      const item = items.shift();
      stats.total -= item.value;
    }

    // Update the elapsedTime (seconds) based on first and last
    // elements and recalculate the speed (bytes/s or frames/s)
    if (items.length > 1) {
      const oldestItem = items[0];
      stats.elapsedTime =
        (newItem.date.getTime() - oldestItem.date.getTime()) / 1000;
      stats.speed = (stats.total - oldestItem.value) / stats.elapsedTime;
    }
  }

  _getProgressId() {
    /**
     * TODO: The id key should be configurable.
     */
    const displaySetInstanceUID = this.stack.displaySetInstanceUID;
    return 'StackProgress:' + displaySetInstanceUID;
  }

  _clearProgress() {
    const progressId = this._getProgressId();
    this._clearProgressById(progressId);
  }

  startListening() {
    throw new Error('`startListening` must be implemented by child classes');
  }

  stopListening() {
    throw new Error('`stopListening` must be implemented by child classes');
  }

  destroy() {
    this.stopListening();
    this._clearProgress();
  }

  static getNewId() {
    const timeSlice = new Date()
      .getTime()
      .toString()
      .slice(-8);
    const randomNumber = parseInt(Math.random() * 1000000000);

    return timeSlice.toString() + randomNumber.toString();
  }
}

class DICOMFileLoadingListener extends BaseLoadingListener {
  constructor(stack, options) {
    super(stack, options);

    this.imageLoadProgressEventHandler = this._imageLoadProgressEventHandle.bind(
      this
    );

    this._dataSetUrl = this._getDataSetUrl(stack);
    this._lastLoaded = 0;

    // Check how many instances has already been download (cached)
    this._checkCachedData();

    this.startListening();
  }

  _checkCachedData() {
    const dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(
      this._dataSetUrl
    );

    if (dataSet) {
      const dataSetLength = dataSet.byteArray.length;

      this._updateProgress({
        percentComplete: 100,
        loaded: dataSetLength,
        total: dataSetLength,
      });
    }
  }

  _getImageLoadProgressEventName() {
    // TODO: Add this event as a constant in Cornerstone
    return 'cornerstoneimageloadprogress.' + this.id;
  }

  startListening() {
    const imageLoadProgressEventName = this._getImageLoadProgressEventName();

    this.stopListening();

    cornerstone.events.addEventListener(
      imageLoadProgressEventName,
      this.imageLoadProgressEventHandle
    );
  }

  stopListening() {
    const imageLoadProgressEventName = this._getImageLoadProgressEventName();
    cornerstone.events.removeEventListener(
      imageLoadProgressEventName,
      this.imageLoadProgressEventHandle
    );
  }

  _imageLoadProgressEventHandler = e => {
    const eventData = e.detail;
    const dataSetUrl = this._convertImageIdToDataSetUrl(eventData.imageId);
    const bytesDiff = eventData.loaded - this._lastLoaded;

    if (!this._dataSetUrl === dataSetUrl) {
      return;
    }

    // Add the bytes downloaded to the stats
    this._addStatsData(bytesDiff);

    // Update the download progress
    this._updateProgress(eventData);

    // Cache the last eventData.loaded value
    this._lastLoaded = eventData.loaded;
  };

  _updateProgress(eventData) {
    const progressId = this._getProgressId();
    eventData = eventData || {};

    const progressData = {
      multiFrame: false,
      percentComplete: eventData.percentComplete,
      bytesLoaded: eventData.loaded,
      bytesTotal: eventData.total,
      bytesPerSecond: this.stats.speed,
    };

    this._setProgressData(progressId, progressData);
  }

  _convertImageIdToDataSetUrl(imageId) {
    // Remove the prefix ("dicomweb:" or "wadouri:"")
    imageId = imageId.replace(/^(dicomweb:|wadouri:)/i, '');

    // Remove "frame=999&" from the imageId
    imageId = imageId.replace(/frame=\d+&?/i, '');

    // Remove the last "&" like in "http://...?foo=1&bar=2&"
    imageId = imageId.replace(/&$/, '');

    return imageId;
  }

  _getDataSetUrl(stack) {
    const imageId = stack.imageIds[0];
    return this._convertImageIdToDataSetUrl(imageId);
  }
}

const StudyLoadingListenerEvents = {
  OnProgress: 'StudyLoadingListenerEvents.OnProgress',
};

function promiseState(promise, callback) {
  // Symbols and RegExps are never content-equal
  var uniqueValue = window['Symbol'] ? Symbol('unique') : /unique/;

  function notifyPendingOrResolved(value) {
    if (value === uniqueValue) {
      return callback('pending');
    } else {
      return callback('fulfilled');
    }
  }

  function notifyRejected(reason) {
    return callback('rejected');
  }

  var race = [promise, Promise.resolve(uniqueValue)];
  Promise.race(race).then(notifyPendingOrResolved, notifyRejected);
}

class StackLoadingListener extends BaseLoadingListener {
  constructor(stack, options = {}) {
    options.statsItemsLimit = 20;

    super(stack, options);

    this.imageLoadedEventHandler = this._imageLoadedEventHandler.bind(this);
    this.imageCachePromiseRemovedEventHandler = this._imageCachePromiseRemovedEventHandler.bind(
      this
    );

    this.imageDataMap = this._convertImageIdsArrayToMap(stack.imageIds);
    this.framesStatus = this._createArray(stack.imageIds.length, false);
    this.loadedCount = 0;

    // Check how many instances has already been download (cached)
    this._debouncedSetProgressData = debounce((...args) => {
      this._setProgressData(...args);

      /** After checking cache, continue prefetch */
      const studyPrefetcher = StudyPrefetcher.getInstance();
      studyPrefetcher.prefetch(studyPrefetcher.getElement());
    }, 300);
    const debounced = true;
    this._checkCachedData(debounced);

    this.startListening();
  }

  _convertImageIdsArrayToMap(imageIds) {
    const imageIdsMap = new Map();

    for (let i = 0; i < imageIds.length; i++) {
      imageIdsMap.set(imageIds[i], {
        index: i,
        loaded: false,
      });
    }

    return imageIdsMap;
  }

  _createArray(length, defaultValue) {
    // `new Array(length)` is an anti-pattern in javascript because its
    // funny API. Otherwise I would go for `new Array(length).fill(false)`
    const array = [];

    for (let i = 0; i < length; i++) {
      array[i] = defaultValue;
    }

    return array;
  }

  /**
   * Check if image id is cached in cornerstone.
   *
   * @param {string} imageId
   * @returns
   */
  isImageCached(imageId) {
    const image = cornerstone.imageCache.imageCache[imageId];
    return image && image.sizeInBytes;
  }

  _checkCachedData(debounced = false) {
    const imageIds = this.stack.imageIds;

    for (let i = 0; i < imageIds.length; i++) {
      const imageId = imageIds[i];

      const imageObject = cornerstone.imageCache.getImageLoadObject(imageId);

      if (this.isImageCached(imageId)) {
        this._updateFrameStatus(imageId, true, debounced);
      }

      if (imageObject && imageObject.promise) {
        promiseState(imageObject.promise, state => {
          if (state === 'fulfilled') {
            this._updateFrameStatus(imageId, true, debounced);
          }
        });
      }
    }
  }

  _getImageLoadedEventName() {
    return `${cornerstone.EVENTS.IMAGE_LOADED}.${this.id}`;
  }

  _getImageCachePromiseRemoveEventName() {
    return `${cornerstone.EVENTS.IMAGE_CACHE_PROMISE_REMOVED}.${this.id}`;
  }

  _imageLoadedEventHandler(e) {
    this._updateFrameStatus(e.detail.image.imageId, true);
  }

  _imageCachePromiseRemovedEventHandler(e) {
    this._updateFrameStatus(e.detail.imageId, false);
  }

  startListening() {
    const imageLoadedEventName = this._getImageLoadedEventName();
    const imageCachePromiseRemovedEventName = this._getImageCachePromiseRemoveEventName();

    this.stopListening();

    cornerstone.events.addEventListener(
      imageLoadedEventName,
      this.imageLoadedEventHandler
    );
    cornerstone.events.addEventListener(
      imageCachePromiseRemovedEventName,
      this.imageCachePromiseRemovedEventHandler
    );
  }

  stopListening() {
    const imageLoadedEventName = this._getImageLoadedEventName();
    const imageCachePromiseRemovedEventName = this._getImageCachePromiseRemoveEventName();

    cornerstone.events.removeEventListener(
      imageLoadedEventName,
      this.imageLoadedEventHandler
    );
    cornerstone.events.removeEventListener(
      imageCachePromiseRemovedEventName,
      this.imageCachePromiseRemovedEventHandler
    );
  }

  _updateFrameStatus(imageId, loaded, debounced) {
    const imageData = this.imageDataMap.get(imageId);

    if (!imageData || imageData.loaded === loaded) {
      return;
    }

    // Add one more frame to the stats
    if (loaded) {
      this._addStatsData(1);
    }

    imageData.loaded = loaded;
    this.framesStatus[imageData.index] = loaded;
    this.loadedCount += loaded ? 1 : -1;
    this._updateProgress(debounced);
  }

  _setProgressData(progressId, progressData) {
    // TODO: This method (and _clearProgressById) need to access
    // the Redux store and should therefore be provided from the
    // application. I've added a workaround to pass this in through
    // the 'options' variable on instantiation, but this is really ugly.
    // We could consider making the StudyLoadingListener a higher-order
    // component which would set this stuff itself.
    throw new Error(
      "The _setProgressData function must be provided in StudyLoadingListener's options"
    );
  }

  _clearProgressById(progressId) {
    throw new Error(
      "The _clearProgressById function must be provided in StudyLoadingListener's options"
    );
  }

  _updateProgress(debounced) {
    const totalFramesCount = this.stack.imageIds.length;
    const loadedFramesCount = this.loadedCount;
    const loadingFramesCount = totalFramesCount - loadedFramesCount;
    const percentComplete = Math.round(
      (loadedFramesCount / totalFramesCount) * 100
    );
    const progressId = this._getProgressId();
    const progressData = {
      multiFrame: true,
      totalFramesCount,
      loadedFramesCount,
      loadingFramesCount,
      percentComplete,
      framesPerSecond: this.stats.speed,
      framesStatus: this.framesStatus,
    };

    if (debounced) {
      this._debouncedSetProgressData(progressId, progressData);
      return;
    }

    this._setProgressData(progressId, progressData);
  }

  _logProgress() {
    const totalFramesCount = this.stack.imageIds.length;
    const displaySetInstanceUID = this.stack.displaySetInstanceUID;
    let progressBar = '[';

    for (let i = 0; i < totalFramesCount; i++) {
      const ch = this.framesStatus[i] ? '|' : '.';
      progressBar += `${ch}`;
    }

    progressBar += ']';
    console.info(`${displaySetInstanceUID}: ${progressBar}`);
  }
}

class StudyLoadingListener {
  static events = StudyLoadingListenerEvents;

  constructor(options) {
    this.listeners = {};
    this.options = options;
  }

  addStack(stack, stackMetaData) {
    // TODO: Make this work for plugins
    if (!stack) {
      //console.log('Skipping adding stack to StudyLoadingListener');
      return;
    }

    const displaySetInstanceUID = stack.displaySetInstanceUID;

    if (!this.listeners[displaySetInstanceUID]) {
      const listener = this._createListener(stack, stackMetaData);
      if (listener) {
        this.listeners[displaySetInstanceUID] = listener;
      }
    }
  }

  addStudy(study) {
    study.displaySets.forEach(displaySet => {
      const stack = StackManager.findOrCreateStack(study, displaySet);

      // TODO: Make this work for plugins
      if (!stack) {
        console.warn('Skipping adding displaySet to StudyLoadingListener');
        console.warn(displaySet);
        return;
      }

      this.addStack(stack, {
        isMultiFrame: displaySet.isMultiFrame,
      });
    });
  }

  addStudies(studies) {
    if (!studies || !studies.length) {
      return;
    }

    studies.forEach(study => this.addStudy(study));
  }

  clear() {
    const displaySetInstanceUIDs = Object.keys(this.listeners);
    const length = displaySetInstanceUIDs.length;

    for (let i = 0; i < length; i++) {
      const displaySetInstanceUID = displaySetInstanceUIDs[i];
      const displaySet = this.listeners[displaySetInstanceUID];

      displaySet.destroy();
    }

    this.listeners = {};
  }

  _createListener(stack, stackMetaData) {
    const schema = this._getSchema(stack);

    // A StackLoadingListener can be created if it's wadors or not a multiframe
    // wadouri instance (single file) that means "N" files will have to be
    // downloaded where "N" is the number of frames. DICOMFileLoadingListener
    // is created only if it's a single DICOM file and there's no way to know
    // how many frames has already been loaded (bytes/s instead of frames/s).
    if (schema === 'wadors' || !stackMetaData.isMultiFrame) {
      return new StackLoadingListener(stack, this.options);
    } else {
      return new DICOMFileLoadingListener(stack, this.options);
    }
  }

  _getSchema(stack) {
    const imageId = stack.imageIds[0];
    if (!imageId) {
      return;
    }
    const colonIndex = imageId.indexOf(':');
    return imageId.substring(0, colonIndex);
  }

  static getInstance(options) {
    /**
     * TODO: Use a different alternative without the use of events.
     */
    const DEFAULT_OPTIONS = {
      _setProgressData: (progressId, progressData) => {
        const event = new CustomEvent(StudyLoadingListenerEvents.OnProgress, {
          detail: { progressId, progressData },
        });
        document.dispatchEvent(event);
      },
      _clearProgressById: progressId => {
        const event = new CustomEvent(StudyLoadingListenerEvents.OnProgress, {
          detail: { progressId, percentComplete: 0 },
        });
        document.dispatchEvent(event);
      },
    };

    if (!StudyLoadingListener._instance) {
      StudyLoadingListener._instance = new StudyLoadingListener(
        options || DEFAULT_OPTIONS
      );
    }

    return StudyLoadingListener._instance;
  }
}

export { StudyLoadingListener, StackLoadingListener, DICOMFileLoadingListener };
<commit_msg>fix: DICOMFileLoadingListener typo in method name (#2647)<commit_after>import cornerstone from 'cornerstone-core';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
import debounce from 'lodash.debounce';

import StackManager from '../utils/StackManager';
import { StudyPrefetcher } from './StudyPrefetcher';

class BaseLoadingListener {
  constructor(stack, options = {}) {
    this.id = BaseLoadingListener.getNewId();
    this.stack = stack;
    this.statsItemsLimit = options.statsItemsLimit || 2;
    this.stats = {
      items: [],
      total: 0,
      elapsedTime: 0,
      speed: 0,
    };

    this._setProgressData = options._setProgressData;
    this._clearProgressById = options._clearProgressById;

    // Register the start point to make it possible to calculate
    // bytes/s or frames/s when the first byte or frame is received
    this._addStatsData(0);

    // Update the progress before starting the download
    // to make it possible to update the UI
    this._updateProgress();
  }

  _addStatsData(value) {
    const date = new Date();
    const stats = this.stats;
    const items = stats.items;
    const newItem = {
      value,
      date,
    };

    items.push(newItem);
    stats.total += newItem.value;

    // Remove items until it gets below the limit
    while (items.length > this.statsItemsLimit) {
      const item = items.shift();
      stats.total -= item.value;
    }

    // Update the elapsedTime (seconds) based on first and last
    // elements and recalculate the speed (bytes/s or frames/s)
    if (items.length > 1) {
      const oldestItem = items[0];
      stats.elapsedTime =
        (newItem.date.getTime() - oldestItem.date.getTime()) / 1000;
      stats.speed = (stats.total - oldestItem.value) / stats.elapsedTime;
    }
  }

  _getProgressId() {
    /**
     * TODO: The id key should be configurable.
     */
    const displaySetInstanceUID = this.stack.displaySetInstanceUID;
    return 'StackProgress:' + displaySetInstanceUID;
  }

  _clearProgress() {
    const progressId = this._getProgressId();
    this._clearProgressById(progressId);
  }

  startListening() {
    throw new Error('`startListening` must be implemented by child classes');
  }

  stopListening() {
    throw new Error('`stopListening` must be implemented by child classes');
  }

  destroy() {
    this.stopListening();
    this._clearProgress();
  }

  static getNewId() {
    const timeSlice = new Date()
      .getTime()
      .toString()
      .slice(-8);
    const randomNumber = parseInt(Math.random() * 1000000000);

    return timeSlice.toString() + randomNumber.toString();
  }
}

class DICOMFileLoadingListener extends BaseLoadingListener {
  constructor(stack, options) {
    super(stack, options);

    this.imageLoadProgressEventHandler = this._imageLoadProgressEventHandler.bind(
      this
    );

    this._dataSetUrl = this._getDataSetUrl(stack);
    this._lastLoaded = 0;

    // Check how many instances has already been download (cached)
    this._checkCachedData();

    this.startListening();
  }

  _checkCachedData() {
    const dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(
      this._dataSetUrl
    );

    if (dataSet) {
      const dataSetLength = dataSet.byteArray.length;

      this._updateProgress({
        percentComplete: 100,
        loaded: dataSetLength,
        total: dataSetLength,
      });
    }
  }

  _getImageLoadProgressEventName() {
    // TODO: Add this event as a constant in Cornerstone
    return 'cornerstoneimageloadprogress.' + this.id;
  }

  startListening() {
    const imageLoadProgressEventName = this._getImageLoadProgressEventName();

    this.stopListening();

    cornerstone.events.addEventListener(
      imageLoadProgressEventName,
      this.imageLoadProgressEventHandle
    );
  }

  stopListening() {
    const imageLoadProgressEventName = this._getImageLoadProgressEventName();
    cornerstone.events.removeEventListener(
      imageLoadProgressEventName,
      this.imageLoadProgressEventHandle
    );
  }

  _imageLoadProgressEventHandler = e => {
    const eventData = e.detail;
    const dataSetUrl = this._convertImageIdToDataSetUrl(eventData.imageId);
    const bytesDiff = eventData.loaded - this._lastLoaded;

    if (!this._dataSetUrl === dataSetUrl) {
      return;
    }

    // Add the bytes downloaded to the stats
    this._addStatsData(bytesDiff);

    // Update the download progress
    this._updateProgress(eventData);

    // Cache the last eventData.loaded value
    this._lastLoaded = eventData.loaded;
  };

  _updateProgress(eventData) {
    const progressId = this._getProgressId();
    eventData = eventData || {};

    const progressData = {
      multiFrame: false,
      percentComplete: eventData.percentComplete,
      bytesLoaded: eventData.loaded,
      bytesTotal: eventData.total,
      bytesPerSecond: this.stats.speed,
    };

    this._setProgressData(progressId, progressData);
  }

  _convertImageIdToDataSetUrl(imageId) {
    // Remove the prefix ("dicomweb:" or "wadouri:"")
    imageId = imageId.replace(/^(dicomweb:|wadouri:)/i, '');

    // Remove "frame=999&" from the imageId
    imageId = imageId.replace(/frame=\d+&?/i, '');

    // Remove the last "&" like in "http://...?foo=1&bar=2&"
    imageId = imageId.replace(/&$/, '');

    return imageId;
  }

  _getDataSetUrl(stack) {
    const imageId = stack.imageIds[0];
    return this._convertImageIdToDataSetUrl(imageId);
  }
}

const StudyLoadingListenerEvents = {
  OnProgress: 'StudyLoadingListenerEvents.OnProgress',
};

function promiseState(promise, callback) {
  // Symbols and RegExps are never content-equal
  var uniqueValue = window['Symbol'] ? Symbol('unique') : /unique/;

  function notifyPendingOrResolved(value) {
    if (value === uniqueValue) {
      return callback('pending');
    } else {
      return callback('fulfilled');
    }
  }

  function notifyRejected(reason) {
    return callback('rejected');
  }

  var race = [promise, Promise.resolve(uniqueValue)];
  Promise.race(race).then(notifyPendingOrResolved, notifyRejected);
}

class StackLoadingListener extends BaseLoadingListener {
  constructor(stack, options = {}) {
    options.statsItemsLimit = 20;

    super(stack, options);

    this.imageLoadedEventHandler = this._imageLoadedEventHandler.bind(this);
    this.imageCachePromiseRemovedEventHandler = this._imageCachePromiseRemovedEventHandler.bind(
      this
    );

    this.imageDataMap = this._convertImageIdsArrayToMap(stack.imageIds);
    this.framesStatus = this._createArray(stack.imageIds.length, false);
    this.loadedCount = 0;

    // Check how many instances has already been download (cached)
    this._debouncedSetProgressData = debounce((...args) => {
      this._setProgressData(...args);

      /** After checking cache, continue prefetch */
      const studyPrefetcher = StudyPrefetcher.getInstance();
      studyPrefetcher.prefetch(studyPrefetcher.getElement());
    }, 300);
    const debounced = true;
    this._checkCachedData(debounced);

    this.startListening();
  }

  _convertImageIdsArrayToMap(imageIds) {
    const imageIdsMap = new Map();

    for (let i = 0; i < imageIds.length; i++) {
      imageIdsMap.set(imageIds[i], {
        index: i,
        loaded: false,
      });
    }

    return imageIdsMap;
  }

  _createArray(length, defaultValue) {
    // `new Array(length)` is an anti-pattern in javascript because its
    // funny API. Otherwise I would go for `new Array(length).fill(false)`
    const array = [];

    for (let i = 0; i < length; i++) {
      array[i] = defaultValue;
    }

    return array;
  }

  /**
   * Check if image id is cached in cornerstone.
   *
   * @param {string} imageId
   * @returns
   */
  isImageCached(imageId) {
    const image = cornerstone.imageCache.imageCache[imageId];
    return image && image.sizeInBytes;
  }

  _checkCachedData(debounced = false) {
    const imageIds = this.stack.imageIds;

    for (let i = 0; i < imageIds.length; i++) {
      const imageId = imageIds[i];

      const imageObject = cornerstone.imageCache.getImageLoadObject(imageId);

      if (this.isImageCached(imageId)) {
        this._updateFrameStatus(imageId, true, debounced);
      }

      if (imageObject && imageObject.promise) {
        promiseState(imageObject.promise, state => {
          if (state === 'fulfilled') {
            this._updateFrameStatus(imageId, true, debounced);
          }
        });
      }
    }
  }

  _getImageLoadedEventName() {
    return `${cornerstone.EVENTS.IMAGE_LOADED}.${this.id}`;
  }

  _getImageCachePromiseRemoveEventName() {
    return `${cornerstone.EVENTS.IMAGE_CACHE_PROMISE_REMOVED}.${this.id}`;
  }

  _imageLoadedEventHandler(e) {
    this._updateFrameStatus(e.detail.image.imageId, true);
  }

  _imageCachePromiseRemovedEventHandler(e) {
    this._updateFrameStatus(e.detail.imageId, false);
  }

  startListening() {
    const imageLoadedEventName = this._getImageLoadedEventName();
    const imageCachePromiseRemovedEventName = this._getImageCachePromiseRemoveEventName();

    this.stopListening();

    cornerstone.events.addEventListener(
      imageLoadedEventName,
      this.imageLoadedEventHandler
    );
    cornerstone.events.addEventListener(
      imageCachePromiseRemovedEventName,
      this.imageCachePromiseRemovedEventHandler
    );
  }

  stopListening() {
    const imageLoadedEventName = this._getImageLoadedEventName();
    const imageCachePromiseRemovedEventName = this._getImageCachePromiseRemoveEventName();

    cornerstone.events.removeEventListener(
      imageLoadedEventName,
      this.imageLoadedEventHandler
    );
    cornerstone.events.removeEventListener(
      imageCachePromiseRemovedEventName,
      this.imageCachePromiseRemovedEventHandler
    );
  }

  _updateFrameStatus(imageId, loaded, debounced) {
    const imageData = this.imageDataMap.get(imageId);

    if (!imageData || imageData.loaded === loaded) {
      return;
    }

    // Add one more frame to the stats
    if (loaded) {
      this._addStatsData(1);
    }

    imageData.loaded = loaded;
    this.framesStatus[imageData.index] = loaded;
    this.loadedCount += loaded ? 1 : -1;
    this._updateProgress(debounced);
  }

  _setProgressData(progressId, progressData) {
    // TODO: This method (and _clearProgressById) need to access
    // the Redux store and should therefore be provided from the
    // application. I've added a workaround to pass this in through
    // the 'options' variable on instantiation, but this is really ugly.
    // We could consider making the StudyLoadingListener a higher-order
    // component which would set this stuff itself.
    throw new Error(
      "The _setProgressData function must be provided in StudyLoadingListener's options"
    );
  }

  _clearProgressById(progressId) {
    throw new Error(
      "The _clearProgressById function must be provided in StudyLoadingListener's options"
    );
  }

  _updateProgress(debounced) {
    const totalFramesCount = this.stack.imageIds.length;
    const loadedFramesCount = this.loadedCount;
    const loadingFramesCount = totalFramesCount - loadedFramesCount;
    const percentComplete = Math.round(
      (loadedFramesCount / totalFramesCount) * 100
    );
    const progressId = this._getProgressId();
    const progressData = {
      multiFrame: true,
      totalFramesCount,
      loadedFramesCount,
      loadingFramesCount,
      percentComplete,
      framesPerSecond: this.stats.speed,
      framesStatus: this.framesStatus,
    };

    if (debounced) {
      this._debouncedSetProgressData(progressId, progressData);
      return;
    }

    this._setProgressData(progressId, progressData);
  }

  _logProgress() {
    const totalFramesCount = this.stack.imageIds.length;
    const displaySetInstanceUID = this.stack.displaySetInstanceUID;
    let progressBar = '[';

    for (let i = 0; i < totalFramesCount; i++) {
      const ch = this.framesStatus[i] ? '|' : '.';
      progressBar += `${ch}`;
    }

    progressBar += ']';
    console.info(`${displaySetInstanceUID}: ${progressBar}`);
  }
}

class StudyLoadingListener {
  static events = StudyLoadingListenerEvents;

  constructor(options) {
    this.listeners = {};
    this.options = options;
  }

  addStack(stack, stackMetaData) {
    // TODO: Make this work for plugins
    if (!stack) {
      //console.log('Skipping adding stack to StudyLoadingListener');
      return;
    }

    const displaySetInstanceUID = stack.displaySetInstanceUID;

    if (!this.listeners[displaySetInstanceUID]) {
      const listener = this._createListener(stack, stackMetaData);
      if (listener) {
        this.listeners[displaySetInstanceUID] = listener;
      }
    }
  }

  addStudy(study) {
    study.displaySets.forEach(displaySet => {
      const stack = StackManager.findOrCreateStack(study, displaySet);

      // TODO: Make this work for plugins
      if (!stack) {
        console.warn('Skipping adding displaySet to StudyLoadingListener');
        console.warn(displaySet);
        return;
      }

      this.addStack(stack, {
        isMultiFrame: displaySet.isMultiFrame,
      });
    });
  }

  addStudies(studies) {
    if (!studies || !studies.length) {
      return;
    }

    studies.forEach(study => this.addStudy(study));
  }

  clear() {
    const displaySetInstanceUIDs = Object.keys(this.listeners);
    const length = displaySetInstanceUIDs.length;

    for (let i = 0; i < length; i++) {
      const displaySetInstanceUID = displaySetInstanceUIDs[i];
      const displaySet = this.listeners[displaySetInstanceUID];

      displaySet.destroy();
    }

    this.listeners = {};
  }

  _createListener(stack, stackMetaData) {
    const schema = this._getSchema(stack);

    // A StackLoadingListener can be created if it's wadors or not a multiframe
    // wadouri instance (single file) that means "N" files will have to be
    // downloaded where "N" is the number of frames. DICOMFileLoadingListener
    // is created only if it's a single DICOM file and there's no way to know
    // how many frames has already been loaded (bytes/s instead of frames/s).
    if (schema === 'wadors' || !stackMetaData.isMultiFrame) {
      return new StackLoadingListener(stack, this.options);
    } else {
      return new DICOMFileLoadingListener(stack, this.options);
    }
  }

  _getSchema(stack) {
    const imageId = stack.imageIds[0];
    if (!imageId) {
      return;
    }
    const colonIndex = imageId.indexOf(':');
    return imageId.substring(0, colonIndex);
  }

  static getInstance(options) {
    /**
     * TODO: Use a different alternative without the use of events.
     */
    const DEFAULT_OPTIONS = {
      _setProgressData: (progressId, progressData) => {
        const event = new CustomEvent(StudyLoadingListenerEvents.OnProgress, {
          detail: { progressId, progressData },
        });
        document.dispatchEvent(event);
      },
      _clearProgressById: progressId => {
        const event = new CustomEvent(StudyLoadingListenerEvents.OnProgress, {
          detail: { progressId, percentComplete: 0 },
        });
        document.dispatchEvent(event);
      },
    };

    if (!StudyLoadingListener._instance) {
      StudyLoadingListener._instance = new StudyLoadingListener(
        options || DEFAULT_OPTIONS
      );
    }

    return StudyLoadingListener._instance;
  }
}

export { StudyLoadingListener, StackLoadingListener, DICOMFileLoadingListener };
<|endoftext|>


<commit_before>var autoprefixer = require('autoprefixer');
var babelify = require('babelify');
var browserify = require('browserify');
var gulp = require('gulp');
var gulpRename = require('gulp-rename');
var gulpPostcss = require('gulp-postcss');
var licensify = require('licensify');
var notifier = require('node-notifier');
var path = require('path');
var postcssCustomProperties = require('postcss-custom-properties');
var postcssNested = require('postcss-nested');
var postcssSassyMixins = require('postcss-sassy-mixins');
var postcssScss = require('postcss-scss');
var vinylSourceStream  = require('vinyl-source-stream');
var watchify = require('watchify');

var browserSync = require('browser-sync').create();

//
// Refs)
// https://github.com/Browsersync/recipes/tree/master/recipes/gulp.browserify
// https://gist.github.com/Fishrock123/8ea81dad3197c2f84366
//

var ROOT = __dirname;
var SRC_ROOT = path.join(ROOT, 'src');
var PUBLIC_ROOT = path.join(ROOT, 'public');
var PUBLIC_DIST_ROOT = path.join(PUBLIC_ROOT, 'dist');
var JS_INDEX_FILE_PATH = path.join(SRC_ROOT, 'index.js');
var CSS_INDEX_FILE_PATH = path.join(SRC_ROOT, 'styles/index.scss');
var IMAGES_FILE_PATH = path.join(SRC_ROOT, '**/*.{gif,jpg,png}');
var STYLES_FILE_PATH = path.join(SRC_ROOT, '**/*.scss');

function onErrorToWarn(err) {
  console.error(err.stack);
  notifier.notify({
    message: err.message,
    title: 'Gulp Error'
  });
  this.emit('end');
}

//
// JavaScripts
//

function createBundler(options) {
  options = options || {};
  var transformer = options.transformer || null;
  var isWatchfied = Boolean(options.isWatchfied);

  var browserifyOptions = {};
  if (isWatchfied) {
    Object.keys(watchify.args).forEach(function(key) {
      browserifyOptions[key] = watchify.args[key];
    });
  }
  // Pass options to browserify by whitelist
  [
    'debug'
  ].forEach(function(key) {
    browserifyOptions[key] = options[key];
  });

  var bundler = browserify(JS_INDEX_FILE_PATH, browserifyOptions);

  if (transformer) {
    bundler.transform(transformer);
  }

  if (isWatchfied) {
    bundler = watchify(bundler);
  }

  return bundler;
}

function createTransformer() {
  return babelify.configure({
    // Configure babel options here
    // Ref) http://babeljs.io/docs/usage/options/
  });
}

function bundle(bundler, options) {
  options = options || {};
  var onError = options.onError || function onError(err) { throw err; };

  return bundler
    .bundle()
    .on('error', onError)
    .pipe(vinylSourceStream('app.js'))
    .pipe(gulp.dest(PUBLIC_DIST_ROOT))
  ;
}

gulp.task('build:js', function() {
  var bundler = createBundler({
    transformer: createTransformer(),
    debug: true  // Enable source map
    //extensions: ['js', 'jsx']
  });
  return bundle(bundler);
});

gulp.task('watch:js', function() {
  var bundler = createBundler({
    transformer: createTransformer(),
    isWatchfied: true,
    debug: true
  });
  bundle(bundler);

  bundler.on('update', function onUpdate() {
    console.log('Build JavaScripts at ' + (new Date()).toTimeString());
    var bundling = bundle(bundler,{
      onError: onErrorToWarn
    });
    bundling.pipe(browserSync.stream({ once: true }));
  });
});

//
// Stylesheets & Other Asserts
//

function createCssBundler(options) {
  options = options || {};
  var onError = options.onError || function onError(err) { throw err; };

  return gulp.src(CSS_INDEX_FILE_PATH)
    .pipe(gulpPostcss([
      postcssCustomProperties(),
      // Output "Container#eachAtRule is deprecated. Use Container#walkAtRules instead." now
      postcssSassyMixins(),
      postcssNested(),
      autoprefixer()
    ], {
      syntax: postcssScss
    }))
    .on('error', onError)
    .pipe(gulpRename('app.css'))
    .pipe(gulp.dest(PUBLIC_DIST_ROOT))
  ;
};

gulp.task('build:css', function() {
  return createCssBundler();
});

gulp.task('build:images', function() {
  return gulp.src(IMAGES_FILE_PATH)
    .pipe(gulp.dest(PUBLIC_DIST_ROOT))
  ;
});

gulp.task('watch:assets', function() {

  // css
  gulp.watch([STYLES_FILE_PATH], function() {
    return createCssBundler({ onError: onErrorToWarn })
      .pipe(browserSync.stream({ once: true }))
      .on('data', function() {
        console.log('Build stylesheets at ' + new Date().toTimeString());
      })
    ;
  });

  // images
  gulp.watch([IMAGES_FILE_PATH], function() {
    return gulp.src(IMAGES_FILE_PATH)
      .on('error', onErrorToWarn)
      .pipe(gulp.dest(PUBLIC_DIST_ROOT))
      .on('data', function() {
        console.log('Build images at ' + new Date().toTimeString());
      })
    ;
  });
});

//
// Others
//

gulp.task('serve', function() {
  browserSync.init({
    server: {
      baseDir: PUBLIC_ROOT
    },
    notify: false
  });
});

gulp.task('build', ['build:images', 'build:css', 'build:js']);
gulp.task('develop', ['watch:assets', 'watch:js', 'serve']);
<commit_msg>Add a comment<commit_after>var autoprefixer = require('autoprefixer');
var babelify = require('babelify');
var browserify = require('browserify');
var gulp = require('gulp');
var gulpRename = require('gulp-rename');
var gulpPostcss = require('gulp-postcss');
var licensify = require('licensify');
var notifier = require('node-notifier');
var path = require('path');
var postcssCustomProperties = require('postcss-custom-properties');
var postcssNested = require('postcss-nested');
var postcssSassyMixins = require('postcss-sassy-mixins');
var postcssScss = require('postcss-scss');
var vinylSourceStream  = require('vinyl-source-stream');
var watchify = require('watchify');

var browserSync = require('browser-sync').create();

//
// Refs)
// https://github.com/Browsersync/recipes/tree/master/recipes/gulp.browserify
// https://gist.github.com/Fishrock123/8ea81dad3197c2f84366
//

var ROOT = __dirname;
var SRC_ROOT = path.join(ROOT, 'src');
var PUBLIC_ROOT = path.join(ROOT, 'public');
var PUBLIC_DIST_ROOT = path.join(PUBLIC_ROOT, 'dist');
var JS_INDEX_FILE_PATH = path.join(SRC_ROOT, 'index.js');
var CSS_INDEX_FILE_PATH = path.join(SRC_ROOT, 'styles/index.scss');
var IMAGES_FILE_PATH = path.join(SRC_ROOT, '**/*.{gif,jpg,png}');
var STYLES_FILE_PATH = path.join(SRC_ROOT, '**/*.scss');

function onErrorToWarn(err) {
  console.error(err.stack);
  notifier.notify({
    message: err.message,
    title: 'Gulp Error'
  });
  this.emit('end');
}

//
// JavaScripts
//

function createBundler(options) {
  options = options || {};
  var transformer = options.transformer || null;
  var isWatchfied = Boolean(options.isWatchfied);

  var browserifyOptions = {};
  if (isWatchfied) {
    Object.keys(watchify.args).forEach(function(key) {
      browserifyOptions[key] = watchify.args[key];
    });
  }
  // Pass options to browserify by whitelist
  [
    'debug'
  ].forEach(function(key) {
    browserifyOptions[key] = options[key];
  });

  var bundler = browserify(JS_INDEX_FILE_PATH, browserifyOptions);

  if (transformer) {
    bundler.transform(transformer);
  }

  if (isWatchfied) {
    bundler = watchify(bundler);
  }

  return bundler;
}

function createTransformer() {
  return babelify.configure({
    // Configure babel options here
    // Ref) http://babeljs.io/docs/usage/options/
  });
}

function bundle(bundler, options) {
  options = options || {};
  var onError = options.onError || function onError(err) { throw err; };

  return bundler
    .bundle()
    .on('error', onError)
    .pipe(vinylSourceStream('app.js'))
    .pipe(gulp.dest(PUBLIC_DIST_ROOT))
  ;
}

gulp.task('build:js', function() {
  var bundler = createBundler({
    transformer: createTransformer(),
    debug: true  // Enable source map
    //extensions: ['js', 'jsx']
  });
  return bundle(bundler);
});

gulp.task('watch:js', function() {
  var bundler = createBundler({
    transformer: createTransformer(),
    isWatchfied: true,
    debug: true
  });
  bundle(bundler);

  bundler.on('update', function onUpdate() {
    console.log('Build JavaScripts at ' + (new Date()).toTimeString());
    var bundling = bundle(bundler,{
      onError: onErrorToWarn
    });
    bundling.pipe(browserSync.stream({ once: true }));
  });
});

//
// Stylesheets & Other Asserts
//

function createCssBundler(options) {
  options = options || {};
  var onError = options.onError || function onError(err) { throw err; };

  return gulp.src(CSS_INDEX_FILE_PATH)
    .pipe(gulpPostcss([
      postcssCustomProperties(),
      // Output "Container#eachAtRule is deprecated. Use Container#walkAtRules instead." now
      postcssSassyMixins(),
      postcssNested(),
      autoprefixer()
    ], {
      syntax: postcssScss
    }))
    .on('error', onError)
    .pipe(gulpRename('app.css'))
    .pipe(gulp.dest(PUBLIC_DIST_ROOT))
  ;
};

gulp.task('build:css', function() {
  return createCssBundler();
});

gulp.task('build:images', function() {
  return gulp.src(IMAGES_FILE_PATH)
    .pipe(gulp.dest(PUBLIC_DIST_ROOT))
  ;
});

gulp.task('watch:assets', function() {

  // css
  gulp.watch([STYLES_FILE_PATH], function() {
    return createCssBundler({ onError: onErrorToWarn })
      .pipe(browserSync.stream({ once: true }))
      .on('data', function() {
        console.log('Build stylesheets at ' + new Date().toTimeString());
      })
    ;
  });

  // images
  // Note: This task is almost useless, because gulp can not observe new files
  gulp.watch([IMAGES_FILE_PATH], function() {
    return gulp.src(IMAGES_FILE_PATH)
      .on('error', onErrorToWarn)
      .pipe(gulp.dest(PUBLIC_DIST_ROOT))
      .on('data', function() {
        console.log('Build images at ' + new Date().toTimeString());
      })
    ;
  });
});

//
// Others
//

gulp.task('serve', function() {
  browserSync.init({
    server: {
      baseDir: PUBLIC_ROOT
    },
    notify: false
  });
});

gulp.task('build', ['build:images', 'build:css', 'build:js']);
gulp.task('develop', ['watch:assets', 'watch:js', 'serve']);
<|endoftext|>


<commit_before>var gulp = require('gulp'),
    gutil = require('gulp-util'),
    os = require('os'),
    path = require('path'),
    bower = require('gulp-bower'),
    rename = require('gulp-rename'),
    less = require('gulp-less'),
    minifyCss = require('gulp-minify-css'),
    uglifyJs = require('gulp-uglifyjs'),
    rimraf = require('gulp-rimraf'),
    buildTypeEnum = {dev: 'dev', prod: 'prod'};

function buildTypeToDistDir(buildType) {
    "use strict";

    if (buildType === buildTypeEnum.dev) {
        return 'dist/dev';
    } else if (buildType === buildTypeEnum.prod) {
        return 'dist/prod';
    } else {
        gutil.log(gutil.colors.red('Invalid build type!'));
    }
}

// todo: add running jshint (with coverage)

// todo: add running unit tests

////////////////////////////////////////////////////////////////////////////////
// Default Task
////////////////////////////////////////////////////////////////////////////////
(function () {
    "use strict";
    gulp.task('default', ['usage']);
})();

////////////////////////////////////////////////////////////////////////////////
// runServer
////////////////////////////////////////////////////////////////////////////////
(function () {
    "use strict";

    var exec = require('child_process').exec;

    function runServer(buildType, cb) {
        var cmd = 'node server',
            options = {
                cwd: path.join(buildTypeToDistDir(buildType), 'server')
            };

        exec(cmd, options, function (error /*, stdout, stderr*/) {

            if (error) {
                cb(error);  // Return error.
            }

            cb();           // The task is now finished.
        });
    }

    gulp.task('runServer:dev', ['build:dev'], function (cb) {
        runServer(buildTypeEnum.dev, cb);
    });

    gulp.task('runServer:prod', ['build:prod'] , function (cb) {
        runServer(buildTypeEnum.prod, cb);
    });

})();

////////////////////////////////////////////////////////////////////////////////
// Usage
////////////////////////////////////////////////////////////////////////////////
(function () {
    "use strict";

    gulp.task('usage', function () {
        var padding = os.EOL + os.EOL,
            text = [
                gutil.colors.cyan("gulp build[:dev|prod]"),
                "    Builds this project (in /dist)",
                "",
                gutil.colors.cyan("gulp clean"),
                "    Deletes build-generated files",
                "",
                gutil.colors.cyan("gulp usage"),
                "    Displays this usage information"
            ];

        console.log(padding + text.join(os.EOL) + padding);
    });
})();

////////////////////////////////////////////////////////////////////////////////
// Build
////////////////////////////////////////////////////////////////////////////////

//
// Stage server
//
(function () {
    "use strict";

    function stageServer(buildType) {
        return gulp.src('server/**/*', {cwdbase: true})
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));
    }

    gulp.task('stageServer:dev', function () {
        return stageServer(buildTypeEnum.dev);
    });

    gulp.task('stageServer:prod', function () {
        return stageServer(buildTypeEnum.prod);
    });
})();

//
// Stage Bower components
//
(function () {
    "use strict";

    function stageBowerFiles(buildType) {
        var bowerDir = buildTypeToDistDir(buildType) + '/www/bower_components';
        bower(bowerDir);
    }

    gulp.task('stageBowerFiles:dev', function () {
        return stageBowerFiles(buildTypeEnum.dev);
    });

    gulp.task('stageBowerFiles:prod', function () {
        return stageBowerFiles(buildTypeEnum.prod);
    });

})();

//
// Stage index.html
//
(function () {
    "use strict";

    function stageIndex(buildType) {
        var indexFileName = 'www/index-' + buildType + '.html';

        return gulp.src(indexFileName, {cwdbase: true})
            .pipe(rename({basename: 'index'}))
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));

    }

    gulp.task('stageIndex:dev', function () {
        return stageIndex(buildTypeEnum.dev);
    });

    gulp.task('stageIndex:prod', function () {
        return stageIndex(buildTypeEnum.prod);
    });

})();

//
// Stage app Less
//
(function () {
    "use strict";

    function stageAppLess(buildType) {
        return gulp.src('www/styles/*.less', {cwdbase: true})
            .pipe(less({paths: [], relativeUrls: true}))
            .pipe(buildType === buildTypeEnum.prod ? minifyCss() : gutil.noop())
            .pipe(buildType === buildTypeEnum.prod ? rename({suffix: '.min'}) : gutil.noop())
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));
    }

    gulp.task('stageAppLess:dev', function () {
        return stageAppLess(buildTypeEnum.dev);
    });

    gulp.task('stageAppLess:prod', function () {
        return stageAppLess(buildTypeEnum.prod);
    });

})();

//
// Stage app resources
//
(function () {
    "use strict";

    function stageAppResources(buildType) {
        var globs = [
            'www/fonts/**/*',
            'www/images/**/*',
            'www/js/**/*.html',
            '!www/js/**/*.tc.html' // Don't include templates that are placed in the template cache
        ];

        return gulp.src(globs, {cwdbase: true})
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));
    }

    gulp.task('stageAppResources:dev', function () {
        return stageAppResources(buildTypeEnum.dev);
    });

    gulp.task('stageAppResources:prod', function () {
        return stageAppResources(buildTypeEnum.prod);
    });

})();

//
// Stage app JavaScript
//
(function () {
    "use strict";

    function stageAppJs(buildType) {
        var globs = [
            'www/js/**/*.js'
        ];

        // todo: Create sourcemaps for prod builds

        return gulp.src(globs, {cwdbase: true})
            .pipe(buildType === buildTypeEnum.prod ? uglifyJs('www/js/app.min.js') : gutil.noop())
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));
    }

    gulp.task('stageAppJs:dev', function () {
        return stageAppJs(buildTypeEnum.dev);
    });

    gulp.task('stageAppJs:prod', function () {
        return stageAppJs(buildTypeEnum.prod);
    });
})();

gulp.task(
    'build:dev',
    [
        'stageServer:dev', 'stageBowerFiles:dev', 'stageIndex:dev',
        'stageAppLess:dev', 'stageAppResources:dev', 'stageAppJs:dev'
    ]
);
gulp.task(
    'build:prod',
    [
        'stageServer:prod', 'stageBowerFiles:prod', 'stageIndex:prod',
        'stageAppLess:prod', 'stageAppResources:prod', 'stageAppJs:prod'
    ]
);
gulp.task('build', ['build:dev', 'build:prod']);

////////////////////////////////////////////////////////////////////////////////
// Clean
////////////////////////////////////////////////////////////////////////////////

(function () {
    "use strict";

    gulp.task('clean', function () {
        var globs = [
            'www/**/*.css',
            'dist/dev',
            'dist/prod',
            'artifacts/*'
        ];

        return gulp.src(globs, {read: false})
            .pipe(rimraf());
    });
})();<commit_msg>Minor cleanup of gulpfile.js.<commit_after>var gulp = require('gulp'),
    gutil = require('gulp-util'),
    os = require('os'),
    path = require('path'),
    bower = require('gulp-bower'),
    rename = require('gulp-rename'),
    less = require('gulp-less'),
    minifyCss = require('gulp-minify-css'),
    uglifyJs = require('gulp-uglifyjs'),
    rimraf = require('gulp-rimraf'),
    buildTypeEnum = {dev: 'dev', prod: 'prod'};

function buildTypeToDistDir(buildType) {
    "use strict";

    if (buildType === buildTypeEnum.dev) {
        return 'dist/dev';
    } else if (buildType === buildTypeEnum.prod) {
        return 'dist/prod';
    } else {
        gutil.log(gutil.colors.red('Invalid build type!'));
    }
}

// todo: add running jshint (with coverage)

// todo: add running unit tests

////////////////////////////////////////////////////////////////////////////////
// Default Task - Usage
////////////////////////////////////////////////////////////////////////////////
(function () {
    "use strict";
    gulp.task('default', ['usage']);
})();

////////////////////////////////////////////////////////////////////////////////
// runServer
////////////////////////////////////////////////////////////////////////////////
(function () {
    "use strict";

    var exec = require('child_process').exec;

    function runServer(buildType, cb) {
        var cmd = 'node server',
            options = {
                cwd: path.join(buildTypeToDistDir(buildType), 'server')
            };

        exec(cmd, options, function (error /*, stdout, stderr*/) {

            if (error) {
                cb(error);  // Return error.
            }

            cb();           // The task is now finished.
        });
    }

    gulp.task('runServer:dev', ['build:dev'], function (cb) {
        runServer(buildTypeEnum.dev, cb);
    });

    gulp.task('runServer:prod', ['build:prod'] , function (cb) {
        runServer(buildTypeEnum.prod, cb);
    });

})();

////////////////////////////////////////////////////////////////////////////////
// Usage
////////////////////////////////////////////////////////////////////////////////
(function () {
    "use strict";

    gulp.task('usage', function () {
        var padding = os.EOL + os.EOL,
            text = [
                gutil.colors.cyan("gulp build[:dev|prod]"),
                "    Builds this project (in /dist)",
                "",
                gutil.colors.cyan("gulp clean"),
                "    Deletes build-generated files",
                "",
                gutil.colors.cyan("gulp usage"),
                "    Displays this usage information"
            ];

        console.log(padding + text.join(os.EOL) + padding);
    });
})();

////////////////////////////////////////////////////////////////////////////////
// Build
////////////////////////////////////////////////////////////////////////////////

//
// Stage server
//
(function () {
    "use strict";

    function stageServer(buildType) {
        return gulp.src('server/**/*', {cwdbase: true})
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));
    }

    gulp.task('stageServer:dev', function () {
        return stageServer(buildTypeEnum.dev);
    });

    gulp.task('stageServer:prod', function () {
        return stageServer(buildTypeEnum.prod);
    });
})();

//
// Stage Bower components
//
(function () {
    "use strict";

    function stageBowerFiles(buildType) {
        var bowerDir = buildTypeToDistDir(buildType) + '/www/bower_components';
        bower(bowerDir);
    }

    gulp.task('stageBowerFiles:dev', function () {
        return stageBowerFiles(buildTypeEnum.dev);
    });

    gulp.task('stageBowerFiles:prod', function () {
        return stageBowerFiles(buildTypeEnum.prod);
    });

})();

//
// Stage index.html
//
(function () {
    "use strict";

    function stageIndex(buildType) {
        var indexFileName = 'www/index-' + buildType + '.html';

        return gulp.src(indexFileName, {cwdbase: true})
            .pipe(rename({basename: 'index'}))
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));

    }

    gulp.task('stageIndex:dev', function () {
        return stageIndex(buildTypeEnum.dev);
    });

    gulp.task('stageIndex:prod', function () {
        return stageIndex(buildTypeEnum.prod);
    });

})();

//
// Stage app Less
//
(function () {
    "use strict";

    function stageAppLess(buildType) {
        return gulp.src('www/styles/*.less', {cwdbase: true})
            .pipe(less({paths: [], relativeUrls: true}))
            .pipe(buildType === buildTypeEnum.prod ? minifyCss() : gutil.noop())
            .pipe(buildType === buildTypeEnum.prod ? rename({suffix: '.min'}) : gutil.noop())
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));
    }

    gulp.task('stageAppLess:dev', function () {
        return stageAppLess(buildTypeEnum.dev);
    });

    gulp.task('stageAppLess:prod', function () {
        return stageAppLess(buildTypeEnum.prod);
    });

})();

//
// Stage app resources
//
(function () {
    "use strict";

    function stageAppResources(buildType) {
        var globs = [
            'www/fonts/**/*',
            'www/images/**/*',
            'www/js/**/*.html',
            '!www/js/**/*.tc.html' // Don't include templates that are placed in the template cache
        ];

        return gulp.src(globs, {cwdbase: true})
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));
    }

    gulp.task('stageAppResources:dev', function () {
        return stageAppResources(buildTypeEnum.dev);
    });

    gulp.task('stageAppResources:prod', function () {
        return stageAppResources(buildTypeEnum.prod);
    });

})();

//
// Stage app JavaScript
//
(function () {
    "use strict";

    function stageAppJs(buildType) {
        var globs = [
            'www/js/**/*.js'
        ];

        // todo: Create sourcemaps for prod builds

        return gulp.src(globs, {cwdbase: true})
            .pipe(buildType === buildTypeEnum.prod ? uglifyJs('www/js/app.min.js') : gutil.noop())
            .pipe(gulp.dest(buildTypeToDistDir(buildType)));
    }

    gulp.task('stageAppJs:dev', function () {
        return stageAppJs(buildTypeEnum.dev);
    });

    gulp.task('stageAppJs:prod', function () {
        return stageAppJs(buildTypeEnum.prod);
    });
})();

//
// Build tasks
//
(function () {

    "use strict";

    gulp.task(
        'build:dev',
        [
            'stageServer:dev', 'stageBowerFiles:dev', 'stageIndex:dev',
            'stageAppLess:dev', 'stageAppResources:dev', 'stageAppJs:dev'
        ]
    );

    gulp.task(
        'build:prod',
        [
            'stageServer:prod', 'stageBowerFiles:prod', 'stageIndex:prod',
            'stageAppLess:prod', 'stageAppResources:prod', 'stageAppJs:prod'
        ]
    );

    gulp.task('build', ['build:dev', 'build:prod']);

})();

////////////////////////////////////////////////////////////////////////////////
// Clean
////////////////////////////////////////////////////////////////////////////////

(function () {
    "use strict";

    gulp.task('clean', function () {
        var globs = [
            'www/**/*.css',
            'dist',
            'artifacts/*'
        ];

        return gulp.src(globs, {read: false})
            .pipe(rimraf());
    });
})();<|endoftext|>


<commit_before>var gulp = require("gulp"),
		sass = require("gulp-sass"),
		path = require("path"),
		del = require("del"),
		zip = require("gulp-zip"),
        karma = require('gulp-karma'),
		sourcemaps = require('gulp-sourcemaps'),
    runSequence = require('run-sequence');

var userModule = "./web/app/user";
var testRoot="./web/test";
var testFiles=testRoot+"/unit/**/*.js";

// SASS Related tasks

gulp.task("sass:compile", function() {

  var outputStyle = "expanded"; // "nested" | "compact" | "compressed" | "expanded"

  return gulp.src(
  					path.join(userModule, "/sass/ajabShahar.scss")
  				)
					.pipe(sourcemaps.init())
					.pipe(sass({outputStyle: outputStyle}))
					.pipe(sourcemaps.write())
					.pipe(gulp.dest(
						path.join(userModule, "/css")
					));
});

gulp.task("sass:watch", function() {

 	gulp.watch(
 		path.join(userModule, "/sass/ajabShahar.scss"),
 		["sass:compile"]
 	)

 	// gutil.log("[watch:sass]", gutil.colors.yellow("Watching SASS files..."));

});

// Common tasks

gulp.task("watch", ["sass:watch"]);
gulp.task("sass", ["sass:compile"]);

gulp.task('js', function () {
    return gulp.src('web/**/*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'))
        .pipe(gulp.dest('dist'));
});

gulp.task ("clean",function(){
    del(['dist/*']);
});

gulp.task("test",["sass:compile"],function(){
    return gulp.src("/blah")                     // there is a bug in gulp-karma which requires a wrong file path to work!
        .pipe(karma({
            configFile: testRoot+'/config/karma.conf.js',
            action: "run"
        }))
        .on('error', function(err) {
            console.log(err);
            throw err;
        });
});

gulp.task("zip",["clean"],function(){
    return gulp.src('web/app/**')
        .pipe(zip('ajabshahar.zip'))
        .pipe(gulp.dest('dist'))
});

gulp.task("default", function(callback){
  runSequence('test','zip')
});<commit_msg>Added sass compile to gulp file. <Jaideep><commit_after>var gulp = require("gulp"),
		sass = require("gulp-sass"),
		path = require("path"),
		del = require("del"),
		zip = require("gulp-zip"),
        karma = require('gulp-karma'),
		sourcemaps = require('gulp-sourcemaps'),
    runSequence = require('run-sequence');

var userModule = "./web/app/user";
var testRoot="./web/test";
var testFiles=testRoot+"/unit/**/*.js";

// SASS Related tasks

gulp.task("sass:compile", function() {

  var outputStyle = "expanded"; // "nested" | "compact" | "compressed" | "expanded"

  return gulp.src(
  					path.join(userModule, "/sass/ajabShahar.scss")
  				)
					.pipe(sourcemaps.init())
					.pipe(sass({outputStyle: outputStyle}))
					.pipe(sourcemaps.write())
					.pipe(gulp.dest(
						path.join(userModule, "/css")
					));
});

gulp.task("sass:watch", function() {

 	gulp.watch(
 		path.join(userModule, "/sass/ajabShahar.scss"),
 		["sass:compile"]
 	)

 	// gutil.log("[watch:sass]", gutil.colors.yellow("Watching SASS files..."));

});

// Common tasks

gulp.task("watch", ["sass:watch"]);
gulp.task("sass", ["sass:compile"]);

gulp.task('js', function () {
    return gulp.src('web/**/*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'))
        .pipe(gulp.dest('dist'));
});

gulp.task ("clean",function(){
    del(['dist/*']);
});

gulp.task("test",["sass:compile"],function(){
    return gulp.src("/blah")                     // there is a bug in gulp-karma which requires a wrong file path to work!
        .pipe(karma({
            configFile: testRoot+'/config/karma.conf.js',
            action: "run"
        }))
        .on('error', function(err) {
            console.log(err);
            throw err;
        });
});

gulp.task("zip",["clean", "sass:compile"],function(){
    return gulp.src('web/app/**')
        .pipe(zip('ajabshahar.zip'))
        .pipe(gulp.dest('dist'))
});

gulp.task("default", function(callback){
  runSequence('test','zip')
});<|endoftext|>


<commit_before>var gulp = require('gulp');
var runSequence = require('run-sequence');
var requireDir = require('require-dir');
var tasks = requireDir('./tasks');

gulp.task('load:db', function (callback) {
    runSequence('mongo:insertListing', 'mongo:indexListing', 'mongo:close',
        'redis:addKeys', callback)
});

gulp.task('solr:index', function (callback) {
    runSequence('extract:ui-tag', 'extract:ui-h1', 'extract:manifest',
        'solr:indexUITag', 'solr:indexH1', 'solr:indexManifest',
        'solr:indexCode', 'solr:commit', callback)
});

gulp.task('default', function (callback) {
    runSequence('solr:create', 'solr:addField', 'extract:archives', 'solr:index',
        'load:db', callback);
});<commit_msg>group tasks by type and reorder them<commit_after>var gulp = require('gulp');
var runSequence = require('run-sequence');
var requireDir = require('require-dir');
var tasks = requireDir('./tasks');

gulp.task('mongo:insert', function (callback) {
    runSequence('mongo:insertListing', 'mongo:indexListing', 'mongo:close',
        callback);
});

gulp.task('solr:insert', function (callback) {
    runSequence('extract:ui-tag', 'extract:ui-h1', 'extract:manifest',
        'solr:indexUITag', 'solr:indexH1', 'solr:indexManifest',
        'solr:indexCode', 'solr:commit', callback);
});

gulp.task('redis:insert', function (callback) {
    runSequence('redis:addSolrKeys', 'redis:addAllKeys', callback);
});

gulp.task('default', function (callback) {
    runSequence('solr:create', 'solr:addField', 'extract:archives', 'solr:insert',
        'mongo:insert', 'redis:insert', callback);
});<|endoftext|>