<commit_before>/*eslint-env node*/

const fs = require('fs');
const gulp = require('gulp');
const runSequence = require('run-sequence');
const useref = require('gulp-useref');
const cleanCSS = require('gulp-clean-css');
const rename = require('gulp-rename');
const concat = require('gulp-concat');
const babelMinify = require('babel-minify');
const child_process = require('child_process');
const merge = require('merge-stream');
const zip = require('gulp-zip');
var packageJson = JSON.parse(fs.readFileSync('./package.json'));
const connect = require('gulp-connect');

function minifyJs(fileName) {
	const content = fs.readFileSync(fileName, 'utf8');
	const minifiedContent = babelMinify(
		content,
		{ mangle: content.length < 700000 },
		{ sourceMaps: false }
	).code;
	fs.writeFileSync(fileName, minifiedContent);
	console.log(
		`[${fileName}]: ${content.length / 1024}K -> ${minifiedContent.length /
			1024}K`
	);
}
gulp.task('runWebpack', function() {
	return child_process.execSync('yarn run build');
});

gulp.task('copyFiles', function() {
	return merge(
		gulp
			.src('src/lib/codemirror/theme/*')
			.pipe(gulp.dest('app/lib/codemirror/theme')),
		gulp
			.src('src/lib/codemirror/mode/**/*')
			.pipe(gulp.dest('app/lib/codemirror/mode')),
		gulp.src('src/lib/transpilers/*').pipe(gulp.dest('app/lib/transpilers')),
		gulp.src('src/lib/prettier-worker.js').pipe(gulp.dest('app/lib/')),
		gulp.src('src/lib/prettier/*').pipe(gulp.dest('app/lib/prettier')),
		gulp
			.src(['!src/lib/monaco/monaco.bundle.js', 'src/lib/monaco/**/*'])
			.pipe(gulp.dest('app/lib/monaco')),
		gulp.src('src/lib/screenlog.js').pipe(gulp.dest('app/lib')),
		gulp.src('icons/*').pipe(gulp.dest('app/icons')),
		gulp.src('src/assets/*').pipe(gulp.dest('app/assets')),
		gulp.src('src/templates/*').pipe(gulp.dest('app/templates')),
		gulp.src('preview/*').pipe(gulp.dest('app/preview')),
		gulp
			.src([
				'src/preview.html',
				'src/detached-window.js',
				'src/icon-48.png',
				'src/icon-128.png',
				'manifest.json'
			])
			.pipe(gulp.dest('app')),

		gulp
			.src('build/bundle.*.js')
			.pipe(rename('script.js'))
			.pipe(gulp.dest('app')),
		gulp
			.src('build/vendor.*.js')
			.pipe(rename('vendor.js'))
			.pipe(gulp.dest('app')),
		gulp.src('build/monaco.*.js').pipe(gulp.dest('app')),

		// Following CSS are copied to build/ folder where they'll be referenced by
		// useRef plugin to concat into one.
		gulp
			.src('src/lib/codemirror/lib/codemirror.css')
			.pipe(gulp.dest('build/lib/codemirror/lib')),
		gulp
			.src('src/lib/codemirror/addon/hint/show-hint.css')
			.pipe(gulp.dest('build/lib/codemirror/addon/hint')),
		gulp
			.src('src/lib/codemirror/addon/fold/foldgutter.css')
			.pipe(gulp.dest('build/lib/codemirror/addon/fold')),
		gulp
			.src('src/lib/codemirror/addon/dialog/dialog.css')
			.pipe(gulp.dest('build/lib/codemirror/addon/dialog')),
		gulp.src('src/lib/hint.min.css').pipe(gulp.dest('build/lib')),
		gulp.src('src/lib/inlet.css').pipe(gulp.dest('build/lib')),
		gulp.src('src/style.css').pipe(gulp.dest('build')),

		gulp
			.src([
				'src/FiraCode.ttf',
				'src/FixedSys.ttf',
				'src/Inconsolata.ttf',
				'src/Monoid.ttf'
			])
			.pipe(gulp.dest('app'))
	);
});

gulp.task('useRef', function() {
	return gulp
		.src('build/index.html')
		.pipe(useref())
		.pipe(gulp.dest('app'));
});

gulp.task('concatSwRegistration', function() {
	return gulp
		.src(['src/service-worker-registration.js', 'app/script.js'])
		.pipe(concat('script.js'))
		.pipe(gulp.dest('app'));
});

gulp.task('minify', function() {
	minifyJs('app/script.js');
	minifyJs('app/vendor.js');
	minifyJs('app/lib/screenlog.js');

	return gulp
		.src('app/*.css')
		.pipe(
			cleanCSS(
				{
					debug: true
				},
				details => {
					console.log(
						`${details.name}: ${details.stats.originalSize} 👉🏼  ${
							details.stats.minifiedSize
						}`
					);
				}
			)
		)
		.pipe(gulp.dest('app'));
});

gulp.task('fixIndex', function() {
	var contents = fs.readFileSync('build/index.html', 'utf8');
	// Replace hashed-filename script tags with unhashed ones
	contents = contents.replace(
		/\<\!\-\- SCRIPT-TAGS \-\-\>[\S\s]*?\<\!\-\- END-SCRIPT-TAGS \-\-\>/,
		'<script defer src="vendor.js"></script><script defer src="script.js"></script>'
	);

	// vendor.hash.js gets created outside our markers, so remove it
	contents = contents.replace(
		/\<script src="[\S\s]*?vendor\.[\S\s]*?\<\/script\>/,
		''
	);

	fs.writeFileSync('build/index.html', contents, 'utf8');
});

gulp.task('generate-service-worker', function(callback) {
	var swPrecache = require('sw-precache');
	var rootDir = 'app';

	swPrecache.write(
		`${rootDir}/service-worker.js`,
		{
			staticFileGlobs: [
				rootDir + '/**/*.{js,html,css,png,jpg,gif,svg,eot,ttf,woff}'
			],
			stripPrefix: `${rootDir}/`,

			// has to be increased to around 2.8mb for sass.worker.js
			maximumFileSizeToCacheInBytes: 2900000
		},
		callback
	);
});

gulp.task('packageExtension', function() {
	child_process.execSync('rm -rf extension');
	child_process.execSync('cp -R app extension');
	child_process.execSync('cp src/manifest.json extension');
	child_process.execSync('cp src/options.js extension');
	child_process.execSync('cp src/options.html extension');
	child_process.execSync('cp src/eventPage.js extension');
	child_process.execSync('cp src/icon-16.png extension');
	child_process.execSync('rm -rf extension/service-worker.js');
	return merge(
		gulp
			.src('build/bundle.*.js')
			.pipe(rename('script.js'))
			.pipe(gulp.dest('extension')),

		gulp
			.src('extension/**/*')
			.pipe(zip(`extension-${packageJson.version}.zip`))
			.pipe(gulp.dest('./'))
	);
});

gulp.task('buildWebsite', function() {
	return child_process.execSync('yarn run build-website');
});

gulp.task('buildDistFolder', function() {
	child_process.execSync('rm -rf dist');
	child_process.execSync('mv packages/website/_site dist');
	child_process.execSync('mv app dist/');
});

gulp.task('cleanup', function() {
	return child_process.execSync('rm -rf build');
});

gulp.task('start-preview-server', function() {
	connect.server({
		root: 'preview',
		port: 7888,
		https: false
	});
});

gulp.task('release', function(callback) {
	runSequence(
		['runWebpack', 'buildWebsite'],
		'copyFiles',
		'fixIndex',
		'useRef',
		'concatSwRegistration',
		'minify',
		'generate-service-worker',
		'packageExtension',
		'buildDistFolder',
		'cleanup',
		function(error) {
			if (error) {
				console.log(error.message);
			} else {
				console.log('RELEASE FINISHED SUCCESSFULLY');
			}
			callback(error);
		}
	);
});

gulp.task('dev-release', function(callback) {
	runSequence(
		['runWebpack', 'buildWebsite'],
		'copyFiles',
		'fixIndex',
		'useRef',
		'concatSwRegistration',
		'generate-service-worker',
		'buildDistFolder',
		'cleanup',
		function(error) {
			if (error) {
				console.log(error.message);
			} else {
				console.log('DEV RELEASE FINISHED SUCCESSFULLY');
			}
			callback(error);
		}
	);
});
<commit_msg>Add build-extension task in gulpfile.js<commit_after>/*eslint-env node*/

const fs = require('fs');
const gulp = require('gulp');
const runSequence = require('run-sequence');
const useref = require('gulp-useref');
const cleanCSS = require('gulp-clean-css');
const rename = require('gulp-rename');
const concat = require('gulp-concat');
const babelMinify = require('babel-minify');
const child_process = require('child_process');
const merge = require('merge-stream');
const zip = require('gulp-zip');
var packageJson = JSON.parse(fs.readFileSync('./package.json'));
const connect = require('gulp-connect');

function minifyJs(fileName) {
	const content = fs.readFileSync(fileName, 'utf8');
	const minifiedContent = babelMinify(
		content,
		{ mangle: content.length < 700000 },
		{ sourceMaps: false }
	).code;
	fs.writeFileSync(fileName, minifiedContent);
	console.log(
		`[${fileName}]: ${content.length / 1024}K -> ${minifiedContent.length /
			1024}K`
	);
}
gulp.task('runWebpack', function() {
	return child_process.execSync('yarn run build');
});

gulp.task('copyFiles', function() {
	return merge(
		gulp
			.src('src/lib/codemirror/theme/*')
			.pipe(gulp.dest('app/lib/codemirror/theme')),
		gulp
			.src('src/lib/codemirror/mode/**/*')
			.pipe(gulp.dest('app/lib/codemirror/mode')),
		gulp.src('src/lib/transpilers/*').pipe(gulp.dest('app/lib/transpilers')),
		gulp.src('src/lib/prettier-worker.js').pipe(gulp.dest('app/lib/')),
		gulp.src('src/lib/prettier/*').pipe(gulp.dest('app/lib/prettier')),
		gulp
			.src(['!src/lib/monaco/monaco.bundle.js', 'src/lib/monaco/**/*'])
			.pipe(gulp.dest('app/lib/monaco')),
		gulp.src('src/lib/screenlog.js').pipe(gulp.dest('app/lib')),
		gulp.src('icons/*').pipe(gulp.dest('app/icons')),
		gulp.src('src/assets/*').pipe(gulp.dest('app/assets')),
		gulp.src('src/templates/*').pipe(gulp.dest('app/templates')),
		gulp.src('preview/*').pipe(gulp.dest('app/preview')),
		gulp
			.src([
				'src/preview.html',
				'src/detached-window.js',
				'src/icon-48.png',
				'src/icon-128.png',
				'manifest.json'
			])
			.pipe(gulp.dest('app')),

		gulp
			.src('build/bundle.*.js')
			.pipe(rename('script.js'))
			.pipe(gulp.dest('app')),
		gulp
			.src('build/vendor.*.js')
			.pipe(rename('vendor.js'))
			.pipe(gulp.dest('app')),
		gulp.src('build/monaco.*.js').pipe(gulp.dest('app')),

		// Following CSS are copied to build/ folder where they'll be referenced by
		// useRef plugin to concat into one.
		gulp
			.src('src/lib/codemirror/lib/codemirror.css')
			.pipe(gulp.dest('build/lib/codemirror/lib')),
		gulp
			.src('src/lib/codemirror/addon/hint/show-hint.css')
			.pipe(gulp.dest('build/lib/codemirror/addon/hint')),
		gulp
			.src('src/lib/codemirror/addon/fold/foldgutter.css')
			.pipe(gulp.dest('build/lib/codemirror/addon/fold')),
		gulp
			.src('src/lib/codemirror/addon/dialog/dialog.css')
			.pipe(gulp.dest('build/lib/codemirror/addon/dialog')),
		gulp.src('src/lib/hint.min.css').pipe(gulp.dest('build/lib')),
		gulp.src('src/lib/inlet.css').pipe(gulp.dest('build/lib')),
		gulp.src('src/style.css').pipe(gulp.dest('build')),

		gulp
			.src([
				'src/FiraCode.ttf',
				'src/FixedSys.ttf',
				'src/Inconsolata.ttf',
				'src/Monoid.ttf'
			])
			.pipe(gulp.dest('app'))
	);
});

