<commit_before>(function () {
  var salaryContainer = '.salary-container';
  var compensationAmount = salaryContainer + ' .compensation .amount';
  var defaultValue = '--';

  var CONTRACT_TYPE_EMPLOYEE = 'employee_factor';
  var CONTRACT_TYPE_CONTRACTOR = 'contractor_factor';

  // Dropdown Core functionality

  var setDropdown = function(event) {
    var $selected = $(event.currentTarget);

    if ($selected.hasClass('filter-container')) {
      return;
    }

    var key = $selected.find('.key').text();
    var value = $selected.find('.value').text();
    var displayValue = $selected.find('.display-value').text();
    var $title = $selected.parents('.dropdown').find('.title');
    var $subtitle = $selected.parents('.dropdown').find('.subtitle');

    // Get range values if available
    var min = $selected.find('.value').data('min');
    var max = $selected.find('.value').data('max');

    $title.text(key);
    $title.data('selected', value || key);

    if (min && max) {
      $title.data('min', min);
      $title.data('max', max);
    }

    if (value) {
      $subtitle.text(value);
    } else if (displayValue) {
      $subtitle.text(displayValue);
    }
  }

  this.SalaryCalculator = (function() {
    function SalaryCalculator() {
      this.bindEvents();
    }

    SalaryCalculator.prototype.bindEvents = function() {
      var $countryDropdown = $(salaryContainer + ' .country li:not(.filter-container)');
      var $countryDropdownContainer = $(salaryContainer + ' .country');
      var $cityDropdown = $(salaryContainer + ' .city li:not(.filter-container)');
      var $cityDropdownContainer = $(salaryContainer + ' .city');
      var $levelDropdown = $(salaryContainer + ' .level li');
      var $experienceDropdown = $(salaryContainer + ' .experience li');
      var $countryFilter = $('.js-country-filter');
      var $cityFilter = $('.js-city-filter');

      // Set selected dropdown value
      $countryDropdown.on('click', setDropdown);
      $cityDropdown.on('click', setDropdown);
      $levelDropdown.on('click', setDropdown);
      $experienceDropdown.on('click', setDropdown);

      // Render compensation
      $countryDropdown.on('click', this.render.bind(this));
      $cityDropdown.on('click', this.render.bind(this));
      $levelDropdown.on('click', this.render.bind(this));
      $experienceDropdown.on('click', this.render.bind(this));

      // Unlock and filter city dropdown
      $countryDropdown.on('click', this.filterCityDropdown.bind(this));
      $countryDropdown.on('click', this.resetCityDropdown.bind(this));

      // Render Formula
      $levelDropdown.on('click', this.renderFormula.bind(this));
      $experienceDropdown.on('click', this.renderFormula.bind(this));

      // Highlighting
      $(salaryContainer + ' .level').on('keydown', this.highlightDropdownItem.bind(this));
      $(salaryContainer + ' .experience').on('keydown', this.highlightDropdownItem.bind(this));

      // Filtering
      $countryFilter.on('keyup', this.search.bind(null, {
        dropdown: 'country'
      }));

      $cityFilter.on('keyup', this.search.bind(this, {
        dropdown: 'city',
        filter: 'country',
      }));

      $countryDropdownContainer.on('shown.bs.dropdown', this.focusInput);
      $cityDropdownContainer.on('shown.bs.dropdown', this.focusInput);
    }

    SalaryCalculator.prototype.focusInput = function(event) {
      $(event.target).find('.filter-input').focus();
    }

    SalaryCalculator.prototype.search = function(data, event) {
      var text = event.target.value.toLowerCase();
      var filterValue = null;
      var $items = $(salaryContainer + ' .' + data.dropdown + ' li:not(.filter-container)');

      if (data.filter) {
        filterValue = this.getElementValues()[data.filter];
      }

      $items.each(function(index, element) {
        var $element = $(element);
        var value = $element.children('.key').text().toLowerCase();
        var searchableElement = true;

        if (data.filter && filterValue) {
          searchableElement = $element.data(data.filter) === filterValue;
        }

        if (value.indexOf(text) == -1 || !searchableElement) {
          $element.addClass('hidden');
        } else {
          $element.removeClass('hidden');
        }
      });
    }

    SalaryCalculator.prototype.highlightDropdownItem = function(e) {
      var $this = $(e.currentTarget),
          list = $this.find('li'),
          nextLi, prevLi;

      if ($this.hasClass('open')) {
        if ((e.keyCode === 38 || e.keyCode === 40) &&
            !$this.find('li.is-focused').length) {
          $this.find('li').first().addClass('is-focused');
        }

        if (e.keyCode === 38 &&
            !list.first().hasClass('is-focused')) { // Up
          prevLi = $this
                    .find('li.is-focused')
                    .removeClass('is-focused')
                    .prev('li');

          if (prevLi[0] === list.first())
            list.first().addClass('is-focused');
          else
            prevLi.addClass('is-focused');
        } else if (e.keyCode === 40 &&
                   !list.last().hasClass('is-focused')) { // Down
          nextLi = $this
                    .find('li.is-focused')
                    .removeClass('is-focused')
                    .next('li');

          if (nextLi[0] === list.last())
            list.last().addClass('is-focused');
          else
            nextLi.addClass('is-focused');
        } else if (e.keyCode === 13) { // Enter/Return
          // Triggering click directly while keydown is active
          // doesn't hide dropdown, this workaround does. Need better way :/
          setTimeout(function() { $this.find('li.is-focused').trigger('click'); });
        }
      }
    }

    // Custom dropdown functionality

    SalaryCalculator.prototype.filterCityDropdown = function() {
      var selectedCountry = this.getElementValues().country;
      var $cities = $(salaryContainer + ' .city li:not(.filter-container)');

      $cities.each(function(index, element) {
        var $element = $(element);
        if ($element.data('country') === selectedCountry) {
          $element.removeClass('hidden');
        } else {
          $element.addClass('hidden');
        }
      });
    }

    SalaryCalculator.prototype.resetCityDropdown = function() {
      var $cityDropdownBtn = $(salaryContainer + ' .city .btn');
      var $cityDropdownTitle = $cityDropdownBtn.find('.title');
      var $filterInput = $('.js-city-filter');
      $filterInput.val('');
      $cityDropdownBtn.removeClass('disabled');
      $cityDropdownTitle.text('--');
      $cityDropdownTitle.data('selected', '');
      $cityDropdownBtn.find('.subtitle').text('');
      this.renderInvalidCompensation();
      this.renderFormula();
    }

    // Render functions

    SalaryCalculator.prototype.getData = function() {
      var deferred = jQuery.Deferred();

      $.get('/salary/data.json').then(function(data) {
        // Cache the data
        this.data = data;
        deferred.resolve();
      }.bind(this));

      return deferred.promise();
    }

    SalaryCalculator.prototype.render = function() {
      var input = this.getElementValues();

      function renderData() {
        if (input.country && input.city && input.level && input.experience.min && input.experience.max) {
          this.renderCompensation(input);
        } else {
          this.renderInvalidCompensation();
        }
        this.renderFormula();
        this.renderContractType();
      }

      if (this.data) {
        renderData.call(this);
      } else {
        $.when(this.getData()).then(function() {
            renderData.call(this);
          }.bind(this),
          this.renderInvalidCompensation.bind(this));
      }
    }

    SalaryCalculator.prototype.renderCompensation = function(input) {
      var numbeo = this.data.numbeo;
      var contracts = this.data.contractTypes;

      var levelIndex = parseFloat(input.level);
      var benchmark = input.salary;

      var rentIndex = this.calculateRentIndex(input.city, input.country);
      var contract = this.calculateContractFactor(input.country);

      if (!rentIndex) {
        //When the city and country combination selected do not exist
        return this.renderInvalidCompensation();
      }

      var min = this.calculateCompensation(benchmark, rentIndex, levelIndex, contract.factor, input.experience.min);
      var max = this.calculateCompensation(benchmark, rentIndex, levelIndex, contract.factor, input.experience.max);
      $(compensationAmount).text(this.formatAmount(min) + ' - ' + this.formatAmount(max) + ' USD');
    }

    SalaryCalculator.prototype.renderContractType = function() {
      var country = this.getElementValues().country;
      var contract = this.calculateContractFactor(country);
      var $container = $('.contract-type-container');

      if (contract.type === CONTRACT_TYPE_EMPLOYEE) {
        $container.find('.grammer').text('an');
        $container.find('.company-type').text('Inc.');
        $container.find('.contract-type').text('employee');
      } else {
        $container.find('.grammer').text('a');
        $container.find('.company-type').text('BV.');
        $container.find('.contract-type').text('contractor');
      }

      $container.removeClass('hidden');
    }

    SalaryCalculator.prototype.renderFormula = function() {
      var values = this.getElementValues();
      var rentIndex = this.calculateRentIndex(values.city, values.country);
      var contract = this.calculateContractFactor(values.country);
      var experience = values.experience;

      $('.formula .level .value').text(values.level ? values.level : defaultValue);
      $('.formula .experience .value').text(experience.min && experience.max ? experience.min + ' to ' + experience.max : defaultValue);

      $('.formula .rentIndex .value').text(rentIndex ? rentIndex : defaultValue);
      $('.formula .contractType .value').text(contract.hasOwnProperty('factor') ? contract.factor.toFixed(2) : defaultValue);
    }

    SalaryCalculator.prototype.renderInvalidCompensation = function() {
      $(compensationAmount).text(defaultValue);
    }

    // Pure functions

    SalaryCalculator.prototype.getElementValues = function() {
      return {
        salary: $(salaryContainer).data('salary') || '',
        country: $(salaryContainer + ' .country .title').data('selected') || '',
        city: $(salaryContainer + ' .city .title').data('selected') || '',
        level: $(salaryContainer + ' .level .title').data('selected') || '',
        experience: {
          min: $(salaryContainer + ' .experience .title').data('min') || '',
          max: $(salaryContainer + ' .experience .title').data('max') || ''
        }
      };
    }

    SalaryCalculator.prototype.calculateRentIndex = function(city, country) {
      if (this.data && this.data.numbeo) {
        var locationData = this.data.numbeo.find(function(o) {
          return o.country === country && o.city === city;
        });

        return locationData ? parseFloat((locationData.rentIndex * 0.01).toFixed(2)) : 0;
      }

      // Rent Index will never be zero, safe to return as error value
      return 0;
    }

    SalaryCalculator.prototype.calculateContractFactor = function(country) {
      var contract = {};

      if (this.data && this.data.contractTypes) {
        var defaultContractorFactor = this.data.contractTypes.find(function (o) {
          return o.country === '*';
        }).contractor_factor;

        var contractType = this.data.contractTypes.find(function(o) {
          return o.country === country
        });

        if (contractType && contractType.hasOwnProperty(CONTRACT_TYPE_EMPLOYEE)) {
          contract.type = CONTRACT_TYPE_EMPLOYEE;
          contract.factor = contractType[CONTRACT_TYPE_EMPLOYEE];
        } else if (contractType) {
          contract.type = CONTRACT_TYPE_CONTRACTOR;
          contract.factor = contractType[CONTRACT_TYPE_CONTRACTOR];
        } else {
          contract.type = CONTRACT_TYPE_CONTRACTOR;
          contract.factor = defaultContractorFactor;
        }
      }

      return contract;
    }

    SalaryCalculator.prototype.calculateCompensation = function(benchmark, rentIndex, levelIndex, contractType, experienceFactor) {
      return Math.round(benchmark * (rentIndex + 0.25) * levelIndex * contractType * experienceFactor);
    };

    SalaryCalculator.prototype.formatAmount = function(amount) {
      return '$' + amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }

    return SalaryCalculator;
  })();

  new SalaryCalculator();
})();
<commit_msg>Arrow key support for dropdowns<commit_after>(function () {
  var salaryContainer = '.salary-container';
  var compensationAmount = salaryContainer + ' .compensation .amount';
  var defaultValue = '--';

  var CONTRACT_TYPE_EMPLOYEE = 'employee_factor';
  var CONTRACT_TYPE_CONTRACTOR = 'contractor_factor';

  // Dropdown Core functionality

  var setDropdown = function(event) {
    var $selected = $(event.currentTarget);

    if ($selected.hasClass('filter-container')) {
      return;
    }

    var key = $selected.find('.key').text();
    var value = $selected.find('.value').text();
    var displayValue = $selected.find('.display-value').text();
    var $title = $selected.parents('.dropdown').find('.title');
    var $subtitle = $selected.parents('.dropdown').find('.subtitle');

    // Get range values if available
    var min = $selected.find('.value').data('min');
    var max = $selected.find('.value').data('max');

    $title.text(key);
    $title.data('selected', value || key);

    if (min && max) {
      $title.data('min', min);
      $title.data('max', max);
    }

    if (value) {
      $subtitle.text(value);
    } else if (displayValue) {
      $subtitle.text(displayValue);
    }
  }

  var isFullyVisible = function(el, parentEl) {
    var parentHeight = parentEl.height() - el.height(), // Make sure last item is not partially visible
        elTop = el.position().top,
        elBottom = elTop + (el.height());

    return (elBottom > 0 && elTop < parentHeight);
  }

  this.SalaryCalculator = (function() {
    function SalaryCalculator() {
      this.bindEvents();
    }

    SalaryCalculator.prototype.bindEvents = function() {
      var $countryDropdown = $(salaryContainer + ' .country li:not(.filter-container)');
      var $countryDropdownContainer = $(salaryContainer + ' .country');
      var $cityDropdown = $(salaryContainer + ' .city li:not(.filter-container)');
      var $cityDropdownContainer = $(salaryContainer + ' .city');
      var $levelDropdown = $(salaryContainer + ' .level li');
      var $experienceDropdown = $(salaryContainer + ' .experience li');
      var $countryFilter = $('.js-country-filter');
      var $cityFilter = $('.js-city-filter');

      // Set selected dropdown value
      $countryDropdown.on('click', setDropdown);
      $cityDropdown.on('click', setDropdown);
      $levelDropdown.on('click', setDropdown);
      $experienceDropdown.on('click', setDropdown);

      // Render compensation
      $countryDropdown.on('click', this.render.bind(this));
      $cityDropdown.on('click', this.render.bind(this));
      $levelDropdown.on('click', this.render.bind(this));
      $experienceDropdown.on('click', this.render.bind(this));

      // Unlock and filter city dropdown
      $countryDropdown.on('click', this.filterCityDropdown.bind(this));
      $countryDropdown.on('click', this.resetCityDropdown.bind(this));

      // Render Formula
      $levelDropdown.on('click', this.renderFormula.bind(this));
      $experienceDropdown.on('click', this.renderFormula.bind(this));

      // Highlighting for Dropdown
      $(salaryContainer + ' .level').on('keydown', this.highlightDropdownItem.bind(this));
      $(salaryContainer + ' .experience').on('keydown', this.highlightDropdownItem.bind(this));

      // Highlighting for Filter
      $countryDropdownContainer.on('keydown', this.highlightDropdownItem.bind(this));
      $cityDropdownContainer.on('keydown', this.highlightDropdownItem.bind(this));

      // Filtering
      $countryFilter.on('keyup', this.search.bind(null, {
        dropdown: 'country'
      }));

      $cityFilter.on('keyup', this.search.bind(this, {
        dropdown: 'city',
        filter: 'country',
      }));

      $countryDropdownContainer.on('shown.bs.dropdown', this.focusInput);
      $cityDropdownContainer.on('shown.bs.dropdown', this.focusInput);
    }

    SalaryCalculator.prototype.focusInput = function(event) {
      $(event.target).find('.filter-input').focus();
    }

    SalaryCalculator.prototype.search = function(data, event) {
      var text = event.target.value.toLowerCase();
      var filterValue = null;
      var $items = $(salaryContainer + ' .' + data.dropdown + ' li:not(.filter-container)');

      if (data.filter) {
        filterValue = this.getElementValues()[data.filter];
      }

      $items.each(function(index, element) {
        var $element = $(element);
        var value = $element.children('.key').text().toLowerCase();
        var searchableElement = true;

        if (data.filter && filterValue) {
          searchableElement = $element.data(data.filter) === filterValue;
        }

        if (value.indexOf(text) == -1 || !searchableElement) {
          $element.addClass('hidden');
        } else {
          $element.removeClass('hidden');
        }
      });
    }

    SalaryCalculator.prototype.highlightDropdownItem = function(e) {
      var $this = $(e.currentTarget),
          listContainer = $this.find('.dropdown-menu.dropdown-scroll'),
          list = $this.find('li:not(.hidden):not(.filter-container)'),
          nextLi, prevLi,
          focusedLi;

      if ($this.hasClass('open')) {
        if ((e.keyCode === 38 || e.keyCode === 40) &&
            !list.filter('li.is-focused').length) {
          list.first().addClass('is-focused');
        }

        if (e.keyCode === 38 &&
            !list.first().hasClass('is-focused')) { // Up
          prevLi = list
                    .filter('li.is-focused')
                    .prevAll('li:not(.hidden)').first();

          list.filter('li.is-focused').removeClass('is-focused');

          if (prevLi[0] === list.first()[0])
            list.first().addClass('is-focused');
          else
            prevLi.addClass('is-focused');
        } else if (e.keyCode === 40 &&
                   !list.last().hasClass('is-focused')) { // Down
          nextLi = list
                    .filter('li.is-focused')
                    .nextAll('li:not(.hidden)').first();

          list.filter('li.is-focused').removeClass('is-focused');

          if (nextLi[0] === list.last()[0])
            list.last().addClass('is-focused');
          else
            nextLi.addClass('is-focused');
        } else if (e.keyCode === 13) { // Enter / Return
          // Triggering click directly while keydown is active
          // doesn't hide dropdown, this workaround does. Need better way :/
          setTimeout(function() { list.filter('li.is-focused').trigger('click'); });
        }

        focusedLi = list.filter('li.is-focused');
        if (list.first()[0] !== focusedLi[0]) {
          if (!isFullyVisible(focusedLi, listContainer))
            listContainer.scrollTop(list.index(focusedLi) * focusedLi.outerHeight());
        }
        else
          listContainer.scrollTop(0)
      }
    }

    // Custom dropdown functionality

    SalaryCalculator.prototype.filterCityDropdown = function() {
      var selectedCountry = this.getElementValues().country;
      var $cities = $(salaryContainer + ' .city li:not(.filter-container)');

      $cities.each(function(index, element) {
        var $element = $(element);
        if ($element.data('country') === selectedCountry) {
          $element.removeClass('hidden');
        } else {
          $element.addClass('hidden');
        }
      });
    }

    SalaryCalculator.prototype.resetCityDropdown = function() {
      var $cityDropdownBtn = $(salaryContainer + ' .city .btn');
      var $cityDropdownTitle = $cityDropdownBtn.find('.title');
      var $filterInput = $('.js-city-filter');
      $filterInput.val('');
      $cityDropdownBtn.removeClass('disabled');
      $cityDropdownTitle.text('--');
      $cityDropdownTitle.data('selected', '');
      $cityDropdownBtn.find('.subtitle').text('');
      this.renderInvalidCompensation();
      this.renderFormula();
    }

    // Render functions

    SalaryCalculator.prototype.getData = function() {
      var deferred = jQuery.Deferred();

      $.get('/salary/data.json').then(function(data) {
        // Cache the data
        this.data = data;
        deferred.resolve();
      }.bind(this));

      return deferred.promise();
    }

    SalaryCalculator.prototype.render = function() {
      var input = this.getElementValues();

      function renderData() {
        if (input.country && input.city && input.level && input.experience.min && input.experience.max) {
          this.renderCompensation(input);
        } else {
          this.renderInvalidCompensation();
        }
        this.renderFormula();
        this.renderContractType();
      }

      if (this.data) {
        renderData.call(this);
      } else {
        $.when(this.getData()).then(function() {
            renderData.call(this);
          }.bind(this),
          this.renderInvalidCompensation.bind(this));
      }
    }

    SalaryCalculator.prototype.renderCompensation = function(input) {
      var numbeo = this.data.numbeo;
      var contracts = this.data.contractTypes;

      var levelIndex = parseFloat(input.level);
      var benchmark = input.salary;

      var rentIndex = this.calculateRentIndex(input.city, input.country);
      var contract = this.calculateContractFactor(input.country);

      if (!rentIndex) {
        //When the city and country combination selected do not exist
        return this.renderInvalidCompensation();
      }

      var min = this.calculateCompensation(benchmark, rentIndex, levelIndex, contract.factor, input.experience.min);
      var max = this.calculateCompensation(benchmark, rentIndex, levelIndex, contract.factor, input.experience.max);
      $(compensationAmount).text(this.formatAmount(min) + ' - ' + this.formatAmount(max) + ' USD');
    }

    SalaryCalculator.prototype.renderContractType = function() {
      var country = this.getElementValues().country;
      var contract = this.calculateContractFactor(country);
      var $container = $('.contract-type-container');

      if (contract.type === CONTRACT_TYPE_EMPLOYEE) {
        $container.find('.grammer').text('an');
        $container.find('.company-type').text('Inc.');
        $container.find('.contract-type').text('employee');
      } else {
        $container.find('.grammer').text('a');
        $container.find('.company-type').text('BV.');
        $container.find('.contract-type').text('contractor');
      }

      $container.removeClass('hidden');
    }

    SalaryCalculator.prototype.renderFormula = function() {
      var values = this.getElementValues();
      var rentIndex = this.calculateRentIndex(values.city, values.country);
      var contract = this.calculateContractFactor(values.country);
      var experience = values.experience;

      $('.formula .level .value').text(values.level ? values.level : defaultValue);
      $('.formula .experience .value').text(experience.min && experience.max ? experience.min + ' to ' + experience.max : defaultValue);

      $('.formula .rentIndex .value').text(rentIndex ? rentIndex : defaultValue);
      $('.formula .contractType .value').text(contract.hasOwnProperty('factor') ? contract.factor.toFixed(2) : defaultValue);
    }

    SalaryCalculator.prototype.renderInvalidCompensation = function() {
      $(compensationAmount).text(defaultValue);
    }

    // Pure functions

    SalaryCalculator.prototype.getElementValues = function() {
      return {
        salary: $(salaryContainer).data('salary') || '',
        country: $(salaryContainer + ' .country .title').data('selected') || '',
        city: $(salaryContainer + ' .city .title').data('selected') || '',
        level: $(salaryContainer + ' .level .title').data('selected') || '',
        experience: {
          min: $(salaryContainer + ' .experience .title').data('min') || '',
          max: $(salaryContainer + ' .experience .title').data('max') || ''
        }
      };
    }

    SalaryCalculator.prototype.calculateRentIndex = function(city, country) {
      if (this.data && this.data.numbeo) {
        var locationData = this.data.numbeo.find(function(o) {
          return o.country === country && o.city === city;
        });

        return locationData ? parseFloat((locationData.rentIndex * 0.01).toFixed(2)) : 0;
      }

      // Rent Index will never be zero, safe to return as error value
      return 0;
    }

    SalaryCalculator.prototype.calculateContractFactor = function(country) {
      var contract = {};

      if (this.data && this.data.contractTypes) {
        var defaultContractorFactor = this.data.contractTypes.find(function (o) {
          return o.country === '*';
        }).contractor_factor;

        var contractType = this.data.contractTypes.find(function(o) {
          return o.country === country
        });

        if (contractType && contractType.hasOwnProperty(CONTRACT_TYPE_EMPLOYEE)) {
          contract.type = CONTRACT_TYPE_EMPLOYEE;
          contract.factor = contractType[CONTRACT_TYPE_EMPLOYEE];
        } else if (contractType) {
          contract.type = CONTRACT_TYPE_CONTRACTOR;
          contract.factor = contractType[CONTRACT_TYPE_CONTRACTOR];
        } else {
          contract.type = CONTRACT_TYPE_CONTRACTOR;
          contract.factor = defaultContractorFactor;
        }
      }

      return contract;
    }

    SalaryCalculator.prototype.calculateCompensation = function(benchmark, rentIndex, levelIndex, contractType, experienceFactor) {
      return Math.round(benchmark * (rentIndex + 0.25) * levelIndex * contractType * experienceFactor);
    };

    SalaryCalculator.prototype.formatAmount = function(amount) {
      return '$' + amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }

    return SalaryCalculator;
  })();

  new SalaryCalculator();
})();
<|endoftext|>


