<commit_before>
/*
 * grunt-replace
 * http://gruntjs.com/
 *
 * Copyright (c) 2014 outaTiME
 * Licensed under the MIT license.
 * https://github.com/outaTiME/grunt-replace/blob/master/LICENSE-MIT
 */

module.exports = function (grunt) {

  'use strict';

  var path = require('path');
  var fs = require('fs');
  var util = require('util');
  var chalk = require('chalk');
  var _ = require('lodash');

  grunt.registerMultiTask('replace', 'Replace text patterns with a given replacement.', function () {

    var options = this.options({
      encoding: grunt.file.defaultEncoding,
      mode: false,
      patterns: [],
      prefix: '@@',
      usePrefix: true,
      preservePrefix: false,
      force: false,
      delimiter: '.',
      processContentExclude: []
    });
    var patterns = options.patterns;
    var locals = [];

    // add prefix

    if (options.usePrefix === false) {
      options.prefix =  '';
    }

    // backward compatible support

    var variables = options.variables;
    if (typeof variables !== 'undefined') {
      patterns.push({
        json: variables
      });
    }

    // intercept and transform json objects

    for (var i = patterns.length - 1; i >= 0; i -= 1) {
      var json = patterns[i].json;
      if (typeof json !== 'undefined') {
        if (_.isPlainObject(json)) {
          var items = flatten(json, options);
          // replace json with flatten data
          Array.prototype.splice.apply(patterns, [i, 1].concat(items));
        } else {
          grunt.fail.fatal('Unsupported type for json (plain object expected).');
          return;
        }
      }
    }

    // register global patterns

    patterns.push({
      context: true,
      match: '__SOURCE_FILE__',
      replacement: function (srcFile, destFile, options) {
        return srcFile;
      }
    }, {
      context: true,
      match: '__SOURCE_PATH__',
      replacement: function (srcFile, destFile, options) {
        return path.dirname(srcFile);
      }
    }, {
      context: true,
      match: '__SOURCE_FILENAME__',
      replacement: function (srcFile, destFile, options) {
        return path.basename(srcFile);
      }
    }, {
      context: true,
      match: '__TARGET_FILE__',
      replacement: function (srcFile, destFile, options) {
        return destFile;
      }
    }, {
      context: true,
      match: '__TARGET_PATH__',
      replacement: function (srcFile, destFile, options) {
        return path.dirname(destFile);
      }
    }, {
      context: true,
      match: '__TARGET_FILENAME__',
      replacement: function (srcFile, destFile, options) {
        return path.basename(destFile);
      }
    });

    // only sort non regex patterns (prevents replace issues like head, header)

    patterns.sort(function (a, b) {
      var x = a.match;
      var y = b.match;
      if (_.isString(x) && _.isString(y)) {
        return y.length - x.length;
      } else if (_.isString(x)) {
        return -1;
      }
      return 1;
    });

    // register patterns

    patterns.forEach(function (pattern) {
      registerPattern(pattern, locals, options);
    });

    // verbose

    grunt.verbose.writeln(util.inspect(locals));

    if (locals.length === 0 && options.force === false) {
      grunt.fail.warn('Not found valid patterns to be replaced.');
    }

    // took code from copy task

    var dest;
    var isExpandedPair;

    this.files.forEach(function (filePair) {
      isExpandedPair = filePair.orig.expand || false;
      filePair.src.forEach(function (src) {
        if (detectDestType(filePair.dest) === 'directory') {
          dest = (isExpandedPair) ? filePair.dest : unixifyPath(path.join(filePair.dest, src));
        } else {
          dest = filePair.dest;
        }
        if (grunt.file.isDir(src)) {
          grunt.file.mkdir(dest);
        } else {
          replace(src, dest, locals, options);
          if (options.mode !== false) {
            fs.chmodSync(dest, (options.mode === true) ? fs.lstatSync(src).mode : options.mode);
          }
        }
      });
    });

  });

  var detectDestType = function (dest) {
    var lastChar = dest.slice(-1);
    if (lastChar === '/') {
      return 'directory';
    } else {
      return 'file';
    }
  };

  var unixifyPath = function (filepath) {
    if (process.platform === 'win32') {
      return filepath.replace(/\\/g, '/');
    } else {
      return filepath;
    }
  };

  var registerPattern = function (pattern, locals, options) {
    var match = pattern.match;
    var replacement = pattern.replacement;
    var expression = pattern.expression === true;
    var context = pattern.context === true;
    // check matching type
    if (_.isRegExp(match)) {
      expression = true;
    } else if (_.isString(match)) {
      if (match.length > 0) {
        if (expression === true) {
          var index = match.lastIndexOf('/');
          if (match[0] === '/' && index > 0) {
            try {
              match = new RegExp(match.slice(1, index), match.slice(index + 1));
            } catch (error) {
              grunt.log.error(error);
              return;
            }
          } else {
            grunt.fail.fatal('Invalid expression found for match: ' + match);
            return;
          }
        } else {
          // old school
          try {
            match = new RegExp(options.prefix + match, 'g');
          } catch (error) {
            grunt.fail.fatal(error);
            return;
          }
        }
      } else {
        // invalid match, ignore rule
        return;
      }
    } else {
      grunt.fail.fatal('Unsupported type for match (RegExp or String expected).');
      return;
    }
    // replacement check
    if (!_.isFunction(replacement)) {
      if (context === true) {
        grunt.fail.fatal('Context matching must require function as replacement.');
        return;
      } else {
        if (!_.isString(replacement)) {
          // transform object to string
          replacement = JSON.stringify(replacement);
        } else {
          // easy way
          if (expression === false && options.preservePrefix === true) {
            replacement = options.prefix + replacement;
          }
        }
      }
    } else {
      // replace using function return value
    }
    locals.push({
      match: match,
      replacement: replacement,
      expression: expression,
      context: context
    });
  };

  var replace = function (srcFile, destFile, locals, options) {
    grunt.file.copy(srcFile, destFile, {
      encoding: options.encoding,
      process: function (contents) {
        var updated = false;
        locals.forEach(function (pattern) {
          var re = pattern.match;
          var replacement = pattern.replacement;
          var context = pattern.context;
          if (context === true) {
            replacement = replacement.call(this, srcFile, destFile, options);
          }
          updated = updated || contents.match(re);
          contents = contents.replace(re, replacement);
        });
        if (!updated && options.force === false) {
          return false;
        }
        grunt.log.writeln('Replace ' + chalk.cyan(srcFile) + ' -> ' +
          chalk.cyan(destFile));
        return contents;
      },
      noProcess: options.noProcess || options.processContentExclude
    });
  };

  var flatten = function (data, options) {
    var delimiter = options.delimiter;
    var result = [];
    function recurse (cur, prop) {
      for (var key in cur) {
        if (cur.hasOwnProperty(key)) {
          var item = cur[key];
          result.push({
            match: prop ? prop + delimiter + key : key,
            replacement: item,
            expression: false
          });
          // deep scan
          if (typeof item === 'object') {
            recurse(item, prop ? prop + delimiter + key : key);
          }
        }
      }
    }
    recurse(data);
    return result;
  };

};
<commit_msg>Comment fixes.<commit_after>
/*
 * grunt-replace
 * http://gruntjs.com/
 *
 * Copyright (c) 2014 outaTiME
 * Licensed under the MIT license.
 * https://github.com/outaTiME/grunt-replace/blob/master/LICENSE-MIT
 */

module.exports = function (grunt) {

  'use strict';

  var path = require('path');
  var fs = require('fs');
  var util = require('util');
  var chalk = require('chalk');
  var _ = require('lodash');

  grunt.registerMultiTask('replace', 'Replace text patterns with a given replacement.', function () {

    var options = this.options({
      encoding: grunt.file.defaultEncoding,
      mode: false,
      patterns: [],
      prefix: '@@',
      usePrefix: true,
      preservePrefix: false,
      force: false,
      delimiter: '.',
      processContentExclude: []
    });
    var patterns = options.patterns;
    var locals = [];

    // add prefix

    if (options.usePrefix === false) {
      options.prefix =  '';
    }

    // backward compatible support

    var variables = options.variables;
    if (typeof variables !== 'undefined') {
      patterns.push({
        json: variables
      });
    }

    // intercept and transform json objects

    for (var i = patterns.length - 1; i >= 0; i -= 1) {
      var json = patterns[i].json;
      if (typeof json !== 'undefined') {
        if (_.isPlainObject(json)) {
          var items = flatten(json, options);
          // replace json with flatten data
          Array.prototype.splice.apply(patterns, [i, 1].concat(items));
        } else {
          grunt.fail.fatal('Unsupported type for json (plain object expected).');
          return;
        }
      }
    }

    // register global patterns

    patterns.push({
      context: true,
      match: '__SOURCE_FILE__',
      replacement: function (srcFile, destFile, options) {
        return srcFile;
      }
    }, {
      context: true,
      match: '__SOURCE_PATH__',
      replacement: function (srcFile, destFile, options) {
        return path.dirname(srcFile);
      }
    }, {
      context: true,
      match: '__SOURCE_FILENAME__',
      replacement: function (srcFile, destFile, options) {
        return path.basename(srcFile);
      }
    }, {
      context: true,
      match: '__TARGET_FILE__',
      replacement: function (srcFile, destFile, options) {
        return destFile;
      }
    }, {
      context: true,
      match: '__TARGET_PATH__',
      replacement: function (srcFile, destFile, options) {
        return path.dirname(destFile);
      }
    }, {
      context: true,
      match: '__TARGET_FILENAME__',
      replacement: function (srcFile, destFile, options) {
        return path.basename(destFile);
      }
    });

    // only sort non regex patterns (prevents replace issues like head, header)

    patterns.sort(function (a, b) {
      var x = a.match;
      var y = b.match;
      if (_.isString(x) && _.isString(y)) {
        return y.length - x.length;
      } else if (_.isString(x)) {
        return -1;
      }
      return 1;
    });

    // register patterns

    patterns.forEach(function (pattern) {
      registerPattern(pattern, locals, options);
    });

    // verbose

    grunt.verbose.writeln(util.inspect(locals));

    if (locals.length === 0 && options.force === false) {
      grunt.fail.warn('Not found valid patterns to be replaced.');
    }

    // took code from copy task

    var dest;
    var isExpandedPair;

    this.files.forEach(function (filePair) {
      isExpandedPair = filePair.orig.expand || false;
      filePair.src.forEach(function (src) {
        if (detectDestType(filePair.dest) === 'directory') {
          dest = (isExpandedPair) ? filePair.dest : unixifyPath(path.join(filePair.dest, src));
        } else {
          dest = filePair.dest;
        }
        if (grunt.file.isDir(src)) {
          grunt.file.mkdir(dest);
        } else {
          replace(src, dest, locals, options);
          if (options.mode !== false) {
            fs.chmodSync(dest, (options.mode === true) ? fs.lstatSync(src).mode : options.mode);
          }
        }
      });
    });

  });

  var detectDestType = function (dest) {
    var lastChar = dest.slice(-1);
    if (lastChar === '/') {
      return 'directory';
    } else {
      return 'file';
    }
  };

  var unixifyPath = function (filepath) {
    if (process.platform === 'win32') {
      return filepath.replace(/\\/g, '/');
    } else {
      return filepath;
    }
  };

  var registerPattern = function (pattern, locals, options) {
    var match = pattern.match;
    var replacement = pattern.replacement;
    var expression = pattern.expression === true;
    var context = pattern.context === true;
    // match check
    if (_.isRegExp(match)) {
      expression = true;
    } else if (_.isString(match)) {
      if (match.length > 0) {
        if (expression === true) {
          var index = match.lastIndexOf('/');
          if (match[0] === '/' && index > 0) {
            try {
              match = new RegExp(match.slice(1, index), match.slice(index + 1));
            } catch (error) {
              grunt.log.error(error);
              return;
            }
          } else {
            grunt.fail.fatal('Invalid expression found for match: ' + match);
            return;
          }
        } else {
          // old school
          try {
            match = new RegExp(options.prefix + match, 'g');
          } catch (error) {
            grunt.fail.fatal(error);
            return;
          }
        }
      } else {
        // empty match
        return;
      }
    } else {
      grunt.fail.fatal('Unsupported type for match (RegExp or String expected).');
      return;
    }
    // replacement check
    if (!_.isFunction(replacement)) {
      if (context === true) {
        grunt.fail.fatal('Context matching must require function as replacement.');
        return;
      } else {
        if (!_.isString(replacement)) {
          // transform object to string
          replacement = JSON.stringify(replacement);
        } else {
          // easy way
          if (expression === false && options.preservePrefix === true) {
            replacement = options.prefix + replacement;
          }
        }
      }
    } else {
      // replace using function return value
    }
    locals.push({
      match: match,
      replacement: replacement,
      expression: expression,
      context: context
    });
  };

  var replace = function (srcFile, destFile, locals, options) {
    grunt.file.copy(srcFile, destFile, {
      encoding: options.encoding,
      process: function (contents) {
        var updated = false;
        locals.forEach(function (pattern) {
          var re = pattern.match;
          var replacement = pattern.replacement;
          var context = pattern.context;
          if (context === true) {
            replacement = replacement.call(this, srcFile, destFile, options);
          }
          updated = updated || contents.match(re);
          contents = contents.replace(re, replacement);
        });
        if (!updated && options.force === false) {
          return false;
        }
        grunt.log.writeln('Replace ' + chalk.cyan(srcFile) + ' -> ' +
          chalk.cyan(destFile));
        return contents;
      },
      noProcess: options.noProcess || options.processContentExclude
    });
  };

  var flatten = function (data, options) {
    var delimiter = options.delimiter;
    var result = [];
    function recurse (cur, prop) {
      for (var key in cur) {
        if (cur.hasOwnProperty(key)) {
          var item = cur[key];
          result.push({
            match: prop ? prop + delimiter + key : key,
            replacement: item,
            expression: false
          });
          // deep scan
          if (typeof item === 'object') {
            recurse(item, prop ? prop + delimiter + key : key);
          }
        }
      }
    }
    recurse(data);
    return result;
  };

};
<|endoftext|>