gulp.task('useRef', function() {
	return gulp
		.src('build/index.html')
		.pipe(useref())
		.pipe(gulp.dest('app'));
});

gulp.task('concatSwRegistration', function() {
	return gulp
		.src(['src/service-worker-registration.js', 'app/script.js'])
		.pipe(concat('script.js'))
		.pipe(gulp.dest('app'));
});

gulp.task('minify', function() {
	minifyJs('app/script.js');
	minifyJs('app/vendor.js');
	minifyJs('app/lib/screenlog.js');

	return gulp
		.src('app/*.css')
		.pipe(
			cleanCSS(
				{
					debug: true
				},
				details => {
					console.log(
						`${details.name}: ${details.stats.originalSize} 👉🏼  ${
							details.stats.minifiedSize
						}`
					);
				}
			)
		)
		.pipe(gulp.dest('app'));
});

gulp.task('fixIndex', function() {
	var contents = fs.readFileSync('build/index.html', 'utf8');
	// Replace hashed-filename script tags with unhashed ones
	contents = contents.replace(
		/\<\!\-\- SCRIPT-TAGS \-\-\>[\S\s]*?\<\!\-\- END-SCRIPT-TAGS \-\-\>/,
		'<script defer src="vendor.js"></script><script defer src="script.js"></script>'
	);

	// vendor.hash.js gets created outside our markers, so remove it
	contents = contents.replace(
		/\<script src="[\S\s]*?vendor\.[\S\s]*?\<\/script\>/,
		''
	);

	fs.writeFileSync('build/index.html', contents, 'utf8');
});

gulp.task('generate-service-worker', function(callback) {
	var swPrecache = require('sw-precache');
	var rootDir = 'app';

	swPrecache.write(
		`${rootDir}/service-worker.js`,
		{
			staticFileGlobs: [
				rootDir + '/**/*.{js,html,css,png,jpg,gif,svg,eot,ttf,woff}'
			],
			stripPrefix: `${rootDir}/`,

			// has to be increased to around 2.8mb for sass.worker.js
			maximumFileSizeToCacheInBytes: 2900000
		},
		callback
	);
});

gulp.task('packageExtension', function() {
	child_process.execSync('rm -rf extension');
	child_process.execSync('cp -R app extension');
	child_process.execSync('cp src/manifest.json extension');
	child_process.execSync('cp src/options.js extension');
	child_process.execSync('cp src/options.html extension');
	child_process.execSync('cp src/eventPage.js extension');
	child_process.execSync('cp src/icon-16.png extension');
	child_process.execSync('rm -rf extension/service-worker.js');
	return merge(
		gulp
			.src('build/bundle.*.js')
			.pipe(rename('script.js'))
			.pipe(gulp.dest('extension')),

		gulp
			.src('extension/**/*')
			.pipe(zip(`extension-${packageJson.version}.zip`))
			.pipe(gulp.dest('./'))
	);
});

gulp.task('buildWebsite', function() {
	return child_process.execSync('yarn run build-website');
});

gulp.task('buildDistFolder', function() {
	child_process.execSync('rm -rf dist');
	child_process.execSync('mv packages/website/_site dist');
	child_process.execSync('mv app dist/');
});

gulp.task('cleanup', function() {
	return child_process.execSync('rm -rf build');
});

gulp.task('start-preview-server', function() {
	connect.server({
		root: 'preview',
		port: 7888,
		https: false
	});
});

gulp.task('release', function(callback) {
	runSequence(
		['runWebpack', 'buildWebsite'],
		'copyFiles',
		'fixIndex',
		'useRef',
		'concatSwRegistration',
		'minify',
		'generate-service-worker',
		'packageExtension',
		'buildDistFolder',
		'cleanup',
		function(error) {
			if (error) {
				console.log(error.message);
			} else {
				console.log('RELEASE FINISHED SUCCESSFULLY');
			}
			callback(error);
		}
	);
});

gulp.task('dev-release', function(callback) {
	runSequence(
		['runWebpack', 'buildWebsite'],
		'copyFiles',
		'fixIndex',
		'useRef',
		'concatSwRegistration',
		'generate-service-worker',
		'buildDistFolder',
		'cleanup',
		function(error) {
			if (error) {
				console.log(error.message);
			} else {
				console.log('DEV RELEASE FINISHED SUCCESSFULLY');
			}
			callback(error);
		}
	);
});

gulp.task('build-extension', function(callback) {
	runSequence(
		'runWebpack',
		'copyFiles',
		'fixIndex',
		'useRef',
		'packageExtension',
		function(error) {
			if (error) {
				console.log(error.message);
			} else {
				console.log('DEV RELEASE FINISHED SUCCESSFULLY');
			}
			callback(error);
		}
	);
});
<|endoftext|>


<commit_before>/* inspired by http://procbits.com/2011/10/29/a-node-js-experiment-thinking-asynchronously-recursion-calculate-file-size-directory */
'use strict';

const fs = require('fs');
const path = require('path');
const EventEmitter = require('events').EventEmitter;

const format = require('format-io');

/*  The lstat() function shall be equivalent to stat(),
    except when path refers to a symbolic link. In that case lstat()
    shall return information about the link, while stat() shall return
    information about the file the link references.
*/
const stat    = fs.lstat;

module.exports = (dir, options, callback) => {
    let type;
    const ERROR_EMPTY = 'could not be empty!';
    const emitter = new EventEmitter();
    let total = 0;

    if (!callback) {
        callback    = options;
        options     = {};
    } else {
        type        = options.type;
    }

    if (!dir)
        throw Error('dir ' + ERROR_EMPTY);

    if (!callback)
        throw Error('callback' + ERROR_EMPTY);

    emitter.on('file', (file, stat) => {
        total      += stat.size;
    });

    emitter.on('error', (error) => {
        callback(error);
    });

    emitter.on('end', () => {
        let result;

        if (type !== 'raw')
            result  = format.size(total);
        else
            result  = total;

        callback(null, result);
    });

    processDir(dir, options, emitter);
};

function processDir(dir, options, emitter) {
    var stopOnError     = options.stopOnError,
        wasError        = false,
        asyncRunning    = 0,
        fileCounter     = 1,

        execCallBack    = function () {
            let noErrors = !wasError || !stopOnError;
            let yesAllDone = !fileCounter && !asyncRunning;

            if (yesAllDone && noErrors)
                emitter.emit('end');
        },

        getDirInfo = (dir) => {
            stat(dir, getStat.bind(null, dir));
        };

    getDirInfo(dir);

    function getStat(dir, error, stat) {
        --fileCounter;

        if (!wasError || !stopOnError) {
            if (error && stopOnError) {
                wasError    = true;
                emitter.emmit('error', error);
            } else if (!error) {
                let isDir = stat.isDirectory();

                if (!isDir)
                    return emitter.emit('file', dir, stat);

                ++asyncRunning;

                fs.readdir(dir, (error, files) => {
                    asyncRunning--;

                    if (!error) {
                        onReaddir(dir, files);
                    } else if (error && stopOnError) {
                        wasError = true;
                        emitter.emit('error', error);
                    }
                });
            }

            execCallBack();
        }
    }

    function onReaddir(dir, files) {
        let n = files.length;

        fileCounter += n;

        if (!n)
            return execCallBack();

        files.forEach((file) => {
            const dirPath = path.join(dir, file);

            process.nextTick(() => {
                getDirInfo(dirPath);
            });
        });
    }
}

<commit_msg>fix(size) end<commit_after>/* inspired by http://procbits.com/2011/10/29/a-node-js-experiment-thinking-asynchronously-recursion-calculate-file-size-directory */
'use strict';

const fs = require('fs');
const path = require('path');
const EventEmitter = require('events').EventEmitter;

const format = require('format-io');

/*  The lstat() function shall be equivalent to stat(),
    except when path refers to a symbolic link. In that case lstat()
    shall return information about the link, while stat() shall return
    information about the file the link references.
*/
const stat = fs.lstat;

module.exports = (dir, options, callback) => {
    let type;
    const ERROR_EMPTY = 'could not be empty!';
    const emitter = new EventEmitter();
    let total = 0;

    if (!callback) {
        callback    = options;
        options     = {};
    } else {
        type        = options.type;
    }

    if (!dir)
        throw Error('dir ' + ERROR_EMPTY);

    if (!callback)
        throw Error('callback' + ERROR_EMPTY);

    emitter.on('file', (file, stat) => {
        total += stat.size;
    });

    emitter.on('error', (error) => {
        callback(error);
    });

    emitter.on('end', () => {
        let result;

        if (type !== 'raw')
            result  = format.size(total);
        else
            result  = total;

        callback(null, result);
    });

    processDir(dir, options, emitter);
};

function processDir(dir, options, emitter) {
    var stopOnError     = options.stopOnError,
        wasError        = false,
        asyncRunning    = 0,
        fileCounter     = 1,

        execCallBack    = function () {
            let noErrors = !wasError || !stopOnError;
            let yesAllDone = !fileCounter && !asyncRunning;

            if (yesAllDone && noErrors)
                emitter.emit('end');
        },

        getDirInfo = (dir) => {
            stat(dir, getStat.bind(null, dir));
        };

    getDirInfo(dir);

    function getStat(dir, error, stat) {
        --fileCounter;

        if (error && stopOnError) {
            wasError    = true;
            emitter.emmit('error', error);
        } else if (!error) {
            const isDir = stat.isDirectory();

            if (!isDir) {
                emitter.emit('file', dir, stat);
                execCallBack();
                return;
            }

            ++asyncRunning;

            execCallBack();

            fs.readdir(dir, (error, files) => {
                asyncRunning--;

                if (!error)
                    return onReaddir(dir, files);

                if (error && stopOnError) {
                    wasError = true;
                    emitter.emit('error', error);
                }
            });
        }
    }

    function onReaddir(dir, files) {
        let n = files.length;

        fileCounter += n;

        if (!n)
            return execCallBack();

        files.forEach((file) => {
            const dirPath = path.join(dir, file);
            getDirInfo(dirPath);
        });
    }
}

<|endoftext|>


<commit_before>// ─────────────────────────────────────────────────────────────────────────────
// import
// ─────────────────────────────────────────────────────────────────────────────

import React from 'react';
import {
  Main, Heading, Text, Article, Link,
} from '../components';
import { SEOContainer } from '../containers';
import { renderMarkdown } from '../utils';

require('prismjs/themes/prism.css');

// ─────────────────────────────────────────────────────────────────────────────
// component
// ─────────────────────────────────────────────────────────────────────────────

export default function BlogPost({
  data: {
    markdownRemark: { frontmatter, htmlAst },
    // allMarkdownRemark: { edges: suggestions },
  },
}) {
  return (
    <Main
      gridTemplate={{
        xs: "'article' 'suggestions'",
        lg: "'article suggestions' / 3fr 1fr",
      }}
      gridGap="5vw"
    >
      <SEOContainer seo={frontmatter} />
      <Article itemScope itemType="http://schema.org/BlogPosting">
        <header style={{ margin: '0 0 4rem 0' }}>
          <Heading itemprop="name" margin="0 0 3rem 0">
            <Link to={frontmatter.permalink} itemProp="url">
              {frontmatter.title}
            </Link>
          </Heading>
          <Text fontSize="3rem">{frontmatter.description}</Text>
          <time
            style={{
              fontSize:      '1.25rem',
              fontWeight:    '300',
              lineHeight:    '2rem',
              textTransform: 'uppercase',
              letterSpacing: '0.2em',
              marginTop:     '-2rem',
            }}
            dateTime={new Date(frontmatter.date).toISOString()}
            itemProp="datePublished"
          >
            {frontmatter.date}
          </time>
        </header>
        {renderMarkdown(htmlAst)}
      </Article>
      {/* <aside>
        <Subheading>
          {'Popular articles'}
        </Subheading>
        {suggestions.map(({ node: { frontmatter: { permalink, title } } }) => (
          <Link key={permalink} to={permalink}>
            {title}
          </Link>
        ))}
      </aside> */}
    </Main>
  );
}