<commit_before>"use strict";

var fs = require('fs');
var path = require('path');

var mkdirp = require('mkdirp');
var async = require('async');
var chalk = require('chalk');
var filesize = require('filesize');
var Optimizer = require('./lib/optimizer');

module.exports = function (grunt) {
  grunt.registerMultiTask('image', 'Optimize PNG, JPEG, GIF images.', function() {
    var done = this.async();
    var options = this.options({});

    async.eachLimit(this.files, 10, function (file, next) {

      // make directory if does not exist
      mkdirp.sync(path.dirname(file.dest));

      var optimizer = new Optimizer({
        src: file.src[0],
        dest: file.dest,
        options: options
      });

      optimizer.optimize(function (error, data) {
        if (error) {
          grunt.warn(error);
          return next(error);
        }
        grunt.log.writeln(
          chalk.green('✔ ') + file.src[0] + chalk.gray(' ->') +
          chalk.gray(' before=') + chalk.yellow(filesize(data.original)) +
          chalk.gray(' after=') + chalk.cyan(filesize(data.optimized)) +
          chalk.gray(' reduced=') + chalk.green.underline(filesize(data.diff) + '(' + data.diffPercent + '%)')
        );
        next();
      });
    }, function (error) {
      if (error) {
        grunt.warn(error);
        return done(error);
      }
      done();
    });
  });
};
<commit_msg>remove dependency<commit_after>"use strict";