<commit_before>/*
 * grunt-sitemap
 * https://github.com/RayViljoen/grunt-sitemap
 *
 * Copyright (c) 2013 Ray Viljoen
 * Licensed under the MIT license.
 */

/*
 * decaffeinate suggestions:
 * DS102: Remove unnecessary code created because of implicit returns
 * DS205: Consider reworking code to avoid use of IIFEs
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */

'use strict';

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

module.exports = function(grunt) {
    grunt.registerMultiTask('sitemap', 'Grunt sitemap generator plugin', function() {
        // Read `homepage` from package.json
        const pkg = grunt.file.readJSON('package.json');
        let url = this.data.homepage || pkg.homepage;

        // Check if `homepage` property is set
        if (!url) {
            grunt.fail.warn('Requires "homepage" parameter. Sitemap was not created.', 3);
        }

        // Site root dir
        let root = path.normalize(this.data.siteRoot || '.');

        // Replace Windows slashes to unix ones
        const tempRoot = root.replace(/\\/g, '/');

        if (tempRoot !== './') {
            root = tempRoot;
        }

        // Check a `siteRoot` was set
        if (root === '.') {
            grunt.log.subhead('No "siteRoot" parameter defined. Using current directory.');
        }

        // Add trailing slash to url if not there
        if (!url.endsWith('/') && !root.endsWith('/')) {
            url += '/';
        }

        // changereq setting
        const changefreq = this.data.changefreq || 'daily';

        // extension setting
        const extension = this.data.extension ? this.data.extension : { required: true };

        // priority setting; must be a string
        const priority = (this.data.priority || 0.5).toString();

        // File pattern
        const pattern = this.data.pattern || path.join(root, '/**/*.html');

        // Glob root
        let files = grunt.file.expand({ cwd: root }, pattern);

        // Remove root from path and prepend homepage url
        files = files.map(file => {
            let rawUrlPath;

            // Do not include 404 page
            if (file.match(/404\.html?$/i)) {
                return false;
            }

            // Create object with url an mtime
            const fileStat = {};

            // Get path relative to root, but still containing index paths
            if (root === '.') {
                rawUrlPath = file;
            } else {
                rawUrlPath = file.replace(root, '');
            }

            // If the rawUrlPath has a slash in the beginning,
            // remove it since we add it in url
            if (rawUrlPath.startsWith('/')) {
                rawUrlPath = rawUrlPath.replace('/', '');
            }

            // Remove index.html
            rawUrlPath = rawUrlPath.replace(/index\.[A-z]+$/i, '');

            const urlPath = (() => {
                switch (false) {
                    case (typeof extension !== 'object') || Boolean(extension.required) || !extension.trailingSlash:
                        // Remove extension with trailing slash
                        return rawUrlPath.replace(/\.html?/i, '/');
                    case (typeof extension !== 'object') || Boolean(extension.required) || Boolean(extension.trailingSlash):
                        // Remove extension without trailing slash
                        return rawUrlPath.replace(/(\.html?|\/)$/i, '');
                    default:
                        // only return path with extension
                        return rawUrlPath;
                }
            })();

            // Join path with homepage url
            fileStat.url = url + urlPath;

            // Get last modified time
            const mtime = fs.statSync(file).mtime.getTime();

            // Format mtime to ISO (same as +00:00)
            fileStat.mtime = new Date(mtime).toISOString();

            // Return fileStat object
            return fileStat;
        });

        // Remove any falsy values (404.html returns false)
        files = files.filter(Boolean);

        // -----------------------
        // Build xml
        // -----------------------

        let xmlStr = '<?xml version="1.0" encoding="UTF-8"?>\n';

        xmlStr += '<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';
        xmlStr += ' xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"';
        xmlStr += ' xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';

        // Create url nodes
        for (const file of files) {
            xmlStr += '  <url>\n';
            xmlStr += `    <loc>${file.url}</loc>\n`;
            xmlStr += `    <lastmod>${file.mtime}</lastmod>\n`;
            xmlStr += `    <changefreq>${changefreq}</changefreq>\n`;
            xmlStr += `    <priority>${priority}</priority>\n`;
            xmlStr += '  </url>\n';
        }

        // Close xml
        xmlStr += '</urlset>';

        // Write sitemap to root
        grunt.file.write(path.join(root, 'sitemap.xml'), xmlStr);

        grunt.log.ok('Sitemap created successfully');

        if (grunt.task.current.errorCount) {
            return false;
        }
        return true;
    });
};
<commit_msg>Revert "Take into consideration the root folder."<commit_after>/*
 * grunt-sitemap
 * https://github.com/RayViljoen/grunt-sitemap
 *
 * Copyright (c) 2013 Ray Viljoen
 * Licensed under the MIT license.
 */

/*
 * decaffeinate suggestions:
 * DS102: Remove unnecessary code created because of implicit returns
 * DS205: Consider reworking code to avoid use of IIFEs
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */

'use strict';

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

module.exports = function(grunt) {
    grunt.registerMultiTask('sitemap', 'Grunt sitemap generator plugin', function() {
        // Read `homepage` from package.json
        const pkg = grunt.file.readJSON('package.json');
        let url = this.data.homepage || pkg.homepage;

        // Check if `homepage` property is set
        if (!url) {
            grunt.fail.warn('Requires "homepage" parameter. Sitemap was not created.', 3);
        }

        // Site root dir
        let root = path.normalize(this.data.siteRoot || '.');

        // Replace Windows slashes to unix ones
        const tempRoot = root.replace(/\\/g, '/');

        if (tempRoot !== './') {
            root = tempRoot;
        }

        // Check a `siteRoot` was set
        if (root === '.') {
            grunt.log.subhead('No "siteRoot" parameter defined. Using current directory.');
        }

        // Add trailing slash to url if not there
        if (!url.endsWith('/') && !root.endsWith('/')) {
            url += '/';
        }

        // changereq setting
        const changefreq = this.data.changefreq || 'daily';

        // extension setting
        const extension = this.data.extension ? this.data.extension : { required: true };

        // priority setting; must be a string
        const priority = (this.data.priority || 0.5).toString();

        // File pattern
        const pattern = this.data.pattern || path.join(root, '/**/*.html');

        // Glob root
        let files = grunt.file.expand(pattern);

        // Remove root from path and prepend homepage url
        files = files.map(file => {
            let rawUrlPath;

            // Do not include 404 page
            if (file.match(/404\.html?$/i)) {
                return false;
            }

            // Create object with url an mtime
            const fileStat = {};

            // Get path relative to root, but still containing index paths
            if (root === '.') {
                rawUrlPath = file;
            } else {
                rawUrlPath = file.replace(root, '');
            }

            // If the rawUrlPath has a slash in the beginning,
            // remove it since we add it in url
            if (rawUrlPath.startsWith('/')) {
                rawUrlPath = rawUrlPath.replace('/', '');
            }

            // Remove index.html
            rawUrlPath = rawUrlPath.replace(/index\.[A-z]+$/i, '');

            const urlPath = (() => {
                switch (false) {
                    case (typeof extension !== 'object') || Boolean(extension.required) || !extension.trailingSlash:
                        // Remove extension with trailing slash
                        return rawUrlPath.replace(/\.html?/i, '/');
                    case (typeof extension !== 'object') || Boolean(extension.required) || Boolean(extension.trailingSlash):
                        // Remove extension without trailing slash
                        return rawUrlPath.replace(/(\.html?|\/)$/i, '');
                    default:
                        // only return path with extension
                        return rawUrlPath;
                }
            })();

            // Join path with homepage url
            fileStat.url = url + urlPath;

            // Get last modified time
            const mtime = fs.statSync(file).mtime.getTime();

            // Format mtime to ISO (same as +00:00)
            fileStat.mtime = new Date(mtime).toISOString();

            // Return fileStat object
            return fileStat;
        });

        // Remove any falsy values (404.html returns false)
        files = files.filter(Boolean);

        // -----------------------
        // Build xml
        // -----------------------

        let xmlStr = '<?xml version="1.0" encoding="UTF-8"?>\n';

        xmlStr += '<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';
        xmlStr += ' xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"';
        xmlStr += ' xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';

        // Create url nodes
        for (const file of files) {
            xmlStr += '  <url>\n';
            xmlStr += `    <loc>${file.url}</loc>\n`;
            xmlStr += `    <lastmod>${file.mtime}</lastmod>\n`;
            xmlStr += `    <changefreq>${changefreq}</changefreq>\n`;
            xmlStr += `    <priority>${priority}</priority>\n`;
            xmlStr += '  </url>\n';
        }

        // Close xml
        xmlStr += '</urlset>';

        // Write sitemap to root
        grunt.file.write(path.join(root, 'sitemap.xml'), xmlStr);

        grunt.log.ok('Sitemap created successfully');

        if (grunt.task.current.errorCount) {
            return false;
        }
        return true;
    });
};
<|endoftext|>


<commit_before>/**
 * SVG to webfont converter for Grunt
 *
 * @requires ttfautohint
 * @author Artem Sapegin (http://sapegin.me)
 */

