<commit_before>'use strict';

var minimist = require('minimist');
var fs = require('fs');
var $ = require('gulp-load-plugins')();
var gulp = require('gulp');
var _ = require('lodash');
var globalTunnel = require('global-tunnel');
var expand = require('glob-expand');

////////////////////////////////////////
// 1. Get build-id and config parameters
////////////////////////////////////////
var knownOptions = {
    string: [ 'build-id', 'config', 'specs' ],
    default: {
        'build-id': process.env.CELLSTORE_BUILD_ID !== undefined ? process.env.CELLSTORE_BUILD_ID : process.env.RANDOM_ID,
        'config': ( process.env.CIRCLE_BRANCH !== undefined && fs.existsSync('config/' + process.env.CIRCLE_BRANCH + '.json.enc') ) ? process.env.CIRCLE_BRANCH : process.env.CELLSTORE_CONFIG
    }
};

var args = minimist(process.argv.slice(2), knownOptions);
var buildId = args['build-id'];
if(buildId === undefined || buildId === ''){
    var msg = 'no buildId available. ' + $.util.colors.red('Command line argument --build-id missing.');
    $.util.log(msg);
    throw new $.util.PluginError(__filename, msg);
}

var configId = args.config;
if(configId === undefined || configId === ''){
    var msg = 'no configId available. ' + $.util.colors.red('Command line argument --config or env variable CELLSTORE_CONFIG missing.');
    $.util.log(msg);
    throw new $.util.PluginError(__filename, msg);
}

////////////////////////////////////////
// 2. Check if the config file is available
////////////////////////////////////////
var unencryptedConfigFile = 'config/' + configId + '.json';
var encryptedConfigFile = unencryptedConfigFile + '.enc';
if(!fs.existsSync(encryptedConfigFile) && !_.find(args._, function(target){ return target === 'encrypt'; })){
    var msg = 'Invalid --config command line argument. ' + $.util.colors.red('Config file ' + encryptedConfigFile + ' does not exist.');
    $.util.log(msg);
    throw new $.util.PluginError(__filename, msg);
}

////////////////////////////////////////
// 3. Are we in deploying for testing or to production?
////////////////////////////////////////
var isOnTravis = process.env.CIRCLECI === 'true';
var isOnTravisAndMaster = isOnTravis && process.env.CI_PULL_REQUEST === '' && process.env.CIRCLE_BRANCH === 'master';
// if a config/<branch>.json.enc exists we are on a production deployment branch
var isProd = fs.existsSync('config/' + process.env.CIRCLE_BRANCH + '.json.enc');
var isOnTravisAndProd = isOnTravis && isProd && process.env.CI_PULL_REQUEST === '';

if(isOnTravisAndProd && process.env.CIRCLE_BRANCH !== configId){
    $.util.log('We are on Travis and on a Production branch.');
    $.util.log('Current production branch "' + process.env.CIRCLE_BRANCH + '" doesn\'t match cellstore configuration "' + configId + '"');
    $.util.log($.util.colors.green('Nothing to do!'));
    process.exit(0);
}

////////////////////////////////////////
// 4. Setting up the test suite
////////////////////////////////////////
var specs = expand('tests/e2e/' + configId + '/*-scenario.js');
specs = _.union(specs, expand('tests/e2e/_all/*-scenario.js'));
//var specs = ['tests/e2e/_all/auth-scenario.js'];
// allow running single protractor specs using --specs arg
if (_.isString(args.specs) ){
    specs = args.specs.split(',');
}

////////////////////////////////////////
// 5. Initialize Config variable
////////////////////////////////////////
var config =
{
    isOnTravis: isOnTravis,
    isOnProduction: isOnTravisAndProd,
    isOnMaster: isOnTravisAndMaster,
    buildId: buildId,
    configId: configId,
    bucketName: '',
    projectName: '',
    portalAPIUrl: '',
    websiteUrl: '',
    paths: {
        //src and build folders
        app: 'app',
        dist: 'dist',
        tmp: '.tmp',
        queries: 'queries',

        //Reports
        reports: 'data/reports/' + configId + '/*.json',

        //Elastic Search meta data
        elasticSearchMapping: 'data/elastic-search/' + configId + '/mapping.json',

        //Static Assets
        json: ['*.json', 'tasks/templates/*.json.mustache', 'swagger/*.json', 'data/**/*.json', 'documentation/**/*.json' ],
        js: ['app/**/*.js'],
        css: ['app/**/*.css'],
        index: 'app/*.html',
        html: ['app/**/*.html'],
        images: 'app/images/**/*.{gif,jpg,png}',
        svgs: 'app/images/**/*.svg',
        sass: ['app/**/*.scss'],
        fonts: ['app/**/*.ttf', 'app/**/*.woff'],

        //CI
        tasks: ['gulpfile.js', 'tasks/*.js'],
        dependencies: ['./bower.json', './package.json'],

        //Crypted config
        encryptedConfigFile: encryptedConfigFile,
        unencryptedConfigFile: unencryptedConfigFile,

        //Queries
        jsoniq: ['queries/**/*.xq', 'queries/**/*.jq'],
        initQueries: [
            'queries/private/InitAuditCollection.jq',
            'queries/private/init.jq',
            [
                'queries/private/UpdateReportSchema.jq',
                'queries/private/cleanupTestUserReports.jq'
            ],
            'queries/private/initElasticSearch.jq',
            'queries/private/migration/db10.jq'
        ],
        apiTestQueries: [
            'queries/public/test/**/*.jq'
        ],

        //Documentation
        documentation: 'documentation/**/*.md',

        //tests
        protractorConfigLocal: 'tests/e2e/config/protractor-conf.js',
        protractorConfigTravis: 'tests/e2e/config/protractor-travis-nosaucelabs-conf.js',
        e2eSpecs: specs,
        e2eReportsDir: '/tmp/e2e-reports'
    },
    credentials: {},
    '$28': undefined
};

var loadRawCredentials = function(config){
    $.util.log('loading credentials from: ' + config.paths.unencryptedConfigFile);
    var rawCredentials = JSON.parse(fs.readFileSync(config.paths.unencryptedConfigFile, 'utf-8'));
    config.rawCredentials = rawCredentials.all;
    var datasources = rawCredentials.all['28-datasources'];
    // fill up/overwrite with either prod or dev credentials
    if(config.isOnProduction){
        _.extend(config.rawCredentials, rawCredentials.prod);
    } else {
        _.extend(config.rawCredentials, rawCredentials.dev);
    }
    config.rawCredentials['28-datasources'] = _.union(config.rawCredentials['28-datasources'], datasources);
    _.defaults(config.rawCredentials, {
        's3-region': 'us-east-1',
        's3-protocol': 'https',
        '28-portal-protocol': 'http',
        '28-portal-project': 'portal',
        '28-portal-domain': '28.io',
        '28-portal-api-prefix': '/api',
        'cellstore-protocol': 'http'
    });
};

gulp.task('config:load', ['crypt:decrypt'], function(done){
    if(!_.isEmpty(config.credentials)){
        done();
        return;
    }

    loadRawCredentials(config);

    var src = fs.readFileSync('tasks/templates/config.json.template', 'utf-8');
    config.credentials = JSON.parse(_.template(src)({ credentials: config.rawCredentials }));
    config.bucketName = config.isOnProduction ? config.credentials.s3.bucketPrefix : config.credentials.s3.bucketPrefix + '-' + config.buildId;
    config.projectName = config.isOnProduction ? config.credentials['28'].projectPrefix : config.credentials['28'].projectPrefix + '-' + buildId;

    // where to deploy the cellstore?
    config.portalAPIUrl =
        _.template('<%= portalProtocol %>://<%= portalProject %>.<%= portalDomain %><%= portalApiPrefix %>')(config.credentials['28']);
    config.websiteUrl =
        _.template('http://<%= bucketName %>.s3-website-<%= credentials.s3.region %>.amazonaws.com')(config);

    $.util.log('Portal: ' + $.util.colors.green(config.portalAPIUrl));
    $.util.log('Bucket: ' + $.util.colors.green(config.bucketName));
    $.util.log('Project: ' + $.util.colors.green(config.projectName));
    $.util.log('Profile: ' + $.util.colors.green(config.credentials.cellstore.profile));

    if(_.isObject(config.credentials.http) && _.isString(config.credentials.http.proxy) && config.credentials.http.proxy !== ''){
        var proxy = config.credentials.http.proxy;
        var hostAndPort = proxy.substring(proxy.indexOf('//') + '//'.length).split(':');
        $.util.log('Setting up global proxy tunnel.');
        globalTunnel.initialize({
            'host': hostAndPort[0],
            'port': parseInt(hostAndPort[1])
        });
    }

    config.$28 = new (require('28').$28)(config.portalAPIUrl);
    done();
});

gulp.task('config', ['config:load', 'templates:create']);

module.exports = config;
<commit_msg>:fire: Remove change.<commit_after>'use strict';

var minimist = require('minimist');
var fs = require('fs');
var $ = require('gulp-load-plugins')();
var gulp = require('gulp');
var _ = require('lodash');
var globalTunnel = require('global-tunnel');
var expand = require('glob-expand');

////////////////////////////////////////
// 1. Get build-id and config parameters
////////////////////////////////////////
var knownOptions = {
    string: [ 'build-id', 'config', 'specs' ],
    default: {
        'build-id': process.env.CELLSTORE_BUILD_ID !== undefined ? process.env.CELLSTORE_BUILD_ID : process.env.RANDOM_ID,
        'config': ( process.env.CIRCLE_BRANCH !== undefined && fs.existsSync('config/' + process.env.CIRCLE_BRANCH + '.json.enc') ) ? process.env.CIRCLE_BRANCH : process.env.CELLSTORE_CONFIG
    }
};

var args = minimist(process.argv.slice(2), knownOptions);
var buildId = args['build-id'];
if(buildId === undefined || buildId === ''){
    var msg = 'no buildId available. ' + $.util.colors.red('Command line argument --build-id missing.');
    $.util.log(msg);
    throw new $.util.PluginError(__filename, msg);
}

var configId = args.config;
if(configId === undefined || configId === ''){
    var msg = 'no configId available. ' + $.util.colors.red('Command line argument --config or env variable CELLSTORE_CONFIG missing.');
    $.util.log(msg);
    throw new $.util.PluginError(__filename, msg);
}

////////////////////////////////////////
// 2. Check if the config file is available
////////////////////////////////////////
var unencryptedConfigFile = 'config/' + configId + '.json';
var encryptedConfigFile = unencryptedConfigFile + '.enc';
if(!fs.existsSync(encryptedConfigFile) && !_.find(args._, function(target){ return target === 'encrypt'; })){
    var msg = 'Invalid --config command line argument. ' + $.util.colors.red('Config file ' + encryptedConfigFile + ' does not exist.');
    $.util.log(msg);
    throw new $.util.PluginError(__filename, msg);
}

////////////////////////////////////////
// 3. Are we in deploying for testing or to production?
////////////////////////////////////////
var isOnTravis = process.env.CIRCLECI === 'true';
var isOnTravisAndMaster = isOnTravis && process.env.CI_PULL_REQUEST === '' && process.env.CIRCLE_BRANCH === 'master';
// if a config/<branch>.json.enc exists we are on a production deployment branch
var isProd = fs.existsSync('config/' + process.env.CIRCLE_BRANCH + '.json.enc');
var isOnTravisAndProd = isOnTravis && isProd && process.env.CI_PULL_REQUEST === '';

if(isOnTravisAndProd && process.env.CIRCLE_BRANCH !== configId){
    $.util.log('We are on Travis and on a Production branch.');
    $.util.log('Current production branch "' + process.env.CIRCLE_BRANCH + '" doesn\'t match cellstore configuration "' + configId + '"');
    $.util.log($.util.colors.green('Nothing to do!'));
    process.exit(0);
}