var path = require('path');
var mkdirp = require('mkdirp');
var async = require('async');
var chalk = require('chalk');
var filesize = require('filesize');
var Optimizer = require('./lib/optimizer');

module.exports = function (grunt) {
  grunt.registerMultiTask('image', 'Optimize PNG, JPEG, GIF images.', function() {
    var done = this.async();
    var options = this.options({});

    async.eachLimit(this.files, 10, function (file, next) {

      // make directory if does not exist
      mkdirp.sync(path.dirname(file.dest));

      var optimizer = new Optimizer({
        src: file.src[0],
        dest: file.dest,
        options: options
      });

      optimizer.optimize(function (error, data) {
        if (error) {
          grunt.warn(error);
          return next(error);
        }
        grunt.log.writeln(
          chalk.green('✔ ') + file.src[0] + chalk.gray(' ->') +
          chalk.gray(' before=') + chalk.yellow(filesize(data.original)) +
          chalk.gray(' after=') + chalk.cyan(filesize(data.optimized)) +
          chalk.gray(' reduced=') + chalk.green.underline(filesize(data.diff) + '(' + data.diffPercent + '%)')
        );
        next();
      });
    }, function (error) {
      if (error) {
        grunt.warn(error);
        return done(error);
      }
      done();
    });
  });
};
<|endoftext|>


<commit_before>// @flow
import assert from 'assert'
import Task from '@start/task/src/'
import Reporter from '@start/reporter/src/'
import subTask from '@start/sub-task/src/'
import env from '@start/env/src'
import find from '@start/find/src/'
import findGitStaged from '@start/find-git-staged/src/'
import clean from '@start/clean/src/'
import read from '@start/read/src'
import babel from '@start/babel/src'
import write from '@start/write/src'
import watch from '@start/watch/src'
import eslint from '@start/eslint/src/'
import { istanbulInstrument, istanbulReport /*, istanbulThresholds */ } from '@start/istanbul/src/'
import tape from '@start/tape/src'
import npmVersion from '@start/npm-version/src/'
import npmPublish from '@start/npm-publish/src/'
import tapDiff from 'tap-diff'

const reporter = Reporter()
const task = Task(reporter)

const babelConfig = {
  babelrc: false,
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 6,
        },
        exclude: ['transform-regenerator'],
      },
    ],
    '@babel/preset-flow',
  ],
  plugins: ['@babel/plugin-proposal-object-rest-spread'],
}

export const build = (packageName: string) => {
  assert(packageName, 'Package name has not been provided')

  return task(
    env('NODE_ENV', 'production'),
    find(`packages/${packageName}/build/`),
    clean,
    find(`packages/${packageName}/src/**/*.js`),
    read,
    babel(babelConfig),
    write(`packages/${packageName}/build/`)
  )
}

export const dev = (packageName: string) => {
  assert(packageName, 'Package name has not been provided')

  return task(
    find(`packages/${packageName}/build/`),
    clean,
    watch(`packages/${packageName}/src/**/*.js`)(
      task(read, babel(babelConfig), write(`packages/${packageName}/build/`))
    )
  )
}

export const lint = () =>
  task(findGitStaged(['packages/*/@(src|test)/**/*.js', 'tasks/**/*.js']), eslint())

export const lintAll = () =>
  task(find(['packages/*/@(src|test)/**/*.js', 'tasks/**/*.js']), eslint())

export const test = () =>
  task(
    find('packages/*/src/**/*.js'),
    istanbulInstrument({ esModules: true }),
    find('packages/*/test/**/*.js'),
    tape(tapDiff),
    istanbulReport(['lcovonly', 'html', 'text-summary'])
    // istanbulThresholds({ functions: 70 })
  )

export const ci = () => task(subTask(lintAll)(), subTask(test)())

export const publish = (packageName: string, version: string, otp: string) =>
  task(
    npmVersion(version, `packages/${packageName}`),
    npmPublish(`packages/${packageName}`, { otp })
  )
<commit_msg>:construction_worker: prepend `ci` subtask to `publish`<commit_after>// @flow
import assert from 'assert'
import Task from '@start/task/src/'
import Reporter from '@start/reporter/src/'
import subTask from '@start/sub-task/src/'
import env from '@start/env/src'
import find from '@start/find/src/'
import findGitStaged from '@start/find-git-staged/src/'
import clean from '@start/clean/src/'
import read from '@start/read/src'
import babel from '@start/babel/src'
import write from '@start/write/src'
import watch from '@start/watch/src'
import eslint from '@start/eslint/src/'
import { istanbulInstrument, istanbulReport /*, istanbulThresholds */ } from '@start/istanbul/src/'
import tape from '@start/tape/src'
import npmVersion from '@start/npm-version/src/'
import npmPublish from '@start/npm-publish/src/'
import tapDiff from 'tap-diff'

const reporter = Reporter()
const task = Task(reporter)

const babelConfig = {
  babelrc: false,
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 6,
        },
        exclude: ['transform-regenerator'],
      },
    ],
    '@babel/preset-flow',
  ],
  plugins: ['@babel/plugin-proposal-object-rest-spread'],
}

export const build = (packageName: string) => {
  assert(packageName, 'Package name has not been provided')

  return task(
    env('NODE_ENV', 'production'),
    find(`packages/${packageName}/build/`),
    clean,
    find(`packages/${packageName}/src/**/*.js`),
    read,
    babel(babelConfig),
    write(`packages/${packageName}/build/`)
  )
}

export const dev = (packageName: string) => {
  assert(packageName, 'Package name has not been provided')

  return task(
    find(`packages/${packageName}/build/`),
    clean,
    watch(`packages/${packageName}/src/**/*.js`)(
      task(read, babel(babelConfig), write(`packages/${packageName}/build/`))
    )
  )
}

export const lint = () =>
  task(findGitStaged(['packages/*/@(src|test)/**/*.js', 'tasks/**/*.js']), eslint())

export const lintAll = () =>
  task(find(['packages/*/@(src|test)/**/*.js', 'tasks/**/*.js']), eslint())

export const test = () =>
  task(
    find('packages/*/src/**/*.js'),
    istanbulInstrument({ esModules: true }),
    find('packages/*/test/**/*.js'),
    tape(tapDiff),
    istanbulReport(['lcovonly', 'html', 'text-summary'])
    // istanbulThresholds({ functions: 70 })
  )

export const ci = () => task(subTask(lintAll)(), subTask(test)())

export const publish = (packageName: string, version: string, otp: string) =>
  task(
    subTask(ci)(),
    npmVersion(version, `packages/${packageName}`),
    npmPublish(`packages/${packageName}`, { otp })
  )
<|endoftext|>


<commit_before>// API/controllers/search.js

/**
* @apiDefine SearchObjectPostParam
*
* @apiParam {String} [name] Name of the ingredient (Regex)
* @apiParam {String[]} [tags] Name of the tags that your ingredient must have.
* @apiParam {Object[]} [order] Order of the return of the search
* @apiParam {String} [order.order] Order (can be asc or desc)
* @apiParam {String} [order.field] Field which is order (ex: fat)
* @apiParam {Object[]} metadata Number of items to return, page of the items
* @apiParam {String} metadata.items number of items that are return for the current page
* @apiParam {String} metadata.page Number of the page that you want to ask
*/

/**
* @apiDefine SearchRequestJSON
*
* @apiParamExample {json} Request-Example:
*{
*    "name": "fu",
*    "order": {"order": "desc",
*              "field": "fat"
*    },
*    "tags": ['fruit'],
*    "metadata": {"items": 1,
*                  "page": 1
*    }
*}
*/

var Ingredients = require('../models/ingredients');
var Recipes = require('../models/recipes')

/*
** POSTS
*/

/**
* @api {post} /search/ingredients/ Search some Ingredients
* @apiName postSearch
* @apiGroup Search
* @apiVersion 0.1.0
*
* @apiUse SearchObjectPostParam
*
* @apiUse SearchRequestJSON
*
* @apiSuccessExample Success-Response
*     HTTP/1.1 200 OK
*	  {
*		"metadata": [{"current_page": "2",
*			      "total_page": "24",
*			       "order": {"field": "fat",
*					 "order": "desc"},
*				"name": "Tom"}],
*		"Ingredients": [{"_id" : "561830c5fecdba4f72668fe8",
*      				"name": "Tomato",
*      				"description": "Very yummy fruit."
*				"fat" : 0.3,
*				"carbohydrates" : 5.8,
*				"protein" : 1.3,
*				"tags" : [{
*					"name" : "fruit",
*					"description" : "Tag concerning fruits",
*					"flag" : {
*								"name" : "SAFE",
*								"level" : 0
*							 }
*				   }]
*	  }
*
* @apiError message Nothing find for this search
* @apiErrorExample Invalid Parameter Value
*     HTTP/1.1 404 Not Found
*     {
*       "message": "You must at least set a name or a tag to search"
*     }
*
* @apiErrorExample  No metadata find
*     HTTP/1.1 404 Not Found
*     {
*       "message": "You must set the metadata"
*     }
*
* @apiErrorExample  No order field find
*     HTTP/1.1 404 Not Found
*     {
*       "message": "The order.field must be set"
*     }
*/