module.exports = function(grunt) {
	'use strict';

	var fs = require('fs');
	var path = require('path');
	var async = require('async');
	var glob = require('glob');
	var chalk = require('chalk');
	var mkdirp = require('mkdirp');
	var _ = require('lodash');
	var _s = require('underscore.string');
	var wf = require('./util/util');

	grunt.registerMultiTask('webfont', 'Compile separate SVG files to webfont', function() {
		['src', 'dest'].forEach(function(name) {
			this.requiresConfig([this.name, this.target, name].join('.'));
		}.bind(this));

		var allDone = this.async();
		var params = this.data;
		var options = params.options || {};

		/**
		 * Winston to Grunt logger adapter.
		 */
		var logger = {
			warn: function() {
				grunt.logger.warn.apply(null, arguments);
			},
			error: function() {
				grunt.warn.apply(null, arguments);
			},
			log: function() {
				grunt.log.writeln.apply(null, arguments);
			},
			verbose: function() {
				grunt.verbose.writeln.apply(null, arguments);
			}
		};

		if (options.skip) {
			allDone();
			return;
		}

		// Source files
		var files = _.filter(this.filesSrc, isSvgFile);
		if (!files.length) {
			logger.warn('Specified empty list of source SVG files.');
		}

		// Options
		var o = {
			fontBaseName: options.font || 'icons',
			destCss: params.destCss || params.dest,
			dest: params.dest,
			relativeFontPath: options.relativeFontPath,
			addHashes: options.hashes !== false,
			addLigatures: options.ligatures === true,
			template: options.template,
			syntax: options.syntax || 'bem',
			templateOptions: options.templateOptions || {},
			stylesheet: options.stylesheet || 'css',
			htmlDemo: options.htmlDemo !== false,
			htmlDemoTemplate: options.htmlDemoTemplate,
			styles: optionToArray(options.styles, 'font,icon'),
			types: optionToArray(options.types, wf.fontFormats),
			order: optionToArray(options.order, wf.fontFormats),
			embed: options.embed === true ? ['woff'] : optionToArray(options.embed, false),
			rename: options.rename || path.basename,
			engine: options.engine || 'fontforge',
			autoHint: options.autoHint !== false,
			codepoints: options.codepoints,
			startCodepoint: options.startCodepoint || wf.UNICODE_PUA_START,
			ie7: options.ie7 === true,
			normalize: options.normalize !== false,
			logger: logger,
			fontHeight: options.fontHeight || 512,
			descent: options.descent || 64,
			ascent: options.ascent || 448
		};

		o = _.extend(o, {
			fontName: o.fontBaseName,
			destHtml: options.destHtml || o.destCss,
			fontfaceStyles: has(o.styles, 'font'),
			baseStyles: has(o.styles, 'icon'),
			extraStyles: has(o.styles, 'extra'),
			files: files,
			glyphs: []
		});

		// “Rename” files
		o.glyphs = o.files.map(function(file) {
			return o.rename(file).replace(path.extname(file), '');
		});

		// Check or generate codepoints
		// @todo Codepoint can be a Unicode code or character.
		var currentCodepoint = o.startCodepoint;
		if (!o.codepoints) o.codepoints = {};
		o.glyphs.forEach(function(name) {
			if (!o.codepoints[name]) {
				o.codepoints[name] = getNextCodepoint();
			}
		});

		// Run!
		async.waterfall([
			createOutputDirs,
			cleanOutputDir,
			generateFont,
			generateStylesheet,
			generateDemoHtml,
			printDone
		], allDone);

		/**
		 * Create output directory
		 *
		 * @param {Function} done
		 */
		function createOutputDirs(done) {
			mkdirp.sync(o.destCss);
			mkdirp.sync(o.dest);
			done();
		}

		/**
		 * Clean output directory
		 *
		 * @param {Function} done
		 */
		function cleanOutputDir(done) {
			var htmlDemoFileMask = path.join(o.destCss, o.fontBaseName + '*.{' + o.stylesheet + ',html}');
			var files = glob.sync(htmlDemoFileMask).concat(generatedFontFiles());
			async.forEach(files, function(file, next) {
				fs.unlink(file, next);
			}, done);
		}

		/**
		 * Generate font using selected engine
		 *
		 * @param {Function} done
		 */
		function generateFont(done) {
			var engine = require('./engines/' + o.engine);
			engine(o, function(result) {
				if (result === false) {
					// Font was not created, exit
					allDone();
				}

				if (result) {
					o = _.extend(o, result);
				}

				done();
			});
		}

		/**
		 * Generate CSS
		 *
		 * @param {Function} done
		 */
		function generateStylesheet(done) {
			// Relative fonts path
			if (!o.relativeFontPath) {
				o.relativeFontPath = path.relative(o.destCss, o.dest);
			}
			o.relativeFontPath = normalizePath(o.relativeFontPath);

			// Generate font URLs to use in @font-face
			var fontSrcs = [[], []];
			o.order.forEach(function(type) {
				if (!has(o.types, type)) return;
				wf.fontsSrcsMap[type].forEach(function(font, idx) {
					if (font) {
						fontSrcs[idx].push(generateFontSrc(type, font));
					}
				});
			});

			// Convert them to strings that could be used in CSS
			var fontSrcSeparator = option(wf.fontSrcSeparators, o.stylesheet);
			fontSrcs.forEach(function(font, idx) {
				// o.fontSrc1, o.fontSrc2
				o['fontSrc'+(idx+1)] = font.join(fontSrcSeparator);
			});

			// Convert codepoints to array of strings
			var codepoints = [];
			_.each(o.glyphs, function(name) {
				codepoints.push(o.codepoints[name].toString(16));
			});
			o.codepoints = codepoints;

			// Prepage glyph names to use as CSS classes
			o.glyphs = _.map(o.glyphs, classnameize);

			// Read JSON file corresponding to CSS template
			var templateJson = readTemplate(o.template, o.syntax, '.json', true);
			if (templateJson) o = _.extend(o, JSON.parse(templateJson.template));

			// Now override values with templateOptions
			if (o.templateOptions) o = _.extend(o, o.templateOptions);

			// Generate CSS
			o.cssTemplate = readTemplate(o.template, o.syntax, '.css');
			var cssFilePrefix = option(wf.cssFilePrefixes, o.stylesheet);
			var cssFile = path.join(o.destCss, cssFilePrefix + o.fontBaseName + '.' + o.stylesheet);
			var cssContext = _.extend(o, {
				iconsStyles: true
			});

			var css = renderTemplate(o.cssTemplate, cssContext);

			// Fix CSS preprocessors comments: single line comments will be removed after compilation
			if (has(['sass', 'scss', 'less', 'styl'], o.stylesheet)) {
				css = css.replace(/\/\* *(.*?) *\*\//g, '// $1');
			}

			// Save file
			fs.writeFileSync(cssFile, css);

			done();
		}

		/**
		 * Generate HTML demo page
		 *
		 * @param {Function} done
		 */
		function generateDemoHtml(done) {
			if (!o.htmlDemo) return done();

			// HTML should not contain relative paths
			// If some styles was not included in CSS we should include them in HTML to properly render icons
			var relativeRe = new RegExp(_s.escapeRegExp(o.relativeFontPath), 'g');
			var htmlRelativeFontPath = normalizePath(path.relative(o.destHtml, o.dest));
			var context = _.extend(o, {
				fontSrc1: o.fontSrc1.replace(relativeRe, htmlRelativeFontPath),
				fontSrc2: o.fontSrc2.replace(relativeRe, htmlRelativeFontPath),
				fontfaceStyles: true,
				baseStyles: true,
				extraStyles: false,
				iconsStyles: true,
				stylesheet: 'css'
			});
			var htmlStyles = renderTemplate(o.cssTemplate, context);
			var htmlContext = _.extend(context, {
				styles: htmlStyles
			});

			// Generate HTML
			var demoTemplate = readTemplate(o.htmlDemoTemplate, 'demo', '.html');
			var demoFile = path.join(o.destHtml, o.fontBaseName + '.html');
			var demo = renderTemplate(demoTemplate, htmlContext);

			// Save file
			fs.writeFileSync(demoFile, demo);

			done();
		}

		/**
		 * Print log
		 *
		 * @param {Function} done
		 */
		function printDone(done) {
			logger.log('Font ' + chalk.cyan(o.fontName) + ' with ' + o.glyphs.length + ' glyphs created.');
			done();
		}

		/**
		 * Helpers
		 */

		/**
		 * Convert a string of comma seperated words into an array
		 *
		 * @param {String} val Input string
		 * @param {String} defVal Default value
		 * @return {Array}
		 */
		function optionToArray(val, defVal) {
			if (val === undefined) val = defVal;
			if (!val) return [];
			if (typeof val !== 'string') return val;
			if (val.indexOf(',') !== -1) {
				return val.split(',');
			}
			else {
				return [val];
			}
		}

		/**
		 * Check if a value exists in an array
		 *
		 * @param {Array} haystack Array to find the needle in
		 * @param {Mixed} needle Value to find
		 * @return {Boolean} Needle was found
		 */
		function has(haystack, needle) {
			return haystack.indexOf(needle) !== -1;
		}

		/**
		 * Return a specified option if it exists in an object or `_default` otherwise
		 *
		 * @param {Object} map Options object
		 * @param {String} key Option to find in the object
		 * @return {Mixed}
		 */
		function option(map, key) {
			if (key in map) {
				return map[key];
			}
			else {
				return map._default;
			}
		}

		/**
		 * Find next unused codepoint.
		 *
		 * @return {Integer}
		 */
		function getNextCodepoint() {
			while (_.contains(o.codepoints, currentCodepoint)) {
				currentCodepoint++;
			}
			return currentCodepoint;
		}

		/**
		 * Check whether file is SVG or not
		 *
		 * @param {String} filepath File path
		 * @return {Boolean}
		 */
		function isSvgFile(filepath) {
			return path.extname(filepath).toLowerCase() === '.svg';
		}

		/**
		 * Convert font file to data:uri and remove source file
		 *
		 * @param {String} fontFile Font file path
		 * @return {String} Base64 encoded string
		 */
		function embedFont(fontFile) {
			// Convert to data:uri
			var dataUri = fs.readFileSync(fontFile, 'base64');
			var type = path.extname(fontFile).substring(1);
			var fontUrl = 'data:application/x-font-' + type + ';charset=utf-8;base64,' + dataUri;

			// Remove font file
			fs.unlinkSync(fontFile);

			return fontUrl;
		}

		/**
		 * Append a slash to end of a filepath if it not exists and make all slashes forward
		 *
		 * @param {String} filepath File path
		 * @return {String}
		 */
		function normalizePath(filepath) {
			if (!filepath.length) return filepath;

			// Make all slashes forward
			filepath = filepath.replace(/\\/g, '/');

			// Make sure path ends with a slash
			if (!_s.endsWith(filepath, '/')) {
				filepath += '/';
			}

			return filepath;
		}

		/**
		 * Generate URL for @font-face
		 *
		 * @param {String} type Type of font
		 * @param {Object} font URL or Base64 string
		 * @return {String}
		 */
		function generateFontSrc(type, font) {
			var filename = template(o.fontName + font.ext, o);

			var url;
			if (font.embeddable && has(o.embed, type)) {
				url = embedFont(path.join(o.dest, filename));
			}
			else {
				url = o.relativeFontPath + filename;
			}

			var src = 'url("' + url + '")';
			if (font.format) src += ' format("' + font.format + '")';

			return src;
		}

		/**
		 * Reat the template file
		 *
		 * @param {String} template Template file path
		 * @param {String} syntax Syntax (bem, bootstrap, etc.)
		 * @param {String} ext Extention of the template
		 * @return {Object} {filename: 'Template filename', template: 'Template code'}
		 */
		function readTemplate(template, syntax, ext, optional) {
			var filename = template
				? path.resolve(template.replace(/\.[^\\\/.]+$/, '') + ext)
				: path.join(__dirname, 'templates/' + syntax + ext)
			;
			if (fs.existsSync(filename)) {
				return {
					filename: filename,
					template: fs.readFileSync(filename, 'utf8')
				};
			}
			else if (!optional) {
				return grunt.fail.fatal('Cannot find template at path: ' + filename);
			}
		}

		/**
		 * Render template with error reporting
		 *
		 * @param {Object} template {filename: 'Template filename', template: 'Template code'}
		 * @param {Object} context Template context
		 * @return {String}
		 */
		function renderTemplate(template, context) {
			try {
				return _.template(template.template, context);
			}
			catch (e) {
				grunt.fail.fatal('Error while rendering template ' + template.filename + ': ' + e.message);
			}
		}

		/**
		 * Return list of generated font files
		 *
		 * @return {Array}
		 */
		function generatedFontFiles() {
			return glob.sync(path.join(o.dest, o.fontBaseName + wf.fontFileMask));
		}

		/**
		 * Basic template function: replaces {variables}
		 *
		 * @param {Template} tmpl Template code
		 * @param {Object} context Values object
		 * @return {String}
		 */
		function template(tmpl, context) {
			return tmpl.replace(/\{([^\}]+)\}/g, function(m, key) {
				return context[key];
			});
		}

		/**
		 * Prepare string to use as CSS class name
		 *
		 * @param {String} str
		 * @return {String}
		 */
		function classnameize(str) {
			return _s.trim(str).replace(/\s+/g, '-');
		}
	});
};
<commit_msg>Warn on empty svgs list, carry on<commit_after>/**
 * SVG to webfont converter for Grunt
 *
 * @requires ttfautohint
 * @author Artem Sapegin (http://sapegin.me)
 */