////////////////////////////////////////
// 4. Setting up the test suite
////////////////////////////////////////
var specs = expand('tests/e2e/' + configId + '/*-scenario.js');
specs = _.union(specs, expand('tests/e2e/_all/*-scenario.js'));
//var specs = ['tests/e2e/_all/auth-scenario.js'];
// allow running single protractor specs using --specs arg
if (_.isString(args.specs) ){
    specs = args.specs.split(',');
}

////////////////////////////////////////
// 5. Initialize Config variable
////////////////////////////////////////
var config =
{
    isOnTravis: isOnTravis,
    isOnProduction: isOnTravisAndProd,
    isOnMaster: isOnTravisAndMaster,
    buildId: buildId,
    configId: configId,
    bucketName: '',
    projectName: '',
    portalAPIUrl: '',
    websiteUrl: '',
    paths: {
        //src and build folders
        app: 'app',
        dist: 'dist',
        tmp: '.tmp',
        queries: 'queries',

        //Reports
        reports: 'data/reports/' + configId + '/*.json',

        //Elastic Search meta data
        elasticSearchMapping: 'data/elastic-search/' + configId + '/mapping.json',

        //Static Assets
        json: ['*.json', 'tasks/templates/*.json.mustache', 'swagger/*.json', 'data/**/*.json', 'documentation/**/*.json' ],
        js: ['app/**/*.js'],
        css: ['app/**/*.css'],
        index: 'app/*.html',
        html: ['app/**/*.html'],
        images: 'app/images/**/*.{gif,jpg,png}',
        svgs: 'app/images/**/*.svg',
        sass: ['app/**/*.scss'],
        fonts: ['app/**/*.ttf', 'app/**/*.woff'],

        //CI
        tasks: ['gulpfile.js', 'tasks/*.js'],
        dependencies: ['./bower.json', './package.json'],

        //Crypted config
        encryptedConfigFile: encryptedConfigFile,
        unencryptedConfigFile: unencryptedConfigFile,

        //Queries
        jsoniq: ['queries/**/*.xq', 'queries/**/*.jq'],
        initQueries: [
            'queries/private/InitAuditCollection.jq',
            'queries/private/init.jq',
            [
                'queries/private/UpdateReportSchema.jq',
                'queries/private/cleanupTestUserReports.jq'
            ],
            'queries/private/initElasticSearch.jq'
        ],
        apiTestQueries: [
            'queries/public/test/**/*.jq'
        ],

        //Documentation
        documentation: 'documentation/**/*.md',

        //tests
        protractorConfigLocal: 'tests/e2e/config/protractor-conf.js',
        protractorConfigTravis: 'tests/e2e/config/protractor-travis-nosaucelabs-conf.js',
        e2eSpecs: specs,
        e2eReportsDir: '/tmp/e2e-reports'
    },
    credentials: {},
    '$28': undefined
};

var loadRawCredentials = function(config){
    $.util.log('loading credentials from: ' + config.paths.unencryptedConfigFile);
    var rawCredentials = JSON.parse(fs.readFileSync(config.paths.unencryptedConfigFile, 'utf-8'));
    config.rawCredentials = rawCredentials.all;
    var datasources = rawCredentials.all['28-datasources'];
    // fill up/overwrite with either prod or dev credentials
    if(config.isOnProduction){
        _.extend(config.rawCredentials, rawCredentials.prod);
    } else {
        _.extend(config.rawCredentials, rawCredentials.dev);
    }
    config.rawCredentials['28-datasources'] = _.union(config.rawCredentials['28-datasources'], datasources);
    _.defaults(config.rawCredentials, {
        's3-region': 'us-east-1',
        's3-protocol': 'https',
        '28-portal-protocol': 'http',
        '28-portal-project': 'portal',
        '28-portal-domain': '28.io',
        '28-portal-api-prefix': '/api',
        'cellstore-protocol': 'http'
    });
};

gulp.task('config:load', ['crypt:decrypt'], function(done){
    if(!_.isEmpty(config.credentials)){
        done();
        return;
    }

    loadRawCredentials(config);

    var src = fs.readFileSync('tasks/templates/config.json.template', 'utf-8');
    config.credentials = JSON.parse(_.template(src)({ credentials: config.rawCredentials }));
    config.bucketName = config.isOnProduction ? config.credentials.s3.bucketPrefix : config.credentials.s3.bucketPrefix + '-' + config.buildId;
    config.projectName = config.isOnProduction ? config.credentials['28'].projectPrefix : config.credentials['28'].projectPrefix + '-' + buildId;

    // where to deploy the cellstore?
    config.portalAPIUrl =
        _.template('<%= portalProtocol %>://<%= portalProject %>.<%= portalDomain %><%= portalApiPrefix %>')(config.credentials['28']);
    config.websiteUrl =
        _.template('http://<%= bucketName %>.s3-website-<%= credentials.s3.region %>.amazonaws.com')(config);

    $.util.log('Portal: ' + $.util.colors.green(config.portalAPIUrl));
    $.util.log('Bucket: ' + $.util.colors.green(config.bucketName));
    $.util.log('Project: ' + $.util.colors.green(config.projectName));
    $.util.log('Profile: ' + $.util.colors.green(config.credentials.cellstore.profile));

    if(_.isObject(config.credentials.http) && _.isString(config.credentials.http.proxy) && config.credentials.http.proxy !== ''){
        var proxy = config.credentials.http.proxy;
        var hostAndPort = proxy.substring(proxy.indexOf('//') + '//'.length).split(':');
        $.util.log('Setting up global proxy tunnel.');
        globalTunnel.initialize({
            'host': hostAndPort[0],
            'port': parseInt(hostAndPort[1])
        });
    }

    config.$28 = new (require('28').$28)(config.portalAPIUrl);
    done();
});

gulp.task('config', ['config:load', 'templates:create']);

module.exports = config;
<|endoftext|>


<commit_before>/*
 * grunt-eiffel
 * https://github.com/oligot/grunt-eiffel
 *
 * Copyright (c) 2013 Olivier Ligot
 * Licensed under the MIT license.
 */

'use strict';

var path = require('path');
var spawn = require('child_process').spawn;
var _ = require('underscore');

module.exports = function(grunt) {

  grunt.registerMultiTask('eiffel', 'Eiffel compilation', function() {
    var done = this.async();
    var workbench = grunt.option('workbench') || false;
    var options = this.options({
      ecf: path.basename(process.cwd()) + '.ecf',
      env: {}
    });
    if (this.target === 'ise') {
      var name = 'ec';
      if (workbench) {
        var args = [];
      } else {
        var args = ['-finalize'];
      }
      args.push('-config', options.ecf, '-c_compile');
    } else {
      var name = 'gec';
      if (workbench) {
        var args = [];
      } else {
        var args = ['--finalize'];
      }
      args.push('--catcall=no', options.ecf);
    }

    grunt.log.writeln('Launching ' + name + ' ' + args.join(' ') + '...');
    var env = _.extend(options.env, process.env);
    var ec = spawn(name, args, {
      env: env
    });

    ec.stdout.on('data', function (data) {
      process.stdout.write(data);
    });

    ec.stderr.on('data', function (data) {
      process.stdout.write(data);
    });

    ec.on('exit', function (code) {
      if (code === 0) {
        grunt.log.ok();
        done();
      } else {
        done(false);
      }
    });
  });
};
<commit_msg>Added an option to specify the target<commit_after>/*
 * grunt-eiffel
 * https://github.com/oligot/grunt-eiffel
 *
 * Copyright (c) 2013 Olivier Ligot
 * Licensed under the MIT license.
 */

'use strict';

var path = require('path');
var spawn = require('child_process').spawn;
var _ = require('underscore');

module.exports = function(grunt) {

  grunt.registerMultiTask('eiffel', 'Eiffel compilation', function() {
    var done = this.async();
    var workbench = grunt.option('workbench') || false;
    var options = this.options({
      ecf: path.basename(process.cwd()) + '.ecf',
      env: {}
    });
    if (this.target === 'ise') {
      var name = 'ec';
      if (workbench) {
        var args = [];
      } else {
        var args = ['-finalize'];
      }
      if (options.target) {
        args.push('-target', options.target);
      }
      args.push('-config', options.ecf, '-c_compile');
    } else {
      var name = 'gec';
      if (workbench) {
        var args = [];
      } else {
        var args = ['--finalize'];
      }
      args.push('--catcall=no', options.ecf);
    }

    grunt.log.writeln('Launching ' + name + ' ' + args.join(' ') + '...');
    var env = _.extend(options.env, process.env);
    var ec = spawn(name, args, {
      env: env
    });

    ec.stdout.on('data', function (data) {
      process.stdout.write(data);
    });

    ec.stderr.on('data', function (data) {
      process.stdout.write(data);
    });

    ec.on('exit', function (code) {
      if (code === 0) {
        grunt.log.ok();
        done();
      } else {
        done(false);
      }
    });
  });
};
<|endoftext|>


<commit_before>/*
 * grunt-jasper
 * https://github.com/jasperjs/grunt-jasper
 *
 * Copyright (c) 2015 bukharin
 * Licensed under the MIT license.
 */

'use strict';
var utils = require('./jasper-utils.js');
var templates = require('./jasper-templates.js');

var getRegistrationScript = function (def) {
  var result = '';
  var type = def.type.toUpperCase();

  delete def.type;
  delete def.__path;
  delete def.templateFile;

  switch (type.toUpperCase()) {
    case 'COMPONENT':
      result = templates.componentRegistration(def);
      break;
    case 'DECORATOR':
      result = templates.decoratorRegistration(def);
      break;
    case 'SERVICE':
      result = templates.serviceRegistration(def);
      break;
    case 'FILTER':
      result = templates.filterRegistration(def);
      break;
    case 'DIRECTIVE':
      result = templates.directiveRegistration(def);
      break;
    case 'TEMPLATE':
      result = templates.templateRegistration(def.url, def.content);
      break;
    case 'PAGE':
      var pageTemplateUrl = utils.getPageTemplateUrl(def);
      var tagName = utils.shakeCase(def.name);
      var pageTemplate = '<' + tagName + '></' + tagName + '>';
      // register page template and the page component
      result = templates.templateRegistration(pageTemplateUrl, pageTemplate);
      result += templates.componentRegistration(def);
      break;
    default:
      grunt.util.error('Unknown definition type "' + def + '" in "' + JSON.stringify(def) + '"');
      break;
  }
  return result;
};