export const pageQuery = graphql`
  query BlogPostByPath($path: String!) {
    markdownRemark(frontmatter: { permalink: { eq: $path } }) {
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        permalink
        title
        description
      }
      htmlAst
    }
    # allMarkdownRemark {
    #   edges {
    #     node {
    #       frontmatter {
    #         permalink
    #         title
    #       }
    #     }
    #   }
    # }
  }
`;
<commit_msg>update blog article page<commit_after>// ─────────────────────────────────────────────────────────────────────────────
// import
// ─────────────────────────────────────────────────────────────────────────────

import React from 'react';
import {
  Article,
  Aside,
  Heading,
  Link,
  Main,
  Subheading,
  Text,
} from '../components';
import { SEOContainer, BlogPreviewsContainer } from '../containers';
import { renderMarkdown, parseLinks } from '../utils';

require('prismjs/themes/prism.css');

// ─────────────────────────────────────────────────────────────────────────────
// component
// ─────────────────────────────────────────────────────────────────────────────

export default function BlogPost({
  data: {
    markdownRemark: { frontmatter, htmlAst },
    allMarkdownRemark: related,
  },
}) {
  return (
    <Main
      gridTemplate={{
        xs: "'article' 'suggestions'",
        lg: "'article suggestions' / 3fr 1fr",
      }}
      gridGap="5vw"
    >
      <SEOContainer seo={frontmatter} />
      <Article itemScope itemType="http://schema.org/BlogPosting">
        <header style={{ margin: '0 0 4rem 0' }}>
          <Heading itemprop="name" margin="0 0 3rem 0">
            <Link to={frontmatter.permalink} itemProp="url">
              {frontmatter.title}
            </Link>
          </Heading>
          <Text fontSize="3rem">{parseLinks(frontmatter.description)}</Text>
          <time
            style={{
              fontSize:      '1.25rem',
              fontWeight:    '300',
              lineHeight:    '2rem',
              textTransform: 'uppercase',
              letterSpacing: '0.2em',
              marginTop:     '-2rem',
            }}
            dateTime={new Date(frontmatter.date).toISOString()}
            itemProp="datePublished"
          >
            {frontmatter.date}
          </time>
        </header>
        {renderMarkdown(htmlAst)}
      </Article>
      {related && (
        <Aside>
          <Subheading>Related articles</Subheading>
          <BlogPreviewsContainer
            posts={related.edges.map(
              ({ node: { frontmatter: post, timeToRead } }) => ({
                ...post,
                timeToRead,
              }),
            )}
          />
        </Aside>
      )}
    </Main>
  );
}

export const pageQuery = graphql`
  query BlogPostByPath($path: String!) {
    markdownRemark(frontmatter: { permalink: { eq: $path } }) {
      frontmatter {
        date(formatString: "MMMM D, YYYY")
        permalink
        title
        description
      }
      htmlAst
    }
    allMarkdownRemark(
      filter: {
        fileAbsolutePath: { regex: "/blog/" }
        frontmatter: { related: { in: [$path] } }
      }
      sort: { fields: [frontmatter___date], order: DESC }
    ) {
      edges {
        node {
          timeToRead
          frontmatter {
            permalink
            title
          }
        }
      }
    }
  }
`;
<|endoftext|>


<commit_before>var gulp = require('gulp');
var serv = require('gulp-webserver');
var jshint = require('gulp-jshint');
var nodemon = require('gulp-nodemon');

var paths = {
  javascript: './js/**/*.js'
};

gulp.task('server', function () {
  return gulp.src('./')
    .pipe(serv({ open: true }));
});

gulp.task('api', function () {
  return nodemon({
    script: './api/image.js'
  });
});