module.exports = function(grunt) {
	'use strict';

	var fs = require('fs');
	var path = require('path');
	var async = require('async');
	var glob = require('glob');
	var chalk = require('chalk');
	var mkdirp = require('mkdirp');
	var _ = require('lodash');
	var _s = require('underscore.string');
	var wf = require('./util/util');

	grunt.registerMultiTask('webfont', 'Compile separate SVG files to webfont', function() {
		['src', 'dest'].forEach(function(name) {
			this.requiresConfig([this.name, this.target, name].join('.'));
		}.bind(this));

		var allDone = this.async();
		var params = this.data;
		var options = params.options || {};

		/**
		 * Winston to Grunt logger adapter.
		 */
		var logger = {
			warn: function() {
				grunt.log.warn.apply(null, arguments);
			},
			error: function() {
				grunt.warn.apply(null, arguments);
			},
			log: function() {
				grunt.log.writeln.apply(null, arguments);
			},
			verbose: function() {
				grunt.verbose.writeln.apply(null, arguments);
			}
		};

		if (options.skip) {
			allDone();
			return;
		}

		// Source files
		var files = _.filter(this.filesSrc, isSvgFile);
		if (!files.length) {
			logger.warn('Specified empty list of source SVG files.');
		}

		// Options
		var o = {
			fontBaseName: options.font || 'icons',
			destCss: params.destCss || params.dest,
			dest: params.dest,
			relativeFontPath: options.relativeFontPath,
			addHashes: options.hashes !== false,
			addLigatures: options.ligatures === true,
			template: options.template,
			syntax: options.syntax || 'bem',
			templateOptions: options.templateOptions || {},
			stylesheet: options.stylesheet || 'css',
			htmlDemo: options.htmlDemo !== false,
			htmlDemoTemplate: options.htmlDemoTemplate,
			styles: optionToArray(options.styles, 'font,icon'),
			types: optionToArray(options.types, wf.fontFormats),
			order: optionToArray(options.order, wf.fontFormats),
			embed: options.embed === true ? ['woff'] : optionToArray(options.embed, false),
			rename: options.rename || path.basename,
			engine: options.engine || 'fontforge',
			autoHint: options.autoHint !== false,
			codepoints: options.codepoints,
			startCodepoint: options.startCodepoint || wf.UNICODE_PUA_START,
			ie7: options.ie7 === true,
			normalize: options.normalize !== false,
			logger: logger,
			fontHeight: options.fontHeight || 512,
			descent: options.descent || 64,
			ascent: options.ascent || 448
		};

		o = _.extend(o, {
			fontName: o.fontBaseName,
			destHtml: options.destHtml || o.destCss,
			fontfaceStyles: has(o.styles, 'font'),
			baseStyles: has(o.styles, 'icon'),
			extraStyles: has(o.styles, 'extra'),
			files: files,
			glyphs: []
		});

		// “Rename” files
		o.glyphs = o.files.map(function(file) {
			return o.rename(file).replace(path.extname(file), '');
		});

		// Check or generate codepoints
		// @todo Codepoint can be a Unicode code or character.
		var currentCodepoint = o.startCodepoint;
		if (!o.codepoints) o.codepoints = {};
		o.glyphs.forEach(function(name) {
			if (!o.codepoints[name]) {
				o.codepoints[name] = getNextCodepoint();
			}
		});

		// Run!
		async.waterfall([
			createOutputDirs,
			cleanOutputDir,
			generateFont,
			generateStylesheet,
			generateDemoHtml,
			printDone
		], allDone);

		/**
		 * Create output directory
		 *
		 * @param {Function} done
		 */
		function createOutputDirs(done) {
			mkdirp.sync(o.destCss);
			mkdirp.sync(o.dest);
			done();
		}

		/**
		 * Clean output directory
		 *
		 * @param {Function} done
		 */
		function cleanOutputDir(done) {
			var htmlDemoFileMask = path.join(o.destCss, o.fontBaseName + '*.{' + o.stylesheet + ',html}');
			var files = glob.sync(htmlDemoFileMask).concat(generatedFontFiles());
			async.forEach(files, function(file, next) {
				fs.unlink(file, next);
			}, done);
		}

		/**
		 * Generate font using selected engine
		 *
		 * @param {Function} done
		 */
		function generateFont(done) {
			var engine = require('./engines/' + o.engine);
			engine(o, function(result) {
				if (result === false) {
					// Font was not created, exit
					allDone();
				}

				if (result) {
					o = _.extend(o, result);
				}

				done();
			});
		}

		/**
		 * Generate CSS
		 *
		 * @param {Function} done
		 */
		function generateStylesheet(done) {
			// Relative fonts path
			if (!o.relativeFontPath) {
				o.relativeFontPath = path.relative(o.destCss, o.dest);
			}
			o.relativeFontPath = normalizePath(o.relativeFontPath);

			// Generate font URLs to use in @font-face
			var fontSrcs = [[], []];
			o.order.forEach(function(type) {
				if (!has(o.types, type)) return;
				wf.fontsSrcsMap[type].forEach(function(font, idx) {
					if (font) {
						fontSrcs[idx].push(generateFontSrc(type, font));
					}
				});
			});

			// Convert them to strings that could be used in CSS
			var fontSrcSeparator = option(wf.fontSrcSeparators, o.stylesheet);
			fontSrcs.forEach(function(font, idx) {
				// o.fontSrc1, o.fontSrc2
				o['fontSrc'+(idx+1)] = font.join(fontSrcSeparator);
			});

			// Convert codepoints to array of strings
			var codepoints = [];
			_.each(o.glyphs, function(name) {
				codepoints.push(o.codepoints[name].toString(16));
			});
			o.codepoints = codepoints;

			// Prepage glyph names to use as CSS classes
			o.glyphs = _.map(o.glyphs, classnameize);

			// Read JSON file corresponding to CSS template
			var templateJson = readTemplate(o.template, o.syntax, '.json', true);
			if (templateJson) o = _.extend(o, JSON.parse(templateJson.template));

			// Now override values with templateOptions
			if (o.templateOptions) o = _.extend(o, o.templateOptions);

			// Generate CSS
			o.cssTemplate = readTemplate(o.template, o.syntax, '.css');
			var cssFilePrefix = option(wf.cssFilePrefixes, o.stylesheet);
			var cssFile = path.join(o.destCss, cssFilePrefix + o.fontBaseName + '.' + o.stylesheet);
			var cssContext = _.extend(o, {
				iconsStyles: true
			});

			var css = renderTemplate(o.cssTemplate, cssContext);

			// Fix CSS preprocessors comments: single line comments will be removed after compilation
			if (has(['sass', 'scss', 'less', 'styl'], o.stylesheet)) {
				css = css.replace(/\/\* *(.*?) *\*\//g, '// $1');
			}

			// Save file
			fs.writeFileSync(cssFile, css);

			done();
		}

		/**
		 * Generate HTML demo page
		 *
		 * @param {Function} done
		 */
		function generateDemoHtml(done) {
			if (!o.htmlDemo) return done();

			// HTML should not contain relative paths
			// If some styles was not included in CSS we should include them in HTML to properly render icons
			var relativeRe = new RegExp(_s.escapeRegExp(o.relativeFontPath), 'g');
			var htmlRelativeFontPath = normalizePath(path.relative(o.destHtml, o.dest));
			var context = _.extend(o, {
				fontSrc1: o.fontSrc1.replace(relativeRe, htmlRelativeFontPath),
				fontSrc2: o.fontSrc2.replace(relativeRe, htmlRelativeFontPath),
				fontfaceStyles: true,
				baseStyles: true,
				extraStyles: false,
				iconsStyles: true,
				stylesheet: 'css'
			});
			var htmlStyles = renderTemplate(o.cssTemplate, context);
			var htmlContext = _.extend(context, {
				styles: htmlStyles
			});

			// Generate HTML
			var demoTemplate = readTemplate(o.htmlDemoTemplate, 'demo', '.html');
			var demoFile = path.join(o.destHtml, o.fontBaseName + '.html');
			var demo = renderTemplate(demoTemplate, htmlContext);

			// Save file
			fs.writeFileSync(demoFile, demo);

			done();
		}

		/**
		 * Print log
		 *
		 * @param {Function} done
		 */
		function printDone(done) {
			logger.log('Font ' + chalk.cyan(o.fontName) + ' with ' + o.glyphs.length + ' glyphs created.');
			done();
		}

		/**
		 * Helpers
		 */

		/**
		 * Convert a string of comma seperated words into an array
		 *
		 * @param {String} val Input string
		 * @param {String} defVal Default value
		 * @return {Array}
		 */
		function optionToArray(val, defVal) {
			if (val === undefined) val = defVal;
			if (!val) return [];
			if (typeof val !== 'string') return val;
			if (val.indexOf(',') !== -1) {
				return val.split(',');
			}
			else {
				return [val];
			}
		}

		/**
		 * Check if a value exists in an array
		 *
		 * @param {Array} haystack Array to find the needle in
		 * @param {Mixed} needle Value to find
		 * @return {Boolean} Needle was found
		 */
		function has(haystack, needle) {
			return haystack.indexOf(needle) !== -1;
		}

		/**
		 * Return a specified option if it exists in an object or `_default` otherwise
		 *
		 * @param {Object} map Options object
		 * @param {String} key Option to find in the object
		 * @return {Mixed}
		 */
		function option(map, key) {
			if (key in map) {
				return map[key];
			}
			else {
				return map._default;
			}
		}

		/**
		 * Find next unused codepoint.
		 *
		 * @return {Integer}
		 */
		function getNextCodepoint() {
			while (_.contains(o.codepoints, currentCodepoint)) {
				currentCodepoint++;
			}
			return currentCodepoint;
		}

		/**
		 * Check whether file is SVG or not
		 *
		 * @param {String} filepath File path
		 * @return {Boolean}
		 */
		function isSvgFile(filepath) {
			return path.extname(filepath).toLowerCase() === '.svg';
		}

		/**
		 * Convert font file to data:uri and remove source file
		 *
		 * @param {String} fontFile Font file path
		 * @return {String} Base64 encoded string
		 */
		function embedFont(fontFile) {
			// Convert to data:uri
			var dataUri = fs.readFileSync(fontFile, 'base64');
			var type = path.extname(fontFile).substring(1);
			var fontUrl = 'data:application/x-font-' + type + ';charset=utf-8;base64,' + dataUri;

			// Remove font file
			fs.unlinkSync(fontFile);

			return fontUrl;
		}

		/**
		 * Append a slash to end of a filepath if it not exists and make all slashes forward
		 *
		 * @param {String} filepath File path
		 * @return {String}
		 */
		function normalizePath(filepath) {
			if (!filepath.length) return filepath;

			// Make all slashes forward
			filepath = filepath.replace(/\\/g, '/');

			// Make sure path ends with a slash
			if (!_s.endsWith(filepath, '/')) {
				filepath += '/';
			}

			return filepath;
		}

		/**
		 * Generate URL for @font-face
		 *
		 * @param {String} type Type of font
		 * @param {Object} font URL or Base64 string
		 * @return {String}
		 */
		function generateFontSrc(type, font) {
			var filename = template(o.fontName + font.ext, o);

			var url;
			if (font.embeddable && has(o.embed, type)) {
				url = embedFont(path.join(o.dest, filename));
			}
			else {
				url = o.relativeFontPath + filename;
			}

			var src = 'url("' + url + '")';
			if (font.format) src += ' format("' + font.format + '")';

			return src;
		}

		/**
		 * Reat the template file
		 *
		 * @param {String} template Template file path
		 * @param {String} syntax Syntax (bem, bootstrap, etc.)
		 * @param {String} ext Extention of the template
		 * @return {Object} {filename: 'Template filename', template: 'Template code'}
		 */
		function readTemplate(template, syntax, ext, optional) {
			var filename = template
				? path.resolve(template.replace(/\.[^\\\/.]+$/, '') + ext)
				: path.join(__dirname, 'templates/' + syntax + ext)
			;
			if (fs.existsSync(filename)) {
				return {
					filename: filename,
					template: fs.readFileSync(filename, 'utf8')
				};
			}
			else if (!optional) {
				return grunt.fail.fatal('Cannot find template at path: ' + filename);
			}
		}

		/**
		 * Render template with error reporting
		 *
		 * @param {Object} template {filename: 'Template filename', template: 'Template code'}
		 * @param {Object} context Template context
		 * @return {String}
		 */
		function renderTemplate(template, context) {
			try {
				return _.template(template.template, context);
			}
			catch (e) {
				grunt.fail.fatal('Error while rendering template ' + template.filename + ': ' + e.message);
			}
		}

		/**
		 * Return list of generated font files
		 *
		 * @return {Array}
		 */
		function generatedFontFiles() {
			return glob.sync(path.join(o.dest, o.fontBaseName + wf.fontFileMask));
		}

		/**
		 * Basic template function: replaces {variables}
		 *
		 * @param {Template} tmpl Template code
		 * @param {Object} context Values object
		 * @return {String}
		 */
		function template(tmpl, context) {
			return tmpl.replace(/\{([^\}]+)\}/g, function(m, key) {
				return context[key];
			});
		}

		/**
		 * Prepare string to use as CSS class name
		 *
		 * @param {String} str
		 * @return {String}
		 */
		function classnameize(str) {
			return _s.trim(str).replace(/\s+/g, '-');
		}
	});
};
<|endoftext|>


