<commit_before>/*************************GO-LICENSE-START*********************************
 * Copyright 2014 ThoughtWorks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *************************GO-LICENSE-END**********************************/

describe("command_auto_complete", function () {
    var originalAjax;
    var originalGet;
    var url = "http://foo.bar/go/autocomplete";

    beforeEach(function () {
        setFixtures("
\n" +
            "    <input type=\"text\" class=\"command\" name=\"command\"/>\n" +
            "    <textarea class=\"arguments\"></textarea>\n" +
            "\n" +
            "
\n" +
            "        <input type=\"text\" class=\"lookup_command\" name=\"lookup_command\"/>\n" +
            "
\n" +
            "\n" +
            "
\n" +
            "
\n" +
            "            \n" +
            "
\n" +
            "
\n" +
            "            \n" +
            "
\n" +
            "
\n" +
            "            Author:\n" +
            "            \n" +
            "            \n" +
            "
\n" +
            "
\n" +
            "            more info\n" +
            "
\n" +
            "
\n" +
            "\n" +
            "
\n" +
            "
\n" +
            "
\n" +
            "\n" +
            "
\n" +
            "    <input type=\"text\" class=\"command\" name=\"command\"/>\n" +
            "    <input type=\"text\" class=\"arguments-text-box-not-text-area\"/>\n" +
            "\n" +
            "
\n" +
            "        <input type=\"text\" class=\"lookup_command\" name=\"lookup_command\"/>\n" +
            "
The lookup feature is only available for the new style of custom commands.
\n" +
            "
\n" +
            "\n" +
            "
\n" +
            "
\n" +
            "
");
        originalAjax = jQuery.ajax;
        originalGet = jQuery.get;
    });

    afterEach(function () {
        jQuery.ajax = originalAjax;
        jQuery.get = originalGet;
    });

    it("testShouldSendWhateverIsEnteredInTheTextboxToTheAjaxCallToLookup", function () {
        var dataItWasCalledWith = null;
        jQuery.ajax = function (data) {
            dataItWasCalledWith = data;
        };
        var commandLookup = new CommandSnippetLookup(jQuery(".under_test .lookup_command").get(0), url);
        jQuery(".under_test .lookup_command").val("");
        commandLookup.hookupAutocomplete();

        var autoCompleteText = jQuery(".under_test .lookup_command");
        autoCompleteText.val("ms");
        autoCompleteText.search();
        assertNotNull(dataItWasCalledWith);
        assertEquals("ms", dataItWasCalledWith.data.lookup_prefix);
        assertEquals(url, dataItWasCalledWith.url);
    });

    it("testShouldPopulateCommandAndArgumentsWhenASnippetIsSelected", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("ls", jQuery(".under_test .command").val());
        assertEquals("-abc\n-def\n", jQuery(".under_test .arguments").val());
    });

    it("testShouldPopulateNameAndDescriptionWhenASnippetIsSelected", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", name: "Command name", description: "Some description"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("Command name", jQuery(".under_test .snippet_details .name .value").text());
        assertEquals("Some description", jQuery(".under_test .snippet_details .description .value").text());
    });

    it("testShouldPopulateAuthorDataWithoutLinkWhenAuthorInfoIsEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "Author - 1", authorinfo: null, moreinfo: "some-link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("Author - 1", jQuery(".under_test .snippet_details .author .value").text());
        assertTrue("Author should be visible", jQuery(".under_test .snippet_details .author .value").is(":visible"));
        assertTrue("Author with link should not be visible", jQuery(".under_test .snippet_details .author .value-with-link").is(":hidden"));
    });

    it("testShouldPopulateAuthorDataWithLinkWhenAuthorInfoIsNotEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "Author - 1", authorinfo: "http://author.link", moreinfo: "some-link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("Author - 1", jQuery(".under_test .snippet_details .author .value-with-link a").text());
        assertEquals("http://author.link", jQuery(".under_test .snippet_details .author .value-with-link a").attr('href'));
        assertTrue("Author should not be visible", jQuery(".under_test .snippet_details .author .value").is(":hidden"));
        assertTrue("Author with link should be visible", jQuery(".under_test .snippet_details .author .value-with-link a").is(":visible"));
    });

    it("testShouldPopulateMoreInfoIfMoreInfoIsNotEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "Author - 1", authorinfo: "http://author.link", moreinfo: "http://some-link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("more info", jQuery(".under_test .snippet_details .more-info .value-with-link a").text());
        assertEquals("http://some-link", jQuery(".under_test .snippet_details .more-info .value-with-link a").attr('href'));
        assertTrue("more info should be visible", jQuery(".under_test .snippet_details .more-info").is(':visible'));
    });

    it("testShouldHideMoreInfoIfMoreInfoIsEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "Author - 1", authorinfo: "http://author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertTrue("more info should be hidden", jQuery(".under_test .snippet_details .more-info .value-with-link a").is(':hidden'));
    });

    it("testShouldHideAuthorInfoIfAllAuthorInfoIsEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: null, moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertTrue("Author info should be hidden", jQuery(".under_test .snippet_details .author").is(':hidden'));
    });

    it("", function () {
    });

    it("testShouldDefaultAuthorNameIfOnlyAuthorInfoIsAvailable", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: "http://author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("link", jQuery(".under_test .snippet_details .author .value-with-link a").text());
        assertEquals("http://author.link", jQuery(".under_test .snippet_details .author .value-with-link a").attr('href'));
        assertTrue("Author should not be visible", jQuery(".under_test .snippet_details .author .value").is(":hidden"));
        assertTrue("Author with link should be visible", jQuery(".under_test .snippet_details .author .value-with-link a").is(":visible"));
    });

    it("testShouldDefaultDefaultDescriptionIfItIsNotAvailable", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, description: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("No description available.", jQuery(".under_test .snippet_details .description .value").text());
    });

    it("testShouldAddHttpSchemePrefixToAuthorInfoLinkIfItDoesNotStartWithASchemeFollowedByColonFollowedByTwoSlashes", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "author", authorinfo: "author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("http://author.link", jQuery(".under_test .snippet_details .author .value-with-link a").attr('href'));
    });

    it("testShouldNotAddHttpSchemePrefixToAuthorInfoLinkIfItStartsWithASchemeFollowedByColonFollowedByTwoSlashes", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "author", authorinfo: "HTTPS://author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("HTTPS://author.link", jQuery(".under_test .snippet_details .author .value-with-link a").attr('href'));
    });

    it("testShouldAddHttpSchemePrefixToMoreInfoInfoLinkIfItDoesNotStartWithASchemeFollowedByColonFollowedByTwoSlashes", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: null, moreinfo: "moreinfo.link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("http://moreinfo.link", jQuery(".under_test .snippet_details .more-info .value-with-link a").attr('href'));
    });

    it("testShouldNotAddHttpSchemePrefixToMoreInfoLinkIfItStartsWithASchemeFollowedByColonFollowedByTwoSlashes", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: null, moreinfo: "ftp://moreinfo.link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("ftp://moreinfo.link", jQuery(".under_test .snippet_details .more-info .value-with-link a").attr('href'));
    });

    it("testShouldDisableCommandRepositoryFeatureIfArgumentsAreOldStyleArgs", function () {
        TaskSnippet.attachClickHandlers('.under_test_for_old_style_args', 'some-command-lookup-url', 'some-command-definition-url', ".command", ".arguments-textarea-which-cannot-be-found");

        assertTrue("Lookup command textbox should be disabled", jQuery(".under_test_for_old_style_args .lookup_command").is(":disabled"));
        assertEquals("The lookup feature is only available for the new style of custom commands.", jQuery(".under_test_for_old_style_args .error-message-for-old-args").text());
        assertTrue("Message about old style args for command repo should be visible", jQuery(".under_test_for_old_style_args .error-message-for-old-args").is(':visible'));
    });

    it("testShouldHideInvalidSnippetDetailsOnFirstCommandSnippetSelection", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: "http://author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        jQuery(".under_test .invalid_snippets").show();

        triggerSelectionFromAutoCompleteOptions();

        assertTrue("Invalid Snippet Details should be hidden. ", jQuery(".under_test .invalid_snippets").is(":hidden"));
    });

    function setupCommandSnippetData(fakeDataFromServer) {
        var urlItWasCalledWith = null;
        var queryParamsItWasCalledWith = null;
        jQuery.get = function (url, queryParams, callBack) {
            urlItWasCalledWith = url;
            queryParamsItWasCalledWith = queryParams;
            return callBack(fakeDataFromServer);
        };

        TaskSnippet.attachClickHandlers('.under_test', 'some-command-lookup-url', 'some-command-definition-url', ".command", ".arguments");
    }

    function triggerSelectionFromAutoCompleteOptions() {
        jQuery(".under_test .lookup_command").trigger('result', ["msbuild", "/path/to/msbuild.xml"]);
    }
});<commit_msg>#1223 - Fixed jasmine spec failing on firefox<commit_after>/*************************GO-LICENSE-START*********************************
 * Copyright 2014 ThoughtWorks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *************************GO-LICENSE-END**********************************/