exports.postSearchIngredients = function (req, res, flag) {
	var name =  req.body.name;
	var order = ""
	if (req.body.order) {
		var order = req.body.order
		var order_order = req.body.order.order;
		var order_field = req.body.order.field;
		var query = {};
		query[order_field] = order_order;
	}
	var metadata = ""
	if (req.body.metadata){
		metadata = req.body.metadata
		var items_number = req.body.metadata.items;
		var items_page = req.body.metadata.page;
	}
	var tag_list = req.body.tags;

	//If name and tags are not set

	if (!name && !tag_list)
		return flag === true ? -1 : res.status(400).send({message : 'You must at least set a name or a tag to search'})

	if (metadata == "")
		return flag === true ? -1 : res.status(400).send({message : 'You must set the metadata'})

	//If name and tags are set

	if (name && tag_list){

	var Json_search = {
				"name": { "$regex": name, "$options": "i" },
				"tags.name": { $all: tag_list}
			  };
	var newjson = {metadata: {current_page: items_page, order: order, tags: tag_list, name: name}}

	}

	//If only name is set

	else if (name && !tag_list){

	var Json_search = {
				"name": { "$regex": name, "$options": "i" }
			  };
	var newjson = {metadata: {current_page: items_page, order: order, name: name}}

	}

	//If only tags is set

	else if (!name && tag_list){

	var Json_search = {
				"tags.name": { $all: tag_list}
			  };
	var newjson = {metadata: {current_page: items_page, order: order, tags: tag_list}}

	}

	var total_page
	Ingredients.find(Json_search,
		function (err, docs) {
			total_page = Math.round(docs.length / items_number);
		if (total_page <= 0)
			total_page = 1
		}
	)

		if (order === ""){
			Ingredients.find(
				Json_search
				,
				function (err, docs) {
					if (err)
						return (res.send(err));
					else if (docs.length <= 0)
						return (res.status(404).send({message : 'Nothing find for this search'}))
					else{
						newjson.metadata.total_page = total_page
						newjson.ingredients = docs
						return (res.json(newjson));
					}
				}
		).skip((items_page - 1) * items_number).limit(items_number);
		}
		else if (order != ""){

			if (order_order == "desc")
				order_order = -1
			else
				order_order = 1
			if (!order_field)
				return flag === true ? -1 : res.status(404).send({message : 'The order.field must be set'})
			Ingredients.find(
				Json_search,
				function (err, docs) {
					if (err){
						return (res.send(err));
						}
					else if (docs.length <= 0){
						return (res.status(404).send({message : 'Nothing find for this search'}))}
					else{
						newjson.metadata.total_page = total_page
						newjson.ingredients = docs
						return (res.json(newjson));
					}
				}
		).skip((items_page - 1) * items_number).sort(query).limit(items_number);
	    }
	return (1);
};

exports.postSearchRecipes = function (req, res, flag) {

	var title =  req.body.title;
	var order = ""
	if (req.body.order) {
		var order = req.body.order
		var order_order = req.body.order.order;
		var order_field = req.body.order.field;
		var query = {};
		query[order_field] = order_order;
	}
	var metadata = ""
	if (req.body.metadata){
		metadata = req.body.metadata
		var items_number = req.body.metadata.items;
		var items_page = req.body.metadata.page;
	}

	var type_list = req.body.type;

	//If title and types are not set

	if (!title && !type_list)
		return flag === true ? -1 : res.status(400).send({message : 'You must at least set a title or a type to search'})

	if (metadata == "")
		return flag === true ? -1 : res.status(400).send({message : 'You must set the metadata'})

		//If title and tags are set

	if (title && type_list){

	var Json_search = {
				"title": { "$regex": title, "$options": "i" },
				"tags.name": { $all: tag_list}
			  };
	var newjson = {metadata: {current_page: items_page, order: order, tags: tag_list, title: title}}

	}

	//If only name is set

	else if (title && !type_list){

	var Json_search = {
				"title": { "$regex": title, "$options": "i" }
			  };
	var newjson = {metadata: {current_page: items_page, order: order, title: title}}

	}

	//If only tags is set

	else if (!title && tag_list){

	var Json_search = {
				"tags.name": { $all: tag_list}
			  };
	var newjson = {metadata: {current_page: items_page, order: order, tags: tag_list}}

	}

	var total_page
	Recipes.find(Json_search,
		function (err, docs) {
			total_page = Math.round(docs.length / items_number);
		if (total_page <= 0)
			total_page = 1
		}
	)

		if (order === ""){
			Recipes.find(
				Json_search
				,
				function (err, docs) {
					if (err)
						return (res.send(err));
					else if (docs.length <= 0)
						return (res.status(404).send({message : 'Nothing find for this search'}))
					else{
						newjson.metadata.total_page = total_page
						newjson.ingredients = docs
						return (res.json(newjson));
					}
				}
		).skip((items_page - 1) * items_number).limit(items_number);
		}
		else if (order != ""){

			if (order_order == "desc")
				order_order = -1
			else
				order_order = 1
			if (!order_field)
				return flag === true ? -1 : res.status(404).send({message : 'The order.field must be set'})
			Recipes.find(
				Json_search,
				function (err, docs) {
					if (err){
						return (res.send(err));
						}
					else if (docs.length <= 0){
						return (res.status(404).send({message : 'Nothing find for this search'}))}
					else{
						newjson.metadata.total_page = total_page
						newjson.ingredients = docs
						return (res.json(newjson));
					}
				}
		).skip((items_page - 1) * items_number).sort(query).limit(items_number);
	    }
	return (1);
}
<commit_msg>Search/Recipes Id_Flag + Fix<commit_after>// API/controllers/search.js

/**
* @apiDefine SearchObjectPostParam
*
* @apiParam {String} [name] Name of the ingredient (Regex)
* @apiParam {String[]} [tags] Name of the tags that your ingredient must have.
* @apiParam {Object[]} [order] Order of the return of the search
* @apiParam {String} [order.order] Order (can be asc or desc)
* @apiParam {String} [order.field] Field which is order (ex: fat)
* @apiParam {Object[]} metadata Number of items to return, page of the items
* @apiParam {String} metadata.items number of items that are return for the current page
* @apiParam {String} metadata.page Number of the page that you want to ask
*/

/**
* @apiDefine SearchRequestJSON
*
* @apiParamExample {json} Request-Example:
*{
*    "name": "fu",
*    "order": {"order": "desc",
*              "field": "fat"
*    },
*    "tags": ['fruit'],
*    "metadata": {"items": 1,
*                  "page": 1
*    }
*}
*/

var Ingredients = require('../models/ingredients');
var Recipes = require('../models/recipes')

/*
** POSTS
*/

/**
* @api {post} /search/ingredients/ Search some Ingredients
* @apiName postSearch
* @apiGroup Search
* @apiVersion 0.1.0
*
* @apiUse SearchObjectPostParam
*
* @apiUse SearchRequestJSON
*
* @apiSuccessExample Success-Response
*     HTTP/1.1 200 OK
*	  {
*		"metadata": [{"current_page": "2",
*			      "total_page": "24",
*			       "order": {"field": "fat",
*					 "order": "desc"},
*				"name": "Tom"}],
*		"Ingredients": [{"_id" : "561830c5fecdba4f72668fe8",
*      				"name": "Tomato",
*      				"description": "Very yummy fruit."
*				"fat" : 0.3,
*				"carbohydrates" : 5.8,
*				"protein" : 1.3,
*				"tags" : [{
*					"name" : "fruit",
*					"description" : "Tag concerning fruits",
*					"flag" : {
*								"name" : "SAFE",
*								"level" : 0
*							 }
*				   }]
*	  }
*
* @apiError message Nothing find for this search
* @apiErrorExample Invalid Parameter Value
*     HTTP/1.1 404 Not Found
*     {
*       "message": "You must at least set a name or a tag to search"
*     }
*
* @apiErrorExample  No metadata find
*     HTTP/1.1 404 Not Found
*     {
*       "message": "You must set the metadata"
*     }
*
* @apiErrorExample  No order field find
*     HTTP/1.1 404 Not Found
*     {
*       "message": "The order.field must be set"
*     }
*/

exports.postSearchIngredients = function (req, res, flag) {
	var name =  req.body.name;
	var order = ""
	if (req.body.order) {
		var order = req.body.order
		var order_order = req.body.order.order;
		var order_field = req.body.order.field;
		var query = {};
		query[order_field] = order_order;
	}
	var metadata = ""
	if (req.body.metadata){
		metadata = req.body.metadata
		var items_number = req.body.metadata.items;
		var items_page = req.body.metadata.page;
	}
	var tag_list = req.body.tags;

	//If name and tags are not set

	if (!name && !tag_list)
		return flag === true ? -1 : res.status(400).send({message : 'You must at least set a name or a tag to search'})

	if (metadata == "")
		return flag === true ? -1 : res.status(400).send({message : 'You must set the metadata'})

	//If name and tags are set

	if (name && tag_list){

	var Json_search = {
				"name": { "$regex": name, "$options": "i" },
				"tags.name": { $all: tag_list}
			  };
	var newjson = {metadata: {current_page: items_page, order: order, tags: tag_list, name: name}}

	}

	//If only name is set

	else if (name && !tag_list){

	var Json_search = {
				"name": { "$regex": name, "$options": "i" }
			  };
	var newjson = {metadata: {current_page: items_page, order: order, name: name}}

	}

	//If only tags is set

	else if (!name && tag_list){

	var Json_search = {
				"tags.name": { $all: tag_list}
			  };
	var newjson = {metadata: {current_page: items_page, order: order, tags: tag_list}}

	}

	var total_page
	Ingredients.find(Json_search,
		function (err, docs) {
			total_page = Math.round(docs.length / items_number);
		if (total_page <= 0)
			total_page = 1
		}
	)

		if (order === ""){
			Ingredients.find(
				Json_search
				,
				function (err, docs) {
					if (err)
						return (res.send(err));
					else if (docs.length <= 0)
						return (res.status(404).send({message : 'Nothing find for this search'}))
					else{
						newjson.metadata.total_page = total_page
						newjson.ingredients = docs
						return (res.json(newjson));
					}
				}
		).skip((items_page - 1) * items_number).limit(items_number);
		}
		else if (order != ""){

			if (order_order == "desc")
				order_order = -1
			else
				order_order = 1
			if (!order_field)
				return flag === true ? -1 : res.status(404).send({message : 'The order.field must be set'})
			Ingredients.find(
				Json_search,
				function (err, docs) {
					if (err){
						return (res.send(err));
						}
					else if (docs.length <= 0){
						return (res.status(404).send({message : 'Nothing find for this search'}))}
					else{
						newjson.metadata.total_page = total_page
						newjson.ingredients = docs
						return (res.json(newjson));
					}
				}
		).skip((items_page - 1) * items_number).sort(query).limit(items_number);
	    }
	return (1);
};