<commit_before>/**
 * app.js
 *
 * Use `app.js` to run your app without `sails lift`.
 * To start the server, run: `node app.js`.
 *
 * This is handy in situations where the sails CLI is not relevant or useful.
 *
 * For example:
 *   => `node app.js`
 *   => `forever start app.js`
 *   => `node debug app.js`
 *   => `modulus deploy`
 *   => `heroku scale`
 *
 *
 * The same command-line arguments are supported, e.g.:
 * `node app.js --silent --port=80 --prod`
 */

// Ensure a "sails" can be located:
var sails;
try {
	sails = require('sails');
} catch (e) {
	console.error('To run an app using `node app.js`, you usually need to have a version of `sails` installed in the same directory as your app.');
	console.error('To do that, run `npm install sails`');
	console.error('');
	console.error('Alternatively, if you have sails installed globally (i.e. you did `npm install -g sails`), you can use `sails lift`.');
	console.error('When you run `sails lift`, your app will still use a local `./node_modules/sails` dependency if it exists,');
	console.error('but if it doesn\'t, the app will run with the global sails instead!');
	return;
}

// Try to get `rc` dependency
var rc;
try {
	rc = require('rc');
} catch (e) {}
try {
	rc = require('sails/node_modules/rc');
} catch (e) {}
if (!rc) {
	console.error('Could not find dependency: `rc`.');
	console.error('Your `.sailsrc` file(s) will be ignored.');
	console.error('To resolve this, run:');
	console.error('npm install rc --save');
	rc = function () { return {}; };
}

// Start server
sails.lift(rc('sails'));
<commit_msg>Fix try/catch blocks.<commit_after>/**
 * app.js
 *
 * Use `app.js` to run your app without `sails lift`.
 * To start the server, run: `node app.js`.
 *
 * This is handy in situations where the sails CLI is not relevant or useful.
 *
 * For example:
 *   => `node app.js`
 *   => `forever start app.js`
 *   => `node debug app.js`
 *   => `modulus deploy`
 *   => `heroku scale`
 *
 *
 * The same command-line arguments are supported, e.g.:
 * `node app.js --silent --port=80 --prod`
 */

// Ensure a "sails" can be located:
var sails;
try {
	sails = require('sails');
} catch (e) {
	console.error('To run an app using `node app.js`, you usually need to have a version of `sails` installed in the same directory as your app.');
	console.error('To do that, run `npm install sails`');
	console.error('');
	console.error('Alternatively, if you have sails installed globally (i.e. you did `npm install -g sails`), you can use `sails lift`.');
	console.error('When you run `sails lift`, your app will still use a local `./node_modules/sails` dependency if it exists,');
	console.error('but if it doesn\'t, the app will run with the global sails instead!');
	return;
}

// Try to get `rc` dependency
var rc;
try {
	rc = require('rc');
} catch (e0) {
	try {
		rc = require('sails/node_modules/rc');
	} catch (e1) {
		console.error('Could not find dependency: `rc`.');
		console.error('Your `.sailsrc` file(s) will be ignored.');
		console.error('To resolve this, run:');
		console.error('npm install rc --save');
		rc = function () { return {}; };
	}
}

// Start server
sails.lift(rc('sails'));
<|endoftext|>


<commit_before>"use strict";

var assert = require('assert');

var Game = function(player1,player2) {

  var WIN = 101; // sentinel

  var pointsProgression = [0,15,30,40,WIN];

  var formatPlayerScore = function(player, score) {
    return player + ' ' + score;
  };

  return {
    _withServes: 0,
    _otherPoints: 0,

    score: function() {
      if (this._withServes === WIN) {
        return player1 + ' won';
      }

      return formatPlayerScore(player1, this._withServes) +
             ' - ' +
             formatPlayerScore(player2, this._otherPoints);
    },

    _advancePoint: function(prop) {
      var i = pointsProgression.indexOf(this[prop]);
      this[prop] = pointsProgression[i+1];
    },

    withServe: function() {
      this._advancePoint('_withServes');
    },

    againstServe: function() {
      var i = pointsProgression.indexOf(this._otherPoints);
      this._otherPoints = pointsProgression[i+1];
    }
  };
};

describe('tennis', function() {
  describe('game', function() {
    it('starts at 0-0', function() {
      var game = new Game('Joe', 'Fred');
      assert.equal('Joe 0 - Fred 0', game.score());
    });

    it ('game to love', function() {
      var game = new Game('Joe', 'Fred');

      game.withServe();
      assert.equal('Joe 15 - Fred 0', game.score());

      game.withServe();
      assert.equal('Joe 30 - Fred 0', game.score());

      game.withServe();
      assert.equal('Joe 40 - Fred 0', game.score());

      game.withServe();
      assert.equal('Joe won', game.score());
    });

    it('game against server to love', function() {
      var game = new Game('Joe', 'Fred');

      game.againstServe();
      assert.equal('Joe 0 - Fred 15', game.score());

      game.againstServe();
      assert.equal('Joe 0 - Fred 30', game.score());

      game.againstServe();
      assert.equal('Joe 0 - Fred 40', game.score());
    });
  });
});
<commit_msg>refactor<commit_after>"use strict";

var assert = require('assert');

var Game = function(player1,player2) {

  var WIN = 101; // sentinel

  var pointsProgression = [0,15,30,40,WIN];

  var formatPlayerScore = function(player, score) {
    return player + ' ' + score;
  };

  return {
    _withServes: 0,
    _otherPoints: 0,

    score: function() {
      if (this._withServes === WIN) {
        return player1 + ' won';
      }

      return formatPlayerScore(player1, this._withServes) +
             ' - ' +
             formatPlayerScore(player2, this._otherPoints);
    },

    _advancePoint: function(prop) {
      var i = pointsProgression.indexOf(this[prop]);
      this[prop] = pointsProgression[i+1];
    },

    withServe: function() {
      this._advancePoint('_withServes');
    },

    againstServe: function() {
      this._advancePoint('_otherPoints');
    }
  };
};

describe('tennis', function() {
  describe('game', function() {
    it('starts at 0-0', function() {
      var game = new Game('Joe', 'Fred');
      assert.equal('Joe 0 - Fred 0', game.score());
    });

    it ('game to love', function() {
      var game = new Game('Joe', 'Fred');

      game.withServe();
      assert.equal('Joe 15 - Fred 0', game.score());

      game.withServe();
      assert.equal('Joe 30 - Fred 0', game.score());

      game.withServe();
      assert.equal('Joe 40 - Fred 0', game.score());

      game.withServe();
      assert.equal('Joe won', game.score());
    });

    it('game against server to love', function() {
      var game = new Game('Joe', 'Fred');

      game.againstServe();
      assert.equal('Joe 0 - Fred 15', game.score());

      game.againstServe();
      assert.equal('Joe 0 - Fred 30', game.score());

      game.againstServe();
      assert.equal('Joe 0 - Fred 40', game.score());
    });
  });
});
<|endoftext|>


<commit_before>var should = require('should');
var net = require('net');
var bignum = require('bignum');
var _ = require('underscore');
var Consumer = require('../index').Consumer;
var Message = require('../index').Message;
var FetchResponse = require('../index').FetchResponse;
var OffsetsResponse = require('../index').OffsetsResponse;
var BufferMaker = require('buffermaker');
var binary = require('binary');

function bufferFromString(str){
    var bytes = str.split(" ");
    bytes = _.map(bytes, function(datum){
      return parseInt(datum, 16);
    });
    bytes = new Buffer(bytes);
    return bytes;
}

function closeServer(server, cb){
  if (!!server){
    try {
      server.close(function(){
        cb();
      });
      server = null;
      setTimeout(function(){cb();}, 1000);
    } catch(ex){
        server = null;
        cb();
    }

  } else {
    cb();
  }
}