module.exports = function (grunt) {
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-typescript');

  grunt.registerMultiTask('jasper', 'Build jasper application', function (release) {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      singlePage: 'index.html',
      appPath: 'app',
      package: false,
      packageOutput: 'dist',

      defaultRoutePath: '/',
      bootstrapScripts: [],
      baseCss: []
    });

    var areas = [], pages = [], areasConfigPath, routesConfigPath;

    /* Find all area's definitions (_area.json) files in the app folder */

    var areasDefinitionFiles = grunt.file.expand(options.appPath + '/**/_area.json');

    areasDefinitionFiles.forEach(function (configFile) {
      var area = grunt.file.readJSON(configFile);
      if (!area.dependencies) {
        area.dependencies = [];
      }
      if (!area.name) {
        area.name = utils.getParentFolderName(configFile);
      }
      area.__path = utils.getPath(configFile);
      areas.push(area);
    });

    /* Find all application component's definitions (_definition.json) files */

    areas.forEach(function (area) {
      var areaDefinitions = [];
      var configurations = grunt.file.expand(area.__path + '/**/_definition.json');

      configurations.forEach(function (config) {
        var def = grunt.file.readJSON(config);
        if (!def.name) {
          var tagName = utils.getParentFolderName(config);
          def.name = utils.camelCaseTagName(tagName);
        }
        if (!def.type) {
          def.type = 'component';
        }

        if(def.attributes){
          def.attributes = utils.getJasperAttributes(def.attributes);
        }

        if (def.type.toUpperCase() === 'PAGE') {
          def.area = area.name;
          pages.push(def);
        }

        def.__path = utils.getPath(config);

        if (def.templateFile) {
          def.templateUrl = def.__path + '/' + def.templateFile;
        }
        // if we package our application, we need to collect all html templates
        if (options.package && def.templateUrl) {
          var htmlContent = grunt.file.read(def.templateUrl);
          var templateDefinition = {
            type: 'template',
            url: def.templateUrl,
            content: utils.minifyHtml(htmlContent, {
              removeComments: true,
              preserveLineBreaks: true
            })
          }
          areaDefinitions.push(templateDefinition);
        }

        areaDefinitions.push(def);
      });
      area.__defs = areaDefinitions;
    });

    /*
     * Building areas initialization files (_.js)
     * This scripts are lazy-loaded on the page and setup area contents (components, decorators etc)
     */

    areas.forEach(function (area) {
      var areaScript = 'jsp.areas.initArea(\'' + area.name + '\').then(function() { \n\n';
      area.__defs.forEach(function (def) {
        areaScript += getRegistrationScript(def, area.name);
      });
      areaScript += '\n});';
      var initFilePath = area.__path + '/_init.js';
      area.__initPath = initFilePath;

      utils.writeContent(grunt, initFilePath, areaScript);

      console.log('Area "' + area.name + '" init file was built at: "' + initFilePath + '"');
    });

    /*
     * Building all areas configuration script (_areas.js)
     * This script attaches to the @options.singlePage and setup
     * client-side areas configuration
     */

    var fileName = options.package ? '_areas_release.js' : '_areas.js';
    areasConfigPath = options.appPath + '/' + fileName;

    var areaConfig = {};

    var findAreaByName = function (areaName) {
      for (var i = 0; i < areas.length; i++) {
        if (areas[i].name === areaName)
          return areas[i];
      }
      return undefined;
    }

    areas.forEach(function (area) {
      var config = {};
      config.dependencies = area.dependencies;
      area.__scripts = utils.getAreaScripts(grunt, area.__path, area.__initPath);

      if (options.package) {
        if (area.bootstrap) {
          return;
        }
        // during package build each area represents by one .js file
        config.scripts = ['scripts/' + area.name + '.min.js'];
        for (var i = area.dependencies.length - 1; i >= 0; i--) {
          var dependencyArea = findAreaByName(area.dependencies[i]);
          if (dependencyArea && dependencyArea.bootstrap) {
            area.dependencies.splice(i, 1);
          }
        }
      } else {
        config.scripts = area.__scripts;
      }
      areaConfig[area.name] = config;
    });

    var areaConfigScript = templates.areasConfigScript(areaConfig);
    utils.writeContent(grunt, areasConfigPath, areaConfigScript);
    console.log('Areas configuration was built at: "' + areasConfigPath + '"');

    /*
     * Building client-side routes configuration script (_routes.js)
     */

    var routesConfig = {
      defaultRoutePath: options.defaultRoutePath,
      routes: {}
    };

    pages.forEach(function (page) {
      page.templateUrl = utils.getPageTemplateUrl(page);
      routesConfig.routes[page.route] = page;
    });

    var routesConfigScript = templates.routesConfigScript(routesConfig);
    var fileName = options.package ? '_routes.release.js' : '_routes.js';
    routesConfigPath = options.appPath + '/' + fileName;

    utils.writeContent(grunt, routesConfigPath, routesConfigScript);
    console.log('Routes configuration was built at: "' + routesConfigPath + '"');

    /*
     * Combine all script and styles (only when package application)
     */

    var processedBootstrapScripts = utils.getBootstrapScripts(options.bootstrapScripts, areasConfigPath, routesConfigPath);

    if (options.package) {

      var concatConf = grunt.config('concat') || {};
      var uglifyConf = grunt.config('uglify') || {};
      var cssMinConf = grunt.config('cssmin') || {};

      // Build bootstrap scripts first
      var bootstrapScripts = processedBootstrapScripts;
      var uglifyFiles = {};
      areas.forEach(function (area) {
        if (!area.bootstrap) {
          var dest = options.packageOutput + '/scripts/' + area.name + '.js';
          var destMin = options.packageOutput + '/scripts/' + area.name + '.min.js';
          concatConf[area.name] = {
            src: area.__scripts,
            dest: dest
          };

          uglifyFiles[destMin] = dest;

        } else {
          bootstrapScripts = options.bootstrapScripts.concat(area.__scripts);
        }
      });

      // concat base
      var baseDest = options.packageOutput + '/scripts/_base.js';
      var baseMinDest = options.packageOutput + '/scripts/_base.min.js';
      var stylesMinDest = options.packageOutput + '/styles/all.min.css';
      concatConf['jasperbase'] = {
        src: bootstrapScripts,
        dest: baseDest
      }

      console.log('concat options', concatConf['jasperbase']);

      uglifyFiles[baseMinDest] = baseDest;

      uglifyConf.dest = {
        files: uglifyFiles
      }

      cssMinConf['release'] = {
        files: [{
          src: utils.getAppStyles(grunt, options.baseCss, options.appPath),
          dest: stylesMinDest,
          ext: '.min.css'
        }]
      }

      grunt.config('uglify', uglifyConf);
      grunt.config('concat', concatConf);
      grunt.config('areas', areas);
      grunt.config('cssmin', cssMinConf);

      grunt.task.run(['concat', 'uglify', 'cssmin']);

    }

    /*
     * Patching index page. Insert all scripts and styles
     */

    var pageContent = grunt.file.read(options.singlePage);

    /* patch scripts */
    var scripts = [];
    if (options.package) {
      scripts.push('scripts/_base.min.js');
    } else {
      scripts = processedBootstrapScripts;
    }

    var scriptsHtml = '';
    for (var i = 0; i < scripts.length; i++) {
      if (scripts[i]) {
        scriptsHtml += '\t<script src="' + scripts[i] + '"></script>\r\n';
      }
    }
    var scriptsRegex = /<!-- SCRIPTS -->([\s\S]*)<!-- \/SCRIPTS -->/gim;
    pageContent = pageContent.replace(scriptsRegex, '<!-- SCRIPTS -->\r\n\r\n' + scriptsHtml + '\r\n\t<!-- /SCRIPTS -->');

    /* patch css */
    var styles = [];
    if (options.package) {
      styles.push('styles/all.min.css');
    } else {
      styles = utils.getAppStyles(grunt, options.baseCss, options.appPath);
    }

    var stylesHtml = '';
    for (var i = 0; i < styles.length; i++) {
      stylesHtml += '\t<link rel="stylesheet" href="' + styles[i] + '"/>\r\n';
    }
    var stylesRegex = /<!-- STYLES -->([\s\S]*)<!-- \/STYLES -->/gim;
    pageContent = pageContent.replace(stylesRegex, '<!-- STYLES -->\r\n\r\n' + stylesHtml + '\r\n\t<!-- /STYLES -->');

    var pageToSave = options.package ? grunt.template.process(options.packageOutput + '/index.html') : options.singlePage;

    utils.writeContent(grunt, pageToSave, pageContent);

  });

};
<commit_msg>Remove wrong log<commit_after>/*
 * grunt-jasper
 * https://github.com/jasperjs/grunt-jasper
 *
 * Copyright (c) 2015 bukharin
 * Licensed under the MIT license.
 */

'use strict';
var utils = require('./jasper-utils.js');
var templates = require('./jasper-templates.js');

var getRegistrationScript = function (def) {
  var result = '';
  var type = def.type.toUpperCase();

  delete def.type;
  delete def.__path;
  delete def.templateFile;

  switch (type.toUpperCase()) {
    case 'COMPONENT':
      result = templates.componentRegistration(def);
      break;
    case 'DECORATOR':
      result = templates.decoratorRegistration(def);
      break;
    case 'SERVICE':
      result = templates.serviceRegistration(def);
      break;
    case 'FILTER':
      result = templates.filterRegistration(def);
      break;
    case 'DIRECTIVE':
      result = templates.directiveRegistration(def);
      break;
    case 'TEMPLATE':
      result = templates.templateRegistration(def.url, def.content);
      break;
    case 'PAGE':
      var pageTemplateUrl = utils.getPageTemplateUrl(def);
      var tagName = utils.shakeCase(def.name);
      var pageTemplate = '<' + tagName + '></' + tagName + '>';
      // register page template and the page component
      result = templates.templateRegistration(pageTemplateUrl, pageTemplate);
      result += templates.componentRegistration(def);
      break;
    default:
      grunt.util.error('Unknown definition type "' + def + '" in "' + JSON.stringify(def) + '"');
      break;
  }
  return result;
};