exports.postSearchRecipes = function (req, res, flag) {

	var title =  req.body.title;
	var order = ""
	if (req.body.order) {
		var order = req.body.order
		var order_order = req.body.order.order;
		var order_field = req.body.order.field;
		var query = {};
		query[order_field] = order_order;
	}
	var metadata = ""
	if (req.body.metadata){
		metadata = req.body.metadata
		var items_number = req.body.metadata.items;
		var items_page = req.body.metadata.page;
	}

	var type_list = req.body.type;

	//If title and types are not set

	if (!title && !type_list)
		return flag === true ? -1 : res.status(400).send({message : 'You must at least set a title or a type to search'})

	if (metadata == "")
		return flag === true ? -1 : res.status(400).send({message : 'You must set the metadata'})

		//If title and tags are set

	if (title && type_list){

	var Json_search = {
				"title": { "$regex": title, "$options": "i" },
				"tags.id_type": { $all: tag_list}
			  };
	var newjson = {metadata: {current_page: items_page, order: order, tags: tag_list, title: title}}

	}

	//If only name is set

	else if (title && !type_list){

	var Json_search = {
				"title": { "$regex": title, "$options": "i" }
			  };
	var newjson = {metadata: {current_page: items_page, order: order, title: title}}

	}

	//If only tags is set

	else if (!title && tag_list){

	var Json_search = {
				"tags.id_type": { $all: tag_list}
			  };
	var newjson = {metadata: {current_page: items_page, order: order, tags: tag_list}}

	}

	var total_page
	Recipes.find(Json_search,
		function (err, docs) {
			total_page = Math.round(docs.length / items_number);
		if (total_page <= 0)
			total_page = 1
		}
	)

		if (order === ""){
			Recipes.find(
				Json_search
				,
				function (err, docs) {
					if (err)
						return (res.send(err));
					else if (docs.length <= 0)
						return (res.status(404).send({message : 'Nothing find for this search'}))
					else{
						newjson.metadata.total_page = total_page
						newjson.ingredients = docs
						return (res.json(newjson));
					}
				}
		).skip((items_page - 1) * items_number).limit(items_number);
		}
		else if (order != ""){

			if (order_order == "desc")
				order_order = -1
			else
				order_order = 1
			if (!order_field)
				return flag === true ? -1 : res.status(404).send({message : 'The order.field must be set'})
			Recipes.find(
				Json_search,
				function (err, docs) {
					if (err){
						return (res.send(err));
						}
					else if (docs.length <= 0){
						return (res.status(404).send({message : 'Nothing find for this search'}))}
					else{
						newjson.metadata.total_page = total_page
						newjson.ingredients = docs
						return (res.json(newjson));
					}
				}
		).skip((items_page - 1) * items_number).sort(query).limit(items_number);
	    }
	return (1);
}
<|endoftext|>