describe("Consumer", function(){
  beforeEach(function(done){
    if (!this.server){  this.server = null; }
    closeServer(this.server, done);
  });
  //afterEach(function(done){
  //  closeServer(this.server, done);
  //});

  describe("#ctor", function(){

    it("creates a consumer with a default topic", function(){
      var consumer = new Consumer();
      consumer.topic.should.equal('test');
    });

    it("creates a consumer withi a default partition", function(){
      var consumer = new Consumer();
      consumer.partition.should.equal(0);
    });

    it("creates a consumer with a default polling time", function(){
      var consumer = new Consumer();
      consumer.polling.should.equal(2);
    });

    it("creates a consumer with a passed in topic", function(){
      var consumer = new Consumer({topic:"newtopic"});
      consumer.topic.should.equal("newtopic");
    });

    it("creates a consumer with a passed in partition", function(){
      var consumer = new Consumer({partition:3});
      consumer.partition.should.equal(3);
    });

    it("creates a consumer with a default host of 'localhost'", function(){
      var consumer = new Consumer();
      consumer.host.should.equal('localhost');
    });

    it("creates a consumer with a default port of 9092", function(){
      var consumer = new Consumer();
      consumer.port.should.equal(9092);
    });

    it("creates a consumer with a default offset of null", function(){
      var consumer = new Consumer();
      should.not.exist(consumer.offset);
    });

    it("creates a consumer with a passed in offset", function(){
      var consumer = new Consumer({offset:1111});
      consumer.offset.should.equal(1111);
    });

    it("creates a consumer with a maximum message size", function(){
      var consumer = new Consumer();
      consumer.maxMessageSize.should.equal(1048576);
    });

  });

  /*

  describe("#sendConsumeRequest", function(){

    it("should send a consumer request", function(done){
      this.timeout(60000);
      var consumer = new Consumer({ port : 9092});
      this.server = net.createServer(function(listener){
        listener.on('data', function(data){
          var expected = "00 00 00 18 00 01 00 04 74 65 73 74 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00";
          data.should.eql(bufferFromString(expected));
          var fetchResponse = new FetchResponse(0, [new Message("ale"), new Message("foobar")]);
          listener.write(fetchResponse.toBytes());
        });

      });

      var server = this.server;
      this.server.listen(9092, function(){
        consumer.connect(function(err){
          consumer.offset = bignum(0);
          consumer.sendConsumeRequest(function(err, fetchResponse){
            if (!!err){console.log(err);}
            should.not.exist(err);
            fetchResponse.error.should.equal(0);
            fetchResponse.messages.length.should.equal(2);
            fetchResponse.messages[0].payload.toString().should.equal("ale");
            if (!!err){throw err;}
            done();
          });
        });
      });
    });
  });
*/

  describe("#getOffsets", function(){

    it("should send an offset request and give a response object" , function(done){
     this.timeout(60000);
     this.server = net.createServer(function(listener){
       listener.on('data', function(data){
         // TODO validate the incoming offsets request

         // create a response
         var binaryResponse = new BufferMaker()
         .UInt32BE(22)   // response length
         .UInt16BE(0)  // error code
         .UInt32BE(2)    // number of offsets
         .Int64BE(0)   // offset 1
         .Int64BE(23)   // offset 23
         .make();

         listener.write(binaryResponse);
       });

     });

     this.server.listen(9092, function(){
     });

     var consumer = new Consumer();
     consumer.connect(function(err){
       consumer.getOffsets(function(err, offsetsResponse){
         if (err) { throw err; }
         if (offsetsResponse.error) { throw offsetsResponse.error; }
         var offsets = offsetsResponse.offsets;
         offsets.length.should.equal(2);
         offsets[1].eq(23).should.equal(true);
         done();
       });
     });

    });

    it("sends offset requests, gather the response OVER TIME, and gives response objects" , function(done){
     this.timeout(60000);
     this.server = net.createServer(function(listener){
       listener.on('data', function(data){
         // TODO validate the incoming offsets request

         // create a response
         var binaryResponse = new BufferMaker()
         .UInt32BE(22)   // response length
         .UInt16BE(0)  // error code
         .UInt32BE(2)    // number of offsets
         .make();
         listener.write(binaryResponse);

         setTimeout(function(){
           binaryResponse = new BufferMaker()
           .Int64BE(54)   // offset 1
           .Int64BE(23)   // offset 23
           .make();

           listener.write(binaryResponse);
         }, 120);  // 120 ms delay on second half
       });

     });

     this.server.listen(9092, function(){
     });

     var consumer = new Consumer();
     consumer.connect(function(err){
       consumer.getOffsets(function(err, offsetsResponse){
         if (err) { throw err; }
         var offsets = offsetsResponse.offsets;
         offsets.length.should.equal(2);
         offsets[1].eq(23).should.equal(true);
         done();
       });
     });

    });

  });

  describe("#handleFetchData", function(){
    it ("should return a fetchResponse object when possible", function(done){
      var consumer = new Consumer({topic : "test"});
      consumer.setOffset(123);
      consumer._setRequestMode('offsets');
      var randomBytes = new Buffer([0,1,2,3]);
      var messages = [new Message("hello"), new Message("there")];
      var res = new FetchResponse(0, messages).toBytes();
      consumer.responseBuffer = Buffer.concat([res, randomBytes]);
      consumer.handleFetchData(function(err, response){
        should.not.exist(err);
        response.messages[0].payload.should.eql(new Buffer("hello"));
        response.messages[1].payload.should.eql(new Buffer("there"));
        consumer.responseBuffer.should.eql(new Buffer([0,1,2,3]));
        should.not.exist(consumer.requestMode);
        consumer.offset.eq(bignum(123 +
                                  messages[0].toBytes().length +
                                  messages[1].toBytes().length )).should.equal(true);
        done();
      });
    });

  });
  describe("#handleOffsetsData", function(){
    it ("should return an offsetResponse object when possible", function(done){
      var consumer = new Consumer({topic : "test"});
      consumer.setOffset(123);
      consumer._setRequestMode('offsets');
      var randomBytes = new Buffer([0,1,2,3]);
      var res = new OffsetsResponse(0, [456]).toBytes();
      consumer.responseBuffer = Buffer.concat([res, randomBytes]);
      consumer.handleOffsetsData(function(err, response){
        response.error.should.equal(0);
        response.offsets[0].eq(bignum(456)).should.equal(true);
        should.not.exist(err);
        consumer.responseBuffer.should.eql(new Buffer([0,1,2,3]));
        should.not.exist(consumer.requestMode);
        done();
      });
    });

  });
  describe("#consume", function(){

    it ("should consume with the latest offset if no offset is provided", function(done){
       this.server = net.createServer(function(listener){
         var requestBuffer = new Buffer([]);

         listener.on('data', function(data){
           requestBuffer = Buffer.concat([requestBuffer, data]);
           data = requestBuffer;
           // check if it's a full request:

           var unpacked = binary(requestBuffer)
                            .word32bu("length")
                            .word16bu("type")
                            .vars;

           var totalExpectedLength = unpacked.length + 4;  // 4 bytes for the length field
           if (data.length >= totalExpectedLength ){
             requestBuffer = requestBuffer.slice(totalExpectedLength);

             switch(unpacked.type){
               case 4 :  // OFFSETS
                   // fake offsets response!
                   var offsetsResponse = new OffsetsResponse(0, [54, 23]);
                   listener.write(offsetsResponse.toBytes());
                   break;

                case 1:  // MESSAGES
                  // fake messages response!

                  var fetchResponse = new FetchResponse(0, [new Message("ale"), new Message("foobar")]);
                  listener.write(fetchResponse.toBytes());
                  break;
                default : throw "unknown request type: " + unpacked.type;
             }
           }
         });

       });

       var consumer = new Consumer({topic : "test"});
       this.server.listen(9092, function(){
         consumer.connect(function(err){
           consumer.consume(function(err, messages){
             should.not.exist(err);
             messages.length.should.equal(2);
             messages[0].payload.toString().should.equal("ale");
             messages[1].payload.toString().should.equal("foobar");
             (consumer.offset.eq(83)).should.equal(true);
             done();
           });
         });
       });

      });
  });

});

<commit_msg>try # 99999999999<commit_after>var should = require('should');
var net = require('net');
var bignum = require('bignum');
var _ = require('underscore');
var Consumer = require('../index').Consumer;
var Message = require('../index').Message;
var FetchResponse = require('../index').FetchResponse;
var OffsetsResponse = require('../index').OffsetsResponse;
var BufferMaker = require('buffermaker');
var binary = require('binary');

function bufferFromString(str){
    var bytes = str.split(" ");
    bytes = _.map(bytes, function(datum){
      return parseInt(datum, 16);
    });
    bytes = new Buffer(bytes);
    return bytes;
}

function closeServer(server, cb){
  if (!!server){
    try {
      server.close(function(){
        cb();
      });
      server = null;
      setTimeout(function(){cb();}, 1000);
    } catch(ex){
        server = null;
        cb();
    }

  } else {
    cb();
  }
}

describe("Consumer", function(){
  beforeEach(function(done){
    if (!this.server){  this.server = null; }
    closeServer(this.server, done);
  });
  //afterEach(function(done){
  //  closeServer(this.server, done);
  //});

  describe("#ctor", function(){

    it("creates a consumer with a default topic", function(){
      var consumer = new Consumer();
      consumer.topic.should.equal('test');
    });

    it("creates a consumer withi a default partition", function(){
      var consumer = new Consumer();
      consumer.partition.should.equal(0);
    });

    it("creates a consumer with a default polling time", function(){
      var consumer = new Consumer();
      consumer.polling.should.equal(2);
    });

    it("creates a consumer with a passed in topic", function(){
      var consumer = new Consumer({topic:"newtopic"});
      consumer.topic.should.equal("newtopic");
    });

    it("creates a consumer with a passed in partition", function(){
      var consumer = new Consumer({partition:3});
      consumer.partition.should.equal(3);
    });

    it("creates a consumer with a default host of 'localhost'", function(){
      var consumer = new Consumer();
      consumer.host.should.equal('localhost');
    });

    it("creates a consumer with a default port of 9092", function(){
      var consumer = new Consumer();
      consumer.port.should.equal(9092);
    });

    it("creates a consumer with a default offset of null", function(){
      var consumer = new Consumer();
      should.not.exist(consumer.offset);
    });

    it("creates a consumer with a passed in offset", function(){
      var consumer = new Consumer({offset:1111});
      consumer.offset.should.equal(1111);
    });

    it("creates a consumer with a maximum message size", function(){
      var consumer = new Consumer();
      consumer.maxMessageSize.should.equal(1048576);
    });

  });

  /*

  describe("#sendConsumeRequest", function(){

    it("should send a consumer request", function(done){
      this.timeout(60000);
      var consumer = new Consumer({ port : 9092});
      this.server = net.createServer(function(listener){
        listener.on('data', function(data){
          var expected = "00 00 00 18 00 01 00 04 74 65 73 74 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00";
          data.should.eql(bufferFromString(expected));
          var fetchResponse = new FetchResponse(0, [new Message("ale"), new Message("foobar")]);
          listener.write(fetchResponse.toBytes());
        });

      });

      var server = this.server;
      this.server.listen(9092, function(){
        consumer.connect(function(err){
          consumer.offset = bignum(0);
          consumer.sendConsumeRequest(function(err, fetchResponse){
            if (!!err){console.log(err);}
            should.not.exist(err);
            fetchResponse.error.should.equal(0);
            fetchResponse.messages.length.should.equal(2);
            fetchResponse.messages[0].payload.toString().should.equal("ale");
            if (!!err){throw err;}
            done();
          });
        });
      });
    });
  });

  describe("#getOffsets", function(){

    it("should send an offset request and give a response object" , function(done){
     this.timeout(60000);
     this.server = net.createServer(function(listener){
       listener.on('data', function(data){
         // TODO validate the incoming offsets request

         // create a response
         var binaryResponse = new BufferMaker()
         .UInt32BE(22)   // response length
         .UInt16BE(0)  // error code
         .UInt32BE(2)    // number of offsets
         .Int64BE(0)   // offset 1
         .Int64BE(23)   // offset 23
         .make();

         listener.write(binaryResponse);
       });

     });

     this.server.listen(9092, function(){
     });

     var consumer = new Consumer();
     consumer.connect(function(err){
       consumer.getOffsets(function(err, offsetsResponse){
         if (err) { throw err; }
         if (offsetsResponse.error) { throw offsetsResponse.error; }
         var offsets = offsetsResponse.offsets;
         offsets.length.should.equal(2);
         offsets[1].eq(23).should.equal(true);
         done();
       });
     });

    });

    it("sends offset requests, gather the response OVER TIME, and gives response objects" , function(done){
     this.timeout(60000);
     this.server = net.createServer(function(listener){
       listener.on('data', function(data){
         // TODO validate the incoming offsets request

         // create a response
         var binaryResponse = new BufferMaker()
         .UInt32BE(22)   // response length
         .UInt16BE(0)  // error code
         .UInt32BE(2)    // number of offsets
         .make();
         listener.write(binaryResponse);

         setTimeout(function(){
           binaryResponse = new BufferMaker()
           .Int64BE(54)   // offset 1
           .Int64BE(23)   // offset 23
           .make();

           listener.write(binaryResponse);
         }, 120);  // 120 ms delay on second half
       });

     });

     this.server.listen(9092, function(){
     });

     var consumer = new Consumer();
     consumer.connect(function(err){
       consumer.getOffsets(function(err, offsetsResponse){
         if (err) { throw err; }
         var offsets = offsetsResponse.offsets;
         offsets.length.should.equal(2);
         offsets[1].eq(23).should.equal(true);
         done();
       });
     });

    });

  });
*/

  describe("#handleFetchData", function(){
    it ("should return a fetchResponse object when possible", function(done){
      var consumer = new Consumer({topic : "test"});
      consumer.setOffset(123);
      consumer._setRequestMode('offsets');
      var randomBytes = new Buffer([0,1,2,3]);
      var messages = [new Message("hello"), new Message("there")];
      var res = new FetchResponse(0, messages).toBytes();
      consumer.responseBuffer = Buffer.concat([res, randomBytes]);
      consumer.handleFetchData(function(err, response){
        should.not.exist(err);
        response.messages[0].payload.should.eql(new Buffer("hello"));
        response.messages[1].payload.should.eql(new Buffer("there"));
        consumer.responseBuffer.should.eql(new Buffer([0,1,2,3]));
        should.not.exist(consumer.requestMode);
        consumer.offset.eq(bignum(123 +
                                  messages[0].toBytes().length +
                                  messages[1].toBytes().length )).should.equal(true);
        done();
      });
    });

  });
  describe("#handleOffsetsData", function(){
    it ("should return an offsetResponse object when possible", function(done){
      var consumer = new Consumer({topic : "test"});
      consumer.setOffset(123);
      consumer._setRequestMode('offsets');
      var randomBytes = new Buffer([0,1,2,3]);
      var res = new OffsetsResponse(0, [456]).toBytes();
      consumer.responseBuffer = Buffer.concat([res, randomBytes]);
      consumer.handleOffsetsData(function(err, response){
        response.error.should.equal(0);
        response.offsets[0].eq(bignum(456)).should.equal(true);
        should.not.exist(err);
        consumer.responseBuffer.should.eql(new Buffer([0,1,2,3]));
        should.not.exist(consumer.requestMode);
        done();
      });
    });

  });
  describe("#consume", function(){

    it ("should consume with the latest offset if no offset is provided", function(done){
       this.server = net.createServer(function(listener){
         var requestBuffer = new Buffer([]);

         listener.on('data', function(data){
           requestBuffer = Buffer.concat([requestBuffer, data]);
           data = requestBuffer;
           // check if it's a full request:

           var unpacked = binary(requestBuffer)
                            .word32bu("length")
                            .word16bu("type")
                            .vars;

           var totalExpectedLength = unpacked.length + 4;  // 4 bytes for the length field
           if (data.length >= totalExpectedLength ){
             requestBuffer = requestBuffer.slice(totalExpectedLength);

             switch(unpacked.type){
               case 4 :  // OFFSETS
                   // fake offsets response!
                   var offsetsResponse = new OffsetsResponse(0, [54, 23]);
                   listener.write(offsetsResponse.toBytes());
                   break;

                case 1:  // MESSAGES
                  // fake messages response!

                  var fetchResponse = new FetchResponse(0, [new Message("ale"), new Message("foobar")]);
                  listener.write(fetchResponse.toBytes());
                  break;
                default : throw "unknown request type: " + unpacked.type;
             }
           }
         });

       });

       var consumer = new Consumer({topic : "test"});
       this.server.listen(9092, function(){
         consumer.connect(function(err){
           consumer.consume(function(err, messages){
             should.not.exist(err);
             messages.length.should.equal(2);
             messages[0].payload.toString().should.equal("ale");
             messages[1].payload.toString().should.equal("foobar");
             (consumer.offset.eq(83)).should.equal(true);
             done();
           });
         });
       });

      });
  });

});