module.exports = function (grunt) {
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-typescript');

  grunt.registerMultiTask('jasper', 'Build jasper application', function (release) {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      singlePage: 'index.html',
      appPath: 'app',
      package: false,
      packageOutput: 'dist',

      defaultRoutePath: '/',
      bootstrapScripts: [],
      baseCss: []
    });

    var areas = [], pages = [], areasConfigPath, routesConfigPath;

    /* Find all area's definitions (_area.json) files in the app folder */

    var areasDefinitionFiles = grunt.file.expand(options.appPath + '/**/_area.json');

    areasDefinitionFiles.forEach(function (configFile) {
      var area = grunt.file.readJSON(configFile);
      if (!area.dependencies) {
        area.dependencies = [];
      }
      if (!area.name) {
        area.name = utils.getParentFolderName(configFile);
      }
      area.__path = utils.getPath(configFile);
      areas.push(area);
    });

    /* Find all application component's definitions (_definition.json) files */

    areas.forEach(function (area) {
      var areaDefinitions = [];
      var configurations = grunt.file.expand(area.__path + '/**/_definition.json');

      configurations.forEach(function (config) {
        var def = grunt.file.readJSON(config);
        if (!def.name) {
          var tagName = utils.getParentFolderName(config);
          def.name = utils.camelCaseTagName(tagName);
        }
        if (!def.type) {
          def.type = 'component';
        }

        if(def.attributes){
          def.attributes = utils.getJasperAttributes(def.attributes);
        }

        if (def.type.toUpperCase() === 'PAGE') {
          def.area = area.name;
          pages.push(def);
        }

        def.__path = utils.getPath(config);

        if (def.templateFile) {
          def.templateUrl = def.__path + '/' + def.templateFile;
        }
        // if we package our application, we need to collect all html templates
        if (options.package && def.templateUrl) {
          var htmlContent = grunt.file.read(def.templateUrl);
          var templateDefinition = {
            type: 'template',
            url: def.templateUrl,
            content: utils.minifyHtml(htmlContent, {
              removeComments: true,
              preserveLineBreaks: true
            })
          }
          areaDefinitions.push(templateDefinition);
        }

        areaDefinitions.push(def);
      });
      area.__defs = areaDefinitions;
    });

    /*
     * Building areas initialization files (_.js)
     * This scripts are lazy-loaded on the page and setup area contents (components, decorators etc)
     */

    areas.forEach(function (area) {
      var areaScript = 'jsp.areas.initArea(\'' + area.name + '\').then(function() { \n\n';
      area.__defs.forEach(function (def) {
        areaScript += getRegistrationScript(def, area.name);
      });
      areaScript += '\n});';
      var initFilePath = area.__path + '/_init.js';
      area.__initPath = initFilePath;

      utils.writeContent(grunt, initFilePath, areaScript);

      console.log('Area "' + area.name + '" init file was built at: "' + initFilePath + '"');
    });

    /*
     * Building all areas configuration script (_areas.js)
     * This script attaches to the @options.singlePage and setup
     * client-side areas configuration
     */

    var fileName = options.package ? '_areas_release.js' : '_areas.js';
    areasConfigPath = options.appPath + '/' + fileName;

    var areaConfig = {};

    var findAreaByName = function (areaName) {
      for (var i = 0; i < areas.length; i++) {
        if (areas[i].name === areaName)
          return areas[i];
      }
      return undefined;
    }

    areas.forEach(function (area) {
      var config = {};
      config.dependencies = area.dependencies;
      area.__scripts = utils.getAreaScripts(grunt, area.__path, area.__initPath);

      if (options.package) {
        if (area.bootstrap) {
          return;
        }
        // during package build each area represents by one .js file
        config.scripts = ['scripts/' + area.name + '.min.js'];
        for (var i = area.dependencies.length - 1; i >= 0; i--) {
          var dependencyArea = findAreaByName(area.dependencies[i]);
          if (dependencyArea && dependencyArea.bootstrap) {
            area.dependencies.splice(i, 1);
          }
        }
      } else {
        config.scripts = area.__scripts;
      }
      areaConfig[area.name] = config;
    });

    var areaConfigScript = templates.areasConfigScript(areaConfig);
    utils.writeContent(grunt, areasConfigPath, areaConfigScript);
    console.log('Areas configuration was built at: "' + areasConfigPath + '"');

    /*
     * Building client-side routes configuration script (_routes.js)
     */

    var routesConfig = {
      defaultRoutePath: options.defaultRoutePath,
      routes: {}
    };

    pages.forEach(function (page) {
      page.templateUrl = utils.getPageTemplateUrl(page);
      routesConfig.routes[page.route] = page;
    });

    var routesConfigScript = templates.routesConfigScript(routesConfig);
    var fileName = options.package ? '_routes.release.js' : '_routes.js';
    routesConfigPath = options.appPath + '/' + fileName;

    utils.writeContent(grunt, routesConfigPath, routesConfigScript);
    console.log('Routes configuration was built at: "' + routesConfigPath + '"');

    /*
     * Combine all script and styles (only when package application)
     */

    var processedBootstrapScripts = utils.getBootstrapScripts(options.bootstrapScripts, areasConfigPath, routesConfigPath);

    if (options.package) {

      var concatConf = grunt.config('concat') || {};
      var uglifyConf = grunt.config('uglify') || {};
      var cssMinConf = grunt.config('cssmin') || {};

      // Build bootstrap scripts first
      var bootstrapScripts = processedBootstrapScripts;
      var uglifyFiles = {};
      areas.forEach(function (area) {
        if (!area.bootstrap) {
          var dest = options.packageOutput + '/scripts/' + area.name + '.js';
          var destMin = options.packageOutput + '/scripts/' + area.name + '.min.js';
          concatConf[area.name] = {
            src: area.__scripts,
            dest: dest
          };

          uglifyFiles[destMin] = dest;

        } else {
          bootstrapScripts = options.bootstrapScripts.concat(area.__scripts);
        }
      });

      // concat base
      var baseDest = options.packageOutput + '/scripts/_base.js';
      var baseMinDest = options.packageOutput + '/scripts/_base.min.js';
      var stylesMinDest = options.packageOutput + '/styles/all.min.css';
      concatConf['jasperbase'] = {
        src: bootstrapScripts,
        dest: baseDest
      }

      uglifyFiles[baseMinDest] = baseDest;

      uglifyConf.dest = {
        files: uglifyFiles
      }

      cssMinConf['release'] = {
        files: [{
          src: utils.getAppStyles(grunt, options.baseCss, options.appPath),
          dest: stylesMinDest,
          ext: '.min.css'
        }]
      }

      grunt.config('uglify', uglifyConf);
      grunt.config('concat', concatConf);
      grunt.config('areas', areas);
      grunt.config('cssmin', cssMinConf);

      grunt.task.run(['concat', 'uglify', 'cssmin']);

    }

    /*
     * Patching index page. Insert all scripts and styles
     */

    var pageContent = grunt.file.read(options.singlePage);

    /* patch scripts */
    var scripts = [];
    if (options.package) {
      scripts.push('scripts/_base.min.js');
    } else {
      scripts = processedBootstrapScripts;
    }

    var scriptsHtml = '';
    for (var i = 0; i < scripts.length; i++) {
      if (scripts[i]) {
        scriptsHtml += '\t<script src="' + scripts[i] + '"></script>\r\n';
      }
    }
    var scriptsRegex = /<!-- SCRIPTS -->([\s\S]*)<!-- \/SCRIPTS -->/gim;
    pageContent = pageContent.replace(scriptsRegex, '<!-- SCRIPTS -->\r\n\r\n' + scriptsHtml + '\r\n\t<!-- /SCRIPTS -->');

    /* patch css */
    var styles = [];
    if (options.package) {
      styles.push('styles/all.min.css');
    } else {
      styles = utils.getAppStyles(grunt, options.baseCss, options.appPath);
    }

    var stylesHtml = '';
    for (var i = 0; i < styles.length; i++) {
      stylesHtml += '\t<link rel="stylesheet" href="' + styles[i] + '"/>\r\n';
    }
    var stylesRegex = /<!-- STYLES -->([\s\S]*)<!-- \/STYLES -->/gim;
    pageContent = pageContent.replace(stylesRegex, '<!-- STYLES -->\r\n\r\n' + stylesHtml + '\r\n\t<!-- /STYLES -->');

    var pageToSave = options.package ? grunt.template.process(options.packageOutput + '/index.html') : options.singlePage;

    utils.writeContent(grunt, pageToSave, pageContent);

  });

};
<|endoftext|>


<commit_before>module.exports = function(gulp, data, util){
	'use strict';

	// The classic and strict javascript lint-tool for gulp.js.
	// @see https://www.npmjs.com/package/gulp-jslint
	var jslint = require('gulp-jslint');

	return function(actionName, callback){
		var scripts = util.path.join(data.appDirs.scripts, '**/*.js');
		var tests = util.path.join(data.appDirs.tests, '**/*.js');
		return gulp.src([tests, scripts])
			.pipe(jslint())
			.pipe(jslint.reporter('default'))
		;
	};
};<commit_msg>Update: spec<commit_after>module.exports = function(gulp, data, util){
	'use strict';

	// The classic and strict javascript lint-tool for gulp.js.
	// @see https://www.npmjs.com/package/gulp-jslint
	var jslint = require('gulp-jslint');

	return function(actionName, callback){
		var scripts = util.path.join(data.appDirs.scripts, '**/*.js');
		var tests = util.path.join(data.appDirs.tests, '**/*.js');
		return gulp.src([tests, scripts])
			.pipe(jslint())
		;
	};
};
<|endoftext|>


<commit_before>var childProcess = require('child_process');

module.exports = function(grunt) {
  grunt.registerTask('parser', 'Generate jison parser.', function() {
    var done = this.async();

    var child = childProcess.spawn('./node_modules/.bin/jison', ['-m', 'js', 'src/handlebars.yy', 'src/handlebars.l'], {stdio: 'inherit'});
    child.on('exit', function(code) {
      if (code != 0) {
        grunt.fatal('Jison failure: ' + code);
        done();
        return;
      }

      var src = ['src/parser-prefix.js', 'handlebars.js', 'src/parser-suffix.js'].map(grunt.file.read).join('');
      grunt.file.delete('handlebars.js');

      grunt.file.write('lib/handlebars/compiler/parser.js', src);
      grunt.log.writeln('Parser "lib/handlebars/compiler/parser.js" created.');
      done();
    });
  });
};
<commit_msg>Fix for issue #673 - Parser task did not execute correctly on windows environments because of forward/backward slash issues<commit_after>var childProcess = require('child_process');

module.exports = function(grunt) {
  grunt.registerTask('parser', 'Generate jison parser.', function() {
    var done = this.async();

    var cmd = './node_modules/.bin/jison';

    if(process.platform === 'win32'){
        cmd = 'node_modules\\.bin\\jison.cmd';
    }

    var child = childProcess.spawn(cmd, ['-m', 'js', 'src/handlebars.yy', 'src/handlebars.l'], {stdio: 'inherit'});
    child.on('exit', function(code) {
      if (code != 0) {
        grunt.fatal('Jison failure: ' + code);
        done();
        return;
      }

      var src = ['src/parser-prefix.js', 'handlebars.js', 'src/parser-suffix.js'].map(grunt.file.read).join('');
      grunt.file.delete('handlebars.js');

      grunt.file.write('lib/handlebars/compiler/parser.js', src);
      grunt.log.writeln('Parser "lib/handlebars/compiler/parser.js" created.');
      done();
    });
  });
};
<|endoftext|>