<commit_before>(function (enyo, scope) {
	/**
	* {@link enyo.TranslateScrollStrategy} is a helper [kind]{@glossary kind} that extends
	* {@link enyo.TouchScrollStrategy}, optimizing it for scrolling environments in which effecting
	* scroll changes with transforms using CSS translations is fastest.
	*
	* `enyo.TranslateScrollStrategy` is not typically created in application code. Instead, it is
	* specified as the value of the [strategyKind]{@link enyo.Scroller#strategyKind} property of
	* an {@link enyo.Scroller} or {@link enyo.List}, or is used by the framework implicitly.
	*
	* @class enyo.TranslateScrollStrategy
	* @extends enyo.TouchScrollStrategy
	* @protected
	*/
	enyo.kind(
		/** @lends enyo.TranslateScrollStrategy.prototype */ {

		/**
		* @private
		*/
		name: 'enyo.TranslateScrollStrategy',

		/**
		* @private
		*/
		kind: 'enyo.TouchScrollStrategy',

		/**
		* Set to `true` to optimize the strategy to only use translation to scroll; this increases
		* fluidity of scrolling animation. It should not be used when the
		* [scroller]{@link enyo.Scroller} contains [controls]{@link enyo.Control} that require
		* keyboard input. This is because when `translateOptimized` is `true`, it is possible to
		* position inputs such that they will not become visible when focused.
		*
		* @type {Boolean}
		* @default false
		* @public
		*/
		translateOptimized: false,

		/**
		* @private
		*/
		components: [
			{name: 'clientContainer', classes: 'enyo-touch-scroller', components: [
				{name: 'client'}
			]}
		],

		/**
		* @method
		* @private
		*/
		rendered: enyo.inherit(function (sup) {
			return function() {
				sup.apply(this, arguments);
				enyo.makeBubble(this.$.clientContainer, 'scroll');
				if (this.translateOptimized) {
					this.setStartPosition();
				}
			};
		}),

		/**
		* @method
		* @private
		*/
		setStartPosition: function() {
			this.startX = this.getScrollLeft();
			this.startY = this.getScrollTop();
		},

		/**
		* @private
		*/
		getScrollSize: function () {
			var n = this.$.client.hasNode();
			return {width: n ? n.scrollWidth : 0, height: n ? n.scrollHeight : 0};
		},

		/**
		* @method
		* @private
		*/
		create: enyo.inherit(function (sup) {
			return function() {
				sup.apply(this, arguments);
				// apply initial transform so we're always composited
				enyo.dom.transformValue(this.$.client, this.translation, '0,0,0');
			};
		}),

		/**
		* @private
		*/
		calcScrollNode: function () {
			return this.$.clientContainer.hasNode();
		},

		/**
		* @private
		*/
		maxHeightChanged: function () {
			// content should cover scroller at a minimum if there's no max-height.
			this.$.client.applyStyle('min-height', this.maxHeight ? null : '100%');
			this.$.client.applyStyle('max-height', this.maxHeight);
			this.$.clientContainer.addRemoveClass('enyo-scrollee-fit', !this.maxHeight);
		},

		/**
		* @method
		* @private
		*/
		shouldDrag: enyo.inherit(function (sup) {
			return function(inEvent) {
				// stop and update drag info before checking drag status
				this.stop();
				this.calcStartInfo();
				return sup.apply(this, arguments);
			};
		}),

		/**
		* @method
		* @private
		*/
		syncScrollMath: enyo.inherit(function (sup) {
			return function() {
				if (!this._translated) {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* Sets the horizontal scroll position.
		*
		* @param {Number} left - The horizontal scroll position in pixels.
		* @method
		* @public
		*/
		setScrollLeft: enyo.inherit(function (sup) {
			return function(inLeft) {
				var m, p;
				if (this.translateOptimized) {
					p = this.scrollLeft;
					m = this.$.scrollMath;
					this.stop(true);
					// This will result in a call to
					// ScrollMath.stabilize(), ensuring
					// that we stay in bounds
					m.setScrollX(-inLeft);
					if (p != -inLeft) {
						// We won't get a native scroll event,
						// so need to make one ourselves
						m.doScroll();
						this.delayHideThumbs(100);
					}
				} else {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* Sets the vertical scroll position.
		*
		* @param {Number} top - The vertical scroll position in pixels.
		* @method
		* @public
		*/
		setScrollTop: enyo.inherit(function (sup) {
			return function(inTop) {
				var m, p;
				if (this.translateOptimized) {
					p = this.scrollTop;
					m = this.$.scrollMath;
					this.stop(true);
					// This will result in a call to
					// ScrollMath.stabilize(), ensuring
					// that we stay in bounds
					m.setScrollY(-inTop);
					if (p != -inTop) {
						// We won't get a native scroll event,
						// so need to make one ourselves
						m.doScroll();
						this.delayHideThumbs(100);
					}
				} else {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* Retrieves the horizontal scroll position.
		*
		* @returns {Number} The horizontal scroll position in pixels.
		* @method
		* @public
		*/
		getScrollLeft: enyo.inherit(function (sup) {
			return function() {
				return this._translated ? this.scrollLeft: sup.apply(this, arguments);
			};
		}),

		/**
		* Retrieves the vertical scroll position.
		*
		* @returns {Number} The vertical scroll position in pixels.
		* @method
		* @private
		*/
		getScrollTop: enyo.inherit(function (sup) {
			return function() {
				return this._translated ? this.scrollTop : sup.apply(this, arguments);
			};
		}),

		/**
		* @method
		* @private
		*/
		calcBoundaries: enyo.inherit(function (sup) {
			return function() {
				sup.apply(this, arguments);
				if (this.translateOptimized && !this.isScrolling()) this.stabilize();
			};
		}),

		/**
		* @method
		* @private
		*/
		handleResize: function() {
			if (this.translateOptimized) {
				this.stabilize();
			}
		},

		/**
		* @method
		* @private
		*/
		scrollMathStart: enyo.inherit(function (sup) {
			return function() {
				sup.apply(this, arguments);
				if (!this._translated) {
					this.setStartPosition();
				}
			};
		}),

		/**
		* @private
		*/
		scrollMathScroll: function (sender) {
			if(!this.overscroll) { //don't overscroll past edges
				this.scrollLeft = -Math.min(sender.leftBoundary, Math.max(sender.rightBoundary, sender.x));
				this.scrollTop = -Math.min(sender.topBoundary, Math.max(sender.bottomBoundary, sender.y));
			} else {
				this.scrollLeft = -sender.x;
				this.scrollTop = -sender.y;
			}
			this.effectScroll(this.scrollLeft, this.scrollTop);
			if (this.thumb) {
				this.showThumbs();
			}
		},

		/**
		* @private
		*/
		scrollMathStabilize: enyo.inherit(function (sup) {
			return function (sender) {
				if (this._translated) {
					this.scrollLeft = -sender.x;
					this.scrollTop = -sender.y;
					this.effectScroll(-sender.x, -sender.y);
				} else {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* While moving, scroller uses translate.
		*
		* @private
		*/
		effectScroll: enyo.inherit(function (sup) {
			return function (x, y) {
				var o;
				if (this.translateOptimized || this.isScrolling()) {
					x = this.startX - x;
					y = this.startY - y;
					o = x + 'px, ' + y + 'px' + (this.accel ? ',0' : '');
					enyo.dom.transformValue(this.$.client, this.translation, o);
					this._translated = true;
				} else {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* When stopped, we use `scrollLeft/scrollTop` (makes cursor positioning automagic).
		*
		* @private
		*/
		effectScrollStop: function () {
			if (!this.translateOptimized) {
				var t = '0,0' + (this.accel ? ',0' : '');
				// FIXME: normally translate3d changes not effect scrollHeight; however
				// there appear to be some dom changes (e.g. showing a node inside the scroller,
				// which do cause the scrollHeight to be changed from the translate3d.
				// In this case setting the translate3d back to 0 does not restore scrollHeight.
				// This causes a problem because setting scrollTop can produced an unexpected result if
				// scrollHeight is less than expected.
				// We detect this fault by validating scroll bounds and (1) un-apply the translate3d,
				// (2) update scrollTop/Left, and (3) re-apply a 0,0,0 translate3d to ensure compositing.
				// Luckily this corrects the problem (which appears to be a webkit bug). Note that
				// it's important to maintain a composited state (translate3d 0,0,0) or Android 4 is
				// slow to start scrolling.
				var m = this.$.scrollMath, sb = this._getScrollBounds();
				var needsBoundsFix = Boolean((sb.maxTop + m.bottomBoundary) || (sb.maxLeft + m.rightBoundary));
				enyo.dom.transformValue(this.$.client, this.translation, needsBoundsFix ? null : t);
				// note: this asynchronously triggers dom scroll event
				this.setScrollLeft(this.scrollLeft);
				this.setScrollTop(this.scrollTop);
				if (needsBoundsFix) {
					enyo.dom.transformValue(this.$.client, this.translation, t);
				}
				this._translated = false;
			}
		},

		/**
		* FIXME: we can fix scrolling artifacts BUGS on Android 4.04 with this heinous incantation.
		*
		* @private
		*/
		twiddle: function () {
			if (this.translateOptimized && this.scrollNode) { // this.scrollNode is not always defined and makes Motorola XOOM crash
				this.scrollNode.scrollTop = 1;
				this.scrollNode.scrollTop = 0;
			}
		}
	});

})(enyo, this);
<commit_msg>ENYO-483: Fixing guard code to avoid extraneous scroll events<commit_after>(function (enyo, scope) {
	/**
	* {@link enyo.TranslateScrollStrategy} is a helper [kind]{@glossary kind} that extends
	* {@link enyo.TouchScrollStrategy}, optimizing it for scrolling environments in which effecting
	* scroll changes with transforms using CSS translations is fastest.
	*
	* `enyo.TranslateScrollStrategy` is not typically created in application code. Instead, it is
	* specified as the value of the [strategyKind]{@link enyo.Scroller#strategyKind} property of
	* an {@link enyo.Scroller} or {@link enyo.List}, or is used by the framework implicitly.
	*
	* @class enyo.TranslateScrollStrategy
	* @extends enyo.TouchScrollStrategy
	* @protected
	*/
	enyo.kind(
		/** @lends enyo.TranslateScrollStrategy.prototype */ {

		/**
		* @private
		*/
		name: 'enyo.TranslateScrollStrategy',

		/**
		* @private
		*/
		kind: 'enyo.TouchScrollStrategy',

		/**
		* Set to `true` to optimize the strategy to only use translation to scroll; this increases
		* fluidity of scrolling animation. It should not be used when the
		* [scroller]{@link enyo.Scroller} contains [controls]{@link enyo.Control} that require
		* keyboard input. This is because when `translateOptimized` is `true`, it is possible to
		* position inputs such that they will not become visible when focused.
		*
		* @type {Boolean}
		* @default false
		* @public
		*/
		translateOptimized: false,

		/**
		* @private
		*/
		components: [
			{name: 'clientContainer', classes: 'enyo-touch-scroller', components: [
				{name: 'client'}
			]}
		],

		/**
		* @method
		* @private
		*/
		rendered: enyo.inherit(function (sup) {
			return function() {
				sup.apply(this, arguments);
				enyo.makeBubble(this.$.clientContainer, 'scroll');
				if (this.translateOptimized) {
					this.setStartPosition();
				}
			};
		}),

		/**
		* @method
		* @private
		*/
		setStartPosition: function() {
			this.startX = this.getScrollLeft();
			this.startY = this.getScrollTop();
		},

		/**
		* @private
		*/
		getScrollSize: function () {
			var n = this.$.client.hasNode();
			return {width: n ? n.scrollWidth : 0, height: n ? n.scrollHeight : 0};
		},

		/**
		* @method
		* @private
		*/
		create: enyo.inherit(function (sup) {
			return function() {
				sup.apply(this, arguments);
				// apply initial transform so we're always composited
				enyo.dom.transformValue(this.$.client, this.translation, '0,0,0');
			};
		}),

		/**
		* @private
		*/
		calcScrollNode: function () {
			return this.$.clientContainer.hasNode();
		},

		/**
		* @private
		*/
		maxHeightChanged: function () {
			// content should cover scroller at a minimum if there's no max-height.
			this.$.client.applyStyle('min-height', this.maxHeight ? null : '100%');
			this.$.client.applyStyle('max-height', this.maxHeight);
			this.$.clientContainer.addRemoveClass('enyo-scrollee-fit', !this.maxHeight);
		},

		/**
		* @method
		* @private
		*/
		shouldDrag: enyo.inherit(function (sup) {
			return function(inEvent) {
				// stop and update drag info before checking drag status
				this.stop();
				this.calcStartInfo();
				return sup.apply(this, arguments);
			};
		}),

		/**
		* @method
		* @private
		*/
		syncScrollMath: enyo.inherit(function (sup) {
			return function() {
				if (!this._translated) {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* Sets the horizontal scroll position.
		*
		* @param {Number} left - The horizontal scroll position in pixels.
		* @method
		* @public
		*/
		setScrollLeft: enyo.inherit(function (sup) {
			return function(inLeft) {
				var m, p;
				if (this.translateOptimized) {
					p = this.scrollLeft;
					m = this.$.scrollMath;
					this.stop(true);
					// This will result in a call to
					// ScrollMath.stabilize(), ensuring
					// that we stay in bounds
					m.setScrollX(-inLeft);
					if (p != -m.x) {
						// We won't get a native scroll event,
						// so need to make one ourselves
						m.doScroll();
						this.delayHideThumbs(100);
					}
				} else {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* Sets the vertical scroll position.
		*
		* @param {Number} top - The vertical scroll position in pixels.
		* @method
		* @public
		*/
		setScrollTop: enyo.inherit(function (sup) {
			return function(inTop) {
				var m, p;
				if (this.translateOptimized) {
					p = this.scrollTop;
					m = this.$.scrollMath;
					this.stop(true);
					// This will result in a call to
					// ScrollMath.stabilize(), ensuring
					// that we stay in bounds
					m.setScrollY(-inTop);
					if (p != -m.y) {
						// We won't get a native scroll event,
						// so need to make one ourselves
						m.doScroll();
						this.delayHideThumbs(100);
					}
				} else {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* Retrieves the horizontal scroll position.
		*
		* @returns {Number} The horizontal scroll position in pixels.
		* @method
		* @public
		*/
		getScrollLeft: enyo.inherit(function (sup) {
			return function() {
				return this._translated ? this.scrollLeft: sup.apply(this, arguments);
			};
		}),

		/**
		* Retrieves the vertical scroll position.
		*
		* @returns {Number} The vertical scroll position in pixels.
		* @method
		* @private
		*/
		getScrollTop: enyo.inherit(function (sup) {
			return function() {
				return this._translated ? this.scrollTop : sup.apply(this, arguments);
			};
		}),

		/**
		* @method
		* @private
		*/
		calcBoundaries: enyo.inherit(function (sup) {
			return function() {
				sup.apply(this, arguments);
				if (this.translateOptimized && !this.isScrolling()) this.stabilize();
			};
		}),

		/**
		* @method
		* @private
		*/
		handleResize: function() {
			if (this.translateOptimized) {
				this.stabilize();
			}
		},

		/**
		* @method
		* @private
		*/
		scrollMathStart: enyo.inherit(function (sup) {
			return function() {
				sup.apply(this, arguments);
				if (!this._translated) {
					this.setStartPosition();
				}
			};
		}),

		/**
		* @private
		*/
		scrollMathScroll: function (sender) {
			if(!this.overscroll) { //don't overscroll past edges
				this.scrollLeft = -Math.min(sender.leftBoundary, Math.max(sender.rightBoundary, sender.x));
				this.scrollTop = -Math.min(sender.topBoundary, Math.max(sender.bottomBoundary, sender.y));
			} else {
				this.scrollLeft = -sender.x;
				this.scrollTop = -sender.y;
			}
			this.effectScroll(this.scrollLeft, this.scrollTop);
			if (this.thumb) {
				this.showThumbs();
			}
		},

		/**
		* @private
		*/
		scrollMathStabilize: enyo.inherit(function (sup) {
			return function (sender) {
				if (this._translated) {
					this.scrollLeft = -sender.x;
					this.scrollTop = -sender.y;
					this.effectScroll(-sender.x, -sender.y);
				} else {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* While moving, scroller uses translate.
		*
		* @private
		*/
		effectScroll: enyo.inherit(function (sup) {
			return function (x, y) {
				var o;
				if (this.translateOptimized || this.isScrolling()) {
					x = this.startX - x;
					y = this.startY - y;
					o = x + 'px, ' + y + 'px' + (this.accel ? ',0' : '');
					enyo.dom.transformValue(this.$.client, this.translation, o);
					this._translated = true;
				} else {
					sup.apply(this, arguments);
				}
			};
		}),

		/**
		* When stopped, we use `scrollLeft/scrollTop` (makes cursor positioning automagic).
		*
		* @private
		*/
		effectScrollStop: function () {
			if (!this.translateOptimized) {
				var t = '0,0' + (this.accel ? ',0' : '');
				// FIXME: normally translate3d changes not effect scrollHeight; however
				// there appear to be some dom changes (e.g. showing a node inside the scroller,
				// which do cause the scrollHeight to be changed from the translate3d.
				// In this case setting the translate3d back to 0 does not restore scrollHeight.
				// This causes a problem because setting scrollTop can produced an unexpected result if
				// scrollHeight is less than expected.
				// We detect this fault by validating scroll bounds and (1) un-apply the translate3d,
				// (2) update scrollTop/Left, and (3) re-apply a 0,0,0 translate3d to ensure compositing.
				// Luckily this corrects the problem (which appears to be a webkit bug). Note that
				// it's important to maintain a composited state (translate3d 0,0,0) or Android 4 is
				// slow to start scrolling.
				var m = this.$.scrollMath, sb = this._getScrollBounds();
				var needsBoundsFix = Boolean((sb.maxTop + m.bottomBoundary) || (sb.maxLeft + m.rightBoundary));
				enyo.dom.transformValue(this.$.client, this.translation, needsBoundsFix ? null : t);
				// note: this asynchronously triggers dom scroll event
				this.setScrollLeft(this.scrollLeft);
				this.setScrollTop(this.scrollTop);
				if (needsBoundsFix) {
					enyo.dom.transformValue(this.$.client, this.translation, t);
				}
				this._translated = false;
			}
		},

		/**
		* FIXME: we can fix scrolling artifacts BUGS on Android 4.04 with this heinous incantation.
		*
		* @private
		*/
		twiddle: function () {
			if (this.translateOptimized && this.scrollNode) { // this.scrollNode is not always defined and makes Motorola XOOM crash
				this.scrollNode.scrollTop = 1;
				this.scrollNode.scrollTop = 0;
			}
		}
	});

})(enyo, this);
<|endoftext|>


<commit_before>var
  concat    = require('gulp-concat'),
  concatCss = require('gulp-concat-css'),
  cssmin    = require('gulp-cssmin'),
  del       = require('del'),
  gulp      = require('gulp'),
  jeditor   = require('gulp-json-editor'),
  notify = require('gulp-notify'),
  prompt    = require('gulp-prompt'),
  sequence  = require('run-sequence'),
  streamqueue  = require('streamqueue'),
  uglify    = require('gulp-uglify');

var meta = require('../package.json');

// Merge sequence
gulp.task('merge', function(callback) {

  gulp.src('build/assets')
    .pipe(prompt.prompt({
        type: 'list',
        name: 'merge',
        message: 'Do you want to merge all assets?',
        choices: [
          {
            name: 'Yes, merge all assets',
            value: 'merge'
          },
          'No, keep individual files'
        ]
    }, function(res){
        if(res.merge === 'merge') {
            console.log('Merging assets…');

            sequence(
                  ['merge:js', 'merge:css'],
                  'post-merge',
                  callback
                );

              gulp
              .src("build/config.json")
              .pipe(jeditor({
                'general': {
                  'concat_assets': true
                }
              }))
              .pipe(gulp.dest("build/"));
        }
    }));

});

// Merge JS files
gulp.task('merge:js', function(){

    return streamqueue({ objectMode: true },
       // gulp.src('build/assets/js/bootstrap.min.js'),
       gulp.src('build/assets/js/highlight.min.js'),
       gulp.src('build/assets/js/jquery.searcher.min.js'),
       gulp.src('build/assets/js/stupidtable.min.js'),
       gulp.src('build/assets/js/listr.min.js')
    )
    .pipe(concat('listr.pack.js'))
    .pipe(uglify())
    .pipe(notify("Merge: <%= file.relative %>"))
    .pipe(gulp.dest('build/assets/js/'));
});

// Merge CSS files
gulp.task('merge:css', function(){

  return gulp.src([
      'build/assets/css/font-awesome.min.css',
      'build/assets/css/bootstrap.min.css',
      'build/assets/css/highlight.min.css',
      'build/assets/css/listr.min.css'
    ])
    .pipe(concatCss('listr.pack.css'))
    .pipe(cssmin())
    .pipe(notify("Merge: <%= file.relative %>"))
    .pipe(gulp.dest('build/assets/css/'));
});

// Clean up after merge
gulp.task('post-merge', function() {

  return del([
    'build/assets/css/*.css',
    '!build/assets/css/listr.pack.css',
    'build/assets/js/*.js',
    '!build/assets/js/bootlint.js',
    '!build/assets/js/bootstrap.min.js',
    '!build/assets/js/jquery.min.js',
    '!build/assets/js/listr.pack.js'
  ]);
});<commit_msg>remove gulp-notify<commit_after>var
  concat    = require('gulp-concat'),
  concatCss = require('gulp-concat-css'),
  cssmin    = require('gulp-cssmin'),
  del       = require('del'),
  gulp      = require('gulp'),
  jeditor   = require('gulp-json-editor'),
  prompt    = require('gulp-prompt'),
  sequence  = require('run-sequence'),
  streamqueue  = require('streamqueue'),
  uglify    = require('gulp-uglify');

var meta = require('../package.json');

// Merge sequence
gulp.task('merge', function(callback) {

  gulp.src('build/assets')
    .pipe(prompt.prompt({
        type: 'list',
        name: 'merge',
        message: 'Do you want to merge all assets?',
        choices: [
          {
            name: 'Yes, merge all assets',
            value: 'merge'
          },
          'No, keep individual files'
        ]
    }, function(res){
        if(res.merge === 'merge') {
            console.log('Merging assets…');

            sequence(
                  ['merge:js', 'merge:css'],
                  'post-merge',
                  callback
                );

              gulp
              .src("build/config.json")
              .pipe(jeditor({
                'general': {
                  'concat_assets': true
                }
              }))
              .pipe(gulp.dest("build/"));
        }
    }));

});

// Merge JS files
gulp.task('merge:js', function(){

    return streamqueue({ objectMode: true },
       // gulp.src('build/assets/js/bootstrap.min.js'),
       gulp.src('build/assets/js/highlight.min.js'),
       gulp.src('build/assets/js/jquery.searcher.min.js'),
       gulp.src('build/assets/js/stupidtable.min.js'),
       gulp.src('build/assets/js/listr.min.js')
    )
    .pipe(concat('listr.pack.js'))
    .pipe(uglify())
    .pipe(gulp.dest('build/assets/js/'));
});

// Merge CSS files
gulp.task('merge:css', function(){

  return gulp.src([
      'build/assets/css/font-awesome.min.css',
      'build/assets/css/bootstrap.min.css',
      'build/assets/css/highlight.min.css',
      'build/assets/css/listr.min.css'
    ])
    .pipe(concatCss('listr.pack.css'))
    .pipe(cssmin())
    .pipe(gulp.dest('build/assets/css/'));
});

// Clean up after merge
gulp.task('post-merge', function() {

  return del([
    'build/assets/css/*.css',
    '!build/assets/css/listr.pack.css',
    'build/assets/js/*.js',
    '!build/assets/js/bootlint.js',
    '!build/assets/js/bootstrap.min.js',
    '!build/assets/js/jquery.min.js',
    '!build/assets/js/listr.pack.js'
  ]);
});<|endoftext|>


<commit_before>/*
 * grunt-mocha-test
 * https://github.com/pghalliday/grunt-mocha-test
 *
 * Copyright (c) 2012 Peter Halliday
 * Licensed under the MIT license.
 */

 module.exports = function(grunt) {
  var MochaWrapper = require('./lib/MochaWrapper');

  grunt.registerMultiTask('mochaTest', 'Run node unit tests with Mocha', function() {
    // tell grunt this is an asynchronous task
    var done = this.async();
    var mochaWrapper = new MochaWrapper({
      files: this.filesSrc,
      options: this.options()
    });
    mochaWrapper.run(function(error, failureCount) {
      if (error) {
        grunt.log.error('Mocha exploded!');
        grunt.log.error(error.stack);
        done(false);
      } else {
        done(failureCount === 0);
      }
    });
  });
};
<commit_msg>tidying<commit_after>module.exports = function(grunt) {
  var MochaWrapper = require('./lib/MochaWrapper');

  grunt.registerMultiTask('mochaTest', 'Run node unit tests with Mocha', function() {
    var done = this.async();
    var mochaWrapper = new MochaWrapper({
      files: this.filesSrc,
      options: this.options()
    });
    mochaWrapper.run(function(error, failureCount) {
      if (error) {
        grunt.log.error('Mocha exploded!');
        grunt.log.error(error.stack);
        done(false);
      } else {
        done(failureCount === 0);
      }
    });
  });
};
<|endoftext|>


<commit_before>/* eslint global-require: ["off", { allow: ["warn"] }] */
/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */
/* eslint import/no-dynamic-require: ["off", { allow: ["warn"] }] */

const browserSync = require('browser-sync').create();
const watch = require('node-watch');
const log = require('./utils/log');

const { build } = require('./build');

const rebuildICON = require('./build/icon').rebuild;
const rebuildCOLOR = require('./build/color').rebuild;
const rebuildHTML = require('./build/html').rebuild;
const rebuildCSS = require('./build/css').rebuild;
const rebuildJS = require('./build/javascript').rebuild;
const rebuildIMG = require('./build/image').rebuild;
const rebuildSTATIC = require('./build/static').rebuild;

const srcFolder = 'src';
const distFolder = 'app';

function startBrowserSync() {
  log.start('Browsersync');

  browserSync.init({
    server: {
      baseDir: distFolder,
    },
  });
}

function startWatchTask() {
  watch(srcFolder, { recursive: true }, async (event, name) => {
    // ToDo: rebuild to switch statement?

    if (/.font\.json$/.test(name)) {
      await rebuildICON(event, name);
    } else if (/.colors\.json/.test(name)) {
      await rebuildCOLOR(event, name);
    } else if (/\.pug$/.test(name)) {
      await rebuildHTML(event, name);
    } else if (/\.scss$/.test(name)) {
      await rebuildCSS(event, name);
    } else if (/\.js$/.test(name)) {
      await rebuildJS(event, name);
    } else if (/\.jpg$|\.png$|\.gif$|\.svg$|\.ico$/.test(name)) {
      await rebuildIMG(event, name);
    } else if (/\.eot$|\.woff$|\.woff2$|\.ttf$|\.json$/.test(name)) {
      await rebuildSTATIC(event, name);
    }

    browserSync.reload();
  });
}

(async () => {
  await build();

  startBrowserSync();
  startWatchTask();
})();
<commit_msg>allow POST request usage during development on json and html files<commit_after>/* eslint global-require: ["off", { allow: ["warn"] }] */
/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */
/* eslint import/no-dynamic-require: ["off", { allow: ["warn"] }] */

const browserSync = require('browser-sync').create();
const watch = require('node-watch');
const log = require('./utils/log');

const { build } = require('./build');

const rebuildICON = require('./build/icon').rebuild;
const rebuildCOLOR = require('./build/color').rebuild;
const rebuildHTML = require('./build/html').rebuild;
const rebuildCSS = require('./build/css').rebuild;
const rebuildJS = require('./build/javascript').rebuild;
const rebuildIMG = require('./build/image').rebuild;
const rebuildSTATIC = require('./build/static').rebuild;

const srcFolder = 'src';
const distFolder = 'app';

function mockPostRequests(req, res, next) {
  if (/\.json|\.html/.test(req.url) && req.method.toUpperCase() === 'POST') {
    req.method = 'GET';
  }
  next();
}

function startBrowserSync() {
  log.start('Browsersync');

  browserSync.init({
    server: {
      baseDir: distFolder,
    },
    middleware: mockPostRequests
  });
}

function startWatchTask() {
  watch(srcFolder, { recursive: true }, async (event, name) => {
    // ToDo: rebuild to switch statement?

    if (/.font\.json$/.test(name)) {
      await rebuildICON(event, name);
    } else if (/.colors\.json/.test(name)) {
      await rebuildCOLOR(event, name);
    } else if (/\.pug$/.test(name)) {
      await rebuildHTML(event, name);
    } else if (/\.scss$/.test(name)) {
      await rebuildCSS(event, name);
    } else if (/\.js$/.test(name)) {
      await rebuildJS(event, name);
    } else if (/\.jpg$|\.png$|\.gif$|\.svg$|\.ico$/.test(name)) {
      await rebuildIMG(event, name);
    } else if (/\.eot$|\.woff$|\.woff2$|\.ttf$|\.json$/.test(name)) {
      await rebuildSTATIC(event, name);
    }

    browserSync.reload();
  });
}

(async () => {
  await build();

  startBrowserSync();
  startWatchTask();
})();
<|endoftext|>


<commit_before>/* eslint no-console: ["off", { allow: ["warn"] }] */
/* eslint global-require: ["off", { allow: ["warn"] }] */
/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */
/* eslint import/no-dynamic-require: ["off", { allow: ["warn"] }] */

const chalk = require('chalk');
const browserSync = require('browser-sync').create();
const watch = require('node-watch');

// tasks
const rebuildHTML = require('./html.build').rebuild;
const rebuildCSS = require('./css.build').rebuild;
const rebuildJS = require('./javascript.build').rebuild;
const rebuildIMG = require('./image.build').rebuild;
const rebuildSTATIC = require('./static.build').rebuild;

const srcFolder = 'src';
const distFolder = 'app';

const tasks = ['html', 'css', 'javascript', 'image', 'static'];

(async () => {
  await Promise.all(tasks.map(async (task) => {
    const startTime = new Date().getTime();
    console.log(
      `[${chalk.gray(new Date().toLocaleTimeString('de-DE'))}]`,
      `Starting ${task}...`,
    );

    const { run } = require(`./${task}.build`);
    await run();

    console.log(
      `[${chalk.gray(new Date().toLocaleTimeString('de-DE'))}]`,
      `Finished ${task} after ${chalk.blue(`${new Date().getTime() - startTime}ms`)}`,
    );
  }));

  console.log(
    `[${chalk.gray(new Date().toLocaleTimeString('de-DE'))}]`,
    'Starting Browsersync...\n',
  );

  browserSync.init({
    server: { baseDir: distFolder },
    open: 'local',
  });

  // @ToDo: move watch tasks

  watch(srcFolder, {
    recursive: true,
    filter: /\.scss$/,
  }, async (event, name) => {
    await rebuildCSS(event, name);
    browserSync.reload();
  });

  watch(srcFolder, {
    recursive: true,
    filter: /\.pug$/,
  }, async (event, name) => {
    await rebuildHTML(event, name);
    browserSync.reload();
  });

  watch(srcFolder, {
    recursive: true,
    filter: /\.jpg$|\.png$|\.svg$|\.ico$/,
  }, async (event, name) => {
    await rebuildIMG(event, name);
    browserSync.reload();
  });

  watch(srcFolder, {
    recursive: true,
    filter: /\.js$/,
  }, async (event, name) => {
    await rebuildJS(event, name);
    browserSync.reload();
  });

  watch(srcFolder, {
    recursive: true,
    filter: /\.eot$|\.woff$|\.woff2$|\.ttf$|\.json$/,
  }, async (event, name) => {
    await rebuildSTATIC(event, name);
    browserSync.reload();
  });
})();
<commit_msg>change watch task<commit_after>/* eslint no-console: ["off", { allow: ["warn"] }] */
/* eslint global-require: ["off", { allow: ["warn"] }] */
/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */
/* eslint import/no-dynamic-require: ["off", { allow: ["warn"] }] */

const chalk = require('chalk');
const browserSync = require('browser-sync').create();
const watch = require('node-watch');

// @ToDo: find a more generic approach
const rebuildHTML = require('./html.build').rebuild;
const rebuildCSS = require('./css.build').rebuild;
const rebuildJS = require('./javascript.build').rebuild;
const rebuildIMG = require('./image.build').rebuild;
const rebuildSTATIC = require('./static.build').rebuild;

const srcFolder = 'src';
const distFolder = 'app';
const tasks = ['html', 'css', 'javascript', 'image', 'static'];

function formatTime(time = 0) {
  let timeString = `${time}ms`;

  if (time > 1000) {
    timeString = `${Number((time / 1000).toFixed(3))}s`;
  } else if (time > (1000 * 60)) {
    timeString = `${Number((time / (1000 * 60)).toFixed(2))}m`;
  }

  return timeString;
}

function startBrowserSync() {
  console.log(
    `[${chalk.gray(new Date().toLocaleTimeString('de-DE'))}]`,
    'Starting Browsersync...\n',
  );
  browserSync.init({
    server: { baseDir: distFolder },
    open: 'local',
  });
}

function startWatchTask() {
  // @ToDo: find a more generic approach

  watch(srcFolder, {
    recursive: true,
    filter: /\.scss$/,
  }, async (event, name) => {
    await rebuildCSS(event, name);
    browserSync.reload();
  });

  watch(srcFolder, {
    recursive: true,
    filter: /\.pug$/,
  }, async (event, name) => {
    await rebuildHTML(event, name);
    browserSync.reload();
  });

  watch(srcFolder, {
    recursive: true,
    filter: /\.jpg$|\.png$|\.svg$|\.ico$/,
  }, async (event, name) => {
    await rebuildIMG(event, name);
    browserSync.reload();
  });

  watch(srcFolder, {
    recursive: true,
    filter: /\.js$/,
  }, async (event, name) => {
    await rebuildJS(event, name);
    browserSync.reload();
  });

  watch(srcFolder, {
    recursive: true,
    filter: /\.eot$|\.woff$|\.woff2$|\.ttf$|\.json$/,
  }, async (event, name) => {
    await rebuildSTATIC(event, name);
    browserSync.reload();
  });
}

(async () => {
  await Promise.all(tasks.map(async (task) => {
    const startTime = new Date().getTime();
    console.log(
      `[${chalk.gray(new Date().toLocaleTimeString('de-DE'))}]`,
      `Starting ${task}...`,
    );

    const { run } = require(`./${task}.build`);
    await run();

    console.log(
      `[${chalk.gray(new Date().toLocaleTimeString('de-DE'))}]`,
      `Finished ${task} after ${chalk.blue(formatTime(new Date().getTime() - startTime))}`,
    );
  }));

  startBrowserSync();
  startWatchTask();
})();
<|endoftext|>


<commit_before>/**
 * Watch
 */

'use strict';

module.exports = function (paths, gulp, plugins) {

	// Return module
	return function () {

		// Source paths
		var pathCSS = plugins.path.resolve(paths.src, '**/*.scss');
		var pathJS = plugins.path.resolve(paths.src, '**/*.js');
		var pathFonts = plugins.path.resolve(paths.src, '**/fonts/**');
		var pathImages = plugins.path.resolve(paths.src, '**/*.{png,jpg,gif}');
		var pathSVG = plugins.path.resolve(paths.src, '**/*.{svg}');
		var pathHTML = plugins.path.resolve(paths.src, '**/*.hbs');

		// Critical build paths (e.g. rebuild HTML when critical styles change)
		var pathCriticalCSS = plugins.path.resolve(paths.build, 'assets/css/starter.min.css');

		// Watch for CSS changes
		plugins.watch(pathCSS, plugins.batch(function (events, done) {
			return plugins.runSequence('css-lint', 'css', done);
		}));

		// Watch for JS changes
		plugins.watch(pathJS, plugins.batch(function (events, done) {
			return plugins.runSequence('javascript-lint', 'javascript', done);
		}));

		// Watch for HTML changes
		plugins.watch([pathHTML, pathCriticalCSS], plugins.batch(function (events, done) {
			return plugins.runSequence('html', done);
		}));

		// Watch for SVG changes
		plugins.watch(pathSVG, plugins.batch(function (events, done) {
			return plugins.runSequence('image-fallbacks', done);
		}));

		// Watch for static asset changes
		plugins.watch([pathFonts, pathImages], plugins.batch(function (events, done) {
			return plugins.runSequence('copy', done);
		}));
	};
};
<commit_msg>Include SVG in copy watch task<commit_after>/**
 * Watch
 */

'use strict';

module.exports = function (paths, gulp, plugins) {

	// Return module
	return function () {

		// Source paths
		var pathCSS = plugins.path.resolve(paths.src, '**/*.scss');
		var pathJS = plugins.path.resolve(paths.src, '**/*.js');
		var pathFonts = plugins.path.resolve(paths.src, '**/fonts/**');
		var pathImages = plugins.path.resolve(paths.src, '**/*.{png,jpg,gif}');
		var pathSVG = plugins.path.resolve(paths.src, '**/*.{svg}');
		var pathHTML = plugins.path.resolve(paths.src, '**/*.hbs');

		// Critical build paths (e.g. rebuild HTML when critical styles change)
		var pathCriticalCSS = plugins.path.resolve(paths.build, 'assets/css/starter.min.css');

		// Watch for CSS changes
		plugins.watch(pathCSS, plugins.batch(function (events, done) {
			return plugins.runSequence('css-lint', 'css', done);
		}));

		// Watch for JS changes
		plugins.watch(pathJS, plugins.batch(function (events, done) {
			return plugins.runSequence('javascript-lint', 'javascript', done);
		}));

		// Watch for HTML changes
		plugins.watch([pathHTML, pathCriticalCSS], plugins.batch(function (events, done) {
			return plugins.runSequence('html', done);
		}));

		// Watch for SVG changes
		plugins.watch(pathSVG, plugins.batch(function (events, done) {
			return plugins.runSequence('image-fallbacks', done);
		}));

		// Watch for static asset changes
		plugins.watch([pathFonts, pathImages, pathSVG], plugins.batch(function (events, done) {
			return plugins.runSequence('copy', done);
		}));
	};
};
<|endoftext|>


<commit_before>/*
 * grunt-xcode
 * https://github.com/matiassingers/grunt-xcode
 *
 * Copyright (c) 2014 Matias Singers
 * Licensed under the MIT license.
 */
'use strict';

var Promise = require('bluebird');
var exec = Promise.promisify(require('child_process').exec);

String.prototype.format = function() {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        formatted = formatted.replace(
            RegExp('\\{' + i + '\\}', 'g'), arguments[i]);
    }
    return formatted;
};

module.exports = function(grunt) {
  function executeCommand(command){
    grunt.verbose.writeln('Running command: {0}'.format(command));
    return exec(command)
      .catch(handleCommandError);
  }
  function handleCommandError(error){
    if (error){
      grunt.warn(error);
    }
  }

  grunt.registerMultiTask('xcode', 'Build and export Xcode projects with Grunt', function() {
    var done = this.async();

  });
};
<commit_msg>Add initial default plugin options<commit_after>/*
 * grunt-xcode
 * https://github.com/matiassingers/grunt-xcode
 *
 * Copyright (c) 2014 Matias Singers
 * Licensed under the MIT license.
 */
'use strict';

var Promise = require('bluebird');
var exec = Promise.promisify(require('child_process').exec);

String.prototype.format = function() {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        formatted = formatted.replace(
            RegExp('\\{' + i + '\\}', 'g'), arguments[i]);
    }
    return formatted;
};

module.exports = function(grunt) {
  function executeCommand(command){
    grunt.verbose.writeln('Running command: {0}'.format(command));
    return exec(command)
      .catch(handleCommandError);
  }
  function handleCommandError(error){
    if (error){
      grunt.warn(error);
    }
  }

  grunt.registerMultiTask('xcode', 'Build and export Xcode projects with Grunt', function() {
    var done = this.async();

    var options = this.options({
      clean: true,
      export: true,
      project: '',
      scheme: '',
      archivePath: '',
      exportPath: process.cwd(),
      exportFilename: 'export.ipa'
    });

    if(!options.project){
      throw new Error('`options.project` is required');
    }

  });
};
<|endoftext|>


<commit_before>exports.config = {
    specs: [
        'test/*.js'
    ],
};
<commit_msg>Tweak timeouts.<commit_after>exports.config = {
    specs: [
        'test/*.js'
    ],
    jasmineNodeOpts: {
        defaultTimeoutInterval: 30000
    },
    allScriptsTimeout: 60000
};
<|endoftext|>


<commit_before>var x11 = require('./lib/x11');
var Mocha = require('mocha');
var fs = require('fs');
var path = require('path');
var util = require('util');
var async = require('async');

var mocha = new Mocha({
    timeout : 80000
});

// To be able to perform the tests we need the server:
// 1 - to support the dpms extension.
// 2 - dpms version is 1.1.
// 3 - to be dpms capable.
var run_dpms_test = function(cb) {
    var client = x11.createClient(function(err, dpy) {
        if (err) return cb(false);
        var display = dpy;
        var X = display.client;
        X.require('dpms', function(ext) {
            if (!util.isError(ext)) {
                dpms = ext;
                dpms.GetVersion(undefined, undefined, function(err, version) {
                    if (!err && version[0] === 1 && version[1] === 1) {
                        dpms.Capable(function(err, capable) {
                            if (!err && capable[0] == 1) cb(true);
                            else cb(false);
                        });
                    } else {
                        cb(false);
                    }
                });
            } else {
                cb(false);
            }
        });
    });

    client.on('error', function() {
        cb(false);
    });
};

var run_xtest_test = function(cb) {
    var client = x11.createClient(function(err, dpy) {
        if (err) return cb(false);
        var display = dpy;
        var X = display.client;
        X.require('dpms', function(ext) {
            if (!util.isError(ext)) cb(true);
            else cb(false);
        });
    });

    client.on('error', function() {
        cb(false);
    });
};

// Add all files from test root directory
async.forEach(
    fs.readdirSync('./test'),
    function(file, cb) {
        if (file === 'dpms.js') {
            run_dpms_test(function(run) {
                if (run) {
                    mocha.addFile(path.join('./test', file));
                }

                cb();
            });
        } else if (file === 'xtest.js') {
            run_xtest_test(function(run) {
                if (run) {
                    mocha.addFile(path.join('./test', file));
                }

                cb();
            });
        } else {
            mocha.addFile(path.join('./test', file));
            cb();
        }
    },
    function(err) {
        mocha.run(function() {
            process.exit();
        });
    }
);
<commit_msg>fix path<commit_after>var x11 = require('./lib');
var Mocha = require('mocha');
var fs = require('fs');
var path = require('path');
var util = require('util');
var async = require('async');

var mocha = new Mocha({
    timeout : 80000
});

// To be able to perform the tests we need the server:
// 1 - to support the dpms extension.
// 2 - dpms version is 1.1.
// 3 - to be dpms capable.
var run_dpms_test = function(cb) {
    var client = x11.createClient(function(err, dpy) {
        if (err) return cb(false);
        var display = dpy;
        var X = display.client;
        X.require('dpms', function(ext) {
            if (!util.isError(ext)) {
                dpms = ext;
                dpms.GetVersion(undefined, undefined, function(err, version) {
                    if (!err && version[0] === 1 && version[1] === 1) {
                        dpms.Capable(function(err, capable) {
                            if (!err && capable[0] == 1) cb(true);
                            else cb(false);
                        });
                    } else {
                        cb(false);
                    }
                });
            } else {
                cb(false);
            }
        });
    });

    client.on('error', function() {
        cb(false);
    });
};

var run_xtest_test = function(cb) {
    var client = x11.createClient(function(err, dpy) {
        if (err) return cb(false);
        var display = dpy;
        var X = display.client;
        X.require('dpms', function(ext) {
            if (!util.isError(ext)) cb(true);
            else cb(false);
        });
    });

    client.on('error', function() {
        cb(false);
    });
};

// Add all files from test root directory
async.forEach(
    fs.readdirSync('./test'),
    function(file, cb) {
        if (file === 'dpms.js') {
            run_dpms_test(function(run) {
                if (run) {
                    mocha.addFile(path.join('./test', file));
                }

                cb();
            });
        } else if (file === 'xtest.js') {
            run_xtest_test(function(run) {
                if (run) {
                    mocha.addFile(path.join('./test', file));
                }

                cb();
            });
        } else {
            mocha.addFile(path.join('./test', file));
            cb();
        }
    },
    function(err) {
        mocha.run(function() {
            process.exit();
        });
    }
);
<|endoftext|>