<|endoftext|>


<commit_before>/* eslint no-console:0 */

'use strict';

const path = require('path');

const { CLIEngine } = require('eslint');

/**
 * Verify if a config file is valid.
 * @param {string} filepath
 * @return {boolean}
 */
function cliOutput(filepath) {
  const configFile = path.join(__dirname, `../${filepath}.js`);
  return new CLIEngine({ useEslintrc: false, configFile }).executeOnText(`/**/
`);
}

// tests

describe('eslint-config-medialaan', () => {

  [
    'index',
    'loose',
    'test',
  ].forEach((configFile) => {

    describe(configFile, () => {

      it('should be valid config', () => {
        const output = cliOutput(configFile);
        if (output.errorCount) {
          console.log(JSON.stringify(output.results, null, 2));
        }
        expect(output.errorCount).toBe(0);
      });

    });

  });

});
<commit_msg>Fix NodeJS v4<commit_after>/* eslint no-console:0 */

'use strict';

const path = require('path');

const CLIEngine = require('eslint').CLIEngine;

/**
 * Verify if a config file is valid.
 * @param {string} filepath
 * @return {boolean}
 */
function cliOutput(filepath) {
  const configFile = path.join(__dirname, `../${filepath}.js`);
  return new CLIEngine({ useEslintrc: false, configFile }).executeOnText(`/**/
`);
}

// tests

describe('eslint-config-medialaan', () => {

  [
    'index',
    'loose',
    'test',
  ].forEach((configFile) => {

    describe(configFile, () => {

      it('should be valid config', () => {
        const output = cliOutput(configFile);
        if (output.errorCount) {
          console.log(JSON.stringify(output.results, null, 2));
        }
        expect(output.errorCount).toBe(0);
      });

    });

  });

});
<|endoftext|>


<commit_before>describe('our super awesome angular app', function() {
  it('should have a 2 way data binding', () => {
    browser.get('http://localhost:4020');
    element(by.model('greeting')).sendKeys('hello world');
    element(by.id('greeting')).getText().then(function(text) {
      expect(text).toEqual('hello world');
    });
  });
});
// // Find element with {{scopelet}} syntax.
// element(by.binding('person.name')).getText().then(function(name) {
//  expect(name).toBe('Foo');
// });