describe("command_auto_complete", function () {
    var originalAjax;
    var originalGet;
    var url = "http://foo.bar/go/autocomplete";

    beforeEach(function () {
        setFixtures("
\n" +
            "    <input type=\"text\" class=\"command\" name=\"command\"/>\n" +
            "    <textarea class=\"arguments\"></textarea>\n" +
            "\n" +
            "
\n" +
            "        <input type=\"text\" class=\"lookup_command\" name=\"lookup_command\"/>\n" +
            "
\n" +
            "\n" +
            "
\n" +
            "
\n" +
            "            \n" +
            "
\n" +
            "
\n" +
            "            \n" +
            "
\n" +
            "
\n" +
            "            Author:\n" +
            "            \n" +
            "            \n" +
            "
\n" +
            "
\n" +
            "            more info\n" +
            "
\n" +
            "
\n" +
            "\n" +
            "
\n" +
            "
\n" +
            "
\n" +
            "\n" +
            "
\n" +
            "    <input type=\"text\" class=\"command\" name=\"command\"/>\n" +
            "    <input type=\"text\" class=\"arguments-text-box-not-text-area\"/>\n" +
            "\n" +
            "
\n" +
            "        <input type=\"text\" class=\"lookup_command\" name=\"lookup_command\"/>\n" +
            "
The lookup feature is only available for the new style of custom commands.
\n" +
            "
\n" +
            "\n" +
            "
\n" +
            "
\n" +
            "
");
        originalAjax = jQuery.ajax;
        originalGet = jQuery.get;
    });

    afterEach(function () {
        jQuery.ajax = originalAjax;
        jQuery.get = originalGet;
    });

    it("testShouldSendWhateverIsEnteredInTheTextboxToTheAjaxCallToLookup", function () {
        var dataItWasCalledWith = null;
        jQuery.ajax = function (data) {
            dataItWasCalledWith = data;
        };
        var commandLookup = new CommandSnippetLookup(jQuery(".under_test .lookup_command").get(0), url);
        jQuery(".under_test .lookup_command").val("");
        commandLookup.hookupAutocomplete();

        var autoCompleteText = jQuery(".under_test .lookup_command");
        autoCompleteText.val("ms");
        autoCompleteText.search();
        assertNotNull(dataItWasCalledWith);
        assertEquals("ms", dataItWasCalledWith.data.lookup_prefix);
        assertEquals(url, dataItWasCalledWith.url);
    });

    it("testShouldPopulateCommandAndArgumentsWhenASnippetIsSelected", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("ls", jQuery(".under_test .command").val());
        assertEquals("-abc\n-def\n", jQuery(".under_test .arguments").val());
    });

    it("testShouldPopulateNameAndDescriptionWhenASnippetIsSelected", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", name: "Command name", description: "Some description"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("Command name", jQuery(".under_test .snippet_details .name .value").text());
        assertEquals("Some description", jQuery(".under_test .snippet_details .description .value").text());
    });

    it("testShouldPopulateAuthorDataWithoutLinkWhenAuthorInfoIsEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "Author - 1", authorinfo: null, moreinfo: "some-link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("Author - 1", jQuery(".under_test .snippet_details .author .value").text());
        assertTrue("Author should be visible", jQuery(".under_test .snippet_details .author .value").is(":visible"));
        assertTrue("Author with link should not be visible", jQuery(".under_test .snippet_details .author .value-with-link a").is(":hidden"));
    });

    it("testShouldPopulateAuthorDataWithLinkWhenAuthorInfoIsNotEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "Author - 1", authorinfo: "http://author.link", moreinfo: "some-link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("Author - 1", jQuery(".under_test .snippet_details .author .value-with-link a").text());
        assertEquals("http://author.link", jQuery(".under_test .snippet_details .author .value-with-link a").attr('href'));
        assertTrue("Author should not be visible", jQuery(".under_test .snippet_details .author .value").is(":hidden"));
        assertTrue("Author with link should be visible", jQuery(".under_test .snippet_details .author .value-with-link a").is(":visible"));
    });

    it("testShouldPopulateMoreInfoIfMoreInfoIsNotEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "Author - 1", authorinfo: "http://author.link", moreinfo: "http://some-link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("more info", jQuery(".under_test .snippet_details .more-info .value-with-link a").text());
        assertEquals("http://some-link", jQuery(".under_test .snippet_details .more-info .value-with-link a").attr('href'));
        assertTrue("more info should be visible", jQuery(".under_test .snippet_details .more-info").is(':visible'));
    });

    it("testShouldHideMoreInfoIfMoreInfoIsEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "Author - 1", authorinfo: "http://author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertTrue("more info should be hidden", jQuery(".under_test .snippet_details .more-info .value-with-link a").is(':hidden'));
    });

    it("testShouldHideAuthorInfoIfAllAuthorInfoIsEmpty", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: null, moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertTrue("Author info should be hidden", jQuery(".under_test .snippet_details .author").is(':hidden'));
    });

    it("", function () {
    });

    it("testShouldDefaultAuthorNameIfOnlyAuthorInfoIsAvailable", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: "http://author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("link", jQuery(".under_test .snippet_details .author .value-with-link a").text());
        assertEquals("http://author.link", jQuery(".under_test .snippet_details .author .value-with-link a").attr('href'));
        assertTrue("Author should not be visible", jQuery(".under_test .snippet_details .author .value").is(":hidden"));
        assertTrue("Author with link should be visible", jQuery(".under_test .snippet_details .author .value-with-link a").is(":visible"));
    });

    it("testShouldDefaultDefaultDescriptionIfItIsNotAvailable", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, description: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("No description available.", jQuery(".under_test .snippet_details .description .value").text());
    });

    it("testShouldAddHttpSchemePrefixToAuthorInfoLinkIfItDoesNotStartWithASchemeFollowedByColonFollowedByTwoSlashes", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "author", authorinfo: "author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("http://author.link", jQuery(".under_test .snippet_details .author .value-with-link a").attr('href'));
    });

    it("testShouldNotAddHttpSchemePrefixToAuthorInfoLinkIfItStartsWithASchemeFollowedByColonFollowedByTwoSlashes", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: "author", authorinfo: "HTTPS://author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("HTTPS://author.link", jQuery(".under_test .snippet_details .author .value-with-link a").attr('href'));
    });

    it("testShouldAddHttpSchemePrefixToMoreInfoInfoLinkIfItDoesNotStartWithASchemeFollowedByColonFollowedByTwoSlashes", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: null, moreinfo: "moreinfo.link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("http://moreinfo.link", jQuery(".under_test .snippet_details .more-info .value-with-link a").attr('href'));
    });

    it("testShouldNotAddHttpSchemePrefixToMoreInfoLinkIfItStartsWithASchemeFollowedByColonFollowedByTwoSlashes", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: null, moreinfo: "ftp://moreinfo.link"};
        setupCommandSnippetData(fakeDataFromServer);

        triggerSelectionFromAutoCompleteOptions();

        assertEquals("ftp://moreinfo.link", jQuery(".under_test .snippet_details .more-info .value-with-link a").attr('href'));
    });

    it("testShouldDisableCommandRepositoryFeatureIfArgumentsAreOldStyleArgs", function () {
        TaskSnippet.attachClickHandlers('.under_test_for_old_style_args', 'some-command-lookup-url', 'some-command-definition-url', ".command", ".arguments-textarea-which-cannot-be-found");

        assertTrue("Lookup command textbox should be disabled", jQuery(".under_test_for_old_style_args .lookup_command").is(":disabled"));
        assertEquals("The lookup feature is only available for the new style of custom commands.", jQuery(".under_test_for_old_style_args .error-message-for-old-args").text());
        assertTrue("Message about old style args for command repo should be visible", jQuery(".under_test_for_old_style_args .error-message-for-old-args").is(':visible'));
    });

    it("testShouldHideInvalidSnippetDetailsOnFirstCommandSnippetSelection", function () {
        var fakeDataFromServer = {command: "ls", arguments: "-abc\n-def\n", author: null, authorinfo: "http://author.link", moreinfo: null};
        setupCommandSnippetData(fakeDataFromServer);

        jQuery(".under_test .invalid_snippets").show();

        triggerSelectionFromAutoCompleteOptions();

        assertTrue("Invalid Snippet Details should be hidden. ", jQuery(".under_test .invalid_snippets").is(":hidden"));
    });

    function setupCommandSnippetData(fakeDataFromServer) {
        var urlItWasCalledWith = null;
        var queryParamsItWasCalledWith = null;
        jQuery.get = function (url, queryParams, callBack) {
            urlItWasCalledWith = url;
            queryParamsItWasCalledWith = queryParams;
            return callBack(fakeDataFromServer);
        };

        TaskSnippet.attachClickHandlers('.under_test', 'some-command-lookup-url', 'some-command-definition-url', ".command", ".arguments");
    }

    function triggerSelectionFromAutoCompleteOptions() {
        jQuery(".under_test .lookup_command").trigger('result', ["msbuild", "/path/to/msbuild.xml"]);
    }
});<|endoftext|>


<commit_before>/// gulp-run
/// ==================================================
/// Pipe to shell commands in gulp.

'use strict';

var child_process = require('child_process');
var Stream = require('stream');

var _ = require('lodash');
var colorize = require('ansi-color').set;
var Vinyl = require('vinyl');

/// `var cmd = run(command)`
/// --------------------------------------------------
/// Gets a through stream for a shell command to which you can pipe vinyl files. For each file
/// piped, a new process is spawned, the file is read into the processes's stdin, and a file
/// containing the processes's stdout is pushed.
///
/// Additionally, `./node_modules/.bin` is prepended to the PATH for the child process, so you have
/// access to all the binaries provided by your module's dependencies.
///
/// ### Arguments
/// 1. `command` *(String)*: The command to run. It can be a [template] interpolating the vinyl file
///     as the variable `file`.
///
/// [template]: http://lodash.com/docs#template
///
/// ### Returns
/// *(Stream.Transform in Object Mode)*: The through stream you so desire.
///
/// ### Example
/// ```javascript
/// gulp.task('even-lines', function () {
/// 	gulp.src('path/to/input/*')            // Get input files.
/// 		.pipe(run('awk "NR % 2 == 0"'))    // Use awk to extract the even lines.
/// 		.pipe(gulp.dest('path/to/output')) // Profit.
/// })
/// ```

var run = module.exports = function (command) {

	// The environment for the child process.
	var env = process.env;
	env.PATH = './node_modules/.bin:' + env.PATH;

	// Compile the command template
	command = _.template(command);

	// The object we return.
	var command_stream = new Stream.Transform({objectMode: true});
	command_stream._transform = function (file, enc, done) {

		// Null files pass through
		if (file.isNull()) {
			command_stream.push(file);
			process.nextTick(done);
			return;
		}

		// Spawn the command
		var child = child_process.spawn('sh', ['-c', command({file:file})], {env:env});
		child.stdin.on('error', command_stream.emit.bind(command_stream, 'error'));
		child.stdout.on('error', command_stream.emit.bind(command_stream, 'error'));
		file.pipe(child.stdin);

		// Streams - pass the child's stdout through
		if (file.isStream()) {
			file.contents = child.stdout;
			command_stream.push(file);
			process.nextTick(done);
			return;
		}

		// Buffers - buffer the entire output before continuing the pipeline
		if (file.isBuffer()) {
			file.contents = new Buffer(0);
			var stdout = child.stdout;
			stdout.on('readable', function () {
				var chunk = stdout.read()
				if (chunk !== null) {
					file.contents = Buffer.concat(
						[file.contents, chunk],
						file.contents.length + chunk.length
					);
				}
			});
			stdout.on('end', function () {
				command_stream.push(file);
				process.nextTick(done);
			});
			return;
		}

		// Else - can't handle the file
		command_stream.emit('error');
		throw new Error("Received a file that is neither a stream nor a buffer");
	}

	/// `cmd.exec([options], [callback])`
	/// --------------------------------------------------
	/// Executes the command immediately, returning the output as a stream of vinyl. Use this
	/// method to start a pipeline in gulp. The name of the file pushed down the pipe is the first
	/// word of the command. I recommend [gulp-rename] for renaming.
	///
	/// ### Arguments
	/// 1. `[options]` *(Object)*: If `options` is `true`, it is treated as `{print: true}`.
	///     - `print` *(Boolean)*: If true, tee the command's output to `process.stdout` with each
	///         line prepended by the string **"[*title*] "** where *title* is the command's name.
	///         Defaults to `false`.
	///     - `color` *(String)*: The color in which the title is printed. Defaults to `'cyan'` to
	///         distinguish the output of `gulp-run` from `gulp` proper.
	/// 2. `[callback]` *(Function)*: Execution is asynchronous. The callback is called once the
	///     command's stdout has closed.
	///
	/// ### Returns
	/// *(Stream.Readable in Object Mode)*: A stream containing exactly one vinyl file. The file's
	/// contents is the stdout stream of the command.
	///
	/// ### Example
	/// ```javascript
	/// gulp.task('hello-world', function () {
	/// 	run('echo Hello World').exec(true) // prints "[echo] Hello World\n"
	/// 		.pipe(gulp.dest('output/dir')) // Writes "Hello World\n" to output/dir/echo
	/// })
	/// ```

	command_stream.exec = function (opts, callback) {
		// Parse arguments
		if (typeof arguments[0] === 'function') {
			callback = arguments[0];
			opts = undefined;
		}
		if (opts === true) {
			opts = {
				print: true
			}
		}
		opts = _.defaults(opts||{}, {
			print: false,
			color: 'cyan'
		});

		// Spawn the command
		var cmd = command({file:file});
		var title = cmd.split(/\s+/)[0];
		var child = child_process.spawn('sh', ['-c', command({file:file})], {env:env});
		child.stdin.end();

		// Setup callback
		if (typeof callback === 'function') {
			child.stdout.on('end', callback);
		}

		// A stream to tee input to stdout
		var tee = new Stream.Transform();
		tee._transform = function (chunk, enc, done) {
			var lines = chunk.toString().split('\n');
			lines.forEach(function (line, index) {
				// Skip the last line if it's blank
				if (index === lines.length - 1 && line.length <= 1) return;
				process.stdout.write('[' + colorize(title, opts.color) + '] ' + line + '\n');
			});
			tee.push(chunk);
			process.nextTick(done);
			return;
		}

		// The file to be pushed down stream
		var file = new Vinyl({
			contents: (opts.print) ? child.stdout.pipe(tee) : child.stdout,
			path: title
		});

		// The vinyl stream
		var stream = new Stream.Transform({objectMode:true});
		stream._transform = function (file, enc, done) {
			stream.push(file);
			process.nextTick(done);
		};
		stream.end(file);
		child.stdin.on('error', stream.emit.bind(stream, 'error'));
		child.stdout.on('error', stream.emit.bind(stream, 'error'));
		return stream;
	}

	return command_stream;
}
<commit_msg>Better error reporting<commit_after>/// gulp-run
/// ==================================================
/// Pipe to shell commands in gulp.