<commit_before>var
spritesmith = require('spritesmith'),
async = require('async'),
path = require('path');

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

	var SLICE_PLACE = '{{$slice_{id}$}}';
	var R_SLICE_PLACE = /\{\{\$slice_(\d+)\$\}\}/g;
	var IMAGE_SET_PLACE = '/*image-set-place*/';
	var IMAGE_SET_CSS_TMPL = 'background-image: -webkit-image-set(url({spriteImg}) 1x, url({retinaSpriteImg}) 2x); background-image: -moz-image-set(url({spriteImg}) 1x, url({retinaSpriteImg}) 2x); background-image: -ms-image-set(url({spriteImg}) 1x, url({retinaSpriteImg}) 2x); background-image: image-set(url({spriteImg}) 1x, url({retinaSpriteImg}) 2x);';
	var IMAGE_SET_PLACE_FILE_BEFORE = '__@__css_sprite_place_before.png';
	var IMAGE_SET_PLACE_FILE_END = '__@__css_sprite_place_end.png';
	var IMAGE_SET_PLACE_FILE = './lib/place.png';
	var MEDIA_QUERY_CSS_TMPL = '\n\n/* {imgDest} */\n@media only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (min--moz-device-pixel-ratio: 1.5), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 240dpi), only screen and (min-resolution: 2dppx) {\n  {cssText}\n}\n';

	function fixPath(path) {
		return String(path).replace(/\\/g, '/').replace(/\/$/, '');
	}

	function getSliceData(src, options) {
		var
		cssPath = path.dirname(src),
		cssData = grunt.file.read(src),
		rabsUrl = /^(\/|https?:|file:)/i,
		rbgs = /background(?:-image)?\s*:[^;]*?url\((["\']?)([^\)]+)\1\)[^};]*;?/ig,
		slicePath = fixPath(options.imagepath),
		slicePathMap = options.imagepath_map,
		_slicePathMap = slicePathMap;

		// map imagepath
		if(Array.isArray(slicePathMap)) {
			slicePathMap = function(uri) {
				return String(uri).replace(_slicePathMap[0], _slicePathMap[1]);
			};
		}

		var cssList = [], cssHash = {}, cssInx = 0;
		var imgList = [], imgHash = {}, imgInx = 0;

		cssData = cssData.replace(rbgs, function(css, b, uri) {
			var imgUri = uri;
			if(typeof slicePathMap === 'function') {
				imgUri = slicePathMap(imgUri);
			}

			// filter absolute path
			if(rabsUrl.test(imgUri)) {
				return css;
			}

			var imgFullPath = fixPath(path.join(cssPath, imgUri));

			if(
				// low call grunt.file.exists
				!imgHash[imgFullPath] &&
				// match path
				(imgFullPath.indexOf(slicePath) !== 0 || !grunt.file.exists(imgFullPath))
			) {
				return css;
			}

			var currCssInx = cssHash[css];
			if(currCssInx === void 0) {
				currCssInx = cssHash[css] = cssInx;

				cssList[cssInx++] = {
					imgFullPath: imgFullPath,
					imgPath: uri,
					css: css
				};
			}

			if(!imgHash[imgFullPath]) {
				imgList[imgInx++] = imgFullPath;
				imgHash[imgFullPath] = true;
			}

			return SLICE_PLACE.replace('{id}', currCssInx);
		});

		return {
			cssData: cssData,
			cssList: cssList,
			cssHash: cssHash,
			imgList: imgList,
			imgHash: imgHash
		};
	}

	function createSprite(list, options, callback) {
        spritesmith({
            algorithm: options.algorithm,
            padding: options.padding,
            engine: options.engine,
            src: list
        }, function(err, ret) {
            if(err) {
                return callback(err);
            }

            callback(null, ret);
        });
    }

	grunt.registerMultiTask('sprite', 'Create sprite image with slices and update the CSS file.', function () {
		var done = this.async();

		var options = this.options({
			// sprite背景图源文件夹，只有匹配此路径才会处理，默认 images/slice/
			imagepath: 'images/slice/',
			// 映射CSS中背景路径，支持函数和数组，默认为 null
			imagepath_map: null,
			// 雪碧图输出目录，注意，会覆盖之前文件！默认 images/
			spritedest: 'images/',
			// 替换后的背景路径，默认 ../images/
			spritepath: '../images/',
			// 各图片间间距，如果设置为奇数，会强制+1以保证生成的2x图片为偶数宽高，默认 0
			padding: 0,
			// 是否使用 image-set 作为2x图片实现，默认不使用
			useimageset: false,
			// 是否以时间戳为文件名生成新的雪碧图文件，如果启用请注意清理之前生成的文件，默认不生成新文件
			newsprite: false,
			// 给雪碧图追加时间戳，默认不追加
			spritestamp: false,
			// 在CSS文件末尾追加时间戳，默认不追加
			cssstamp: false,
			// 默认使用二叉树最优排列算法
			algorithm: 'binary-tree',
			// 默认使用`pngsmith`图像处理引擎
			engine: 'pngsmith',

			// 扩展参数，不建议修改，image-set 模板，占位文件
			IMAGE_SET_CSS_TMPL: IMAGE_SET_CSS_TMPL,
			IMAGE_SET_PLACE_FILE_BEFORE: IMAGE_SET_PLACE_FILE_BEFORE,
			IMAGE_SET_PLACE_FILE_END: IMAGE_SET_PLACE_FILE_END,
			IMAGE_SET_PLACE_FILE: IMAGE_SET_PLACE_FILE,
			// 扩展参数，不建议修改， media query 模板
			MEDIA_QUERY_CSS_TMPL: MEDIA_QUERY_CSS_TMPL
		});

		// `padding` must be even
		if(options.padding % 2 !== 0){
			options.padding += 1;
		}

		async.each(this.files, function(file, callback) {
			var
			src = file.src[0],
			cssDest = file.dest,
			sliceData = getSliceData(src, options),
			cssList = sliceData.cssList;

			if(!cssList || cssList.length <= 0) {
				grunt.file.copy(src, cssDest);
                grunt.log.writelns(('Done! [Copied] -> ' + cssDest));
                return callback(null);
			}

			async.waterfall([
				// base config
				function baseConfig(cb) {
					var
					cssFilename = path.basename(src, '.css'),
					timeNow = grunt.template.today('yyyymmddHHmmss');

					if(options.newsprite) {
		                cssFilename += '-' + timeNow;
		            }

					sliceData.timestamp = options.spritestamp ? ('?'+timeNow) : '';
					sliceData.imgDest = path.join(options.spritedest, cssFilename + '.png');
					sliceData.spriteImg = path.join(options.spritepath, cssFilename + '.png') +
						sliceData.timestamp;

					sliceData.retinaImgDest = sliceData.imgDest.replace(/\.png$/, '@2x.png');
					sliceData.retinaSpriteImg = path.join(options.spritepath, cssFilename + '@2x.png') +
						sliceData.timestamp;

					cb(null);
				},
				// create sprite image
				function createSpriteImg(cb) {
					createSprite(sliceData.imgList, options, cb);
				},
				// write sprite image file
				function writeSrpiteFile(spriteImgData, cb) {
		            // cssFilename, timestamp
		            var cssFilename = path.basename(src, '.css');

		            if(options.newsprite) {
		                cssFilename += '-' + timeNow;
		            }

		            // write file
	                grunt.file.write(sliceData.imgDest, spriteImgData.image, { encoding: 'binary' });
	                grunt.log.writelns(('Done! [Created] -> ' + sliceData.imgDest));

	                sliceData.spriteImgData = spriteImgData;
	                cb(null, spriteImgData.coordinates);
				},
				// set slice position
				function setSlicePosition(coords, cb) {
					var rsemicolon = /;\s*$/;

					sliceData.cssList.forEach(function(cssItem) {
						var
						css = cssItem.css,
						coord = coords[cssItem.imgFullPath];

						css = css.replace(cssItem.imgPath, sliceData.spriteImg);

						// Add a semicolon if needed
	                    if(!rsemicolon.test(css)){
	                        css += ';';
	                    }
	                    css += IMAGE_SET_PLACE;
						css += 'background-position:-'+ coord.x +'px -'+ coord.y +'px;';

						cssItem.newCss = css;
						cssItem.height = coord.height;
						cssItem.width = coord.width;
						cssItem.x = coord.x;
						cssItem.y = coord.y;
					});

					cb(null);
				},
				// get retina image & add image-set css
				function getRetinaImg(cb) {
					var
					useimageset = options.useimageset,
					retinaImgList = sliceData.retinaImgList = [],
					retinaImgHash = sliceData.retinaImgHash = {};

					sliceData.cssList.forEach(function(cssItem, id) {
						var
						extName = path.extname(cssItem.imgFullPath),
						filename = path.basename(cssItem.imgFullPath, extName),
						retinaImgFullPath = path.join(path.dirname(cssItem.imgFullPath), filename + '@2x' + extName);

						if(!retinaImgHash[retinaImgFullPath] && grunt.file.exists(retinaImgFullPath)) {
							cssItem.retinaImgFullPath = retinaImgFullPath;
							retinaImgHash[retinaImgFullPath] = {
								id: id,
								height: 2 * cssItem.height,
								width: 2 * cssItem.width,
								x: 2 * cssItem.x,
								y: 2 * cssItem.y
							};

							retinaImgList.push(retinaImgFullPath);
						}

						// add image-set css, only when file exists
						var imageSetCSS = useimageset && retinaImgHash[retinaImgFullPath] ?
							options.IMAGE_SET_CSS_TMPL.replace(/\{spriteImg\}/g, sliceData.spriteImg)
								.replace(/\{retinaSpriteImg\}/g, sliceData.retinaSpriteImg) :
							'';
						cssItem.newCss = cssItem.newCss.replace(IMAGE_SET_PLACE, imageSetCSS);
					});

					if(retinaImgList.length > 0) {
						if(!useimageset) {
							return createSprite(retinaImgList, options, cb);
						}

						var retinaImageCreater = require('../lib/retinaImageCreater');

						return retinaImageCreater.createBySliceData(sliceData, options, grunt.file, cb);
					}

					cb(null, null);
				},
				// write retina sprite image file
				function writeRetinaeImgFile(retinaSpriteImgData, cb) {
					if(retinaSpriteImgData) {
						sliceData.retinaSpriteImgData = retinaSpriteImgData;

						var retinaImgDest = sliceData.retinaImgDest;

                        grunt.file.write(retinaImgDest, retinaSpriteImgData.image, { encoding: 'binary' });
                        grunt.log.writelns(('Done! [Created] -> ' + retinaImgDest));
					}

					cb(null);
				},
				// replace css
				function replaceCss(cb) {
					var
					cssList = sliceData.cssList,
					useimageset = options.useimageset,
					retinaSpriteImgData = sliceData.retinaSpriteImgData,
					coords = retinaSpriteImgData ? retinaSpriteImgData.coordinates : {};

				    var
				    cssData = sliceData.cssData,
				    // a[href*='}{']::after{ content:'}{';} 规避此类奇葩CSS
				    tmpCss = cssData.replace(/[:=]\s*([\'\"]).*?\1/g, function(a){
				        return a.replace(/\}/g, '');
				    });

					var
					rreEscape = /[-\/\\^$*+?.()|[\]{}]/g,
					cssSelectorHash = {},
					cssSelectors = [],
					cssProps = [],
					lastInx = -1;

					sliceData.cssData = cssData.replace(R_SLICE_PLACE, function(place, id) {
						var
						cssItem = cssList[parseInt(id, 10)],
						ret = cssItem ? cssItem.newCss : '';

						if(!cssItem || useimageset) {
							return ret;
						}

						var coordData = coords[cssItem.retinaImgFullPath];
						if(!coordData || !cssItem.retinaImgFullPath) {
							return ret;
						}

						place = SLICE_PLACE.replace('{id}', id);

						// media query retina css
						var
						selector,
						rselector = new RegExp('([^}\\n\\/]+)\\{[^\\}]*?' + place.replace(rreEscape, '\\$&'));
						tmpCss =  tmpCss.replace(rselector, function(a, b) {
							selector = b;
							return b + '{';
						});

						if(!selector) {
							return ret;
						}

						var selectorInx = ++lastInx;
		                cssSelectors[selectorInx] = selector;
		                cssProps[selectorInx] = selector + ' { background-position:-';
		                cssProps[selectorInx] += (coordData.x/2) + 'px -' + (coordData.y/2) + 'px;}';

		                // unique selector, and keep selector order
		                selectorInx = cssSelectorHash[selector];
		                if(isFinite(selectorInx)) {
		                    cssSelectorHash[selector] = --lastInx;
		                    cssSelectors.splice(selectorInx, 1);
		                    cssProps.splice(selectorInx, 1);
		                }
		                else {
		                    cssSelectorHash[selector] = lastInx;
		                }

						return ret;
					});

					if(retinaSpriteImgData && !useimageset) {
						var
						retinaSpriteImg = sliceData.retinaSpriteImg,
						bgWidth = Math.floor(retinaSpriteImgData.properties.width / 2);

						var retinaCss = cssSelectors.join(',\n  ');
						retinaCss += ' { background-image:url('+ retinaSpriteImg +'); background-size:' + bgWidth + 'px auto;}';
			            retinaCss += '\n  ';
			            retinaCss += cssProps.join('\n  ');

			            retinaCss = options.MEDIA_QUERY_CSS_TMPL.replace(/\{cssText\}/g, retinaCss)
			            	.replace(/\{imgDest\}/g, retinaSpriteImg);

			            sliceData.cssData += retinaCss;
					}

					cb(null);
				},
				// write css file
				function writeCssFile(cb) {
					// timestamp
					if(options.cssstamp) {
						sliceData.cssData += '\n.css_stamp{ content:"'+ sliceData.timestamp.slice(1) +'";}';
					}

					grunt.file.write(cssDest, sliceData.cssData);
            		grunt.log.writelns(('Done! [Created] -> ' + cssDest));

					cb(null);
				}
			], callback);
		}, function(ret) {
			done(ret);
		});
	});
};<commit_msg>修正 windows 下路径兼容问题<commit_after>var
spritesmith = require('spritesmith'),
async = require('async'),
path = require('path');

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

	var SLICE_PLACE = '{{$slice_{id}$}}';
	var R_SLICE_PLACE = /\{\{\$slice_(\d+)\$\}\}/g;
	var IMAGE_SET_PLACE = '/*image-set-place*/';
	var IMAGE_SET_CSS_TMPL = 'background-image: -webkit-image-set(url({spriteImg}) 1x, url({retinaSpriteImg}) 2x); background-image: -moz-image-set(url({spriteImg}) 1x, url({retinaSpriteImg}) 2x); background-image: -ms-image-set(url({spriteImg}) 1x, url({retinaSpriteImg}) 2x); background-image: image-set(url({spriteImg}) 1x, url({retinaSpriteImg}) 2x);';
	var IMAGE_SET_PLACE_FILE_BEFORE = '__@__css_sprite_place_before.png';
	var IMAGE_SET_PLACE_FILE_END = '__@__css_sprite_place_end.png';
	var IMAGE_SET_PLACE_FILE = './lib/place.png';
	var MEDIA_QUERY_CSS_TMPL = '\n\n/* {imgDest} */\n@media only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (min--moz-device-pixel-ratio: 1.5), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 240dpi), only screen and (min-resolution: 2dppx) {\n  {cssText}\n}\n';

	function fixPath(path) {
		return String(path).replace(/\\/g, '/').replace(/\/$/, '');
	}

	function getSliceData(src, options) {
		var
		cssPath = path.dirname(src),
		cssData = grunt.file.read(src),
		rabsUrl = /^(\/|https?:|file:)/i,
		rbgs = /background(?:-image)?\s*:[^;]*?url\((["\']?)([^\)]+)\1\)[^};]*;?/ig,
		slicePath = fixPath(options.imagepath),
		slicePathMap = options.imagepath_map,
		_slicePathMap = slicePathMap;

		// map imagepath
		if(Array.isArray(slicePathMap)) {
			slicePathMap = function(uri) {
				return String(uri).replace(_slicePathMap[0], _slicePathMap[1]);
			};
		}

		var cssList = [], cssHash = {}, cssInx = 0;
		var imgList = [], imgHash = {}, imgInx = 0;

		cssData = cssData.replace(rbgs, function(css, b, uri) {
			var imgUri = uri;
			if(typeof slicePathMap === 'function') {
				imgUri = slicePathMap(imgUri);
			}

			// filter absolute path
			if(rabsUrl.test(imgUri)) {
				return css;
			}

			var imgFullPath = fixPath(path.join(cssPath, imgUri));

			if(
				// low call grunt.file.exists
				!imgHash[imgFullPath] &&
				// match path
				(imgFullPath.indexOf(slicePath) !== 0 || !grunt.file.exists(imgFullPath))
			) {
				return css;
			}

			var currCssInx = cssHash[css];
			if(currCssInx === void 0) {
				currCssInx = cssHash[css] = cssInx;

				cssList[cssInx++] = {
					imgFullPath: imgFullPath,
					imgPath: uri,
					css: css
				};
			}

			if(!imgHash[imgFullPath]) {
				imgList[imgInx++] = imgFullPath;
				imgHash[imgFullPath] = true;
			}

			return SLICE_PLACE.replace('{id}', currCssInx);
		});

		return {
			cssData: cssData,
			cssList: cssList,
			cssHash: cssHash,
			imgList: imgList,
			imgHash: imgHash
		};
	}

	function createSprite(list, options, callback) {
        spritesmith({
            algorithm: options.algorithm,
            padding: options.padding,
            engine: options.engine,
            src: list
        }, function(err, ret) {
            if(err) {
                return callback(err);
            }

            callback(null, ret);
        });
    }

	grunt.registerMultiTask('sprite', 'Create sprite image with slices and update the CSS file.', function () {
		var done = this.async();

		var options = this.options({
			// sprite背景图源文件夹，只有匹配此路径才会处理，默认 images/slice/
			imagepath: 'images/slice/',
			// 映射CSS中背景路径，支持函数和数组，默认为 null
			imagepath_map: null,
			// 雪碧图输出目录，注意，会覆盖之前文件！默认 images/
			spritedest: 'images/',
			// 替换后的背景路径，默认 ../images/
			spritepath: '../images/',
			// 各图片间间距，如果设置为奇数，会强制+1以保证生成的2x图片为偶数宽高，默认 0
			padding: 0,
			// 是否使用 image-set 作为2x图片实现，默认不使用
			useimageset: false,
			// 是否以时间戳为文件名生成新的雪碧图文件，如果启用请注意清理之前生成的文件，默认不生成新文件
			newsprite: false,
			// 给雪碧图追加时间戳，默认不追加
			spritestamp: false,
			// 在CSS文件末尾追加时间戳，默认不追加
			cssstamp: false,
			// 默认使用二叉树最优排列算法
			algorithm: 'binary-tree',
			// 默认使用`pngsmith`图像处理引擎
			engine: 'pngsmith',

			// 扩展参数，不建议修改，image-set 模板，占位文件
			IMAGE_SET_CSS_TMPL: IMAGE_SET_CSS_TMPL,
			IMAGE_SET_PLACE_FILE_BEFORE: IMAGE_SET_PLACE_FILE_BEFORE,
			IMAGE_SET_PLACE_FILE_END: IMAGE_SET_PLACE_FILE_END,
			IMAGE_SET_PLACE_FILE: IMAGE_SET_PLACE_FILE,
			// 扩展参数，不建议修改， media query 模板
			MEDIA_QUERY_CSS_TMPL: MEDIA_QUERY_CSS_TMPL
		});

		// `padding` must be even
		if(options.padding % 2 !== 0){
			options.padding += 1;
		}

		async.each(this.files, function(file, callback) {
			var
			src = file.src[0],
			cssDest = file.dest,
			sliceData = getSliceData(src, options),
			cssList = sliceData.cssList;

			if(!cssList || cssList.length <= 0) {
				grunt.file.copy(src, cssDest);
                grunt.log.writelns(('Done! [Copied] -> ' + cssDest));
                return callback(null);
			}

			async.waterfall([
				// base config
				function baseConfig(cb) {
					var
					cssFilename = path.basename(src, '.css'),
					timeNow = grunt.template.today('yyyymmddHHmmss');

					if(options.newsprite) {
		                cssFilename += '-' + timeNow;
		            }

					sliceData.timestamp = options.spritestamp ? ('?'+timeNow) : '';
					sliceData.imgDest = fixPath(path.join(options.spritedest, cssFilename + '.png'));
					sliceData.spriteImg = fixPath(path.join(options.spritepath, cssFilename + '.png')) +
						sliceData.timestamp;

					sliceData.retinaImgDest = fixPath(sliceData.imgDest.replace(/\.png$/, '@2x.png'));
					sliceData.retinaSpriteImg = fixPath(path.join(options.spritepath, cssFilename + '@2x.png')) +  sliceData.timestamp;

					cb(null);
				},
				// create sprite image
				function createSpriteImg(cb) {
					createSprite(sliceData.imgList, options, cb);
				},
				// write sprite image file
				function writeSrpiteFile(spriteImgData, cb) {
		            // write file
	                grunt.file.write(sliceData.imgDest, spriteImgData.image, { encoding: 'binary' });
	                grunt.log.writelns(('Done! [Created] -> ' + sliceData.imgDest));

	                sliceData.spriteImgData = spriteImgData;
	                cb(null, spriteImgData.coordinates);
				},
				// set slice position
				function setSlicePosition(coords, cb) {
					var rsemicolon = /;\s*$/;

					sliceData.cssList.forEach(function(cssItem) {
						var
						css = cssItem.css,
						coord = coords[cssItem.imgFullPath];

						css = css.replace(cssItem.imgPath, sliceData.spriteImg);

						// Add a semicolon if needed
	                    if(!rsemicolon.test(css)) {
	                        css += ';';
	                    }
	                    css += IMAGE_SET_PLACE;
						css += 'background-position:-'+ coord.x +'px -'+ coord.y +'px;';

						cssItem.newCss = css;
						cssItem.height = coord.height;
						cssItem.width = coord.width;
						cssItem.x = coord.x;
						cssItem.y = coord.y;
					});

					cb(null);
				},
				// get retina image & add image-set css
				function getRetinaImg(cb) {
					var
					useimageset = options.useimageset,
					retinaImgList = sliceData.retinaImgList = [],
					retinaImgHash = sliceData.retinaImgHash = {};

					sliceData.cssList.forEach(function(cssItem, id) {
						var
						extName = path.extname(cssItem.imgFullPath),
						filename = path.basename(cssItem.imgFullPath, extName),
						retinaImgFullPath = path.join(path.dirname(cssItem.imgFullPath), filename + '@2x' + extName);

						if(!retinaImgHash[retinaImgFullPath] && grunt.file.exists(retinaImgFullPath)) {
							cssItem.retinaImgFullPath = retinaImgFullPath;
							retinaImgHash[retinaImgFullPath] = {
								id: id,
								height: 2 * cssItem.height,
								width: 2 * cssItem.width,
								x: 2 * cssItem.x,
								y: 2 * cssItem.y
							};

							retinaImgList.push(retinaImgFullPath);
						}

						// add image-set css, only when file exists
						var imageSetCSS = useimageset && retinaImgHash[retinaImgFullPath] ?
							options.IMAGE_SET_CSS_TMPL.replace(/\{spriteImg\}/g, sliceData.spriteImg)
								.replace(/\{retinaSpriteImg\}/g, sliceData.retinaSpriteImg) :
							'';
						cssItem.newCss = cssItem.newCss.replace(IMAGE_SET_PLACE, imageSetCSS);
					});

					if(retinaImgList.length > 0) {
						if(!useimageset) {
							return createSprite(retinaImgList, options, cb);
						}

						var retinaImageCreater = require('../lib/retinaImageCreater');

						return retinaImageCreater.createBySliceData(sliceData, options, grunt.file, cb);
					}

					cb(null, null);
				},
				// write retina sprite image file
				function writeRetinaeImgFile(retinaSpriteImgData, cb) {
					if(retinaSpriteImgData) {
						sliceData.retinaSpriteImgData = retinaSpriteImgData;

						var retinaImgDest = sliceData.retinaImgDest;

                        grunt.file.write(retinaImgDest, retinaSpriteImgData.image, { encoding: 'binary' });
                        grunt.log.writelns(('Done! [Created] -> ' + retinaImgDest));
					}

					cb(null);
				},
				// replace css
				function replaceCss(cb) {
					var
					cssList = sliceData.cssList,
					useimageset = options.useimageset,
					retinaSpriteImgData = sliceData.retinaSpriteImgData,
					coords = retinaSpriteImgData ? retinaSpriteImgData.coordinates : {};

				    var
				    cssData = sliceData.cssData,
				    // a[href*='}{']::after{ content:'}{';} 规避此类奇葩CSS
				    tmpCss = cssData.replace(/[:=]\s*([\'\"]).*?\1/g, function(a){
				        return a.replace(/\}/g, '');
				    });

					var
					rreEscape = /[-\/\\^$*+?.()|[\]{}]/g,
					cssSelectorHash = {},
					cssSelectors = [],
					cssProps = [],
					lastInx = -1;

					sliceData.cssData = cssData.replace(R_SLICE_PLACE, function(place, id) {
						var
						cssItem = cssList[parseInt(id, 10)],
						ret = cssItem ? cssItem.newCss : '';

						if(!cssItem || useimageset) {
							return ret;
						}

						var coordData = coords[cssItem.retinaImgFullPath];
						if(!coordData || !cssItem.retinaImgFullPath) {
							return ret;
						}

						place = SLICE_PLACE.replace('{id}', id);

						// media query retina css
						var
						selector,
						rselector = new RegExp('([^}\\n\\/]+)\\{[^\\}]*?' + place.replace(rreEscape, '\\$&'));
						tmpCss =  tmpCss.replace(rselector, function(a, b) {
							selector = b;
							return b + '{';
						});

						if(!selector) {
							return ret;
						}

						var selectorInx = ++lastInx;
		                cssSelectors[selectorInx] = selector;
		                cssProps[selectorInx] = selector + ' { background-position:-';
		                cssProps[selectorInx] += (coordData.x/2) + 'px -' + (coordData.y/2) + 'px;}';

		                // unique selector, and keep selector order
		                selectorInx = cssSelectorHash[selector];
		                if(isFinite(selectorInx)) {
		                    cssSelectorHash[selector] = --lastInx;
		                    cssSelectors.splice(selectorInx, 1);
		                    cssProps.splice(selectorInx, 1);
		                }
		                else {
		                    cssSelectorHash[selector] = lastInx;
		                }

						return ret;
					});

					if(retinaSpriteImgData && !useimageset) {
						var
						retinaSpriteImg = sliceData.retinaSpriteImg,
						bgWidth = Math.floor(retinaSpriteImgData.properties.width / 2);

						var retinaCss = cssSelectors.join(',\n  ');
						retinaCss += ' { background-image:url('+ retinaSpriteImg +'); background-size:' + bgWidth + 'px auto;}';
			            retinaCss += '\n  ';
			            retinaCss += cssProps.join('\n  ');

			            retinaCss = options.MEDIA_QUERY_CSS_TMPL.replace(/\{cssText\}/g, retinaCss)
			            	.replace(/\{imgDest\}/g, retinaSpriteImg);

			            sliceData.cssData += retinaCss;
					}

					cb(null);
				},
				// write css file
				function writeCssFile(cb) {
					// timestamp
					if(options.cssstamp) {
						sliceData.cssData += '\n.css_stamp{ content:"'+ sliceData.timestamp.slice(1) +'";}';
					}

					grunt.file.write(cssDest, sliceData.cssData);
            		grunt.log.writelns(('Done! [Created] -> ' + cssDest));

					cb(null);
				}
			], callback);
		}, function(ret) {
			done(ret);
		});
	});
};<|endoftext|>


<commit_before><commit_msg>img fix<commit_after><|endoftext|>


<commit_before>var restify = require('restify');
var expect = require('expect.js');
var fs = require('fs');
var request = require('request');

describe('/hdfs', function() {
  var client;

  before(function(done) {
    client = restify.createStringClient({
      url: process.env.HDFS_VIEWER_URL
    });
    var hdfs = require('../hdfs');
    hdfs.mkdir('/unittest', function() {
      var localStream = fs.createReadStream(__dirname + '/data/zipfile1.zip');
      var remoteStream = hdfs.createWriteStream('/unittest/zipfile1.zip');
      localStream.pipe(remoteStream);
      remoteStream.on('end', done);
    });
  });

  after(function(done) {
    var hdfs = require('../hdfs');
    hdfs.rmdir('/unittest', true, done);
  });

  it('GET /hdfs/ return 404 when file not found', function(done) {
    client.get('/hdfs/unexist!/', function(err, req, res, obj) {
      expect(err).not.to.eql(null);
      expect(res.statusCode).to.eql(404);
      done();
    });
  });

  it('GET /hdfs/ return 200 when file exist', function(done) {
    client.get('/hdfs/unittest/zipfile1.zip!/?type=raw', function(err, req, res, obj) {
      expect(err).to.eql(null);
      expect(res.statusCode).to.eql(200);
      done();
    });
  });

  it('GET /hdfs/ return file content in zip', function(done) {
    client.get('/hdfs/unittest/zipfile1.zip!/file1.txt', function(err, req, res, obj) {
      expect(err).to.eql(null);
      expect(res.statusCode).to.eql(200);
      expect(obj).to.eql('file1\n');
      done();
    });
  });

  it('GET /hdfs/ return file list in top directory of zip', function(done) {
    client.get('/hdfs/unittest/zipfile1.zip!/', function(err, req, res, obj) {
      expect(err).to.eql(null);
      expect(res.statusCode).to.eql(200);
      expect(obj).to.eql('[{"path":"sub/","type":"Directory","url":"sub/"},{"path":"file1.txt","type":"File","url":"file1.txt"},{"path":"file2.txt","type":"File","url":"file2.txt"}]');
      done();
    });
  });

  it('GET /hdfs/ return file list in sub directory of zip', function(done) {
    client.get('/hdfs/unittest/zipfile1.zip!/sub/', function(err, req, res, obj) {
      expect(err).to.eql(null);
      expect(res.statusCode).to.eql(200);
      expect(obj).to.eql('[{"path":"sub/empty","type":"File","url":"empty"},{"path":"sub/subsub/","type":"Directory","url":"subsub/"}]');
      done();
    });
  });

  it('POST /hdfs/ return 200', function(done) {
    var req = request.post(process.env.HDFS_VIEWER_URL + '/hdfs');
    fs.createReadStream(__dirname + '/data/zipfile1.zip').pipe(req);
    req.on('response', function(res) {
      expect(res.statusCode).to.eql(200);
      var hdfs = require('../hdfs');
      hdfs.exists(res.headers.hdfsurl, function(fileExist) {
        expect(fileExist).to.eql(true);
        done();
      });
    });
  });
});

<commit_msg>fix ut issue<commit_after>var restify = require('restify');
var expect = require('expect.js');
var fs = require('fs');
var request = require('request');

describe('/hdfs', function() {
  var client;

  before(function(done) {
    client = restify.createStringClient({
      url: process.env.HDFS_VIEWER_URL
    });
    var hdfs = require('../hdfs');
    hdfs.mkdir('/unittest', function() {
      var localStream = fs.createReadStream(__dirname + '/data/zipfile1.zip');
      var remoteStream = hdfs.createWriteStream('/unittest/zipfile1.zip');
      localStream.pipe(remoteStream);
      remoteStream.on('end', done);
    });
  });

  after(function(done) {
    var hdfs = require('../hdfs');
    hdfs.rmdir('/unittest', true, done);
  });

  it('GET /hdfs/ return 404 when file not found', function(done) {
    client.get('/hdfs/unexist!/', function(err, req, res, obj) {
      expect(err).not.to.eql(null);
      expect(res.statusCode).to.eql(404);
      done();
    });
  });

  it('GET /hdfs/ return 200 when file exist', function(done) {
    client.get('/hdfs/unittest/zipfile1.zip!/?type=raw', function(err, req, res, obj) {
      expect(err).to.eql(null);
      expect(res.statusCode).to.eql(200);
      done();
    });
  });

  it('GET /hdfs/ return file content in zip', function(done) {
    client.get('/hdfs/unittest/zipfile1.zip!/file1.txt', function(err, req, res, obj) {
      expect(err).to.eql(null);
      expect(res.statusCode).to.eql(200);
      expect(obj).to.eql('file1\n');
      done();
    });
  });

  it('GET /hdfs/ return file list in top directory of zip', function(done) {
    client.get('/hdfs/unittest/zipfile1.zip!/', function(err, req, res, obj) {
      expect(err).to.eql(null);
      expect(res.statusCode).to.eql(200);
      expect(obj).to.eql('[{"path":"sub/","type":"Directory","size":0,"url":"sub/"},{"path":"file1.txt","type":"File","size":6,"url":"file1.txt"},{"path":"file2.txt","type":"File","size":6,"url":"file2.txt"}]');
      done();
    });
  });

  it('GET /hdfs/ return file list in sub directory of zip', function(done) {
    client.get('/hdfs/unittest/zipfile1.zip!/sub/', function(err, req, res, obj) {
      expect(err).to.eql(null);
      expect(res.statusCode).to.eql(200);
      expect(obj).to.eql('[{"path":"sub/empty","type":"File","size":0,"url":"empty"},{"path":"sub/subsub/","type":"Directory","size":0,"url":"subsub/"}]');
      done();
    });
  });

  it('POST /hdfs/ return 200', function(done) {
    var req = request.post(process.env.HDFS_VIEWER_URL + '/hdfs');
    fs.createReadStream(__dirname + '/data/zipfile1.zip').pipe(req);
    req.on('response', function(res) {
      expect(res.statusCode).to.eql(200);
      var hdfs = require('../hdfs');
      hdfs.exists(res.headers.hdfsurl, function(fileExist) {
        expect(fileExist).to.eql(true);
        done();
      });
    });
  });
});

<|endoftext|>


<commit_before>// Mini version of select-dom
const select = (sel, el) => (el || document).querySelector(sel);
select.all = (sel, el) => (el || document).querySelectorAll(sel);
select.exists = (sel, el) => Boolean(select(sel, el));

// Mini version of element-ready
function elementReady(selector, fn) {
	(function check() {
		const el = document.querySelector(selector);

		if (el) {
			fn();
		} else {
			requestAnimationFrame(check);
		}
	})();
}

/**
 * Utilities
 */
function domify(html) {
	const temp = document.createElement('template');
	temp.innerHTML = html;
	return temp.content;
}

function empty(el) {
	el.textContent = '';
}

function setTimeoutUntilVisible(cb, ms) {
	return setTimeout(requestAnimationFrame, ms, cb);
}

// Is the popup open? Is it opening?
function isOpen() {
	return select.exists('#NPG-opener[aria-expanded="true"], .NPG-loading');
}

/**
 * Extension
 */

let rawNotifications; // Unparsed notification page request

function restoreUnreadIndicator() {
	const indicator = select('.notification-indicator');
	const status = select('.mail-status', indicator);
	if (!status.classList.contains('unread')) {
		status.classList.add('unread');
		indicator.dataset.gaClick = indicator.dataset.gaClick.replace(':read', ':unread');
	}
}

function addNotificationsDropdown() {
	if (select.exists('#NPG')) {
		return;
	}
	const indicator = select('a.notification-indicator');
	indicator.parentNode.insertAdjacentHTML('beforeend', `

	`);
}

async function openPopup() {
	const indicator = select('.notification-indicator');
	if (isOpen()) {
		return;
	}

	// Fetch the notifications
	let notificationsList;
	indicator.classList.add('NPG-loading');
	try {
		const notificationsPage = await rawNotifications.then(domify);

		notificationsList = select.all('.boxed-group', notificationsPage);
		if (notificationsList.length === 0) {
			return;
		}
	} catch (err) {
		return;
	} finally {
		indicator.classList.remove('NPG-loading');
	}

	restoreUnreadIndicator();
	const container = select('#NPG-dropdown');
	empty(container);
	container.append(...notificationsList);

	// Open
	select('#NPG-opener').click();

	// Change tooltip direction
	for (const {classList} of select.all('.tooltipped-s', container)) {
		classList.remove('tooltipped-s');
		classList.add('tooltipped-n');
	}
}

async function fetchNotifications() {
	// Don't fetch while it's open
	if (!isOpen()) {
		rawNotifications = fetch('/notifications', {
			credentials: 'include'
		}).then(r => r.text());
	}

	// Wait for request to be done first, so they don't overlap
	await rawNotifications;

	// Wait three seconds, but don't run if tab is not visible
	setTimeoutUntilVisible(fetchNotifications, 3000);
}

function init() {
	addNotificationsDropdown();
	fetchNotifications();

	const indicator = select('a.notification-indicator');
	indicator.addEventListener('mouseenter', openPopup);

	// Restore link after it's disabled by the modal
	indicator.addEventListener('click', () => {
		location.href = indicator.href;
	});
}

// Init everywhere but on the notifications page
if (!location.pathname.startsWith('/notifications')) {
	elementReady('.notification-indicator', init);
}
<commit_msg>Avoid silencing errors, let 'em free in the console<commit_after>// Mini version of select-dom
const select = (sel, el) => (el || document).querySelector(sel);
select.all = (sel, el) => (el || document).querySelectorAll(sel);
select.exists = (sel, el) => Boolean(select(sel, el));

// Mini version of element-ready
function elementReady(selector, fn) {
	(function check() {
		const el = document.querySelector(selector);

		if (el) {
			fn();
		} else {
			requestAnimationFrame(check);
		}
	})();
}

/**
 * Utilities
 */
function domify(html) {
	const temp = document.createElement('template');
	temp.innerHTML = html;
	return temp.content;
}

function empty(el) {
	el.textContent = '';
}

function setTimeoutUntilVisible(cb, ms) {
	return setTimeout(requestAnimationFrame, ms, cb);
}

// Is the popup open? Is it opening?
function isOpen() {
	return select.exists('#NPG-opener[aria-expanded="true"], .NPG-loading');
}

/**
 * Extension
 */

let rawNotifications; // Unparsed notification page request

function restoreUnreadIndicator() {
	const indicator = select('.notification-indicator');
	const status = select('.mail-status', indicator);
	if (!status.classList.contains('unread')) {
		status.classList.add('unread');
		indicator.dataset.gaClick = indicator.dataset.gaClick.replace(':read', ':unread');
	}
}

function addNotificationsDropdown() {
	if (select.exists('#NPG')) {
		return;
	}
	const indicator = select('a.notification-indicator');
	indicator.parentNode.insertAdjacentHTML('beforeend', `

	`);
}

async function openPopup() {
	const indicator = select('.notification-indicator');
	if (isOpen()) {
		return;
	}

	// Fetch the notifications
	let notificationsList;
	indicator.classList.add('NPG-loading');
	try {
		const notificationsPage = await rawNotifications.then(domify);

		notificationsList = select.all('.boxed-group', notificationsPage);
		if (notificationsList.length === 0) {
			return;
		}
	} finally {
		indicator.classList.remove('NPG-loading');
	}

	restoreUnreadIndicator();
	const container = select('#NPG-dropdown');
	empty(container);
	container.append(...notificationsList);

	// Open
	select('#NPG-opener').click();

	// Change tooltip direction
	for (const {classList} of select.all('.tooltipped-s', container)) {
		classList.remove('tooltipped-s');
		classList.add('tooltipped-n');
	}
}

async function fetchNotifications() {
	// Don't fetch while it's open
	if (!isOpen()) {
		rawNotifications = fetch('/notifications', {
			credentials: 'include'
		}).then(r => r.text());
	}

	// Wait for request to be done first, so they don't overlap
	await rawNotifications;

	// Wait three seconds, but don't run if tab is not visible
	setTimeoutUntilVisible(fetchNotifications, 3000);
}

function init() {
	addNotificationsDropdown();
	fetchNotifications();

	const indicator = select('a.notification-indicator');
	indicator.addEventListener('mouseenter', openPopup);

	// Restore link after it's disabled by the modal
	indicator.addEventListener('click', () => {
		location.href = indicator.href;
	});
}

// Init everywhere but on the notifications page
if (!location.pathname.startsWith('/notifications')) {
	elementReady('.notification-indicator', init);
}
<|endoftext|>


<commit_before>
var fs = require('fs'),
  path = require('path');

//
// ### Usemin Task
//
// Replaces references ton non-optimized scripts / stylesheets into a
// set of html files (or any template / views).
//
// Right now the replacement is based on the filename parsed from
// content and the files present in accoding dir (eg. looking up
// matching revved filename into `intermediate/` dir to know the sha
// generated).
//
// Todo: Use a file dictionary during build process and rev task to
// store each optimized assets and their associated sha1.
//

module.exports = function(grunt) {

  var linefeed = grunt.utils.linefeed;

  grunt.registerMultiTask('usemin', 'Replaces references to non-minified scripts / stylesheets', function() {

    var name = this.target,
      data = this.data,
      files = grunt.file.expand(data);

    files.map(grunt.file.read).forEach(function(content, i) {
      var p = files[i];
      grunt.log.subhead('usemin - ' + p);

      // make sure to convert back into utf8, `file.read` when used as a
      // forEach handler will take additional arguments, and thus trigger the
      // raw buffer read
      content = content.toString();

      // todo fallback to the usemin replace we have if no sections were found.
      var blocks = getBlocks(content);

      //
      // {
      //    'css/site.css ':[
      //      '  <!-- build:css css/site.css -->',
      //      '  <link rel="stylesheet" href="css/style.css">',
      //      '  <!-- endbuild -->'
      //    ],
      //    'js/head.js ': [
      //      '  <!-- build:js js/head.js -->',
      //      '  <script src="js/libs/modernizr-2.5.3.min.js"></script>',
      //      '  <!-- endbuild -->'
      //    ],
      //    'js/site.js ': [
      //      '  <!-- build:js js/site.js -->',
      //      '  <script src="js/plugins.js"></script>',
      //      '  <script src="js/script.js"></script>',
      //      '  <!-- endbuild -->'
      //    ]
      // }
      //

      // handle blocks
      Object.keys(blocks).forEach(function(key) {
        var block = blocks[key].join(linefeed),
          parts = key.split(':'),
          type = parts[0],
          target = parts[1];

        content = grunt.helper('usemin', content, block, target, type);
      });

      // handle revving, each script / link tags are searching for a
      // matching file in intermediate dir, replacing the href/src with their
      // hash-prepended version.
      content = grunt.helper('usemin:replace', content);

      // write the new content to disk
      grunt.file.write(p, content);
    });

  });

  grunt.registerHelper('usemin', function(content, block, target, type) {
    target = target || 'replace';
    return grunt.helper('usemin:' + type, content, block, target);
  });

  grunt.registerHelper('usemin:css', function(content, block, target) {
    var indent = (block.split(linefeed)[0].match(/^\s*/) || [])[0];
    return content.replace(block, indent + '<link rel="stylesheet" href="' + target + '">');
  });

  grunt.registerHelper('usemin:js', function(content, block, target) {
    var indent = (block.split(linefeed)[0].match(/^\s*/) || [])[0];
    return content.replace(block, indent + '<script src="' + target + '"></script>');
  });

  grunt.registerHelper('usemin:replace', function(content) {

    grunt.log.verbose.writeln('Update the HTML to reference our concat/min/revved script files');
    content = grunt.helper('replace', content, /<script.+src=['"](.+)["'][\/>]?><[\\]?\/script>/gm);

    grunt.log.verbose.writeln('Update the HTML with the new css filename');
    content = grunt.helper('replace', content, /<link rel=["']?stylesheet["']?\shref=['"](.+)["']\s*>/gm);

    grunt.log.verbose.writeln('Update the HTML with the new img filename');
    content = grunt.helper('replace', content, /<img[^\>]+src=['"]([^"']+)["']/gm);

    grunt.log.verbose.writeln('Update the HTML with background imgs, case there is some inline style');
    content = grunt.helper('replace', content, /url\(\s*['"]([^"']+)["']\s*\)/gm);

    return content;
  });

  grunt.registerHelper('replace', function(content, regexp) {
    return content.replace(regexp, function(match, src) {
      //do not touch external files
      if(src.match(/\/\//)) return match;
      var basename = path.basename(src);
      var dirname = path.dirname(src);

      // todo: don't lookup for every files on each replace. suboptimal.
      // files won't change, the filepath should filter the original list of files.
      var filepath = grunt.file.expand(path.join('**/*') + basename)[0];

      // not a file in intermediate, skip it
      if(!filepath) return match;
      var filename = path.basename(filepath);
      // handle the relative prefix (with always unix like path even on win32)
      filename = [dirname, filename].join('/');

      // if file not exists probaly was concatenated into another file so skip it
      if(!filename) return '';

      var res = match.replace(src, filename);
      // output some verbose info on what get replaced
      grunt.log
        .ok(src)
        .writeln('was ' + match)
        .writeln('now ' + res);

      return res;
    });
  });
};

//
// Helpers: todo, register as grunt helper
//

// start build pattern --> <!-- build:[target] output -->
var regbuild = /<!--\s*build:(\w+)\s*(.+)\s*-->/;

// end build pattern -- <!-- endbuild -->
var regend = /<!--\s*endbuild\s*-->/;

function getBlocks(body) {
  var lines = body.replace(/\r\n/g, '\n').split(/\n/),
    block = false,
    sections = {},
    last;

  lines.forEach(function(l) {
    var build = l.match(regbuild),
      endbuild = regend.test(l);

    if(build) {
      block = true;
      sections[[build[1], build[2].trim()].join(':')] = last = [];
    }

    // switch back block flag when endbuild
    if(block && endbuild) {
      last.push(l);
      block = false;
    }

    if(block && last) {
      last.push(l);
    }
  });

  return sections;
}
<commit_msg>Add credits to @krzychukula for the replace helper<commit_after>
var fs = require('fs'),
  path = require('path');

//
// ### Usemin Task
//
// Replaces references ton non-optimized scripts / stylesheets into a
// set of html files (or any template / views).
//
// Right now the replacement is based on the filename parsed from
// content and the files present in accoding dir (eg. looking up
// matching revved filename into `intermediate/` dir to know the sha
// generated).
//
// Todo: Use a file dictionary during build process and rev task to
// store each optimized assets and their associated sha1.
//
// Thx to @krzychukula for the new, super handy replace helper.
//

module.exports = function(grunt) {

  var linefeed = grunt.utils.linefeed;

  grunt.registerMultiTask('usemin', 'Replaces references to non-minified scripts / stylesheets', function() {

    var name = this.target,
      data = this.data,
      files = grunt.file.expand(data);

    files.map(grunt.file.read).forEach(function(content, i) {
      var p = files[i];
      grunt.log.subhead('usemin - ' + p);

      // make sure to convert back into utf8, `file.read` when used as a
      // forEach handler will take additional arguments, and thus trigger the
      // raw buffer read
      content = content.toString();

      // todo fallback to the usemin replace we have if no sections were found.
      var blocks = getBlocks(content);

      //
      // {
      //    'css/site.css ':[
      //      '  <!-- build:css css/site.css -->',
      //      '  <link rel="stylesheet" href="css/style.css">',
      //      '  <!-- endbuild -->'
      //    ],
      //    'js/head.js ': [
      //      '  <!-- build:js js/head.js -->',
      //      '  <script src="js/libs/modernizr-2.5.3.min.js"></script>',
      //      '  <!-- endbuild -->'
      //    ],
      //    'js/site.js ': [
      //      '  <!-- build:js js/site.js -->',
      //      '  <script src="js/plugins.js"></script>',
      //      '  <script src="js/script.js"></script>',
      //      '  <!-- endbuild -->'
      //    ]
      // }
      //

      // handle blocks
      Object.keys(blocks).forEach(function(key) {
        var block = blocks[key].join(linefeed),
          parts = key.split(':'),
          type = parts[0],
          target = parts[1];

        content = grunt.helper('usemin', content, block, target, type);
      });

      // handle revving, each script / link tags are searching for a
      // matching file in intermediate dir, replacing the href/src with their
      // hash-prepended version.
      content = grunt.helper('usemin:replace', content);

      // write the new content to disk
      grunt.file.write(p, content);
    });

  });

  grunt.registerHelper('usemin', function(content, block, target, type) {
    target = target || 'replace';
    return grunt.helper('usemin:' + type, content, block, target);
  });

  grunt.registerHelper('usemin:css', function(content, block, target) {
    var indent = (block.split(linefeed)[0].match(/^\s*/) || [])[0];
    return content.replace(block, indent + '<link rel="stylesheet" href="' + target + '">');
  });

  grunt.registerHelper('usemin:js', function(content, block, target) {
    var indent = (block.split(linefeed)[0].match(/^\s*/) || [])[0];
    return content.replace(block, indent + '<script src="' + target + '"></script>');
  });

  grunt.registerHelper('usemin:replace', function(content) {

    grunt.log.verbose.writeln('Update the HTML to reference our concat/min/revved script files');
    content = grunt.helper('replace', content, /<script.+src=['"](.+)["'][\/>]?><[\\]?\/script>/gm);

    grunt.log.verbose.writeln('Update the HTML with the new css filename');
    content = grunt.helper('replace', content, /<link rel=["']?stylesheet["']?\shref=['"](.+)["']\s*>/gm);

    grunt.log.verbose.writeln('Update the HTML with the new img filename');
    content = grunt.helper('replace', content, /<img[^\>]+src=['"]([^"']+)["']/gm);

    grunt.log.verbose.writeln('Update the HTML with background imgs, case there is some inline style');
    content = grunt.helper('replace', content, /url\(\s*['"]([^"']+)["']\s*\)/gm);

    return content;
  });

  grunt.registerHelper('replace', function(content, regexp) {
    return content.replace(regexp, function(match, src) {
      //do not touch external files
      if(src.match(/\/\//)) return match;
      var basename = path.basename(src);
      var dirname = path.dirname(src);

      // todo: don't lookup for every files on each replace. suboptimal.
      // files won't change, the filepath should filter the original list of files.
      var filepath = grunt.file.expand(path.join('**/*') + basename)[0];

      // not a file in intermediate, skip it
      if(!filepath) return match;
      var filename = path.basename(filepath);
      // handle the relative prefix (with always unix like path even on win32)
      filename = [dirname, filename].join('/');

      // if file not exists probaly was concatenated into another file so skip it
      if(!filename) return '';

      var res = match.replace(src, filename);
      // output some verbose info on what get replaced
      grunt.log
        .ok(src)
        .writeln('was ' + match)
        .writeln('now ' + res);

      return res;
    });
  });
};

//
// Helpers: todo, register as grunt helper
//

// start build pattern --> <!-- build:[target] output -->
var regbuild = /<!--\s*build:(\w+)\s*(.+)\s*-->/;

// end build pattern -- <!-- endbuild -->
var regend = /<!--\s*endbuild\s*-->/;

function getBlocks(body) {
  var lines = body.replace(/\r\n/g, '\n').split(/\n/),
    block = false,
    sections = {},
    last;

  lines.forEach(function(l) {
    var build = l.match(regbuild),
      endbuild = regend.test(l);

    if(build) {
      block = true;
      sections[[build[1], build[2].trim()].join(':')] = last = [];
    }

    // switch back block flag when endbuild
    if(block && endbuild) {
      last.push(l);
      block = false;
    }

    if(block && last) {
      last.push(l);
    }
  });

  return sections;
}
<|endoftext|>