gulp.task('lint', function () {
  return gulp.src(paths.javascript)
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('default', ['server', 'api']);
<commit_msg>Add task to default, change name to jslint<commit_after>var gulp = require('gulp');
var serv = require('gulp-webserver');
var jshint = require('gulp-jshint');
var nodemon = require('gulp-nodemon');

var paths = {
  javascript: './js/**/*.js'
};

gulp.task('server', function () {
  return gulp.src('./')
    .pipe(serv({ open: true }));
});

gulp.task('api', function () {
  return nodemon({
    script: './api/image.js'
  });
});

gulp.task('jshint', function () {
  return gulp.src(paths.javascript)
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('default', ['server', 'api', 'jshint']);
<|endoftext|>


<commit_before>
commands = [
	"left",
	"right",
	"up",
	"down"
]

var net = require('net');

var server = net.createServer();

connections = []

server.on("connection", function(socket) {
	connections.push(socket)
	// console.log(connections);
	socket.setEncoding("utf8")
	socket.on("data", function (data) {
		console.log(data)
		socket.write('Received:\t' + data + "\n");
	});
	socket.on("close", function () {
		console.log("socket done");
		// pop this socket from connections
		connections.splice(connections.indexOf(socket), 1)
	})
	socket.on("error", function (err) {
		console.log("error:", err);
	})
})

server.on("error", function (err) {
	console.log(err);
})

writeSomething = function () {
	console.log("connections:", connections.length);
	for (var i = 0; i < connections.length; i++) {
		// console.log(connections[i])
		connections[i].write(commands[Math.floor(Math.random() * commands.length)])
	}
}

setInterval(writeSomething, 1000)

server.listen(42124);
<commit_msg>removing receipt of data<commit_after>
commands = [
	"left",
	"right",
	"up",
	"down"
]

var net = require('net');

var server = net.createServer();

connections = []

server.on("connection", function(socket) {
	connections.push(socket)
	// console.log(connections);
	socket.setEncoding("utf8")
	socket.on("data", function (data) {
		console.log(data)
		// socket.write('Received:\t' + data + "\n");
	});
	socket.on("close", function () {
		console.log("socket done");
		// pop this socket from connections
		connections.splice(connections.indexOf(socket), 1)
	})
	socket.on("error", function (err) {
		console.log("error:", err);
	})
})

server.on("error", function (err) {
	console.log(err);
})

writeSomething = function () {
	console.log("connections:", connections.length);
	for (var i = 0; i < connections.length; i++) {
		// console.log(connections[i])
		connections[i].write(commands[Math.floor(Math.random() * commands.length)])
	}
}

setInterval(writeSomething, 1000)

server.listen(42124);
<|endoftext|>


<commit_before>const       gulp = require('gulp'),
         wiredep = require('gulp-wiredep'),
           bsync = require('browser-sync').create(),
          dotenv = require('dotenv'),
            argv = require('yargs').argv,
           watch = require('gulp-watch');

const  lib = require('./gulp')

dotenv.config();
const config = {
      srcDir   : "src",
      buildDir : "dist",
      tmpDir   : ".tmp",
      contDir  : "contents"
};

/**
 * Init tasks stored in ./gulp folder
 */

gulp.task( "sass"       , lib.sass(config, bsync) );
gulp.task( 'contents'   , lib.contents(config, bsync) );
gulp.task( 'ngTemplates', lib.ngTemplates(config, bsync) );
gulp.task( "js"         , lib.javascript(config, bsync) );
gulp.task( 'wiredep'    , lib.wiredep(config , bsync) );
gulp.task( 'images'     , lib.images(config , bsync) );
gulp.task( 'fonts'      , ['contents'], lib.fonts(config , bsync) );

/**
 * Dev tasks
 */

gulp.task('bsync', () => {
  bsync.init({
                server: { baseDir: [ './', config.tmpDir, config.buildDir]},
       injectFileTypes: ["css","map", "png", "jpg", "jpeg", "gif", "webp"],
                online: false,
                  open: false,
             });
});

gulp.task('reload',()=>{
    return gulp.src([`./${config.tmpDir}/**/*.html`,`./${config.tmpDir}/**/*.js`,`./${config.buildDir}/**/*.svg`])
        .pipe(bsync.stream());
})

/**
 *  Default task
 */

gulp.task('default', ['contents','sass','wiredep','ngTemplates','js','images','fonts'])

gulp.task('watch',['default'], () => {

  gulp.start('bsync');
  gulp.watch([`bower.json`],['wiredep']);
  gulp.watch([`./${config.srcDir}/sass/**/*.scss`], ['sass']);
  gulp.watch([`./${config.srcDir}/ng/**/*.js`], ['js']);
  gulp.watch([`./${config.srcDir}/ng/**/*.html`], ['ngTemplates']);
  gulp.watch([`./${config.srcDir}/render/**/*.{html,js}`,
              `./${config.contDir}/**/*{.json,.md}`], ['contents']);

  gulp.watch([`./${config.srcDir}/fonts/**/*.{eot,svg,ttf,woff,woff2}`],['fonts'])
  gulp.watch([ `./${config.srcDir}/images/**/*.{svg, jpg, png, gif}`],['images'])

});

<commit_msg>support image files<commit_after>const       gulp = require('gulp'),
         wiredep = require('gulp-wiredep'),
           bsync = require('browser-sync').create(),
          dotenv = require('dotenv'),
            argv = require('yargs').argv,
           watch = require('gulp-watch');

const  lib = require('./gulp')

dotenv.config();
const config = {
      srcDir   : "src",
      buildDir : "dist",
      tmpDir   : ".tmp",
      contDir  : "contents"
};

/**
 * Init tasks stored in ./gulp folder
 */

gulp.task( "sass"       , lib.sass(config, bsync) );
gulp.task( 'contents'   , lib.contents(config, bsync) );
gulp.task( 'ngTemplates', lib.ngTemplates(config, bsync) );
gulp.task( "js"         , lib.javascript(config, bsync) );
gulp.task( 'wiredep'    , lib.wiredep(config , bsync) );
gulp.task( 'images'     , lib.images(config , bsync) );
gulp.task( 'fonts'      , ['contents'], lib.fonts(config , bsync) );

/**
 * Dev tasks
 */

gulp.task('bsync', () => {
  bsync.init({
                server: { baseDir: [ './', config.tmpDir, config.buildDir]},
       injectFileTypes: ["css","map", "png", "jpg", "jpeg", "gif", "webp"],
                online: false,
                  open: false,
             });
});

gulp.task('reload',()=>{
    return gulp.src([`./${config.tmpDir}/**/*.html`,`./${config.tmpDir}/**/*.js`,`./${config.buildDir}/**/*.svg`])
        .pipe(bsync.stream());
})

/**
 *  Default task
 */

gulp.task('default', ['contents','sass','wiredep','ngTemplates','js','images','fonts'])

gulp.task('watch',['default'], () => {

  gulp.start('bsync');
  gulp.watch([`bower.json`],['wiredep']);
  watch([`./${config.srcDir}/sass/**/*.scss`], function(){ gulp.start(['sass']);});
  watch([`./${config.srcDir}/ng/**/*.js`], function(){ gulp.start(['js']);});
  watch([`./${config.srcDir}/ng/**/*.html`], function(){ gulp.start(['ngTemplates']);});
  watch([`./${config.srcDir}/render/**/*.{html,js}`,
         `./${config.contDir}/**/*.{json,md}`], function(){ gulp.start(['contents']);});

  watch([`./${config.srcDir}/fonts/**/*.{eot,svg,ttf,woff,woff2}`],function(){ gulp.start(['fonts'])});
  watch([ `./${config.srcDir}/images/**/*.{svg, jpg, png, gif}`],function(){ gulp.start(['images'])});

});

<|endoftext|>


<commit_before>var path = require('path');
var PassThrough = require('stream').PassThrough;
var _ = require('underscore');
var gulp = require('gulp');
var gulpif = require('gulp-if');
var gutil = require('gulp-util');
var s3 = require('gulp-s3');
var gzip = require('gulp-gzip');
var less = require('gulp-less');
var cssmin = require('gulp-minify-css');
var webpack = require('gulp-webpack');
var plumber = require('gulp-plumber');
var merge = require('merge-stream');
var sourcemaps = require('gulp-sourcemaps');
var sitemap = require('gulp-sitemap');
var jscs = require('gulp-jscs');
var jshint = require('gulp-jshint');
var autoprefixer = require('gulp-autoprefixer');
var rename = require('gulp-rename');

var IndexFileStream = require('./lib/gulp-index-file-stream');
var webpackConfig = require('./webpack.config');
var config = require('./lib/config');
var travis = require('./lib/travis');
var staticServer = require('./test/browser/server');
var lightweightDynamicServer = require('./app');
var indexStaticWatcher = require('./lib/index-static-watcher').create();

var MINIMAL_BUILD_TASKS = [
  'copy-static-files',
  'less',
  'webpack'
];

var BUILD_TASKS = MINIMAL_BUILD_TASKS.concat([
  'sitemap'
]);

var LINT_DIRS = [
    '*.js',
    'lib/**/*.js',
    'test/**/*.js',
    // Google analytics contains code from GA's snippet, which
    // is intentionally uglified and obfuscated and crap.
    '!lib/googleanalytics.js',
    // TODO let's figure out how to let our linters handle the test suite: delete the line below when we're ready
    '!test/**/*.js'
];

var LESS_FILES = './less/**/*.less';
var WATCH_DELAY = 200;

function onError(err) {
  gutil.log(gutil.colors.red(err));
  gutil.beep();
  this.emit('end');
}

function handleError() {
  return plumber({
    errorHandler: onError
  });
}

function createIndexFileStream() {
  var stream = new PassThrough({ objectMode: true });
  var meta = {};
  var execSync = require('child_process').execSync;

  try {
    meta['git-rev'] = execSync('git rev-parse HEAD', {
      cwd: __dirname,
      encoding: 'utf8'
    }).slice(0, 40);
  } catch (e) {}

  indexStaticWatcher.build(function(err, indexStatic) {
    if (err) {
      return stream.emit('error', err);
    }
    new IndexFileStream(indexStatic, {
      meta: meta
    }).on('error', function(err) {
      stream.emit('error', err);
    }).pipe(stream);
  });

  return stream;
}

gulp.task('sitemap', ['generate-index-files'], function() {
  gulp.src('dist/**/*.html')
    .pipe(sitemap({
      siteUrl: config.ORIGIN
    }))
    .pipe(gulp.dest('./dist'));
});

gulp.task('copy-static-files', [
  'copy-test-dirs',
  'copy-images',
  'copy-bootstrap',
  'copy-webmaker-app-icons'
]);

gulp.task('copy-test-dirs', function() {
  return merge(
    gulp.src('test/browser/static/**', {
      base: './test/browser/static'
    }),
    gulp.src('node_modules/mocha/mocha.*', {
      base: './node_modules/mocha'
    })
  ).pipe(gulp.dest('./dist/test'));
});

gulp.task('copy-images', function () {
  return gulp.src('img/**', {
    base: '.'
  }).pipe(gulp.dest('./dist'));
});

gulp.task('copy-webmaker-app-icons', function () {
  return gulp.src(['node_modules/webmaker-app-icons/css/**', 'node_modules/webmaker-app-icons/fonts/**'], {
    base: 'node_modules/webmaker-app-icons'
  }).pipe(gulp.dest('./dist/vendor/webmaker-app-icons'));
});

gulp.task('copy-bootstrap', function () {
  return gulp.src(['node_modules/bootstrap/dist/css/**', 'node_modules/bootstrap/dist/fonts/**'], {
    base: 'node_modules/bootstrap/dist'
  }).pipe(gulp.dest('./dist/vendor/bootstrap'));
});

gulp.task('less', function() {
  return gulp.src('./less/index.less')
    .pipe(handleError())
    .pipe(sourcemaps.init())
    .pipe(less({
      paths: [path.join(__dirname, 'less')],
      filename: 'styles.css'
    }))
    .pipe(gulpif(process.env.LESS_AUTOPREFIXER != 'off', autoprefixer({
      browsers: ['last 2 versions'],
      cascade: false,
      remove: true
    })))
    .pipe(gulpif(process.env.NODE_ENV === 'production', cssmin()))
    .pipe(rename('styles.css'))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./dist'));
});

gulp.task('webpack', function() {
  return gulp.src(webpackConfig.entry.app)
    .pipe(webpack(webpackConfig))
    .pipe(gulp.dest('./dist'));
});

gulp.task('smoketest', BUILD_TASKS.concat([
  'test-react-warnings'
]), function() {
  gutil.log(gutil.colors.green.bold('Yay, smoke test passes!'));
});

gulp.task('test-react-warnings', function() {
  var oldWarn = console.warn;
  var warnings = 0;

  console.warn = function(message) {
    warnings++;
    gutil.log(gutil.colors.red.bold(message));
  };

  return createIndexFileStream()
    .on('end', function() {
      console.warn = oldWarn;
      if (warnings) {
        this.emit('error', new Error('At least one warning was logged.'));
      }
    })
    .on('data', function() {
      // Drain the stream. We don't actually need to do anything with
      // the data, we just want to make sure no warnings are logged while
      // the stream's data is being generated.
    });
});

gulp.task('generate-index-files', function() {
  return createIndexFileStream().pipe(gulp.dest('./dist'));
});

gulp.task('jshint', function() {
  return gulp.src(LINT_DIRS)
      .pipe(jshint({ lookup: 'node_modules/mofo-style/linters/.jshintrc' }))
      .pipe(jshint.reporter('default'));
});

gulp.task('jscs', function () {
  // jscs doesn't play nice with *.jsx files so we're avoiding lib/*.jsx
  return gulp.src(LINT_DIRS)
      .pipe(jscs({ configPath: 'node_modules/mofo-style/linters/.jscsrc' }));
});

gulp.task('lint-test', ['jscs', 'jshint']);

gulp.task('default', BUILD_TASKS);

gulp.task('watch-webpack', function() {
  // We're specifically not returning the stream here,
  // because if we do that, this task would never end,
  // and tasks that depend on this one would never be run.
  gulp.src(webpackConfig.entry.app)
    .pipe(webpack(_.extend({
      watch: true
    }, webpackConfig)))
    .pipe(gulp.dest('./dist'));
});

gulp.task('watch-static-files', function() {
  gulp.watch('img/**', ['copy-images']);
  gulp.watch('test/browser/static/**', ['copy-test-dirs']);
});

gulp.task('watch-non-reloadable-files', function() {
  gulp.watch([
    'gulpfile.js',
    'package.json',
    'webpack.config.js',
    'app.js'
  ], function(event) {
    var filename = path.basename(event.path);
    var cmd = process.argv[2] === 'app' ? 'npm run app' : 'npm start';
    gutil.log(gutil.colors.red.bold(filename + ' was ' + event.type + '.'));
    gutil.log(gutil.colors.red.bold('Please restart the server ' +
                                    'with "' + cmd + '".'));
    process.exit(0);
  });
});

gulp.task('watch', _.without(BUILD_TASKS, 'webpack').concat([
  'watch-webpack',
  'watch-static-files',
  'watch-non-reloadable-files'
]), function() {
  require('./lib/developer-help')();

  indexStaticWatcher.watch(WATCH_DELAY, function() {
    createIndexFileStream()
      .on('error', function(err) {
        gutil.log('Error rebuilding index HTML files.');
        gutil.log(gutil.colors.red.bold(err.stack));
      })
      .on('end', function() {
        gutil.log('Index HTML files rebuilt.');
      })
      .pipe(gulp.dest('./dist'));
  });

  gulp.watch(LESS_FILES, ['less']);

  staticServer.create().listen(config.DEV_SERVER_PORT, function() {
    gutil.log('Development server listening at ' +
              gutil.colors.green.bold(config.ORIGIN) + '.');
  });
});

gulp.task('app', _.without(MINIMAL_BUILD_TASKS, 'webpack').concat([
  'watch-webpack',
  'watch-static-files',
  'watch-non-reloadable-files'
]), function() {
  require('./lib/developer-help')();

  indexStaticWatcher.watch(WATCH_DELAY, function(newIndexStatic) {
    lightweightDynamicServer.updateIndexStatic(newIndexStatic);
    console.log('Rebuilt server-side bundle.');
  });

  gulp.watch(LESS_FILES, ['less']);

  lightweightDynamicServer.listen(config.DEV_SERVER_PORT, function() {
    gutil.log('Lightweight dynamic server listening at ' +
              gutil.colors.green.bold(config.ORIGIN) + '.');
  });
});

gulp.task('travis-after-success', function(cb) {
  var env = travis.getS3Env();

  if (env === null) {
    gutil.log('Current build does not need to be pushed to S3.');
    return;
  }

  require('child_process')
    .spawn(process.execPath, [process.argv[1], 's3'], {
      env: _.extend({}, process.env, env),
      stdio: 'inherit'
    }).on('close', function(code) {
      if (code !== 0) {
        gutil.log(gutil.colors.red.bold('Error deploying to S3!'));
        cb(new Error('gulp s3 failed with exit code ' + code));
      } else {
        gutil.log('Site deployed to S3.');
        cb(null);
      }
    });
});

gulp.task('s3', BUILD_TASKS, function() {
  var key = process.env.AWS_ACCESS_KEY;
  var secret = process.env.AWS_SECRET_KEY;

  gutil.log('NODE_ENV is ' + process.env.NODE_ENV + '.');

  if (!key || !secret) {
    throw new Error('Please set AWS_ACCESS_KEY and AWS_SECRET_KEY ' +
    'in your environment.');
  }

  // WARNING: Even if deploying to S3 fails, no errors will be raised.
  // https://github.com/nkostelnik/gulp-s3/issues/47

  return gulp.src('./dist/**')
    .pipe(gzip())
    .pipe(s3({
      key: key,
      secret: secret,
      bucket: process.env.AWS_BUCKET || 'teach.mofostaging.net',
      region: process.env.AWS_REGION || 'us-east-1'
    }, {
      gzippedOnly: true,
      headers: {
        'Cache-Control': 'max-age=600, public'
      }
    }));
});

if (process.env.NODE_ENV === 'production') {
  gulp.task('postinstall', MINIMAL_BUILD_TASKS);
} else {
  gulp.task('postinstall');
}

module.exports.LESS_FILES = LESS_FILES;
<commit_msg>Fixes #1019 - watch only .jpg .svg .png files in /img dir<commit_after>var path = require('path');
var PassThrough = require('stream').PassThrough;
var _ = require('underscore');
var gulp = require('gulp');
var gulpif = require('gulp-if');
var gutil = require('gulp-util');
var s3 = require('gulp-s3');
var gzip = require('gulp-gzip');
var less = require('gulp-less');
var cssmin = require('gulp-minify-css');
var webpack = require('gulp-webpack');
var plumber = require('gulp-plumber');
var merge = require('merge-stream');
var sourcemaps = require('gulp-sourcemaps');
var sitemap = require('gulp-sitemap');
var jscs = require('gulp-jscs');
var jshint = require('gulp-jshint');
var autoprefixer = require('gulp-autoprefixer');
var rename = require('gulp-rename');

var IndexFileStream = require('./lib/gulp-index-file-stream');
var webpackConfig = require('./webpack.config');
var config = require('./lib/config');
var travis = require('./lib/travis');
var staticServer = require('./test/browser/server');
var lightweightDynamicServer = require('./app');
var indexStaticWatcher = require('./lib/index-static-watcher').create();

var MINIMAL_BUILD_TASKS = [
  'copy-static-files',
  'less',
  'webpack'
];

var BUILD_TASKS = MINIMAL_BUILD_TASKS.concat([
  'sitemap'
]);

var LINT_DIRS = [
    '*.js',
    'lib/**/*.js',
    'test/**/*.js',
    // Google analytics contains code from GA's snippet, which
    // is intentionally uglified and obfuscated and crap.
    '!lib/googleanalytics.js',
    // TODO let's figure out how to let our linters handle the test suite: delete the line below when we're ready
    '!test/**/*.js'
];

var LESS_FILES = './less/**/*.less';
var WATCH_DELAY = 200;

function onError(err) {
  gutil.log(gutil.colors.red(err));
  gutil.beep();
  this.emit('end');
}

function handleError() {
  return plumber({
    errorHandler: onError
  });
}

function createIndexFileStream() {
  var stream = new PassThrough({ objectMode: true });
  var meta = {};
  var execSync = require('child_process').execSync;

  try {
    meta['git-rev'] = execSync('git rev-parse HEAD', {
      cwd: __dirname,
      encoding: 'utf8'
    }).slice(0, 40);
  } catch (e) {}

  indexStaticWatcher.build(function(err, indexStatic) {
    if (err) {
      return stream.emit('error', err);
    }
    new IndexFileStream(indexStatic, {
      meta: meta
    }).on('error', function(err) {
      stream.emit('error', err);
    }).pipe(stream);
  });

  return stream;
}

gulp.task('sitemap', ['generate-index-files'], function() {
  gulp.src('dist/**/*.html')
    .pipe(sitemap({
      siteUrl: config.ORIGIN
    }))
    .pipe(gulp.dest('./dist'));
});

gulp.task('copy-static-files', [
  'copy-test-dirs',
  'copy-images',
  'copy-bootstrap',
  'copy-webmaker-app-icons'
]);

gulp.task('copy-test-dirs', function() {
  return merge(
    gulp.src('test/browser/static/**', {
      base: './test/browser/static'
    }),
    gulp.src('node_modules/mocha/mocha.*', {
      base: './node_modules/mocha'
    })
  ).pipe(gulp.dest('./dist/test'));
});

gulp.task('copy-images', function () {
  return gulp.src('img/**', {
    base: '.'
  }).pipe(gulp.dest('./dist'));
});

gulp.task('copy-webmaker-app-icons', function () {
  return gulp.src(['node_modules/webmaker-app-icons/css/**', 'node_modules/webmaker-app-icons/fonts/**'], {
    base: 'node_modules/webmaker-app-icons'
  }).pipe(gulp.dest('./dist/vendor/webmaker-app-icons'));
});

gulp.task('copy-bootstrap', function () {
  return gulp.src(['node_modules/bootstrap/dist/css/**', 'node_modules/bootstrap/dist/fonts/**'], {
    base: 'node_modules/bootstrap/dist'
  }).pipe(gulp.dest('./dist/vendor/bootstrap'));
});

gulp.task('less', function() {
  return gulp.src('./less/index.less')
    .pipe(handleError())
    .pipe(sourcemaps.init())
    .pipe(less({
      paths: [path.join(__dirname, 'less')],
      filename: 'styles.css'
    }))
    .pipe(gulpif(process.env.LESS_AUTOPREFIXER != 'off', autoprefixer({
      browsers: ['last 2 versions'],
      cascade: false,
      remove: true
    })))
    .pipe(gulpif(process.env.NODE_ENV === 'production', cssmin()))
    .pipe(rename('styles.css'))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./dist'));
});

gulp.task('webpack', function() {
  return gulp.src(webpackConfig.entry.app)
    .pipe(webpack(webpackConfig))
    .pipe(gulp.dest('./dist'));
});

gulp.task('smoketest', BUILD_TASKS.concat([
  'test-react-warnings'
]), function() {
  gutil.log(gutil.colors.green.bold('Yay, smoke test passes!'));
});

gulp.task('test-react-warnings', function() {
  var oldWarn = console.warn;
  var warnings = 0;

  console.warn = function(message) {
    warnings++;
    gutil.log(gutil.colors.red.bold(message));
  };

  return createIndexFileStream()
    .on('end', function() {
      console.warn = oldWarn;
      if (warnings) {
        this.emit('error', new Error('At least one warning was logged.'));
      }
    })
    .on('data', function() {
      // Drain the stream. We don't actually need to do anything with
      // the data, we just want to make sure no warnings are logged while
      // the stream's data is being generated.
    });
});

gulp.task('generate-index-files', function() {
  return createIndexFileStream().pipe(gulp.dest('./dist'));
});

gulp.task('jshint', function() {
  return gulp.src(LINT_DIRS)
      .pipe(jshint({ lookup: 'node_modules/mofo-style/linters/.jshintrc' }))
      .pipe(jshint.reporter('default'));
});

gulp.task('jscs', function () {
  // jscs doesn't play nice with *.jsx files so we're avoiding lib/*.jsx
  return gulp.src(LINT_DIRS)
      .pipe(jscs({ configPath: 'node_modules/mofo-style/linters/.jscsrc' }));
});

gulp.task('lint-test', ['jscs', 'jshint']);

gulp.task('default', BUILD_TASKS);

gulp.task('watch-webpack', function() {
  // We're specifically not returning the stream here,
  // because if we do that, this task would never end,
  // and tasks that depend on this one would never be run.
  gulp.src(webpackConfig.entry.app)
    .pipe(webpack(_.extend({
      watch: true
    }, webpackConfig)))
    .pipe(gulp.dest('./dist'));
});

gulp.task('watch-static-files', function() {
  gulp.watch([
    'img/**/*.png',
    'img/**/*.jpg',
    'img/**/*.svg'
  ], ['copy-images']);
  gulp.watch('test/browser/static/**', ['copy-test-dirs']);
});

gulp.task('watch-non-reloadable-files', function() {
  gulp.watch([
    'gulpfile.js',
    'package.json',
    'webpack.config.js',
    'app.js'
  ], function(event) {
    var filename = path.basename(event.path);
    var cmd = process.argv[2] === 'app' ? 'npm run app' : 'npm start';
    gutil.log(gutil.colors.red.bold(filename + ' was ' + event.type + '.'));
    gutil.log(gutil.colors.red.bold('Please restart the server ' +
                                    'with "' + cmd + '".'));
    process.exit(0);
  });
});

gulp.task('watch', _.without(BUILD_TASKS, 'webpack').concat([
  'watch-webpack',
  'watch-static-files',
  'watch-non-reloadable-files'
]), function() {
  require('./lib/developer-help')();

  indexStaticWatcher.watch(WATCH_DELAY, function() {
    createIndexFileStream()
      .on('error', function(err) {
        gutil.log('Error rebuilding index HTML files.');
        gutil.log(gutil.colors.red.bold(err.stack));
      })
      .on('end', function() {
        gutil.log('Index HTML files rebuilt.');
      })
      .pipe(gulp.dest('./dist'));
  });

  gulp.watch(LESS_FILES, ['less']);

  staticServer.create().listen(config.DEV_SERVER_PORT, function() {
    gutil.log('Development server listening at ' +
              gutil.colors.green.bold(config.ORIGIN) + '.');
  });
});

gulp.task('app', _.without(MINIMAL_BUILD_TASKS, 'webpack').concat([
  'watch-webpack',
  'watch-static-files',
  'watch-non-reloadable-files'
]), function() {
  require('./lib/developer-help')();

  indexStaticWatcher.watch(WATCH_DELAY, function(newIndexStatic) {
    lightweightDynamicServer.updateIndexStatic(newIndexStatic);
    console.log('Rebuilt server-side bundle.');
  });

  gulp.watch(LESS_FILES, ['less']);

  lightweightDynamicServer.listen(config.DEV_SERVER_PORT, function() {
    gutil.log('Lightweight dynamic server listening at ' +
              gutil.colors.green.bold(config.ORIGIN) + '.');
  });
});

gulp.task('travis-after-success', function(cb) {
  var env = travis.getS3Env();

  if (env === null) {
    gutil.log('Current build does not need to be pushed to S3.');
    return;
  }

  require('child_process')
    .spawn(process.execPath, [process.argv[1], 's3'], {
      env: _.extend({}, process.env, env),
      stdio: 'inherit'
    }).on('close', function(code) {
      if (code !== 0) {
        gutil.log(gutil.colors.red.bold('Error deploying to S3!'));
        cb(new Error('gulp s3 failed with exit code ' + code));
      } else {
        gutil.log('Site deployed to S3.');
        cb(null);
      }
    });
});

gulp.task('s3', BUILD_TASKS, function() {
  var key = process.env.AWS_ACCESS_KEY;
  var secret = process.env.AWS_SECRET_KEY;

  gutil.log('NODE_ENV is ' + process.env.NODE_ENV + '.');

  if (!key || !secret) {
    throw new Error('Please set AWS_ACCESS_KEY and AWS_SECRET_KEY ' +
    'in your environment.');
  }

  // WARNING: Even if deploying to S3 fails, no errors will be raised.
  // https://github.com/nkostelnik/gulp-s3/issues/47

  return gulp.src('./dist/**')
    .pipe(gzip())
    .pipe(s3({
      key: key,
      secret: secret,
      bucket: process.env.AWS_BUCKET || 'teach.mofostaging.net',
      region: process.env.AWS_REGION || 'us-east-1'
    }, {
      gzippedOnly: true,
      headers: {
        'Cache-Control': 'max-age=600, public'
      }
    }));
});

if (process.env.NODE_ENV === 'production') {
  gulp.task('postinstall', MINIMAL_BUILD_TASKS);
} else {
  gulp.task('postinstall');
}

module.exports.LESS_FILES = LESS_FILES;
<|endoftext|>


<commit_before>/*
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

'use strict';

// Include Gulp & tools we'll use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var browserSync = require('browser-sync');
var reload = browserSync.reload;
var merge = require('merge-stream');
var path = require('path');
var fs = require('fs');
var glob = require('glob-all');
var historyApiFallback = require('connect-history-api-fallback');
var packageJson = require('./package.json');
var crypto = require('crypto');
var minimist = require('minimist');
var requireDir = require('require-dir');
var ghPages = require('gulp-gh-pages');

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

var DIST = 'www';

var dist = function(subpath) {
  return !subpath ? DIST : path.join(DIST, subpath);
};

var styleTask = function(stylesPath, srcs) {
  return gulp.src(srcs.map(function(src) {
      return path.join('app', stylesPath, src);
    }))
    .pipe($.changed(stylesPath, {extension: '.css'}))
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe(gulp.dest('.tmp/' + stylesPath))
    .pipe($.minifyCss())
    .pipe(gulp.dest(dist(stylesPath)))
    .pipe($.size({title: stylesPath}));
};

var imageOptimizeTask = function(src, dest) {
  return gulp.src(src)
    .pipe($.imagemin({
      progressive: true,
      interlaced: true
    }))
    .pipe(gulp.dest(dest))
    .pipe($.size({title: 'images'}));
};

var optimizeHtmlTask = function(src, dest) {
  var assets = $.useref.assets({
    searchPath: ['.tmp', 'app', dist()]
  });

  return gulp.src(src)
    // Replace path for vulcanized assets
    .pipe($.if('*.html', $.replace('elements/elements.html', 'elements/elements.vulcanized.html')))
    .pipe(assets)
    // Concatenate and minify JavaScript
    .pipe($.if('*.js', $.uglify({
      preserveComments: 'some'
    })))
    // Concatenate and minify styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.minifyCss()))
    .pipe(assets.restore())
    .pipe($.useref())
    // Minify any HTML
    .pipe($.if('*.html', $.minifyHtml({
      quotes: true,
      empty: true,
      spare: true
    })))
    // Output files
    .pipe(gulp.dest(dest))
    .pipe($.size({
      title: 'html'
    }));
};

// Compile and automatically prefix stylesheets
gulp.task('styles', function() {
  return styleTask('styles', ['**/*.css']);
});

gulp.task('elements', function() {
  return styleTask('elements', ['**/*.css']);
});

// Lint JavaScript
gulp.task('lint', function() {
  return gulp.src([
      'app/scripts/**/*.js',
      'app/elements/**/*.js',
      'app/elements/**/*.html',
      'gulpfile.js'
    ])
    .pipe(reload({
      stream: true,
      once: true
    }))

  // JSCS has not yet a extract option
  .pipe($.if('*.html', $.htmlExtract()))
  .pipe($.jshint())
  .pipe($.jscs())
  .pipe($.jscsStylish.combineWithHintResults())
  .pipe($.jshint.reporter('jshint-stylish'))
  .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

// Optimize images
gulp.task('images', function() {
  return imageOptimizeTask('app/images/**/*', dist('images'));
});

// Copy all files at the root level (app)
gulp.task('copy', function() {
  var app = gulp.src([
    'app/*',
    '!app/test',
    '!app/cache-config.json'
  ], {
    dot: true
  }).pipe(gulp.dest(dist()));

  var bower = gulp.src([
    'bower_components/**/*'
  ]).pipe(gulp.dest(dist('bower_components')));

  var elements = gulp.src(['app/elements/**/*.html',
      'app/elements/**/*.css',
      'app/elements/**/*.js'
    ])
    .pipe(gulp.dest(dist('elements')));

  var swBootstrap = gulp.src(['bower_components/platinum-sw/bootstrap/*.js'])
    .pipe(gulp.dest(dist('elements/bootstrap')));

  var swToolbox = gulp.src(['bower_components/sw-toolbox/*.js'])
    .pipe(gulp.dest(dist('sw-toolbox')));

  var vulcanized = gulp.src(['app/elements/elements.html'])
    .pipe($.rename('elements.vulcanized.html'))
    .pipe(gulp.dest(dist('elements')));

  return merge(app, bower, elements, vulcanized, swBootstrap, swToolbox)
    .pipe($.size({
      title: 'copy'
    }));
});

// Copy web fonts to dist
gulp.task('fonts', function() {
  return gulp.src(['app/fonts/**'])
    .pipe(gulp.dest(dist('fonts')))
    .pipe($.size({
      title: 'fonts'
    }));
});

// Scan your HTML for assets & optimize them
gulp.task('html', function() {
  return optimizeHtmlTask(
    ['app/**/*.html', '!app/{elements,test}/**/*.html'],
    dist());
});

// Vulcanize granular configuration
gulp.task('vulcanize', function() {
  var DEST_DIR = dist('elements');
  return gulp.src(dist('elements/elements.vulcanized.html'))
    .pipe($.vulcanize({
      stripComments: true,
      inlineCss: true,
      inlineScripts: true
    }))
    .pipe($.minifyInline())
    .pipe(gulp.dest(DEST_DIR))
    .pipe($.size({title: 'vulcanize'}));
});

// Generate config data for the <sw-precache-cache> element.
// This include a list of files that should be precached, as well as a (hopefully unique) cache
// id that ensure that multiple PSK projects don't share the same Cache Storage.
// This task does not run by default, but if you are interested in using service worker caching
// in your project, please enable it within the 'default' task.
// See https://github.com/PolymerElements/polymer-starter-kit#enable-service-worker-support
// for more context.
gulp.task('cache-config', function(callback) {
  var dir = dist();
  var config = {
    cacheId: packageJson.name || path.basename(__dirname),
    disabled: false
  };

  glob([
    'index.html',
    './',
    'bower_components/webcomponentsjs/webcomponents-lite.min.js',
    '{elements,scripts,styles}/**/*.*'],
    {cwd: dir}, function(error, files) {
    if (error) {
      callback(error);
    } else {
      config.precache = files;

      var md5 = crypto.createHash('md5');
      md5.update(JSON.stringify(config.precache));
      config.precacheFingerprint = md5.digest('hex');

      var configPath = path.join(dir, 'cache-config.json');
      fs.writeFile(configPath, JSON.stringify(config), callback);
    }
  });
});

// Clean output directory
gulp.task('clean', function() {
  return del(['.tmp', dist()]);
});

// Watch files for changes & reload
gulp.task('serve', ['lint', 'styles', 'elements', 'images'], function() {
  browserSync({
    port: 5000,
    notify: false,
    logPrefix: 'PSK',
    snippetOptions: {
      rule: {
        match: '',
        fn: function(snippet) {
          return snippet;
        }
      }
    },
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: {
      baseDir: ['.tmp', 'app'],
      middleware: [historyApiFallback()],
      routes: {
        '/bower_components': 'bower_components'
      }
    }
  });

  gulp.watch(['app/**/*.html'], reload);
  gulp.watch(['app/styles/**/*.css'], ['styles', reload]);
  gulp.watch(['app/elements/**/*.css'], ['elements', reload]);
  gulp.watch(['app/{scripts,elements}/**/{*.js,*.html}'], ['lint']);
  gulp.watch(['app/images/**/*'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['build'], function() {
  browserSync({
    port: 5001,
    notify: false,
    logPrefix: 'PSK',
    snippetOptions: {
      rule: {
        match: '',
        fn: function(snippet) {
          return snippet;
        }
      }
    },
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: dist(),
    middleware: [historyApiFallback()]
  });
});

// Clean bower components once finished with them directory
gulp.task('optimize', function() {
  del([dist('/bower_components'), dist('/elements/elements.html')]);
});

gulp.task('build', ['clean'], function(cb) {
  // Uncomment 'cache-config' if you are going to use service workers.
  runSequence(
    ['copy', 'styles'],
    'elements',
    ['lint', 'images', 'fonts', 'html'],
    'vulcanize', // 'cache-config',
    'optimize',
    cb);
});

/* Cordova setting and tasks */
// OPTIONS
var options = gulp.options = minimist(process.argv.slice(2));

// cordova command one of cordova's build commands?
if (options.cordova) {
  var cmds = ['build', 'run', 'emulate', 'prepare', 'serve'];

  for (var i = 0, cmd; (cmd = cmds[i]); i++) {
    if (options.cordova.indexOf(cmd) >= 0) {
      options.cordovaBuild = true;
      break;
    }
  }
}

// load tasks
requireDir('./gulp');

// default task
gulp.task('default', function() {
  options.build = true;
  return gulp.start('');
});

/* End Cordova setting and tasks */

// Build production files, the default task
gulp.task('default', function(cb) {
  // cordova build command & gulp build
  if (options.cordovaBuild && options.build !== false) {
    return gulp.start('cordova-with-build');
  }
  // cordova build command & no gulp build
  else if (options.cordovaBuild && options.build === false) {
    return gulp.start('cordova-only-resources');
  }
  // cordova non-build command
  else if (options.cordova) {
    return gulp.start('cordova');
  }
  // just default task when cordova option not present
  else {
    return gulp.start('build', cb);
  }
});

// Build then deploy to GitHub pages gh-pages branch
gulp.task('build-deploy-gh-pages', function(cb) {
  runSequence(
    'build',
    'deploy-gh-pages',
    cb);
});

// Deploy to GitHub pages gh-pages branch
gulp.task('deploy-gh-pages', function() {
  return gulp.src(dist('**/*'))
    .pipe($.ghPages());
});

// Load tasks for web-component-tester
// Adds tasks for `gulp test:local` and `gulp test:remote`
require('web-component-tester').gulp.init(gulp);

// Load custom tasks from the `tasks` directory
try {
  require('require-dir')('tasks');
} catch (err) {}
<commit_msg>so multithreaded<commit_after>/*
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

'use strict';

// Include Gulp & tools we'll use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var browserSync = require('browser-sync');
var reload = browserSync.reload;
var merge = require('merge-stream');
var path = require('path');
var fs = require('fs');
var glob = require('glob-all');
var historyApiFallback = require('connect-history-api-fallback');
var packageJson = require('./package.json');
var crypto = require('crypto');
var minimist = require('minimist');
var requireDir = require('require-dir');
// var ghPages = require('gulp-gh-pages');

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

var DIST = 'www';

var dist = function(subpath) {
  return !subpath ? DIST : path.join(DIST, subpath);
};

var styleTask = function(stylesPath, srcs) {
  return gulp.src(srcs.map(function(src) {
      return path.join('app', stylesPath, src);
    }))
    .pipe($.changed(stylesPath, {extension: '.css'}))
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe(gulp.dest('.tmp/' + stylesPath))
    .pipe($.minifyCss())
    .pipe(gulp.dest(dist(stylesPath)))
    .pipe($.size({title: stylesPath}));
};

var imageOptimizeTask = function(src, dest) {
  return gulp.src(src)
    .pipe($.imagemin({
      progressive: true,
      interlaced: true
    }))
    .pipe(gulp.dest(dest))
    .pipe($.size({title: 'images'}));
};

var optimizeHtmlTask = function(src, dest) {
  var assets = $.useref.assets({
    searchPath: ['.tmp', 'app', dist()]
  });

  return gulp.src(src)
    // Replace path for vulcanized assets
    .pipe($.if('*.html', $.replace('elements/elements.html', 'elements/elements.vulcanized.html')))
    .pipe(assets)
    // Concatenate and minify JavaScript
    .pipe($.if('*.js', $.uglify({
      preserveComments: 'some'
    })))
    // Concatenate and minify styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.minifyCss()))
    .pipe(assets.restore())
    .pipe($.useref())
    // Minify any HTML
    .pipe($.if('*.html', $.minifyHtml({
      quotes: true,
      empty: true,
      spare: true
    })))
    // Output files
    .pipe(gulp.dest(dest))
    .pipe($.size({
      title: 'html'
    }));
};

// Compile and automatically prefix stylesheets
gulp.task('styles', function() {
  return styleTask('styles', ['**/*.css']);
});

gulp.task('elements', function() {
  return styleTask('elements', ['**/*.css']);
});

// Lint JavaScript
gulp.task('lint', function() {
  return gulp.src([
      'app/scripts/**/*.js',
      'app/elements/**/*.js',
      'app/elements/**/*.html',
      'gulpfile.js'
    ])
    .pipe(reload({
      stream: true,
      once: true
    }))

  // JSCS has not yet a extract option
  .pipe($.if('*.html', $.htmlExtract()))
  .pipe($.jshint())
  .pipe($.jscs())
  .pipe($.jscsStylish.combineWithHintResults())
  .pipe($.jshint.reporter('jshint-stylish'))
  .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

// Optimize images
gulp.task('images', function() {
  return imageOptimizeTask('app/images/**/*', dist('images'));
});

// Copy all files at the root level (app)
gulp.task('copy', function() {
  var app = gulp.src([
    'app/*',
    '!app/test',
    '!app/cache-config.json'
  ], {
    dot: true
  }).pipe(gulp.dest(dist()));

  var bower = gulp.src([
    'bower_components/**/*'
  ]).pipe(gulp.dest(dist('bower_components')));

  var elements = gulp.src(['app/elements/**/*.html',
      'app/elements/**/*.css',
      'app/elements/**/*.js'
    ])
    .pipe(gulp.dest(dist('elements')));

  var swBootstrap = gulp.src(['bower_components/platinum-sw/bootstrap/*.js'])
    .pipe(gulp.dest(dist('elements/bootstrap')));

  var swToolbox = gulp.src(['bower_components/sw-toolbox/*.js'])
    .pipe(gulp.dest(dist('sw-toolbox')));

  var vulcanized = gulp.src(['app/elements/elements.html'])
    .pipe($.rename('elements.vulcanized.html'))
    .pipe(gulp.dest(dist('elements')));

  return merge(app, bower, elements, vulcanized, swBootstrap, swToolbox)
    .pipe($.size({
      title: 'copy'
    }));
});

// Copy web fonts to dist
gulp.task('fonts', function() {
  return gulp.src(['app/fonts/**'])
    .pipe(gulp.dest(dist('fonts')))
    .pipe($.size({
      title: 'fonts'
    }));
});

// Scan your HTML for assets & optimize them
gulp.task('html', function() {
  return optimizeHtmlTask(
    ['app/**/*.html', '!app/{elements,test}/**/*.html'],
    dist());
});

// Vulcanize granular configuration
gulp.task('vulcanize', function() {
  var DEST_DIR = dist('elements');
  return gulp.src(dist('elements/elements.vulcanized.html'))
    .pipe($.vulcanize({
      stripComments: true,
      inlineCss: true,
      inlineScripts: true
    }))
    .pipe($.minifyInline())
    .pipe(gulp.dest(DEST_DIR))
    .pipe($.size({title: 'vulcanize'}));
});

// Generate config data for the <sw-precache-cache> element.
// This include a list of files that should be precached, as well as a (hopefully unique) cache
// id that ensure that multiple PSK projects don't share the same Cache Storage.
// This task does not run by default, but if you are interested in using service worker caching
// in your project, please enable it within the 'default' task.
// See https://github.com/PolymerElements/polymer-starter-kit#enable-service-worker-support
// for more context.
gulp.task('cache-config', function(callback) {
  var dir = dist();
  var config = {
    cacheId: packageJson.name || path.basename(__dirname),
    disabled: false
  };

  glob([
    'index.html',
    './',
    'bower_components/webcomponentsjs/webcomponents-lite.min.js',
    '{elements,scripts,styles}/**/*.*'],
    {cwd: dir}, function(error, files) {
    if (error) {
      callback(error);
    } else {
      config.precache = files;

      var md5 = crypto.createHash('md5');
      md5.update(JSON.stringify(config.precache));
      config.precacheFingerprint = md5.digest('hex');

      var configPath = path.join(dir, 'cache-config.json');
      fs.writeFile(configPath, JSON.stringify(config), callback);
    }
  });
});

// Clean output directory
gulp.task('clean', function() {
  return del(['.tmp', dist()]);
});

// Watch files for changes & reload
gulp.task('serve', ['lint', 'styles', 'elements', 'images'], function() {
  browserSync({
    port: 5000,
    notify: false,
    logPrefix: 'PSK',
    snippetOptions: {
      rule: {
        match: '',
        fn: function(snippet) {
          return snippet;
        }
      }
    },
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: {
      baseDir: ['.tmp', 'app'],
      middleware: [historyApiFallback()],
      routes: {
        '/bower_components': 'bower_components'
      }
    }
  });

  gulp.watch(['app/**/*.html'], reload);
  gulp.watch(['app/styles/**/*.css'], ['styles', reload]);
  gulp.watch(['app/elements/**/*.css'], ['elements', reload]);
  gulp.watch(['app/{scripts,elements}/**/{*.js,*.html}'], ['lint']);
  gulp.watch(['app/images/**/*'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['build'], function() {
  browserSync({
    port: 5001,
    notify: false,
    logPrefix: 'PSK',
    snippetOptions: {
      rule: {
        match: '',
        fn: function(snippet) {
          return snippet;
        }
      }
    },
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: dist(),
    middleware: [historyApiFallback()]
  });
});

// Clean bower components once finished with them directory
gulp.task('optimize', function() {
  del([dist('/bower_components'), dist('/elements/elements.html')]);
});

gulp.task('build', ['clean'], function(cb) {
  // Uncomment 'cache-config' if you are going to use service workers.
  runSequence(
    ['copy', 'styles'],
    'elements',
    ['lint', 'images', 'fonts', 'html'],
    'vulcanize', // 'cache-config',
    'optimize',
    cb);
});

/* Cordova setting and tasks */
// OPTIONS
var options = gulp.options = minimist(process.argv.slice(2));

// cordova command one of cordova's build commands?
if (options.cordova) {
  var cmds = ['build', 'run', 'emulate', 'prepare', 'serve'];

  for (var i = 0, cmd; (cmd = cmds[i]); i++) {
    if (options.cordova.indexOf(cmd) >= 0) {
      options.cordovaBuild = true;
      break;
    }
  }
}

// load tasks
requireDir('./gulp');

// default task
gulp.task('default', function() {
  options.build = true;
});

/* End Cordova setting and tasks */

// Build production files, the default task
gulp.task('default', function(cb) {
  // cordova build command & gulp build
  if (options.cordovaBuild && options.build !== false) {
    return gulp.start('cordova-with-build');
  }
  // cordova build command & no gulp build
  else if (options.cordovaBuild && options.build === false) {
    return gulp.start('cordova-only-resources');
  }
  // cordova non-build command
  else if (options.cordova) {
    return gulp.start('cordova');
  }
  // just default task when cordova option not present
  else {
    return gulp.start('build', cb);
  }
});

// Build then deploy to GitHub pages gh-pages branch
gulp.task('build-deploy-gh-pages', function(cb) {
  runSequence(
    'build',
    'deploy-gh-pages',
    cb);
});

// Deploy to GitHub pages gh-pages branch
gulp.task('deploy-gh-pages', function() {
  return gulp.src(dist('**/*'))
    .pipe($.ghPages());
});

// Load tasks for web-component-tester
// Adds tasks for `gulp test:local` and `gulp test:remote`
require('web-component-tester').gulp.init(gulp);

// Load custom tasks from the `tasks` directory
try {
  require('require-dir')('tasks');
} catch (err) {}
<|endoftext|>


<commit_before>// Sync
// ---------------
'use strict';

var _ = require('lodash');
var Promise = require('./base/promise');

// Sync is the dispatcher for any database queries,
// taking the "syncing" `model` or `collection` being queried, along with
// a hash of options that are used in the various query methods.
// If the `transacting` option is set, the query is assumed to be
// part of a transaction, and this information is passed along to `Knex`.
var Sync = function Sync(syncing, options) {
  options = options || {};
  this.query = syncing.query();
  this.syncing = syncing.resetQuery();
  this.options = options;
  if (options.debug) this.query.debug();
  if (options.transacting) this.query.transacting(options.transacting);
};

_.extend(Sync.prototype, {

  // Prefix all keys of the passed in object with the
  // current table name
  prefixFields: function prefixFields(fields) {
    var tableName = this.syncing.tableName;
    var prefixed = {};
    for (var key in fields) {
      prefixed[tableName + '.' + key] = fields[key];
    }
    return prefixed;
  },

  // Select the first item from the database - only used by models.
  first: Promise.method(function (attributes) {

    var model = this.syncing,
        query = this.query,
        whereAttributes,
        formatted;

    // We'll never use an JSON object for a search, because even
    // PostgreSQL, which has JSON type columns, does not support the `=`
    // operator.
    //
    // NOTE: `_.omit` returns an empty object, even if attributes are null.
    whereAttributes = _.omit(attributes, _.isPlainObject);

    if (!_.isEmpty(whereAttributes)) {

      // Format and prefix attributes.
      formatted = this.prefixFields(model.format(whereAttributes));
      query.where(formatted);
    }

    // Limit to a single result.
    query.limit(1);

    return this.select();
  }),

  // Add relational constraints required for either a `count` or `select` query.
  constrain: Promise.method(function () {
    var knex = this.query,
        options = this.options,
        relatedData = this.syncing.relatedData,
        fks = {},
        through;

    // Set the query builder on the options, in-case we need to
    // access in the `fetching` event handlers.
    options.query = knex;

    // Inject all appropriate select costraints dealing with the relation
    // into the `knex` query builder for the current instance.
    if (relatedData) return Promise['try'](function () {
      if (relatedData.isThrough()) {
        fks[relatedData.key('foreignKey')] = relatedData.parentFk;
        through = new relatedData.throughTarget(fks);

        /**
         * Fired before a `fetch` operation. A promise may be returned from the
         * event handler for async behaviour.
         *
         * @event Model#fetching
         * @param   {Model}    model      The model that has been fetched.
         * @param   {string[]} columns    The columns being retrieved by the query.
         * @param   {Object}   options    Options object passed to {@link Model#fetch fetch}.
         * @returns {Promise}
         */
        return through.triggerThen('fetching', through, relatedData.pivotColumns, options).then(function () {
          relatedData.pivotColumns = through.parse(relatedData.pivotColumns);
        });
      }
    });
  }),

  // Runs a `count` query on the database, adding any necessary relational
  // constraints. Returns a promise that resolves to an integer count.
  count: Promise.method(function (column) {
    var knex = this.query,
        options = this.options;

    return Promise.bind(this).then(function () {
      return this.constrain();
    }).then(function () {
      return this.syncing.triggerThen('counting', this.syncing, options);
    }).then(function () {
      return knex.count((column || '*') + ' as count');
    }).then(function (rows) {
      return rows[0].count;
    });
  }),

  // Runs a `select` query on the database, adding any necessary relational
  // constraints, resetting the query when complete. If there are results and
  // eager loaded relations, those are fetched and returned on the model before
  // the promise is resolved. Any `success` handler passed in the
  // options will be called - used by both models & collections.
  select: Promise.method(function () {
    var _this = this;

    var knex = this.query,
        options = this.options,
        relatedData = this.syncing.relatedData,
        queryContainsColumns,
        columns;

    // Check if any `select` style statements have been called with column
    // specifications. This could include `distinct()` with no arguments, which
    // does not affect inform the columns returned.
    queryContainsColumns = _(knex._statements).where({ grouping: 'columns' }).some('value.length');

    return Promise.resolve(this.constrain()).tap(function () {

      // If this is a relation, apply the appropriate constraints.
      if (relatedData) {
        relatedData.selectConstraints(knex, options);
      } else {

        // Call the function, if one exists, to constrain the eager loaded query.
        if (options._beforeFn) options._beforeFn.call(knex, knex);

        if (options.columns) {

          // Normalize single column name into array.
          columns = _.isArray(options.columns) ? options.columns : [options.columns];
        } else if (!queryContainsColumns) {

          // If columns have already been selected via the `query` method
          // we will use them. Otherwise, select all columns in this table.
          columns = [_.result(_this.syncing, 'tableName') + '.*'];
        }
      }

      // Set the query builder on the options, for access in the `fetching`
      // event handlers.
      options.query = knex;
      return _this.syncing.triggerThen('fetching', _this.syncing, columns, options);
    }).then(function () {
      return knex.select(columns);
    });
  }),

  // Issues an `insert` command on the query - only used by models.
  insert: Promise.method(function () {
    var syncing = this.syncing;
    return this.query.insert(syncing.format(_.extend(Object.create(null), syncing.attributes)), '*');
    // return this.query.insert(syncing.format(_.extend(Object.create(null), syncing.attributes)), syncing.idAttribute);
  }),

  // Issues an `update` command on the query - only used by models.
  update: Promise.method(function (attrs) {
    var syncing = this.syncing,
        query = this.query;
    if (syncing.id != null) query.where(syncing.idAttribute, syncing.id);
    if (_.where(query._statements, { grouping: 'where' }).length === 0) {
      throw new Error('A model cannot be updated without a "where" clause or an idAttribute.');
    }
    return query.update(syncing.format(_.extend(Object.create(null), attrs)));
  }),

  // Issues a `delete` command on the query.
  del: Promise.method(function () {
    var query = this.query,
        syncing = this.syncing;
    if (syncing.id != null) query.where(syncing.idAttribute, syncing.id);
    if (_.where(query._statements, { grouping: 'where' }).length === 0) {
      throw new Error('A model cannot be destroyed without a "where" clause or an idAttribute.');
    }
    return this.query.del();
  })

});

module.exports = Sync;
<commit_msg>have updates return all attributes<commit_after>// Sync
// ---------------
'use strict';

var _ = require('lodash');
var Promise = require('./base/promise');

// Sync is the dispatcher for any database queries,
// taking the "syncing" `model` or `collection` being queried, along with
// a hash of options that are used in the various query methods.
// If the `transacting` option is set, the query is assumed to be
// part of a transaction, and this information is passed along to `Knex`.
var Sync = function Sync(syncing, options) {
  options = options || {};
  this.query = syncing.query();
  this.syncing = syncing.resetQuery();
  this.options = options;
  if (options.debug) this.query.debug();
  if (options.transacting) this.query.transacting(options.transacting);
};

_.extend(Sync.prototype, {

  // Prefix all keys of the passed in object with the
  // current table name
  prefixFields: function prefixFields(fields) {
    var tableName = this.syncing.tableName;
    var prefixed = {};
    for (var key in fields) {
      prefixed[tableName + '.' + key] = fields[key];
    }
    return prefixed;
  },

  // Select the first item from the database - only used by models.
  first: Promise.method(function (attributes) {

    var model = this.syncing,
        query = this.query,
        whereAttributes,
        formatted;

    // We'll never use an JSON object for a search, because even
    // PostgreSQL, which has JSON type columns, does not support the `=`
    // operator.
    //
    // NOTE: `_.omit` returns an empty object, even if attributes are null.
    whereAttributes = _.omit(attributes, _.isPlainObject);

    if (!_.isEmpty(whereAttributes)) {

      // Format and prefix attributes.
      formatted = this.prefixFields(model.format(whereAttributes));
      query.where(formatted);
    }

    // Limit to a single result.
    query.limit(1);

    return this.select();
  }),

  // Add relational constraints required for either a `count` or `select` query.
  constrain: Promise.method(function () {
    var knex = this.query,
        options = this.options,
        relatedData = this.syncing.relatedData,
        fks = {},
        through;

    // Set the query builder on the options, in-case we need to
    // access in the `fetching` event handlers.
    options.query = knex;

    // Inject all appropriate select costraints dealing with the relation
    // into the `knex` query builder for the current instance.
    if (relatedData) return Promise['try'](function () {
      if (relatedData.isThrough()) {
        fks[relatedData.key('foreignKey')] = relatedData.parentFk;
        through = new relatedData.throughTarget(fks);

        /**
         * Fired before a `fetch` operation. A promise may be returned from the
         * event handler for async behaviour.
         *
         * @event Model#fetching
         * @param   {Model}    model      The model that has been fetched.
         * @param   {string[]} columns    The columns being retrieved by the query.
         * @param   {Object}   options    Options object passed to {@link Model#fetch fetch}.
         * @returns {Promise}
         */
        return through.triggerThen('fetching', through, relatedData.pivotColumns, options).then(function () {
          relatedData.pivotColumns = through.parse(relatedData.pivotColumns);
        });
      }
    });
  }),

  // Runs a `count` query on the database, adding any necessary relational
  // constraints. Returns a promise that resolves to an integer count.
  count: Promise.method(function (column) {
    var knex = this.query,
        options = this.options;

    return Promise.bind(this).then(function () {
      return this.constrain();
    }).then(function () {
      return this.syncing.triggerThen('counting', this.syncing, options);
    }).then(function () {
      return knex.count((column || '*') + ' as count');
    }).then(function (rows) {
      return rows[0].count;
    });
  }),

  // Runs a `select` query on the database, adding any necessary relational
  // constraints, resetting the query when complete. If there are results and
  // eager loaded relations, those are fetched and returned on the model before
  // the promise is resolved. Any `success` handler passed in the
  // options will be called - used by both models & collections.
  select: Promise.method(function () {
    var _this = this;

    var knex = this.query,
        options = this.options,
        relatedData = this.syncing.relatedData,
        queryContainsColumns,
        columns;

    // Check if any `select` style statements have been called with column
    // specifications. This could include `distinct()` with no arguments, which
    // does not affect inform the columns returned.
    queryContainsColumns = _(knex._statements).where({ grouping: 'columns' }).some('value.length');

    return Promise.resolve(this.constrain()).tap(function () {

      // If this is a relation, apply the appropriate constraints.
      if (relatedData) {
        relatedData.selectConstraints(knex, options);
      } else {

        // Call the function, if one exists, to constrain the eager loaded query.
        if (options._beforeFn) options._beforeFn.call(knex, knex);

        if (options.columns) {

          // Normalize single column name into array.
          columns = _.isArray(options.columns) ? options.columns : [options.columns];
        } else if (!queryContainsColumns) {

          // If columns have already been selected via the `query` method
          // we will use them. Otherwise, select all columns in this table.
          columns = [_.result(_this.syncing, 'tableName') + '.*'];
        }
      }

      // Set the query builder on the options, for access in the `fetching`
      // event handlers.
      options.query = knex;
      return _this.syncing.triggerThen('fetching', _this.syncing, columns, options);
    }).then(function () {
      return knex.select(columns);
    });
  }),

  // Issues an `insert` command on the query - only used by models.
  insert: Promise.method(function () {
    var syncing = this.syncing;
    return this.query.insert(syncing.format(_.extend(Object.create(null), syncing.attributes)), '*');
    // return this.query.insert(syncing.format(_.extend(Object.create(null), syncing.attributes)), syncing.idAttribute);
  }),

  // Issues an `update` command on the query - only used by models.
  update: Promise.method(function (attrs) {
    var syncing = this.syncing,
        query = this.query;
    if (syncing.id != null) query.where(syncing.idAttribute, syncing.id);
    if (_.where(query._statements, { grouping: 'where' }).length === 0) {
      throw new Error('A model cannot be updated without a "where" clause or an idAttribute.');
    }
    return query.update(syncing.format(_.extend(Object.create(null), attrs)), '*');
  }),

  // Issues a `delete` command on the query.
  del: Promise.method(function () {
    var query = this.query,
        syncing = this.syncing;
    if (syncing.id != null) query.where(syncing.idAttribute, syncing.id);
    if (_.where(query._statements, { grouping: 'where' }).length === 0) {
      throw new Error('A model cannot be destroyed without a "where" clause or an idAttribute.');
    }
    return this.query.del();
  })

});

module.exports = Sync;
<|endoftext|>


<commit_before>/*global -$ */
'use strict';
// generated on 2015-05-11 using generator-gulp-webapp 0.3.0
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var browserSync = require('browser-sync');
var reload = browserSync.reload;

gulp.task('styles', function () {
  return gulp.src('app/styles/main.scss')
    .pipe($.sourcemaps.init())
    .pipe($.sass({
      outputStyle: 'nested', // libsass doesn't support expanded yet
      precision: 10,
      includePaths: ['.'],
      onError: console.error.bind(console, 'Sass error:')
    }))
    .pipe($.postcss([
      require('autoprefixer-core')({browsers: ['last 1 version']})
    ]))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('.tmp/styles'))
    .pipe(reload({stream: true}));
});

gulp.task('jshint', function () {
  return gulp.src('app/scripts/**/*.js')
    .pipe(reload({stream: true, once: true}))
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

gulp.task('html', ['styles'], function () {
  var assets = $.useref.assets({searchPath: ['.tmp', 'app', '.']});

  return gulp.src('app/*.html')
    .pipe(assets)
    .pipe($.if('*.js', $.uglify()))
    .pipe($.if('*.css', $.csso()))
    .pipe(assets.restore())
    .pipe($.useref())
    .pipe($.if('*.html', $.minifyHtml({conditionals: true, loose: true})))
    .pipe(gulp.dest('dist'));
});

gulp.task('images', function () {
  return gulp.src('app/images/**/*')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true,
      // don't remove IDs from SVGs, they are often used
      // as hooks for embedding and styling
      svgoPlugins: [{cleanupIDs: false}]
    })))
    .pipe(gulp.dest('dist/images'));
});

gulp.task('fonts', function () {
  return gulp.src(require('main-bower-files')({
    filter: '**/*.{eot,svg,ttf,woff,woff2}'
  }).concat('app/fonts/**/*'))
    .pipe(gulp.dest('.tmp/fonts'))
    .pipe(gulp.dest('dist/fonts'));
});

gulp.task('extras', function () {
  return gulp.src([
    'app/*.*',
    '!app/*.html'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'));
});

gulp.task('clean', require('del').bind(null, ['.tmp', 'dist']));

gulp.task('serve', ['styles', 'fonts'], function () {
  browserSync({
    notify: false,
    port: 9000,
    server: {
      baseDir: ['.tmp', 'app'],
      routes: {
        '/bower_components': 'bower_components'
      }
    }
  });

  // watch for changes
  gulp.watch([
    'app/*.html',
    'app/scripts/**/*.js',
    'app/images/**/*',
    '.tmp/fonts/**/*'
  ]).on('change', reload);

  gulp.watch('app/styles/**/*.scss', ['styles']);
  gulp.watch('app/fonts/**/*', ['fonts']);
  gulp.watch('bower.json', ['wiredep', 'fonts']);
});

// inject bower components
gulp.task('wiredep', function () {
  var wiredep = require('wiredep').stream;

  gulp.src('app/styles/*.scss')
    .pipe(wiredep({
      ignorePath: /^(\.\.\/)+/
    }))
    .pipe(gulp.dest('app/styles'));

  gulp.src('app/*.html')
    .pipe(wiredep({
      exclude: ['bootstrap-sass-official'],
      ignorePath: /^(\.\.\/)*\.\./
    }))
    .pipe(gulp.dest('app'));
});

gulp.task('build', ['jshint', 'html', 'images', 'fonts', 'extras'], function () {
  return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true}));
});

gulp.task('default', ['clean'], function () {
  gulp.start('build');
});
<commit_msg>Force standardised quotes in build<commit_after>/*global -$ */
'use strict';
// generated on 2015-05-11 using generator-gulp-webapp 0.3.0
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var browserSync = require('browser-sync');
var reload = browserSync.reload;

gulp.task('styles', function () {
  return gulp.src('app/styles/main.scss')
    .pipe($.sourcemaps.init())
    .pipe($.sass({
      outputStyle: 'nested', // libsass doesn't support expanded yet
      precision: 10,
      includePaths: ['.'],
      onError: console.error.bind(console, 'Sass error:')
    }))
    .pipe($.postcss([
      require('autoprefixer-core')({browsers: ['last 1 version']})
    ]))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('.tmp/styles'))
    .pipe(reload({stream: true}));
});

gulp.task('jshint', function () {
  return gulp.src('app/scripts/**/*.js')
    .pipe(reload({stream: true, once: true}))
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

gulp.task('html', ['styles'], function () {
  var assets = $.useref.assets({searchPath: ['.tmp', 'app', '.']});

  return gulp.src('app/*.html')
    .pipe(assets)
    .pipe($.if('*.js', $.uglify()))
    .pipe($.if('*.css', $.csso()))
    .pipe(assets.restore())
    .pipe($.useref())
    .pipe($.if('*.html', $.minifyHtml({conditionals: true, loose: true, quotes: true })))
    .pipe(gulp.dest('dist'));
});

gulp.task('images', function () {
  return gulp.src('app/images/**/*')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true,
      // don't remove IDs from SVGs, they are often used
      // as hooks for embedding and styling
      svgoPlugins: [{cleanupIDs: false}]
    })))
    .pipe(gulp.dest('dist/images'));
});

gulp.task('fonts', function () {
  return gulp.src(require('main-bower-files')({
    filter: '**/*.{eot,svg,ttf,woff,woff2}'
  }).concat('app/fonts/**/*'))
    .pipe(gulp.dest('.tmp/fonts'))
    .pipe(gulp.dest('dist/fonts'));
});

gulp.task('extras', function () {
  return gulp.src([
    'app/*.*',
    '!app/*.html'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'));
});

gulp.task('clean', require('del').bind(null, ['.tmp', 'dist']));

gulp.task('serve', ['styles', 'fonts'], function () {
  browserSync({
    notify: false,
    port: 9000,
    server: {
      baseDir: ['.tmp', 'app'],
      routes: {
        '/bower_components': 'bower_components'
      }
    }
  });

  // watch for changes
  gulp.watch([
    'app/*.html',
    'app/scripts/**/*.js',
    'app/images/**/*',
    '.tmp/fonts/**/*'
  ]).on('change', reload);

  gulp.watch('app/styles/**/*.scss', ['styles']);
  gulp.watch('app/fonts/**/*', ['fonts']);
  gulp.watch('bower.json', ['wiredep', 'fonts']);
});

// inject bower components
gulp.task('wiredep', function () {
  var wiredep = require('wiredep').stream;

  gulp.src('app/styles/*.scss')
    .pipe(wiredep({
      ignorePath: /^(\.\.\/)+/
    }))
    .pipe(gulp.dest('app/styles'));

  gulp.src('app/*.html')
    .pipe(wiredep({
      exclude: ['bootstrap-sass-official'],
      ignorePath: /^(\.\.\/)*\.\./
    }))
    .pipe(gulp.dest('app'));
});

gulp.task('build', ['jshint', 'html', 'images', 'fonts', 'extras'], function () {
  return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true}));
});

gulp.task('default', ['clean'], function () {
  gulp.start('build');
});
<|endoftext|>