'use strict';

var child_process = require('child_process');
var Stream = require('stream');

var _ = require('lodash');
var colorize = require('ansi-color').set;
var Vinyl = require('vinyl');

/// `var cmd = run(command)`
/// --------------------------------------------------
/// Gets a through stream for a shell command to which you can pipe vinyl files. For each file
/// piped, a new process is spawned, the file is read into the processes's stdin, and a file
/// containing the processes's stdout is pushed.
///
/// Additionally, `./node_modules/.bin` is prepended to the PATH for the child process, so you have
/// access to all the binaries provided by your module's dependencies.
///
/// ### Arguments
/// 1. `command` *(String)*: The command to run. It can be a [template] interpolating the vinyl file
///     as the variable `file`.
///
/// [template]: http://lodash.com/docs#template
///
/// ### Returns
/// *(Stream.Transform in Object Mode)*: The through stream you so desire.
///
/// ### Example
/// ```javascript
/// gulp.task('even-lines', function () {
/// 	gulp.src('path/to/input/*')            // Get input files.
/// 		.pipe(run('awk "NR % 2 == 0"'))    // Use awk to extract the even lines.
/// 		.pipe(gulp.dest('path/to/output')) // Profit.
/// })
/// ```

var run = module.exports = function (command) {

	// The environment for the child process.
	var env = process.env;
	env.PATH = './node_modules/.bin:' + env.PATH;

	// Compile the command template
	command = _.template(command);

	// The object we return.
	var command_stream = new Stream.Transform({objectMode: true});
	command_stream._transform = function (file, enc, done) {

		// Null files pass through
		if (file.isNull()) {
			command_stream.push(file);
			process.nextTick(done);
			return;
		}

		// Spawn the command
		var cmd = command({file:file});
		var child = child_process.spawn('sh', ['-c', cmd], {env:env});
		child.stdin.on('error', command_stream.emit.bind(command_stream, 'error'));
		child.stdout.on('error', command_stream.emit.bind(command_stream, 'error'));
		file.pipe(child.stdin);

		// Streams - pass the child's stdout through
		if (file.isStream()) {
			file.contents = child.stdout;
			command_stream.push(file);
		}

		// Buffers - buffer the entire output before continuing the pipeline
		if (file.isBuffer()) {
			file.contents = new Buffer(0);
			var stdout = child.stdout;
			stdout.on('readable', function () {
				var chunk = stdout.read()
				if (chunk !== null) {
					file.contents = Buffer.concat(
						[file.contents, chunk],
						file.contents.length + chunk.length
					);
				}
			});
			stdout.on('end', function () {
				command_stream.push(file);
			});
		}

		child.on('close', function (code) {
			if (code !== 0) {
				var title = cmd.split(/\s+/)[0];
				var err = '[' + colorize(title, 'red') + '] Exited with status: ' + code + '\n';
				console.error(err);
				command_stream.emit('error');
			}
			done();
		});
	}

	/// `cmd.exec([options], [callback])`
	/// --------------------------------------------------
	/// Executes the command immediately, returning the output as a stream of vinyl. Use this
	/// method to start a pipeline in gulp. The name of the file pushed down the pipe is the first
	/// word of the command. I recommend [gulp-rename] for renaming.
	///
	/// ### Arguments
	/// 1. `[options]` *(Object)*: If `options` is `true`, it is treated as `{print: true}`.
	///     - `print` *(Boolean)*: If true, tee the command's output to `process.stdout` with each
	///         line prepended by the string **"[*title*] "** where *title* is the command's name.
	///         Defaults to `false`.
	///     - `color` *(String)*: The color in which the title is printed. Defaults to `'cyan'` to
	///         distinguish the output of `gulp-run` from `gulp` proper.
	/// 2. `[callback]` *(Function)*: Execution is asynchronous. The callback is called once the
	///     command's stdout has closed.
	///
	/// ### Returns
	/// *(Stream.Readable in Object Mode)*: A stream containing exactly one vinyl file. The file's
	/// contents is the stdout stream of the command.
	///
	/// ### Example
	/// ```javascript
	/// gulp.task('hello-world', function () {
	/// 	run('echo Hello World').exec(true) // prints "[echo] Hello World\n"
	/// 		.pipe(gulp.dest('output/dir')) // Writes "Hello World\n" to output/dir/echo
	/// })
	/// ```

	command_stream.exec = function (opts, callback) {
		// Parse arguments
		if (typeof arguments[0] === 'function') {
			callback = arguments[0];
			opts = undefined;
		}
		if (opts === true) {
			opts = {
				print: true
			}
		}
		opts = _.defaults(opts||{}, {
			print: false,
			color: 'cyan'
		});

		// Spawn the command
		var cmd = command({file:file});
		var title = cmd.split(/\s+/)[0];
		var child = child_process.spawn('sh', ['-c', command({file:file})], {env:env});
		child.stdin.end();

		// Setup callback
		if (typeof callback === 'function') {
			child.stdout.on('end', callback);
		}

		// A stream to tee input to stdout
		var tee = new Stream.Transform();
		tee._transform = function (chunk, enc, done) {
			var lines = chunk.toString().split('\n');
			lines.forEach(function (line, index) {
				// Skip the last line if it's blank
				if (index === lines.length - 1 && line.length <= 1) return;
				process.stdout.write('[' + colorize(title, opts.color) + '] ' + line + '\n');
			});
			tee.push(chunk);
			process.nextTick(done);
			return;
		}

		// The file to be pushed down stream
		var file = new Vinyl({
			contents: (opts.print) ? child.stdout.pipe(tee) : child.stdout,
			path: title
		});

		// The vinyl stream
		var stream = new Stream.Transform({objectMode:true});
		stream._transform = function (file, enc, done) {
			stream.push(file);
			process.nextTick(done);
		};
		stream.end(file);

		// Error handling
		child.on('close', function (code) {
			if (code !== 0) {
				var title = cmd.split(/\s+/)[0];
				var err = '[' + colorize(title, 'red') + '] Exited with status: ' + code + '\n';
				console.error(err);
				stream.emit('error');
			}
		});

		return stream;
	}

	return command_stream;
}
<|endoftext|>


<commit_before>var fs = require('fs');
var mdast = require('../index.js');

fs.readdirSync('./spec/input').filter(function (path) {
    return path.indexOf('.') !== 0;
}).forEach(function (path) {
    var filename = path.split('.'),
        flag, options, index;

    filename.pop();

    if (filename.length > 1) {
        index = 0;
        options = {};

        while (filename[++index]) {
            flag = filename[index];

            if (flag === 'gfm' || flag === 'nogfm') {
                options.gfm = flag === 'gfm';
            }

            if (flag === 'tables' || flag === 'notables') {
                options.tables = flag === 'tables';
            }

            if (flag === 'breaks' || flag === 'nobreaks') {
                options.breaks = flag === 'breaks';
            }

            if (flag === 'pedantic' || flag === 'nopedantic') {
                options.pedantic = flag === 'pedantic';
            }

            if (flag === 'smartlists' || flag === 'nosmartlists') {
                options.smartLists = flag === 'smartlists';
            }
        }
    }

    filename = filename.join('.');

    var file = fs.readFileSync('./spec/input/' + path, 'utf-8');
    var json;

    try {
        console.log('+' + filename);
        json = mdast(file, options);
        fs.writeFileSync('./spec/output/' + filename + '.json', JSON.stringify(json, null, 2));
    } catch (error) {
        console.log('-' + filename);
        throw error;
        fs.writeFileSync('./spec/output/' + filename.toUpperCase() + '.json', '');
    }
})
<commit_msg>Removed build.js<commit_after><|endoftext|>


<commit_before>var gulp = require('gulp');
var imagemin = require('gulp-imagemin');
var sass = require('gulp-sass');
let cleanCSS = require('gulp-clean-css');
var responsive = require('gulp-responsive');
var purgecss = require('gulp-purgecss')
var concat = require('gulp-concat');
var replace = require('gulp-replace');
var rename = require('gulp-rename');
var webp = require("imagemin-webp");
var gulpAmpValidator = require('gulp-amphtml-validator');
var del = require('del');

var paths = {
  styles: {
    src: '_sass/main.scss',
    tmp: 'assets/css/dist',
    dest: '_includes'
  },
  images: {
    src: 'assets/img',
    dest: 'assets/img'
  },
  html: {
    src: [
      '_site/{about,blog}/*.html',
      '!_site/blog/withings-data.html',
      '!_site/blog/santorini-experience.html',
      '!_site/blog/marathon-mirabelle.html'
    ]
  }
};

function thumbnails() {
  return gulp.src([`${paths.images.src}/**/main.{png,jpg,jpeg,svg}`, `${paths.images.src}/external-articles/*.{png,jpg,jpeg,svg}`])
    .pipe(
      responsive({
        '*': [
          {
            width: 400,
            height: 225,
            format: 'jpg',
            rename: {
              suffix: '-thumb',
              dirname: 'external-articles-responsive'
            },
          },
          {
            width: 400,
            height: 225,
            format: 'webp',
            rename: {
              suffix: '-thumb',
              dirname: 'external-articles-responsive'
            },
          },
          {
            width: 1400,
            height: 788,
            format: 'jpg',
            rename: {
              suffix: '-16x9',
              dirname: 'external-articles-responsive'
            },
          },
          {
            width: 1400,
            height: 788,
            format: 'webp',
            rename: {
              suffix: '-16x9',
              dirname: 'external-articles-responsive'
            },
          }
        ],
        '*/main.*': [
          {
            width: 400,
            height: 225,
            format: 'jpg',
            rename: { suffix: '-thumb'},
          },
          {
            width: 400,
            height: 225,
            format: 'webp',
            rename: { suffix: '-thumb'},
          },
          {
            width: 1400,
            height: 788,
            format: 'jpg',
            rename: { suffix: '-16x9'},
          },
          {
            width: 1400,
            height: 788,
            format: 'webp',
            rename: { suffix: '-16x9'},
          }
        ],
      }, {
        // Global configuration for all images
        // The output quality for JPEG, WebP and TIFF output formats
        quality: 70,
        // Use progressive (interlace) scan for JPEG and PNG output
        progressive: true,
        // Zlib compression level of PNG output format
        compressionLevel: 6,
        // Strip all metadata
        withMetadata: false,
        errorOnEnlargement: false,
        crop: 'entropy'
      }))
    .pipe(imagemin([
      webp({
        quality: 75
      }),
      imagemin.gifsicle({interlaced: true}),
      imagemin.jpegtran({progressive: true}),
      imagemin.optipng({optimizationLevel: 5}),
      imagemin.svgo({
        plugins: [
          {removeViewBox: true},
          {cleanupIDs: false}
        ]
      })
    ], {verbose: true}))
    .pipe(gulp.dest(paths.images.dest));
}