// // Find element with ng-bind="scopelet" syntax.
// expect(element(by.binding('person.email')).getText()).toBe('foo@bar.com');
<commit_msg>removed corpse code<commit_after>describe('our super awesome angular app', function() {
  it('should have a 2 way data binding', () => {
    browser.get('http://localhost:4020');
    element(by.model('greeting')).sendKeys('hello world');
    element(by.id('greeting')).getText().then(function(text) {
      expect(text).toEqual('hello world');
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

var Module = require('./../build/jpegasm');
var Runtime = Module['Runtime'];

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

var SIZE_OF_POINTER = 4;

describe('JpegAsm', function () {

  var rgbWidth = 32;
  var rgbHeight = 32;
  var rgbArray = new ArrayBuffer(rgbWidth * rgbHeight * 3);

  function initRgbImage() {
    var view = new Uint8Array(rgbArray);
    var index;
    for (var y = 0; y != rgbHeight; ++y) {
      for (var x = 0; x != rgbWidth * 3; x += 3) {
        index = y * rgbWidth * 3 + x;
        view[index + 0] = 0x00; // R
        view[index + 1] = 0x00; // G
        view[index + 2] = 0xFF; // B
      }
    }
  }

  function saveFile(arr, filename) {
    var outDir = __dirname + '/out/';
    if(!fs.existsSync(outDir)) {
      fs.mkdirSync(outDir);
    }
    fs.writeFileSync(outDir + filename, new Buffer(arr));
  }

  before(function () {
    initRgbImage();
  });

  // wrap functions
  var encode_jpeg = Module.cwrap('encode_jpeg', 'number', ['number', 'number', 'number', 'number', 'number', 'number', 'number']);
  var decode_jpeg = Module.cwrap('decode_jpeg', 'number', ['number', 'number', 'number', 'number', 'number', 'number']);

  it('encodes JPEG', function () {
    var stack = Runtime.stackSave();

    var quality = 80;

    var rgbBufferPtr = Module._malloc(rgbArray.byteLength);
    Module.HEAPU8.set(new Uint8Array(rgbArray), rgbBufferPtr);

    var outBufferPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferSizePtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outMsgPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);

    Module.setValue(outBufferPtrPtr, 0, 'i32');
    Module.setValue(outBufferSizePtr, 0, 'i32');
    Module.setValue(outMsgPtrPtr, 0, 'i32');

    // invoke
    var result = encode_jpeg(rgbBufferPtr, rgbWidth, rgbHeight, quality, outBufferPtrPtr, outBufferSizePtr, outMsgPtrPtr);

    var outBufferPtr = Module.getValue(outBufferPtrPtr, 'i32');
    var outBufferSize = Module.getValue(outBufferSizePtr, 'i32');
    var outMsgPtr = Module.getValue(outMsgPtrPtr, 'i32');
    var outMsg = Module.Pointer_stringify(outMsgPtr);

    var jpegBuffer = new Uint8Array(Module.HEAPU8.buffer, outBufferPtr, outBufferSize);
    saveFile(jpegBuffer, 'encoded-by-js.jpeg');

    result.should.be.equal(0);
    outBufferPtr.should.be.greaterThan(0);
    outBufferSize.should.be.greaterThan(0);
    outMsg.length.should.be.equal(0);

    Module._free(rgbBufferPtr);
    Module._free(outBufferPtr);
    Module._free(outMsgPtr);

    Runtime.stackRestore(stack);
  });

  it('decodes JPEG', function () {
    var stack = Runtime.stackSave();

    var jpegBuffer = fs.readFileSync(__dirname + '/data/sample.jpg');

    var jpegBufferPtr = Module._malloc(jpegBuffer.length);
    var dataHeap = new Uint8Array(Module.HEAPU8.buffer, jpegBufferPtr, jpegBuffer.length);
    for(var i = 0; i != jpegBuffer.length; ++i) {
      dataHeap[i] = jpegBuffer[i];
    }

    var outBufferPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferWidthPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferHeightPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outMsgPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);

    Module.setValue(outBufferPtrPtr, 0, 'i32');
    Module.setValue(outBufferWidthPtr, 0, 'i32');
    Module.setValue(outBufferHeightPtr, 0, 'i32');
    Module.setValue(outMsgPtrPtr, 0, 'i32');

    // invoke
    var result = decode_jpeg(jpegBufferPtr, jpegBuffer.length, outBufferPtrPtr, outBufferWidthPtr, outBufferHeightPtr, outMsgPtrPtr);

    var outBufferPtr = Module.getValue(outBufferPtrPtr, 'i32');
    var outBufferWidth = Module.getValue(outBufferWidthPtr, 'i32');
    var outBufferHeight = Module.getValue(outBufferHeightPtr, 'i32');
    var outMsgPtr = Module.getValue(outMsgPtrPtr, 'i32');
    var outMsg = Module.Pointer_stringify(outMsgPtr);

    result.should.be.equal(0);
    outBufferPtr.should.be.greaterThan(0);
    outBufferWidth.should.be.equal(32);
    outBufferHeight.should.be.equal(32);
    outMsg.length.should.be.equal(0);

    Module._free(jpegBufferPtr);
    Module._free(outBufferPtr);
    Module._free(outMsgPtr);

    Runtime.stackRestore(stack);
  });

  it('cannot encode the image with invalid dimensions', function () {
    var stack = Runtime.stackSave();

    var quality = 80;

    var rgbBufferPtr = Module._malloc(rgbArray.byteLength);
    Module.HEAPU8.set(new Uint8Array(rgbArray), rgbBufferPtr);

    var outBufferPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferSizePtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outMsgPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);

    Module.setValue(outBufferPtrPtr, 0, 'i32');
    Module.setValue(outBufferSizePtr, 0, 'i32');
    Module.setValue(outMsgPtrPtr, 0, 'i32');

    // invoke
    var result = encode_jpeg(rgbBufferPtr, 0, 0, quality, outBufferPtrPtr, outBufferSizePtr, outMsgPtrPtr);

    var outBufferPtr = Module.getValue(outBufferPtrPtr, 'i32');
    var outBufferSize = Module.getValue(outBufferSizePtr, 'i32');
    var outMsgPtr = Module.getValue(outMsgPtrPtr, 'i32');
    var outMsg = Module.Pointer_stringify(outMsgPtr);

    result.should.be.equal(33);
    outBufferPtr.should.be.equal(0);
    outBufferSize.should.be.equal(0);
    outMsg.should.be.equal('Empty JPEG image (DNL not supported)');

    Module._free(rgbBufferPtr);
    Module._free(outBufferPtr);
    Module._free(outMsgPtr);

    Runtime.stackRestore(stack);
  });

});
<commit_msg>added test for corrupted JPEGs<commit_after>'use strict';

var Module = require('./../build/jpegasm');
var Runtime = Module['Runtime'];

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

var SIZE_OF_POINTER = 4;

describe('JpegAsm', function () {

  var rgbWidth = 32;
  var rgbHeight = 32;
  var rgbArray = new ArrayBuffer(rgbWidth * rgbHeight * 3);

  function initRgbImage() {
    var view = new Uint8Array(rgbArray);
    var index;
    for (var y = 0; y != rgbHeight; ++y) {
      for (var x = 0; x != rgbWidth * 3; x += 3) {
        index = y * rgbWidth * 3 + x;
        view[index + 0] = 0x00; // R
        view[index + 1] = 0x00; // G
        view[index + 2] = 0xFF; // B
      }
    }
  }

  function saveFile(arr, filename) {
    var outDir = __dirname + '/out/';
    if(!fs.existsSync(outDir)) {
      fs.mkdirSync(outDir);
    }
    fs.writeFileSync(outDir + filename, new Buffer(arr));
  }

  before(function () {
    initRgbImage();
  });

  // wrap functions
  var encode_jpeg = Module.cwrap('encode_jpeg', 'number', ['number', 'number', 'number', 'number', 'number', 'number', 'number']);
  var decode_jpeg = Module.cwrap('decode_jpeg', 'number', ['number', 'number', 'number', 'number', 'number', 'number']);

  it('encodes JPEG', function () {
    var stack = Runtime.stackSave();

    var quality = 80;

    var rgbBufferPtr = Module._malloc(rgbArray.byteLength);
    Module.HEAPU8.set(new Uint8Array(rgbArray), rgbBufferPtr);

    var outBufferPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferSizePtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outMsgPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);

    Module.setValue(outBufferPtrPtr, 0, 'i32');
    Module.setValue(outBufferSizePtr, 0, 'i32');
    Module.setValue(outMsgPtrPtr, 0, 'i32');

    // invoke
    var result = encode_jpeg(rgbBufferPtr, rgbWidth, rgbHeight, quality, outBufferPtrPtr, outBufferSizePtr, outMsgPtrPtr);

    var outBufferPtr = Module.getValue(outBufferPtrPtr, 'i32');
    var outBufferSize = Module.getValue(outBufferSizePtr, 'i32');
    var outMsgPtr = Module.getValue(outMsgPtrPtr, 'i32');
    var outMsg = Module.Pointer_stringify(outMsgPtr);

    var jpegBuffer = new Uint8Array(Module.HEAPU8.buffer, outBufferPtr, outBufferSize);
    saveFile(jpegBuffer, 'encoded-by-js.jpeg');

    result.should.be.equal(0);
    outBufferPtr.should.be.greaterThan(0);
    outBufferSize.should.be.greaterThan(0);
    outMsg.length.should.be.equal(0);

    Module._free(rgbBufferPtr);
    Module._free(outBufferPtr);
    Module._free(outMsgPtr);

    Runtime.stackRestore(stack);
  });

  it('decodes JPEG', function () {
    var stack = Runtime.stackSave();

    var jpegBuffer = fs.readFileSync(__dirname + '/data/sample.jpg');

    var jpegBufferPtr = Module._malloc(jpegBuffer.length);
    var dataHeap = new Uint8Array(Module.HEAPU8.buffer, jpegBufferPtr, jpegBuffer.length);
    for(var i = 0; i != jpegBuffer.length; ++i) {
      dataHeap[i] = jpegBuffer[i];
    }

    var outBufferPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferWidthPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferHeightPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outMsgPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);

    Module.setValue(outBufferPtrPtr, 0, 'i32');
    Module.setValue(outBufferWidthPtr, 0, 'i32');
    Module.setValue(outBufferHeightPtr, 0, 'i32');
    Module.setValue(outMsgPtrPtr, 0, 'i32');

    // invoke
    var result = decode_jpeg(jpegBufferPtr, jpegBuffer.length, outBufferPtrPtr, outBufferWidthPtr, outBufferHeightPtr, outMsgPtrPtr);

    var outBufferPtr = Module.getValue(outBufferPtrPtr, 'i32');
    var outBufferWidth = Module.getValue(outBufferWidthPtr, 'i32');
    var outBufferHeight = Module.getValue(outBufferHeightPtr, 'i32');
    var outMsgPtr = Module.getValue(outMsgPtrPtr, 'i32');
    var outMsg = Module.Pointer_stringify(outMsgPtr);

    result.should.be.equal(0);
    outBufferPtr.should.be.greaterThan(0);
    outBufferWidth.should.be.equal(32);
    outBufferHeight.should.be.equal(32);
    outMsg.length.should.be.equal(0);

    Module._free(jpegBufferPtr);
    Module._free(outBufferPtr);
    Module._free(outMsgPtr);

    Runtime.stackRestore(stack);
  });

  it('cannot encode the image with invalid dimensions', function () {
    var stack = Runtime.stackSave();

    var quality = 80;

    var rgbBufferPtr = Module._malloc(rgbArray.byteLength);
    Module.HEAPU8.set(new Uint8Array(rgbArray), rgbBufferPtr);

    var outBufferPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferSizePtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outMsgPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);

    Module.setValue(outBufferPtrPtr, 0, 'i32');
    Module.setValue(outBufferSizePtr, 0, 'i32');
    Module.setValue(outMsgPtrPtr, 0, 'i32');

    // invoke
    var result = encode_jpeg(rgbBufferPtr, 0, 0, quality, outBufferPtrPtr, outBufferSizePtr, outMsgPtrPtr);

    var outBufferPtr = Module.getValue(outBufferPtrPtr, 'i32');
    var outBufferSize = Module.getValue(outBufferSizePtr, 'i32');
    var outMsgPtr = Module.getValue(outMsgPtrPtr, 'i32');
    var outMsg = Module.Pointer_stringify(outMsgPtr);

    result.should.be.equal(33);
    outBufferPtr.should.be.equal(0);
    outBufferSize.should.be.equal(0);
    outMsg.should.be.equal('Empty JPEG image (DNL not supported)');

    Module._free(rgbBufferPtr);
    Module._free(outBufferPtr);
    Module._free(outMsgPtr);

    Runtime.stackRestore(stack);
  });

  it('cannot decode a corrupted JPEG', function () {
    var stack = Runtime.stackSave();

    var jpegArrayBuffer = new ArrayBuffer(4);
    var jpegView = new Uint8Array(jpegArrayBuffer);
    jpegView[0] = 0xAA;
    jpegView[1] = 0xBB;
    jpegView[2] = 0xCC;
    jpegView[3] = 0xDD;

    var jpegBufferPtr = Module._malloc(jpegArrayBuffer.byteLength);
    Module.HEAPU8.set(jpegView, jpegBufferPtr);

    var outBufferPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferWidthPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outBufferHeightPtr = Runtime.stackAlloc(SIZE_OF_POINTER);
    var outMsgPtrPtr = Runtime.stackAlloc(SIZE_OF_POINTER);

    Module.setValue(outBufferPtrPtr, 0, 'i32');
    Module.setValue(outBufferWidthPtr, 0, 'i32');
    Module.setValue(outBufferHeightPtr, 0, 'i32');
    Module.setValue(outMsgPtrPtr, 0, 'i32');

    // invoke
    var result = decode_jpeg(jpegBufferPtr, jpegArrayBuffer.byteLength, outBufferPtrPtr, outBufferWidthPtr, outBufferHeightPtr, outMsgPtrPtr);

    var outBufferPtr = Module.getValue(outBufferPtrPtr, 'i32');
    var outBufferWidth = Module.getValue(outBufferWidthPtr, 'i32');
    var outBufferHeight = Module.getValue(outBufferHeightPtr, 'i32');
    var outMsgPtr = Module.getValue(outMsgPtrPtr, 'i32');
    var outMsg = Module.Pointer_stringify(outMsgPtr);

    result.should.be.equal(55);
    outBufferPtr.should.be.equal(0);
    outBufferWidth.should.be.equal(0);
    outBufferHeight.should.be.equal(0);
    outMsg.should.be.equal('Not a JPEG file: starts with 0xaa 0xbb');

    Module._free(jpegBufferPtr);
    Module._free(outBufferPtr);
    Module._free(outMsgPtr);

    Runtime.stackRestore(stack);
  });

});
<|endoftext|>


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

var assert = require('assert'),
    vows = require('vows'),
    databank = require('databank'),
    Step = require('step'),
    schema = require('../lib/schema'),
    URLMaker = require('../lib/urlmaker').URLMaker,
    randomString = require('../lib/randomstring').randomString,
    Client = require('../lib/model/client').Client,
    RequestToken = require('../lib/model/requesttoken').RequestToken,
    AccessToken = require('../lib/model/accesstoken').AccessToken,
    User = require('../lib/model/user').User,
    methodContext = require('./lib/methods').methodContext,
    Databank = databank.Databank,
    DatabankObject = databank.DatabankObject;

var ignore = function(err) {};

vows.describe('app module interface').addBatch({

    'When we get the app module': {

        topic: function() {
            return require('../lib/app');
        },
        'there is one': function(mod) {
            assert.isObject(mod);
        },
        'it has the makeApp() export': function(mod) {
            assert.isFunction(mod.makeApp);
        }
    }
}).export(module);<commit_msg>Add a suite for running<commit_after>// app-test.js
//
// Test the app module
//
// Copyright 2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var assert = require('assert'),
    vows = require('vows'),
    databank = require('databank'),
    Step = require('step'),
    schema = require('../lib/schema'),
    URLMaker = require('../lib/urlmaker').URLMaker,
    randomString = require('../lib/randomstring').randomString,
    Client = require('../lib/model/client').Client,
    RequestToken = require('../lib/model/requesttoken').RequestToken,
    AccessToken = require('../lib/model/accesstoken').AccessToken,
    User = require('../lib/model/user').User,
    methodContext = require('./lib/methods').methodContext,
    Databank = databank.Databank,
    DatabankObject = databank.DatabankObject;

var ignore = function(err) {};

var suite = vows.describe('app module interface');

suite.addBatch({
    'When we get the app module': {
        topic: function() {
            return require('../lib/app');
        },
        'there is one': function(mod) {
            assert.isObject(mod);
        },
        'it has the makeApp() export': function(mod) {
            assert.isFunction(mod.makeApp);
        }
    }
});

suite.addBatch({
    'When we makeApp()': {
        topic: function() {
            var config = {port: 4815,
                          hostname: 'localhost',
                          driver: 'memory',
                          params: {}
                         },
                makeApp = require('../lib/app').makeApp;

            makeApp(config, this.callback);
        },
        'it works': function(err, app) {
            assert.ifError(err);
            assert.isObject(app);
        },
        'app has the run() method': function(err, app) {
            assert.isFunction(app.run);
        }
    }
});

suite.export(module);<|endoftext|>