function images() {
  return gulp.src(`${paths.images.src}/**/*.{png,jpg,jpeg,gif}`)
    .pipe(imagemin([
      imagemin.gifsicle({interlaced: true}),
      imagemin.jpegtran({progressive: true}),
      imagemin.optipng({optimizationLevel: 5}),
      imagemin.svgo({
        plugins: [
          {removeViewBox: true},
          {cleanupIDs: false}
        ]
      })
    ], {verbose: true}))
    .pipe(gulp.dest(paths.images.dest))
}

function amp_validator() {
  return gulp.src(paths.html.src)
    .pipe(gulpAmpValidator.validate())
    .pipe(gulpAmpValidator.format())
    .pipe(gulpAmpValidator.failAfterError());
}

function clean() {
  return del([ paths.styles.tmp ]);
}

function purificationPosts() {
  return gulp.src(paths.styles.src)
    .pipe(sass().on('error', sass.logError))
    .pipe(purgecss({content: ['_includes/*.html', '_layouts/default.html', '_layouts/post.html', 'jekyll_collections/_blog/*.html']}))
    .pipe(replace(/!important/gm, ''))
    .pipe(gulp.dest(paths.styles.tmp));
}

function concatenation() {
  return gulp.src([`${paths.styles.tmp}/main.css`, 'assets/css/github.css'])
    .pipe(concat('main.css'))
    .pipe(cleanCSS({compatibility: 'ie8'}, (details) => {
      console.log(`Minification of ${details.name} posts: ${details.stats.originalSize} -> ${details.stats.minifiedSize} b`);
    }))
    .pipe(rename({ suffix: '-post-min' }))
    .pipe(gulp.dest('./_includes/'));
}

function purificationDefault() {
  return gulp.src(paths.styles.src)
    .pipe(sass().on('error', sass.logError))
    .pipe(purgecss({ content: ['_includes/*.html', '_layouts/default.html', 'jekyll_collections/_pages/*.html', '_data/about/*.yml'] }))
    .pipe(replace(/!important/gm, ''))
    .pipe(cleanCSS({compatibility: 'ie8'}, (details) => {
      console.log(`Minification of ${details.name}: ${details.stats.originalSize} -> ${details.stats.minifiedSize} b`);
    }))
    .pipe(rename({ suffix: '-min' }))
    .pipe(gulp.dest('./_includes/'));
}

var build = gulp.series(clean, purificationPosts, concatenation, purificationDefault, clean);

function watch() {
  gulp.watch(["_layouts/**", "_includes/**.html", "jekyll_collections/**", "_sass/*", "assets/css/*"], build);
}

exports.images = images;
exports.thumbnails = thumbnails;
exports.amp_validator = amp_validator;
exports.clean = clean;
exports.concatenation = concatenation;
exports.build = build;
exports.watch = watch;
/*
 * Define default task that can be called by just running `gulp` from cli
 */
exports.default = build;
<commit_msg>➖ dont use imagemin webp because creates always webp images<commit_after>var gulp = require('gulp');
var imagemin = require('gulp-imagemin');
var sass = require('gulp-sass');
let cleanCSS = require('gulp-clean-css');
var responsive = require('gulp-responsive');
var purgecss = require('gulp-purgecss')
var concat = require('gulp-concat');
var replace = require('gulp-replace');
var rename = require('gulp-rename');
var gulpAmpValidator = require('gulp-amphtml-validator');
var del = require('del');

var paths = {
  styles: {
    src: '_sass/main.scss',
    tmp: 'assets/css/dist',
    dest: '_includes'
  },
  images: {
    src: 'assets/img',
    dest: 'assets/img'
  },
  html: {
    src: [
      '_site/{about,blog}/*.html',
      '!_site/blog/withings-data.html',
      '!_site/blog/santorini-experience.html',
      '!_site/blog/marathon-mirabelle.html'
    ]
  }
};

function thumbnails() {
  return gulp.src([`${paths.images.src}/**/main.{png,jpg,jpeg,svg}`, `${paths.images.src}/external-articles/*.{png,jpg,jpeg,svg}`])
    .pipe(
      responsive({
        '*': [
          {
            width: 400,
            height: 225,
            format: 'jpg',
            rename: {
              suffix: '-thumb',
              dirname: 'external-articles-responsive'
            },
          },
          {
            width: 400,
            height: 225,
            format: 'webp',
            rename: {
              suffix: '-thumb',
              dirname: 'external-articles-responsive'
            },
          },
          {
            width: 1400,
            height: 788,
            format: 'jpg',
            rename: {
              suffix: '-16x9',
              dirname: 'external-articles-responsive'
            },
          },
          {
            width: 1400,
            height: 788,
            format: 'webp',
            rename: {
              suffix: '-16x9',
              dirname: 'external-articles-responsive'
            },
          }
        ],
        '*/main.*': [
          {
            width: 400,
            height: 225,
            format: 'jpg',
            rename: { suffix: '-thumb'},
          },
          {
            width: 400,
            height: 225,
            format: 'webp',
            rename: { suffix: '-thumb'},
          },
          {
            width: 1400,
            height: 788,
            format: 'jpg',
            rename: { suffix: '-16x9'},
          },
          {
            width: 1400,
            height: 788,
            format: 'webp',
            rename: { suffix: '-16x9'},
          }
        ],
      }, {
        // Global configuration for all images
        // The output quality for JPEG, WebP and TIFF output formats
        quality: 70,
        // Use progressive (interlace) scan for JPEG and PNG output
        progressive: true,
        // Zlib compression level of PNG output format
        compressionLevel: 6,
        // Strip all metadata
        withMetadata: false,
        errorOnEnlargement: false,
        crop: 'entropy'
      }))
    .pipe(imagemin([
      imagemin.gifsicle({interlaced: true}),
      imagemin.jpegtran({progressive: true}),
      imagemin.optipng({optimizationLevel: 5}),
      imagemin.svgo({
        plugins: [
          {removeViewBox: true},
          {cleanupIDs: false}
        ]
      })
    ], {verbose: true}))
    .pipe(gulp.dest(paths.images.dest));
}

function images() {
  return gulp.src(`${paths.images.src}/**/*.{png,jpg,jpeg,gif}`)
    .pipe(imagemin([
      imagemin.gifsicle({interlaced: true}),
      imagemin.jpegtran({progressive: true}),
      imagemin.optipng({optimizationLevel: 5}),
      imagemin.svgo({
        plugins: [
          {removeViewBox: true},
          {cleanupIDs: false}
        ]
      })
    ], {verbose: true}))
    .pipe(gulp.dest(paths.images.dest))
}

function amp_validator() {
  return gulp.src(paths.html.src)
    .pipe(gulpAmpValidator.validate())
    .pipe(gulpAmpValidator.format())
    .pipe(gulpAmpValidator.failAfterError());
}

function clean() {
  return del([ paths.styles.tmp ]);
}

function purificationPosts() {
  return gulp.src(paths.styles.src)
    .pipe(sass().on('error', sass.logError))
    .pipe(purgecss({content: ['_includes/*.html', '_layouts/default.html', '_layouts/post.html', 'jekyll_collections/_blog/*.html']}))
    .pipe(replace(/!important/gm, ''))
    .pipe(gulp.dest(paths.styles.tmp));
}

function concatenation() {
  return gulp.src([`${paths.styles.tmp}/main.css`, 'assets/css/github.css'])
    .pipe(concat('main.css'))
    .pipe(cleanCSS({compatibility: 'ie8'}, (details) => {
      console.log(`Minification of ${details.name} posts: ${details.stats.originalSize} -> ${details.stats.minifiedSize} b`);
    }))
    .pipe(rename({ suffix: '-post-min' }))
    .pipe(gulp.dest('./_includes/'));
}

function purificationDefault() {
  return gulp.src(paths.styles.src)
    .pipe(sass().on('error', sass.logError))
    .pipe(purgecss({ content: ['_includes/*.html', '_layouts/default.html', 'jekyll_collections/_pages/*.html', '_data/about/*.yml'] }))
    .pipe(replace(/!important/gm, ''))
    .pipe(cleanCSS({compatibility: 'ie8'}, (details) => {
      console.log(`Minification of ${details.name}: ${details.stats.originalSize} -> ${details.stats.minifiedSize} b`);
    }))
    .pipe(rename({ suffix: '-min' }))
    .pipe(gulp.dest('./_includes/'));
}

var build = gulp.series(clean, purificationPosts, concatenation, purificationDefault, clean);

function watch() {
  gulp.watch(["_layouts/**", "_includes/**.html", "jekyll_collections/**", "_sass/*", "assets/css/*"], build);
}

exports.images = images;
exports.thumbnails = thumbnails;
exports.amp_validator = amp_validator;
exports.clean = clean;
exports.concatenation = concatenation;
exports.build = build;
exports.watch = watch;
/*
 * Define default task that can be called by just running `gulp` from cli
 */
exports.default = build;
<|endoftext|>


<commit_before>describe('pingPong', function() {
  it("is true for a number that is divisible by 3", function() {
    expect(pingPong(6)).to.equal(true);
  });

  it("is true for a number that is divisible by 5", function() {
    expect(pingPong(10)).to.equal(True)
  });

});
<commit_msg>Fix syntax capitalization error in line 7<commit_after>describe('pingPong', function() {
  it("is true for a number that is divisible by 3", function() {
    expect(pingPong(6)).to.equal(true);
  });

  it("is true for a number that is divisible by 5", function() {
    expect(pingPong(10)).to.equal(true);
  });

});
<|endoftext|>


<commit_before>var EXPRESS_PORT = 4000;
var EXPRESS_ROOT = __dirname + '/app';
var LIVERELOAD_PORT = 35729;

// Load plugins
var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    minifycss = require('gulp-minify-css'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    rename = require('gulp-rename'),
    clean = require('gulp-clean'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    cache = require('gulp-cache'),
    livereload = require('gulp-livereload'),
    lr = require('tiny-lr'),
    server = lr();

// Set up server

function startExpress() {

  var express = require('express');
  var app = express();
  app.use(require('connect-livereload')());
  app.use(express.static(EXPRESS_ROOT));
  app.listen(EXPRESS_PORT);
}

// Scripts
gulp.task('scripts', function() {
    return gulp.src([
        'app/scripts/stubs/famous.angular.0.js',
        'app/scripts/directives/**/*.js',
        'app/scripts/stubs/famous.angular.1.js'
    ])
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('default'))
    .pipe(concat('famous.angular.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(livereload(server))
    .pipe(notify({ message: 'Scripts task complete' }));
});

// Clean
gulp.task('clean', function() {
  return gulp.src(['dist/scripts'], {read: false})
    .pipe(clean());
});

// Watch
gulp.task('watch', function(event) {

  server.listen(LIVERELOAD_PORT, function (err) {
    if (err) {
      return console.log(err)
    };

    // Watch .js files
    gulp.watch(['app/scripts/**/*.js', 'app/index.html', 'app/views/**/*.html'], ['scripts']).on('change', function(file){
        server.changed(file.path);
    });
  });

});

// Default task
gulp.task('default', ['clean'], function() {
    startExpress();
    gulp.start('scripts');
    gulp.start('watch');
});

<commit_msg>fix watch issue with symlink<commit_after>var EXPRESS_PORT = 4000;
var EXPRESS_ROOT = __dirname + '/app';
var LIVERELOAD_PORT = 35729;

// Load plugins
var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    minifycss = require('gulp-minify-css'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    rename = require('gulp-rename'),
    clean = require('gulp-clean'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    cache = require('gulp-cache'),
    livereload = require('gulp-livereload'),
    lr = require('tiny-lr'),
    server = lr();

// Set up server

function startExpress() {

  var express = require('express');
  var app = express();
  app.use(require('connect-livereload')());
  app.use(express.static(EXPRESS_ROOT));
  app.listen(EXPRESS_PORT);
}

// Scripts
gulp.task('scripts', function() {
    return gulp.src([
        'app/scripts/stubs/famous.angular.0.js',
        'app/scripts/directives/**/*.js',
        'app/scripts/stubs/famous.angular.1.js'
    ])
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('default'))
    .pipe(concat('famous.angular.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(livereload(server))
    .pipe(notify({ message: 'Scripts task complete' }));
});

// Clean
gulp.task('clean', function() {
  return gulp.src(['dist/scripts'], {read: false})
    .pipe(clean());
});

// Watch
gulp.task('watch', function(event) {

  server.listen(LIVERELOAD_PORT, function (err) {
    if (err) {
      return console.log(err)
    };

    // Watch .js files
    gulp.watch(['app/scripts/*/**/*.js', 'app/index.html', 'app/views/**/*.html'], ['scripts']).on('change', function(file){
        server.changed(file.path);
    });
  });

});

// Default task
gulp.task('default', ['clean'], function() {
    startExpress();
    gulp.start('scripts');
    gulp.start('watch');
});

<|endoftext|>


<commit_before>'use strict';

var location             = require('mano/lib/client/location')
  , _                    = require('mano').i18n.bind('View: Statistics')
  , db                   = require('mano').db
  , capitalize           = require('es5-ext/string/#/capitalize')
  , uncapitalize         = require('es5-ext/string/#/uncapitalize')
  , ObservableValue      = require('observable-value')
  , setupQueryHandler    = require('../utils/setup-client-query-handler')
  , resolveFullStepPath  = require('../utils/resolve-processing-step-full-path')
  , getData              = require('mano/lib/client/xhr-driver').get
  , getQueryHandlerConf  = require('../routes/utils/get-statistics-time-query-handler-conf')
  , getDurationDaysHours = require('./utils/get-duration-days-hours')
  , memoize              = require('memoizee');

exports._parent        = require('./statistics-time');
exports._customFilters = Function.prototype;

exports['time-nav'] = { class: { 'pills-nav-active': true } };
exports['per-person-nav'] = { class: { 'pills-nav-active': true } };

var queryServer = memoize(function (query) {
	return getData('/get-processing-time-data/', query);
}, {
	normalizer: function (args) { return JSON.stringify(args[0]); }
});

exports['statistics-main'] = function () {
	var processingStepsMeta = this.processingStepsMeta, stepsMap = {}, stepTotals = {}, queryHandler;
	Object.keys(processingStepsMeta).forEach(function (stepShortPath) {
		stepsMap[stepShortPath]   = new ObservableValue();
		stepTotals[stepShortPath] = new ObservableValue();
	});
	queryHandler = setupQueryHandler(getQueryHandlerConf({
		db: db,
		processingStepsMeta: processingStepsMeta
	}), location, '/time/per-person/');

	queryHandler.on('query', function (query) {
		if (query.dateFrom) {
			query.dateFrom = query.dateFrom.toJSON();
		}
		if (query.dateTo) {
			query.dateTo = query.dateTo.toJSON();
		}
		queryServer(query)(function (result) {
			Object.keys(stepsMap).forEach(function (key) {
				var total;
				stepsMap[key].value = result[key];
				if (!result[key] || !result[key].length) {
					stepTotals[key].value = null;
					return;
				}
				total = {
					processed: 0,
					avgTime: 0,
					minTime: Infinity,
					maxTime: 0,
					totalTime: 0
				};
				result[key].forEach(function (byProcessor) {
					total.processed += byProcessor.processed;
					total.totalTime += byProcessor.totalTime;
					total.minTime = Math.min(byProcessor.minTime, total.minTime);
					total.maxTime = Math.max(byProcessor.maxTime, total.maxTime);
				});
				total.avgTime = total.totalTime / total.processed;
				stepTotals[key].value = total;
			});
		});
	});
	section({ class: 'section-primary users-table-filter-bar' },
		form({ action: '/time/per-person', autoSubmit: true },
			div({ class: 'users-table-filter-bar-status' },
				label({ for: 'service-select' }, _("Service"), ":"),
				select({ id: 'service-select', name: 'service' },
					option(
						{ value: '', selected: location.query.get('service').map(function (value) {
							return (value == null);
						})
							},
						_("All")
					),
					list(db.BusinessProcess.extensions, function (service) {
						var serviceName = uncapitalize.call(service.__id__.slice('BusinessProcess'.length));
						return option({ value: serviceName, selected:
								location.query.get('service').map(function (value) {
								var selected = (serviceName ? (value === serviceName) : (value == null));
								return selected ? 'selected' : null;
							}) },
							service.prototype.label);
					}, null)),
				exports._customFilters.call(this),
				label({ for: 'date-from-input' }, _("Date from"), ":"),
				input({ id: 'date-from-input', type: 'date',
					name: 'dateFrom', value: location.query.get('dateFrom') }),
				label({ for: 'date-to-input' }, _("Date to"), ":"),
				input({ id: 'date-to-input', type: 'date',
					name: 'dateTo', value: location.query.get('dateTo') }),
				a({ class: 'button-resource-link', href:
					location.query.get('dateTo').map(function (dateTo) {
						return location.query.get('dateFrom').map(function (dateFrom) {
							return location.query.get('service').map(function (service) {
								var href = '/get-time-per-person-print/';
								if (!Object.keys(location.query).length) {
									return href;
								}
								href += '?';
								href += Object.keys(location.query).map(function (key) {
									return key + '=' + location.query[key];
								}).join('&');

								return href;
							});
						});
					}),
					target: '_blank' }, span({ class: 'fa fa-print' }), " ", _("Print pdf"))
				)));
	insert(list(Object.keys(stepsMap), function (shortStepPath) {
		return stepsMap[shortStepPath].map(function (data) {
			if (!data) return;
			var step = db['BusinessProcess' +
				capitalize.call(processingStepsMeta[shortStepPath]._services[0])].prototype
				.processingSteps.map.getBySKeyPath(resolveFullStepPath(shortStepPath));
			return section({ class: "section-primary" },
				h3(step.label),
				table(
					thead(
						th(),
						th(_("Files processed")),
						th(_("Average time")),
						th(_("Min time")),
						th(_("Max time"))
					),
					tbody({ onEmpty: tr(td({ class: 'empty', colspan: 5 },
						_("There are no files processed at this step"))) }, data, function (rowData) {
						tr(
							td(db.User.getById(rowData.processor).fullName),
							td(rowData.processed),
							td(getDurationDaysHours(rowData.avgTime)),
							td(getDurationDaysHours(rowData.minTime)),
							td(getDurationDaysHours(rowData.maxTime))
						);
					}, stepTotals[shortStepPath].map(function (totals) {
						if (!totals) return;
						return tr(
							td(_("Total & times")),
							td(totals.processed),
							td(getDurationDaysHours(totals.avgTime)),
							td(getDurationDaysHours(totals.minTime)),
							td(getDurationDaysHours(totals.maxTime))
						);
					}))
				));
		});
	}));
};
<commit_msg>#1520 fixed totals display in regular view<commit_after>'use strict';

var location             = require('mano/lib/client/location')
  , _                    = require('mano').i18n.bind('View: Statistics')
  , db                   = require('mano').db
  , capitalize           = require('es5-ext/string/#/capitalize')
  , uncapitalize         = require('es5-ext/string/#/uncapitalize')
  , ObservableValue      = require('observable-value')
  , setupQueryHandler    = require('../utils/setup-client-query-handler')
  , resolveFullStepPath  = require('../utils/resolve-processing-step-full-path')
  , getData              = require('mano/lib/client/xhr-driver').get
  , getQueryHandlerConf  = require('../routes/utils/get-statistics-time-query-handler-conf')
  , getDurationDaysHours = require('./utils/get-duration-days-hours')
  , memoize              = require('memoizee');

exports._parent        = require('./statistics-time');
exports._customFilters = Function.prototype;

exports['time-nav'] = { class: { 'pills-nav-active': true } };
exports['per-person-nav'] = { class: { 'pills-nav-active': true } };

var queryServer = memoize(function (query) {
	return getData('/get-processing-time-data/', query);
}, {
	normalizer: function (args) { return JSON.stringify(args[0]); }
});

exports['statistics-main'] = function () {
	var processingStepsMeta = this.processingStepsMeta, stepsMap = {}, stepTotals = {}, queryHandler;
	Object.keys(processingStepsMeta).forEach(function (stepShortPath) {
		stepsMap[stepShortPath]   = new ObservableValue();
		stepTotals[stepShortPath] = new ObservableValue();
	});
	queryHandler = setupQueryHandler(getQueryHandlerConf({
		db: db,
		processingStepsMeta: processingStepsMeta
	}), location, '/time/per-person/');

	queryHandler.on('query', function (query) {
		if (query.dateFrom) {
			query.dateFrom = query.dateFrom.toJSON();
		}
		if (query.dateTo) {
			query.dateTo = query.dateTo.toJSON();
		}
		queryServer(query)(function (result) {
			Object.keys(stepsMap).forEach(function (key) {
				var total;
				stepsMap[key].value = result[key];
				if (!result[key] || !result[key].length) {
					stepTotals[key].value = null;
					return;
				}
				total = {
					processed: 0,
					avgTime: 0,
					minTime: Infinity,
					maxTime: 0,
					totalTime: 0
				};
				result[key].forEach(function (byProcessor) {
					total.processed += byProcessor.processed;
					total.totalTime += byProcessor.totalTime;
					total.minTime = Math.min(byProcessor.minTime, total.minTime);
					total.maxTime = Math.max(byProcessor.maxTime, total.maxTime);
				});
				total.avgTime = total.totalTime / total.processed;
				stepTotals[key].value = total;
			});
		});
	});
	section({ class: 'section-primary users-table-filter-bar' },
		form({ action: '/time/per-person', autoSubmit: true },
			div({ class: 'users-table-filter-bar-status' },
				label({ for: 'service-select' }, _("Service"), ":"),
				select({ id: 'service-select', name: 'service' },
					option(
						{ value: '', selected: location.query.get('service').map(function (value) {
							return (value == null);
						})
							},
						_("All")
					),
					list(db.BusinessProcess.extensions, function (service) {
						var serviceName = uncapitalize.call(service.__id__.slice('BusinessProcess'.length));
						return option({ value: serviceName, selected:
								location.query.get('service').map(function (value) {
								var selected = (serviceName ? (value === serviceName) : (value == null));
								return selected ? 'selected' : null;
							}) },
							service.prototype.label);
					}, null)),
				exports._customFilters.call(this),
				label({ for: 'date-from-input' }, _("Date from"), ":"),
				input({ id: 'date-from-input', type: 'date',
					name: 'dateFrom', value: location.query.get('dateFrom') }),
				label({ for: 'date-to-input' }, _("Date to"), ":"),
				input({ id: 'date-to-input', type: 'date',
					name: 'dateTo', value: location.query.get('dateTo') }),
				a({ class: 'button-resource-link', href:
					location.query.get('dateTo').map(function (dateTo) {
						return location.query.get('dateFrom').map(function (dateFrom) {
							return location.query.get('service').map(function (service) {
								var href = '/get-time-per-person-print/';
								if (!Object.keys(location.query).length) {
									return href;
								}
								href += '?';
								href += Object.keys(location.query).map(function (key) {
									return key + '=' + location.query[key];
								}).join('&');

								return href;
							});
						});
					}),
					target: '_blank' }, span({ class: 'fa fa-print' }), " ", _("Print pdf"))
				)));
	insert(list(Object.keys(stepsMap), function (shortStepPath) {
		return stepsMap[shortStepPath].map(function (data) {
			if (!data) return;
			var step = db['BusinessProcess' +
				capitalize.call(processingStepsMeta[shortStepPath]._services[0])].prototype
				.processingSteps.map.getBySKeyPath(resolveFullStepPath(shortStepPath));
			return section({ class: "section-primary" },
				h3(step.label),
				table(
					thead(
						th(),
						th(_("Files processed")),
						th(_("Average time")),
						th(_("Min time")),
						th(_("Max time"))
					),
					tbody({ onEmpty: tr(td({ class: 'empty', colspan: 5 },
						_("There are no files processed at this step"))) }, list(data, function (rowData) {
						tr(
							td(db.User.getById(rowData.processor).fullName),
							td(rowData.processed),
							td(getDurationDaysHours(rowData.avgTime)),
							td(getDurationDaysHours(rowData.minTime)),
							td(getDurationDaysHours(rowData.maxTime))
						);
					}), stepTotals[shortStepPath].map(function (totals) {
						if (!totals) return;
						return tr(
							td(_("Total & times")),
							td(totals.processed),
							td(getDurationDaysHours(totals.avgTime)),
							td(getDurationDaysHours(totals.minTime)),
							td(getDurationDaysHours(totals.maxTime))
						);
					}))
				));
		});
	}));
};
<|endoftext|>


<commit_before>/**
 * Ai-Thinker RGBW Light Firmware
 *
 * This file is part of the Ai-Thinker RGBW Light Firmware.
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.

 * Created by Sacha Telgenhof <stelgenhof at gmail dot com>
 * (https://www.sachatelgenhof.nl)
 * Copyright (c) 2016 - 2017 Sacha Telgenhof
 */

const fs = require('fs');
const gulp = require('gulp');
const del = require('del');
const plumber = require('gulp-plumber');
const htmlmin = require('gulp-htmlmin');
const cleancss = require('gulp-clean-css');
const gzip = require('gulp-gzip');
const inline = require('gulp-inline');
const uglify = require('gulp-uglify');
const sass = require('gulp-sass');
const favicon = require('gulp-base64-favicon');
const cssBase64 = require('gulp-css-base64');

const sourceFolder = 'src/';
const targetFolder = 'html/';

// Clean the generated output files
gulp.task('clean', function() {
  del([sourceFolder + 'html.*']);
  del([sourceFolder + '*.html']);
  del([targetFolder + '*.css']);
  return true;
});

// Build the C++ include header file
gulp.task('build', ['html'], function() {
  var source = sourceFolder + 'index.html.gz';
  var destination = sourceFolder + 'html.gz.h';

  var ws = fs.createWriteStream(destination);

  ws.on('error', function(err) {
    console.log(err);
  });

  var data = fs.readFileSync(source);

  ws.write('#define html_gz_len ' + data.length + '\n');
  ws.write('const uint8_t html_gz[] PROGMEM = {');

  for (i = 0; i < data.length; i++) {
    if (i % 1000 === 0) ws.write('\n');
    ws.write('0x' + ('00' + data[i].toString(16)).slice(-2));
    if (i < data.length - 1) ws.write(',');
  }

  ws.write('\n};');
  ws.end();

  // Remove intermediate files
  fs.unlinkSync(source);
  fs.unlinkSync(targetFolder + 'style.css');
});

// Convert the SCSS to CSS
gulp.task('sass', function() {
  return gulp.src(targetFolder + 'style.scss')
    .pipe(plumber())
    .pipe(sass().on('error', sass.logError))
    .pipe(gulp.dest('html'));
});

// Base 64
gulp.task('css', ['sass'], function() {
  return gulp.src(targetFolder + 'style.css')
    .pipe(cssBase64())
    .pipe(gulp.dest('html'));
});

// Process HTML files
gulp.task('html', ['clean', 'css'], function() {
  return gulp.src(targetFolder + '*.html')
    .pipe(favicon())
    .pipe(inline({
      js: function() {
        return uglify({
          mangle: true
        });
      },
      css: [cleancss],
      disabledTypes: ['svg']
    }))
    .pipe(htmlmin({
      collapseWhitespace: true,
      removeComments: true,
      removeEmptyAttributes: true,
      includeAutoGeneratedTags: false,
      minifyCSS: true,
      minifyJS: true
    }))
    .pipe(gzip())
    .pipe(gulp.dest(sourceFolder));
});

// Default task
gulp.task('default', ['build']);
<commit_msg>Added task for generating gamma correction table.<commit_after>/**
 * Ai-Thinker RGBW Light Firmware
 *
 * This file is part of the Ai-Thinker RGBW Light Firmware.
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.

 * Created by Sacha Telgenhof <stelgenhof at gmail dot com>
 * (https://www.sachatelgenhof.nl)
 * Copyright (c) 2016 - 2017 Sacha Telgenhof
 */

const fs = require('fs');
const gulp = require('gulp');
const del = require('del');
const plumber = require('gulp-plumber');
const htmlmin = require('gulp-htmlmin');
const cleancss = require('gulp-clean-css');
const gzip = require('gulp-gzip');
const inline = require('gulp-inline');
const uglify = require('gulp-uglify');
const sass = require('gulp-sass');
const favicon = require('gulp-base64-favicon');
const cssBase64 = require('gulp-css-base64');

const sourceFolder = 'src/';
const targetFolder = 'html/';

// Clean the generated output files
gulp.task('clean', function() {
  del([sourceFolder + 'html.*']);
  del([sourceFolder + '*.html']);
  del([targetFolder + '*.css']);
  return true;
});

// Build the C++ include header file
gulp.task('build', ['html'], function() {
  var source = sourceFolder + 'index.html.gz';
  var destination = sourceFolder + 'html.gz.h';

  var ws = fs.createWriteStream(destination);

  ws.on('error', function(err) {
    console.log(err);
  });

  var data = fs.readFileSync(source);

  ws.write('#define html_gz_len ' + data.length + '\n');
  ws.write('const uint8_t html_gz[] PROGMEM = {');

  for (i = 0; i < data.length; i++) {
    if (i % 1000 === 0) ws.write('\n');
    ws.write('0x' + ('00' + data[i].toString(16)).slice(-2));
    if (i < data.length - 1) ws.write(',');
  }

  ws.write('\n};');
  ws.end();

  // Remove intermediate files
  fs.unlinkSync(source);
  fs.unlinkSync(targetFolder + 'style.css');
});

// Convert the SCSS to CSS
gulp.task('sass', function() {
  return gulp.src(targetFolder + 'style.scss')
    .pipe(plumber())
    .pipe(sass().on('error', sass.logError))
    .pipe(gulp.dest('html'));
});

// Base 64
gulp.task('css', ['sass'], function() {
  return gulp.src(targetFolder + 'style.css')
    .pipe(cssBase64())
    .pipe(gulp.dest('html'));
});

// Process HTML files
gulp.task('html', ['clean', 'css'], function() {
  return gulp.src(targetFolder + '*.html')
    .pipe(favicon())
    .pipe(inline({
      js: function() {
        return uglify({
          mangle: true
        });
      },
      css: [cleancss],
      disabledTypes: ['svg']
    }))
    .pipe(htmlmin({
      collapseWhitespace: true,
      removeComments: true,
      removeEmptyAttributes: true,
      includeAutoGeneratedTags: false,
      minifyCSS: true,
      minifyJS: true
    }))
    .pipe(gzip())
    .pipe(gulp.dest(sourceFolder));
});

// Creates a gamma correction table
// Copy the contents of this file in the lib/AiLight/AiLight.hpp file
gulp.task('gamma', function() {
  var gamma = 2.8; // Correction factor
  var MAX_IN = 255; // Tope end of INPUT range
  var MAX_OUT = 255; // Tope end of OUTPUT range
  var destination = 'gamma.h';

  var ws = fs.createWriteStream(destination);

  ws.on('error', function(err) {
    console.log(err);
  });

  ws.write('// This table remaps linear input values to nonlinear gamma-corrected output\n');
  ws.write('// values. The output values are specified for 8-bit colours with a gamma\n');
  ws.write('// correction factor of 2.8\n');
  ws.write('const static uint8_t PROGMEM gamma8[256] = {');
  for (var i = 0; i <= MAX_IN; i++) {
    if (i > 0) {
      ws.write(',');
    }

    if ((i & 15) === 0) {
      ws.write('\n');
    }

    var level = (Math.floor(Math.pow(i / MAX_IN, gamma) * MAX_OUT + 0.5));
    ws.write(("    " + level).slice(-4));
  }

  ws.write(' };\n');
  ws.end();
});

// Default task
gulp.task('default', ['build']);
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();

var browserSync = require('browser-sync').create();
var buffer = require('vinyl-buffer');
var del = require('del');
var fs = require('fs');
var imageminPngquant = require('imagemin-pngquant');
var path = require('path');
var posthtmlAttrsSorter = require('posthtml-attrs-sorter');
var runSequence = require('run-sequence');
var rupture = require('rupture');
var spritesmith = require('gulp.spritesmith');
var autoprefixer = require('autoprefixer');
var stylefmt = require('stylefmt');
var postcssSorting = require('postcss-sorting');
var postcssSortingConfig = JSON.parse(
		fs.readFileSync(
			path.join(__dirname, './.postcss-sorting.json')
		)
	);

// Error handler for gulp-plumber
var errorHandler = function(err) {
	$.util.log([ (err.name + ' in ' + err.plugin).bold.red, '', err.message, '' ].join('\n'));

	this.emit('end');
};

var correctNumber = function correctNumber(number) {
	return number < 10 ? '0' + number : number;
};

// Return timestamp
var getDateTime = function getDateTime() {
	var now = new Date();
	var year = now.getFullYear();
	var month = correctNumber(now.getMonth() + 1);
	var day = correctNumber(now.getDate());
	var hours = correctNumber(now.getHours());
	var minutes = correctNumber(now.getMinutes());
	return year + '-' + month + '-' + day + '-' + hours + minutes;
};

// https://github.com/stylus/stylus/issues/1872#issuecomment-86553717
var stylusFileExists = function() {
	return function(style) {
		style.define('file-exists', function(path) {
			return !!$.stylus.stylus.utils.lookup(path.string, this.paths);
		});
	};
};

// Plugins options
var options = {
	del: [
		'dest',
		'tmp'
	],

	plumber: {
		errorHandler: errorHandler
	},

	browserSync: {
		server: {
			baseDir: './dest'
		}
	},

	stylus: {
		use: [
			rupture(),
			stylusFileExists()
		],
		'include css': true
	},

	include: {
		hardFail: true,
		includePaths: [
			__dirname + '/',
			__dirname + '/node_modules',
			__dirname + '/source/static/scripts/plugins'
		]
	},

	pug: {
		pretty: '\t'
	},

	htmlPrettify: {
		'unformatted': ['pre', 'code', 'textarea'],
		'indent_with_tabs': true,
		'preserve_newlines': true,
		'brace_style': 'expand',
		'end_with_newline': true
	},

	svgSymbols: {
		title: false,
		id: '%f',
		className: '%f',
		svgClassname: 'icons-sprite',
		templates: [
			path.join(__dirname, 'source/static/styles/templates/icons-template.styl'),
			path.join(__dirname, 'source/static/styles/templates/icons-template.svg')
		]
	},

	spritesmith: {
		retinaSrcFilter: '**/*@2x.png',
		imgName: 'sprite.png',
		retinaImgName: 'sprite@2x.png',
		cssName: 'sprite.styl',
		algorithm: 'binary-tree',
		padding: 8,
		cssTemplate: './source/static/styles/templates/sprite-template.mustache'
	},

	imagemin: {
		images: [
			$.imagemin.gifsicle({
				interlaced: true,
				optimizationLevel: 3
			}),
			$.imagemin.jpegtran({
				progressive: true
			}),
			imageminPngquant(),
			$.imagemin.svgo({
				plugins: [
					{ cleanupIDs: false },
					{ removeViewBox: false },
					{ convertPathData: false },
					{ mergePaths: false }
				]
			})
		],

		icons: [
			$.imagemin.svgo({
				plugins: [
					{ removeTitle: true },
					{ removeStyleElement: true },
					{ removeAttrs: { attrs: ['id', 'class', 'data-name', 'fill', 'fill-rule'] }},
					{ removeEmptyContainers: true },
					{ sortAttrs: true },
					{ removeUselessDefs: true },
					{ removeEmptyText: true },
					{ removeEditorsNSData: true },
					{ removeEmptyAttrs: true },
					{ removeHiddenElems: true },
					{ transformsWithOnePath: true }
				]
			})
		]
	},

	posthtml: {
		plugins: [
			posthtmlAttrsSorter({
				order: [
					'class',
					'id',
					'name',
					'data',
					'ng',
					'src',
					'for',
					'type',
					'href',
					'values',
					'title',
					'alt',
					'role',
					'aria'
				]
			})
		],
		options: {}
	},

	postcss: [
		autoprefixer({
			cascade: false
		}),
		stylefmt(),
		postcssSorting(postcssSortingConfig)
	],

	csso: {
		restructure: true,
		sourceMap: true
	}

};

gulp.task('cleanup', function(cb) {
	return del(options.del, cb);
});

gulp.task('serve', function() {
	return browserSync.init(options.browserSync);
});

gulp.task('build:css', function() {
	return gulp.src([ '*.styl', '!_*.styl' ], { cwd: 'source/static/styles' })
		.pipe($.plumber(options.plumber))
		.pipe($.sourcemaps.init())
		.pipe($.stylus(options.stylus))
		.pipe($.combineMq({ beautify: true }))
		.pipe($.postcss(options.postcss))
		.pipe(gulp.dest('dest/assets/stylesheets'))
		.pipe($.csso(options.csso))
		.pipe($.rename({ suffix: '.min' }))
		.pipe($.sourcemaps.write('.'))
		.pipe(gulp.dest('dest/assets/stylesheets'))
		.pipe(browserSync.stream());
});

gulp.task('build:data', function() {
	return gulp.src([ '**/*.yml', '!**/_*.yml' ], { cwd: 'source/modules/*/data' })
		.pipe($.plumber(options.plumber))
		.pipe($.yaml({ space: '\t' }))
		.pipe($.mergeJson('data.json'))
		.pipe(gulp.dest('tmp'));
});

gulp.task('build:pages', function() {
	var jsonData = JSON.parse(fs.readFileSync('./tmp/data.json'));
	options.pug.locals = jsonData;

	return gulp.src([ '**/*.pug', '!**/_*.pug' ], { cwd: 'source/pages' })
		.pipe($.plumber(options.plumber))
		.pipe($.pug(options.pug))
		.pipe($.posthtml(options.posthtml.plugins, options.posthtml.options))
		.pipe($.prettify(options.htmlPrettify))
		.pipe(gulp.dest('dest'));
});

gulp.task('modules:assets', function() {
	return gulp.src('**/*.{jpg,gif,svg,png}', { cwd: 'source/modules/*/assets' })
		.pipe($.plumber(options.plumber))
		.pipe($.changed('dest/assets/images'))
		.pipe($.imagemin(options.imagemin.images))
		.pipe($.flatten())
		.pipe(gulp.dest('dest/assets/images'));
});

gulp.task('build:assets', function() {
	var imageFilter = $.filter('**/*.{jpg,gif,svg,png}', { restore: true });
	var scriptsFilter = $.filter([ '**/*.js', '!**/*.min.js' ], { restore: true });
	var stylesFilter = $.filter([ '**/*.css', '!**/*.min.css' ], { restore: true });

	return gulp.src([ '**/*.*', '!**/_*.*' ], { cwd: 'source/static/assets' })
		.pipe($.plumber(options.plumber))
		.pipe($.changed('dest/assets'))

		// Minify images
		.pipe(imageFilter)
		.pipe($.changed('dest/assets'))
		.pipe($.imagemin(options.imagemin.images))
		.pipe(imageFilter.restore)

		// Minify JavaScript files
		.pipe(scriptsFilter)
		.pipe(gulp.dest('dest/assets'))
		.pipe($.uglify())
		.pipe($.rename({ suffix: '.min' }))
		.pipe(scriptsFilter.restore)

		// Minify css
		.pipe(stylesFilter)
		.pipe($.csso())
		.pipe($.rename({ suffix: '.min' }))
		.pipe(stylesFilter.restore)

		// Copy other files
		.pipe(gulp.dest('dest/assets'));
});

gulp.task('build:scripts', function() {
	return gulp.src([ '*.js', '!_*.js' ], { cwd: 'source/static/scripts' })
		.pipe($.plumber(options.plumber))
		.pipe($.sourcemaps.init())
		.pipe($.include(options.include))
		.pipe(gulp.dest('dest/assets/javascripts'))
		.pipe($.uglify())
		.pipe($.rename({ suffix: '.min' }))
		.pipe($.sourcemaps.write('.'))
		.pipe(gulp.dest('dest/assets/javascripts'));
});

gulp.task('build:icons', function() {
	return gulp.src([ '**/*.svg', '!**/_*.svg' ], { cwd: 'source/static/icons' })
		.pipe($.plumber(options.plumber))
		.pipe($.imagemin(options.imagemin.icons))
		.pipe($.svgSymbols(options.svgSymbols))
		.pipe($.if(/\.styl$/, gulp.dest('tmp')))
		.pipe($.if(/\.svg$/, $.rename('icons.svg')))
		.pipe($.if(/\.svg$/, gulp.dest('dest/assets/images')));
});

gulp.task('build:sprite', function() {
	var spriteData = gulp.src([ '**/*.png', '!**/_*.png' ], { cwd: 'source/static/sprite' })
		.pipe(spritesmith(options.spritesmith));

	spriteData.img.pipe(buffer())
		.pipe($.imagemin(options.imagemin.images))
		.pipe(gulp.dest('dest/assets/images'));

	spriteData.css.pipe(buffer())
		.pipe(gulp.dest('tmp'));

	return spriteData.img.pipe(buffer());
});

// Semver
gulp.task('semver:patch', function() {
	return gulp.src('package.json')
		.pipe($.bump())
		.pipe(gulp.dest('./'));
});

gulp.task('semver:minor', function() {
	return gulp.src('package.json')
		.pipe($.bump({ type: 'minor' }))
		.pipe(gulp.dest('./'));
});

gulp.task('semver:major', function() {
	return gulp.src('package.json')
		.pipe($.bump({ type: 'major' }))
		.pipe(gulp.dest('./'));
});

gulp.task('semver:reset', function() {
	return gulp.src('package.json')
		.pipe($.bump({ version: '0.1.0' }))
		.pipe(gulp.dest('./'));
});

gulp.task('build:zip', function() {
	var datetime = '-' + getDateTime();
	var zipName = 'dist' + datetime + '.zip';

	return gulp.src('dest/**/*')
		.pipe($.zip(zipName))
		.pipe(gulp.dest('zip'));
});

gulp.task('deploy:publish', function() {
	return gulp.src('**/*', { cwd: 'dest' })
		.pipe($.ghPages({ branch: 'build' }));
});

// Service tasks
gulp.task('build:html', function(cb) {
	return runSequence(
		'build:data',
		'build:pages',
		cb
	);
});

// Main tasks
gulp.task('build', function(cb) {
	return runSequence(
		'cleanup',
		[
			'build:html',
			'build:icons',
			'build:sprite',
			'modules:assets',
			'build:assets',
			'build:scripts'
		],
		'build:css',
		cb
	);
});

gulp.task('zip', function(cb) {
	return runSequence(
		'build',
		'build:zip',
		cb
	);
});

gulp.task('deploy', function(cb) {
	return runSequence(
		'build',
		'deploy:publish',
		cb
	);
});

gulp.task('dev', function(cb) {
	return runSequence(
		'build',
		[
			'serve',
			'watch'
		],
		cb
	);
});

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

	// Modules, pages
	$.watch('source/**/*.pug', function() {
		return runSequence('build:pages', browserSync.reload);
	});

	// Modules data
	$.watch([ 'source/modules/*/data/*.yml' ], function() {
		return runSequence('build:html', browserSync.reload);
	});

	// Static styles
	$.watch('source/static/styles/**/*.styl', function() {
		gulp.start('compile-styles');
	});

	// Modules styles
	$.watch('source/modules/**/*.styl', function() {
		gulp.start('build:css');
	});

	// Static scripts
	$.watch('source/static/scripts/**/*.js', function() {
		return runSequence('build:scripts', browserSync.reload);
	});

	// Modules scripts
	$.watch('source/modules/*/*.js', function() {
		return runSequence('build:scripts', browserSync.reload);
	});

	// Modules images
	$.watch('source/modules/*/assets/**/*.{jpg,gif,svg,png}', function() {
		return runSequence('modules:assets', browserSync.reload);
	});

	// Static files
	$.watch('source/static/assets/**/*', function() {
		return runSequence('build:assets', browserSync.reload);
	});

	// Svg icons
	$.watch('source/static/icons/**/*.svg', function() {
		return runSequence('build:icons', 'build:css', browserSync.reload);
	});

	// Png sprites
	$.watch('source/static/sprite/**/*.png', function() {
		return runSequence('build:sprite', browserSync.reload);
	});
});

gulp.task('default', function() {
	gulp.start('build');
});
<commit_msg>Some optimizations in utiyty functions<commit_after>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();

var browserSync = require('browser-sync').create();
var buffer = require('vinyl-buffer');
var del = require('del');
var fs = require('fs');
var imageminPngquant = require('imagemin-pngquant');
var path = require('path');
var posthtmlAttrsSorter = require('posthtml-attrs-sorter');
var runSequence = require('run-sequence');
var rupture = require('rupture');
var spritesmith = require('gulp.spritesmith');
var autoprefixer = require('autoprefixer');
var stylefmt = require('stylefmt');
var postcssSorting = require('postcss-sorting');
var postcssSortingConfig = getJsonData('.postcss-sorting.json');

// Read json and return object
function getJsonData(file) {
	var fs = require('fs');
	var path = require('path');

	return JSON.parse(
			fs.readFileSync(
				path.join(__dirname, file),
				'utf8'
			)
		);
}

// Error handler for gulp-plumber
function errorHandler(err) {
	$.util.log([ (err.name + ' in ' + err.plugin).bold.red, '', err.message, '' ].join('\n'));

	this.emit('end');
};

function correctNumber(number) {
	return number < 10 ? '0' + number : number;
};

// Return timestamp
function getDateTime() {
	var now = new Date();
	var year = now.getFullYear();
	var month = correctNumber(now.getMonth() + 1);
	var day = correctNumber(now.getDate());
	var hours = correctNumber(now.getHours());
	var minutes = correctNumber(now.getMinutes());
	return year + '-' + month + '-' + day + '-' + hours + minutes;
};

// https://github.com/stylus/stylus/issues/1872#issuecomment-86553717
function stylusFileExists() {
	return function(style) {
		style.define('file-exists', function(path) {
			return !!$.stylus.stylus.utils.lookup(path.string, this.paths);
		});
	};
};

// Plugins options
var options = {
	del: [
		'dest',
		'tmp'
	],

	plumber: {
		errorHandler: errorHandler
	},

	browserSync: {
		server: {
			baseDir: './dest'
		}
	},

	stylus: {
		use: [
			rupture(),
			stylusFileExists()
		],
		'include css': true
	},

	include: {
		hardFail: true,
		includePaths: [
			__dirname + '/',
			__dirname + '/node_modules',
			__dirname + '/source/static/scripts/plugins'
		]
	},

	pug: {
		pretty: '\t'
	},

	htmlPrettify: {
		'unformatted': ['pre', 'code', 'textarea'],
		'indent_with_tabs': true,
		'preserve_newlines': true,
		'brace_style': 'expand',
		'end_with_newline': true
	},

	svgSymbols: {
		title: false,
		id: '%f',
		className: '%f',
		svgClassname: 'icons-sprite',
		templates: [
			path.join(__dirname, 'source/static/styles/templates/icons-template.styl'),
			path.join(__dirname, 'source/static/styles/templates/icons-template.svg')
		]
	},

	spritesmith: {
		retinaSrcFilter: '**/*@2x.png',
		imgName: 'sprite.png',
		retinaImgName: 'sprite@2x.png',
		cssName: 'sprite.styl',
		algorithm: 'binary-tree',
		padding: 8,
		cssTemplate: './source/static/styles/templates/sprite-template.mustache'
	},

	imagemin: {
		images: [
			$.imagemin.gifsicle({
				interlaced: true,
				optimizationLevel: 3
			}),
			$.imagemin.jpegtran({
				progressive: true
			}),
			imageminPngquant(),
			$.imagemin.svgo({
				plugins: [
					{ cleanupIDs: false },
					{ removeViewBox: false },
					{ convertPathData: false },
					{ mergePaths: false }
				]
			})
		],

		icons: [
			$.imagemin.svgo({
				plugins: [
					{ removeTitle: true },
					{ removeStyleElement: true },
					{ removeAttrs: { attrs: ['id', 'class', 'data-name', 'fill', 'fill-rule'] }},
					{ removeEmptyContainers: true },
					{ sortAttrs: true },
					{ removeUselessDefs: true },
					{ removeEmptyText: true },
					{ removeEditorsNSData: true },
					{ removeEmptyAttrs: true },
					{ removeHiddenElems: true },
					{ transformsWithOnePath: true }
				]
			})
		]
	},

	posthtml: {
		plugins: [
			posthtmlAttrsSorter({
				order: [
					'class',
					'id',
					'name',
					'data',
					'ng',
					'src',
					'for',
					'type',
					'href',
					'values',
					'title',
					'alt',
					'role',
					'aria'
				]
			})
		],
		options: {}
	},

	postcss: [
		autoprefixer({
			cascade: false
		}),
		stylefmt(),
		postcssSorting(postcssSortingConfig)
	],

	csso: {
		restructure: true,
		sourceMap: true
	}

};

gulp.task('cleanup', function(cb) {
	return del(options.del, cb);
});

gulp.task('serve', function() {
	return browserSync.init(options.browserSync);
});

gulp.task('build:css', function() {
	return gulp.src([ '*.styl', '!_*.styl' ], { cwd: 'source/static/styles' })
		.pipe($.plumber(options.plumber))
		.pipe($.sourcemaps.init())
		.pipe($.stylus(options.stylus))
		.pipe($.combineMq({ beautify: true }))
		.pipe($.postcss(options.postcss))
		.pipe(gulp.dest('dest/assets/stylesheets'))
		.pipe($.csso(options.csso))
		.pipe($.rename({ suffix: '.min' }))
		.pipe($.sourcemaps.write('.'))
		.pipe(gulp.dest('dest/assets/stylesheets'))
		.pipe(browserSync.stream());
});

gulp.task('build:data', function() {
	return gulp.src([ '**/*.yml', '!**/_*.yml' ], { cwd: 'source/modules/*/data' })
		.pipe($.plumber(options.plumber))
		.pipe($.yaml({ space: '\t' }))
		.pipe($.mergeJson('data.json'))
		.pipe(gulp.dest('tmp'));
});

gulp.task('build:pages', function() {
	var jsonData = getJsonData('./tmp/data.json');

	options.pug.locals = jsonData;

	return gulp.src([ '**/*.pug', '!**/_*.pug' ], { cwd: 'source/pages' })
		.pipe($.plumber(options.plumber))
		.pipe($.pug(options.pug))
		.pipe($.posthtml(options.posthtml.plugins, options.posthtml.options))
		.pipe($.prettify(options.htmlPrettify))
		.pipe(gulp.dest('dest'));
});

gulp.task('modules:assets', function() {
	return gulp.src('**/*.{jpg,gif,svg,png}', { cwd: 'source/modules/*/assets' })
		.pipe($.plumber(options.plumber))
		.pipe($.changed('dest/assets/images'))
		.pipe($.imagemin(options.imagemin.images))
		.pipe($.flatten())
		.pipe(gulp.dest('dest/assets/images'));
});

gulp.task('build:assets', function() {
	var imageFilter = $.filter('**/*.{jpg,gif,svg,png}', { restore: true });
	var scriptsFilter = $.filter([ '**/*.js', '!**/*.min.js' ], { restore: true });
	var stylesFilter = $.filter([ '**/*.css', '!**/*.min.css' ], { restore: true });

	return gulp.src([ '**/*.*', '!**/_*.*' ], { cwd: 'source/static/assets' })
		.pipe($.plumber(options.plumber))
		.pipe($.changed('dest/assets'))

		// Minify images
		.pipe(imageFilter)
		.pipe($.changed('dest/assets'))
		.pipe($.imagemin(options.imagemin.images))
		.pipe(imageFilter.restore)

		// Minify JavaScript files
		.pipe(scriptsFilter)
		.pipe(gulp.dest('dest/assets'))
		.pipe($.uglify())
		.pipe($.rename({ suffix: '.min' }))
		.pipe(scriptsFilter.restore)

		// Minify css
		.pipe(stylesFilter)
		.pipe($.csso())
		.pipe($.rename({ suffix: '.min' }))
		.pipe(stylesFilter.restore)

		// Copy other files
		.pipe(gulp.dest('dest/assets'));
});

gulp.task('build:scripts', function() {
	return gulp.src([ '*.js', '!_*.js' ], { cwd: 'source/static/scripts' })
		.pipe($.plumber(options.plumber))
		.pipe($.sourcemaps.init())
		.pipe($.include(options.include))
		.pipe(gulp.dest('dest/assets/javascripts'))
		.pipe($.uglify())
		.pipe($.rename({ suffix: '.min' }))
		.pipe($.sourcemaps.write('.'))
		.pipe(gulp.dest('dest/assets/javascripts'));
});

gulp.task('build:icons', function() {
	return gulp.src([ '**/*.svg', '!**/_*.svg' ], { cwd: 'source/static/icons' })
		.pipe($.plumber(options.plumber))
		.pipe($.imagemin(options.imagemin.icons))
		.pipe($.svgSymbols(options.svgSymbols))
		.pipe($.if(/\.styl$/, gulp.dest('tmp')))
		.pipe($.if(/\.svg$/, $.rename('icons.svg')))
		.pipe($.if(/\.svg$/, gulp.dest('dest/assets/images')));
});

gulp.task('build:sprite', function() {
	var spriteData = gulp.src([ '**/*.png', '!**/_*.png' ], { cwd: 'source/static/sprite' })
		.pipe(spritesmith(options.spritesmith));

	spriteData.img.pipe(buffer())
		.pipe($.imagemin(options.imagemin.images))
		.pipe(gulp.dest('dest/assets/images'));

	spriteData.css.pipe(buffer())
		.pipe(gulp.dest('tmp'));

	return spriteData.img.pipe(buffer());
});

// Semver
gulp.task('semver:patch', function() {
	return gulp.src('package.json')
		.pipe($.bump())
		.pipe(gulp.dest('./'));
});

gulp.task('semver:minor', function() {
	return gulp.src('package.json')
		.pipe($.bump({ type: 'minor' }))
		.pipe(gulp.dest('./'));
});

gulp.task('semver:major', function() {
	return gulp.src('package.json')
		.pipe($.bump({ type: 'major' }))
		.pipe(gulp.dest('./'));
});

gulp.task('semver:reset', function() {
	return gulp.src('package.json')
		.pipe($.bump({ version: '0.1.0' }))
		.pipe(gulp.dest('./'));
});

gulp.task('build:zip', function() {
	var datetime = '-' + getDateTime();
	var zipName = 'dist' + datetime + '.zip';

	return gulp.src('dest/**/*')
		.pipe($.zip(zipName))
		.pipe(gulp.dest('zip'));
});

gulp.task('deploy:publish', function() {
	return gulp.src('**/*', { cwd: 'dest' })
		.pipe($.ghPages({ branch: 'build' }));
});

// Service tasks
gulp.task('build:html', function(cb) {
	return runSequence(
		'build:data',
		'build:pages',
		cb
	);
});

// Main tasks
gulp.task('build', function(cb) {
	return runSequence(
		'cleanup',
		[
			'build:html',
			'build:icons',
			'build:sprite',
			'modules:assets',
			'build:assets',
			'build:scripts'
		],
		'build:css',
		cb
	);
});

gulp.task('zip', function(cb) {
	return runSequence(
		'build',
		'build:zip',
		cb
	);
});

gulp.task('deploy', function(cb) {
	return runSequence(
		'build',
		'deploy:publish',
		cb
	);
});

gulp.task('dev', function(cb) {
	return runSequence(
		'build',
		[
			'serve',
			'watch'
		],
		cb
	);
});

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

	// Modules, pages
	$.watch('source/**/*.pug', function() {
		return runSequence('build:pages', browserSync.reload);
	});

	// Modules data
	$.watch([ 'source/modules/*/data/*.yml' ], function() {
		return runSequence('build:html', browserSync.reload);
	});

	// Static styles
	$.watch('source/static/styles/**/*.styl', function() {
		gulp.start('compile-styles');
	});

	// Modules styles
	$.watch('source/modules/**/*.styl', function() {
		gulp.start('build:css');
	});

	// Static scripts
	$.watch('source/static/scripts/**/*.js', function() {
		return runSequence('build:scripts', browserSync.reload);
	});

	// Modules scripts
	$.watch('source/modules/*/*.js', function() {
		return runSequence('build:scripts', browserSync.reload);
	});

	// Modules images
	$.watch('source/modules/*/assets/**/*.{jpg,gif,svg,png}', function() {
		return runSequence('modules:assets', browserSync.reload);
	});

	// Static files
	$.watch('source/static/assets/**/*', function() {
		return runSequence('build:assets', browserSync.reload);
	});

	// Svg icons
	$.watch('source/static/icons/**/*.svg', function() {
		return runSequence('build:icons', 'build:css', browserSync.reload);
	});

	// Png sprites
	$.watch('source/static/sprite/**/*.png', function() {
		return runSequence('build:sprite', browserSync.reload);
	});
});

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