<commit_before>var addressQuery;
var bounds = [[37.708, -122.515], [37.8125, -122.355]];
var geoJSON = [];
var map;
var mapId = 'jeffreyseifried.h1n3d7d4' ;
var mapId = 'examples.map-20v6611k' ;
var poiPaths = [];
var poiMetrics = [];
var pathOptions = {color : 'red', opacity : 0.5, weight : 4};
var scoreColor;
var scoreDistance;
var scoreHi = 70.;
var scoreLo = 30.;
var scoreMax = 4;
var scoreMinutes2Distance = 15;
var scorePower = 0.5;
var scoreText;

function DogShit() {
    // ... reset map ...
    ResetMap();
    // ... and reset score ...
    ResetScore()
    // ... and hide loading
    ShowLoading(false);
};

function POISum(poiType, metrics) {
    // Sum POI's
    var total = 0;
    for (i = 0; i < metrics.length; i++) {
        if (poiType == metrics[i][0]) {
            total += Math.min(1, Math.pow(scoreDistance / metrics[i][1], scorePower));
        };
    };
    // Return
    return total;
};

function Score() {
    // Grab slider weights
    weightPark = parseFloat($('#play').val());
    weightPark = 0;
    weightBar = parseFloat($('#drink').val());
    weightRest = parseFloat($('#food').val());
    // Normalize them
    weightTotal = Math.max(1, weightPark + weightBar + weightRest);
    weightPark /= weightTotal;
    weightBar /= weightTotal;
    weightRest /= weightTotal;
    // Calculate score
    var score = weightPark * POISum('park', poiMetrics)
              + weightBar * POISum('bar', poiMetrics)
              + weightRest * POISum('restaurant', poiMetrics);
    // Normalize score
    score = Math.floor(Math.min(1, score / scoreMax) * 100);
    // Pick color
    switch(true) {
    case (score < scoreLo):
        color = 'salmon';
        break;
    case (score > scoreHi):
        color = 'limegreen';
        break;
    default:
        color = 'khaki'
        break;
    };
    // Set score text
    document.getElementById('score').innerText = score + ' / 100';
    // Set score color
    $('#score').css('background-color', color);
    // Show slider
    $('#slider').css('display', 'block');
    // Show score
    $('#score').css('display', 'block');
    // Hide loading
    ShowLoading(false);
};

function FindAndRoute(box) {
    // Grab address ...
    addressQuery = box;
    // ... show loading ...
    ShowLoading(true);
    // ... and grab minutes
    minutes = 7; // FIXME
    // Scale score distance with duration
    scoreDistance = minutes * scoreMinutes2Distance / 2;
    // Geocode it
    $.getJSON('/findAddress', {'q' : addressQuery, 'm' : minutes}, function(findJSON) {
        // Maybe reset on bad query
        if (findJSON != {}) {
            // Pan and zoom
            map.fitBounds(findJSON['bounds']);
            // Push address
            geoJSON.push(findJSON['address']);
            // Push POIs
            geoJSON = geoJSON.concat(findJSON['POIs']);
            // Draw geoJSON markers
            map.markerLayer.setGeoJSON(geoJSON);
            // Grab nodeIds
            nodeId = findJSON['nodeId'];
            poiIds = findJSON['poiIds'];
            // Route to each POI
            for (var j = 0; j < poiIds.length; j++) {
                $.getJSON('/routePOI', {'s' : nodeId, 'p' : poiIds[j]}, function(routeJSON) {
                    // Add address and POI to path
                    var latlngs = routeJSON['latlngs'];
                    latlngs.unshift(findJSON['addressLatlng']);
                    latlngs.push(routeJSON['poiLatlng']);
                    // Draw path
                    poiPaths.push(new L.polyline(latlngs, pathOptions).addTo(map));
                    // Populate score metrics
                    poiMetrics.push([routeJSON['poiType'], findJSON['offset'] + routeJSON['distance'] + routeJSON['offset']]);
                    // If we are at the last POI ...
                    if (j == poiMetrics.length) {
                        // ... push trees ...
                        geoJSON = geoJSON.concat(findJSON['trees']);
                        // ... and redraw geoJSON markers
                        map.markerLayer.setGeoJSON(geoJSON);
                        // ... score ...
                        Score();
                    };
                });
            };
            // Score if no POI's are found
            if (poiIds.length == 0) {
                // Score
                Score();
            };
        } else {
            // FIXME Declare that it wasn't found
            // Hide loading
            ShowLoading(false);
        };
    });
};

function SliderMove() {
    // If a query exists ...
    if (addressQuery) {
        // ... update score
        Score();
    };
};

function ResetScore() {
    // Reset score text
    document.getElementById('score').innerText = scoreText;
    // Reset score color
    $('#score').css('background-color', scoreColor);
    // Hide score
    $('#score').css('display', 'none');
    // Hide slider
    $('#slider').css('display', 'none');
};

function ResetMap() {
    // Clear address query
    addressQuery = null;
    // Clear POI paths
    for (var i = poiPaths.length; i > 0; i--) {
        poiPaths.pop().setLatLngs([]).redraw();
    };
    // Clear POI metrics
    poiMetrics = [];
    // Clear address, tree, and POI markers
    geoJSON = [];
    map.markerLayer.setGeoJSON(geoJSON);
    // Reset pan and zoom
    map.fitBounds(bounds);
};

function PawClick() {
    // Grab address box value
    var box = $('#address').val();
    // Reset map ...
    ResetMap();
    // ... and reset score ...
    ResetScore()
    // If it is not empty ...
    if (box != '' && box != null) {
        // ... and find and route
        FindAndRoute(box);
    };
};

function KeyPress(event) {
    // Grab address box value
    var box = $('#address').val();
    // If it is empty ...
    if (box == '' || box == null) {
        // ... reset map ...
        ResetMap();
        // ... and reset score ...
        ResetScore()
    } else {
        // ... otherwise, if [enter] was pressed
        if (13 == event.keyCode) {
            // ... reset map ...
            ResetMap();
            // ... and reset score ...
            ResetScore()
            // ... and find and route
            FindAndRoute(box);
        };
    };
};

function ShowLoading(showLoading) {
    if (showLoading) {
        $('#loading').css('visibility', 'visible');
    } else {
        $('#loading').css('visibility', 'hidden');
    };
};

function Load() {
    // Grab default score color
    scoreColor = $('#menu').css('background-color');
    // Grab default score text
    scoreText = document.getElementById('score').innerText;
    // Initialize MapBox map
    map = L.mapbox.map('map', mapId, {zoomControl : false}).fitBounds(bounds);
    // Move zoom controls to top-right
    new L.Control.Zoom({position : 'topright'}).addTo(map);
    // Customize marker drawing
    map.markerLayer.on('layeradd', function(e) {
        var marker = e.layer,
            feature = marker.feature;
        //
        marker.setIcon(L.icon(feature.properties.icon));
        //
        if (feature.properties.yelpUrl != undefined) {
            var popup = '' +
                        feature.properties.title + '';
            //
            marker.bindPopup(popup);
        };
    });
    // Debug
    if (false) {
        L.marker([37.74, -122.41], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/bar-24.svg'})}).addTo(map);
        L.marker([37.74, -122.42], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/circle-24.svg'})}).addTo(map);
        L.marker([37.74, -122.425], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/circle-24.svg'})}).addTo(map);
        L.marker([37.74, -122.43], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/park-24.svg'})}).addTo(map);
        L.marker([37.74, -122.44], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/restaurant-24.svg'})}).addTo(map);
        L.marker([37.74, -122.45], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/square-24.svg'})}).addTo(map);
        L.marker([37.74, -122.46], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/star-24.svg'})}).addTo(map);
    };
};
<commit_msg>- Draw trees when no POIs are found<commit_after>var addressQuery;
var bounds = [[37.708, -122.515], [37.8125, -122.355]];
var geoJSON = [];
var map;
var mapId = 'jeffreyseifried.h1n3d7d4' ;
var mapId = 'examples.map-20v6611k' ;
var poiPaths = [];
var poiMetrics = [];
var pathOptions = {color : 'red', opacity : 0.5, weight : 4};
var scoreColor;
var scoreDistance;
var scoreHi = 70.;
var scoreLo = 30.;
var scoreMax = 4;
var scoreMinutes2Distance = 15;
var scorePower = 0.5;
var scoreText;

function DogShit() {
    // ... reset map ...
    ResetMap();
    // ... and reset score ...
    ResetScore()
    // ... and hide loading
    ShowLoading(false);
};

function POISum(poiType, metrics) {
    // Sum POI's
    var total = 0;
    for (i = 0; i < metrics.length; i++) {
        if (poiType == metrics[i][0]) {
            total += Math.min(1, Math.pow(scoreDistance / metrics[i][1], scorePower));
        };
    };
    // Return
    return total;
};

function Score() {
    // Grab slider weights
    weightPark = parseFloat($('#play').val());
    weightPark = 0;
    weightBar = parseFloat($('#drink').val());
    weightRest = parseFloat($('#food').val());
    // Normalize them
    weightTotal = Math.max(1, weightPark + weightBar + weightRest);
    weightPark /= weightTotal;
    weightBar /= weightTotal;
    weightRest /= weightTotal;
    // Calculate score
    var score = weightPark * POISum('park', poiMetrics)
              + weightBar * POISum('bar', poiMetrics)
              + weightRest * POISum('restaurant', poiMetrics);
    // Normalize score
    score = Math.floor(Math.min(1, score / scoreMax) * 100);
    // Pick color
    switch(true) {
    case (score < scoreLo):
        color = 'salmon';
        break;
    case (score > scoreHi):
        color = 'limegreen';
        break;
    default:
        color = 'khaki'
        break;
    };
    // Set score text
    document.getElementById('score').innerText = score + ' / 100';
    // Set score color
    $('#score').css('background-color', color);
    // Show slider
    $('#slider').css('display', 'block');
    // Show score
    $('#score').css('display', 'block');
    // Hide loading
    ShowLoading(false);
};

function FindAndRoute(box) {
    // Grab address ...
    addressQuery = box;
    // ... show loading ...
    ShowLoading(true);
    // ... and grab minutes
    minutes = 7; // FIXME
    // Scale score distance with duration
    scoreDistance = minutes * scoreMinutes2Distance / 2;
    // Geocode it
    $.getJSON('/findAddress', {'q' : addressQuery, 'm' : minutes}, function(findJSON) {
        // Maybe reset on bad query
        if (findJSON != {}) {
            // Pan and zoom
            map.fitBounds(findJSON['bounds']);
            // Push address
            geoJSON.push(findJSON['address']);
            // Push POIs
            geoJSON = geoJSON.concat(findJSON['POIs']);
            // Draw geoJSON markers
            map.markerLayer.setGeoJSON(geoJSON);
            // Grab nodeIds
            nodeId = findJSON['nodeId'];
            poiIds = findJSON['poiIds'];
            // Route to each POI
            for (var j = 0; j < poiIds.length; j++) {
                $.getJSON('/routePOI', {'s' : nodeId, 'p' : poiIds[j]}, function(routeJSON) {
                    // Add address and POI to path
                    var latlngs = routeJSON['latlngs'];
                    latlngs.unshift(findJSON['addressLatlng']);
                    latlngs.push(routeJSON['poiLatlng']);
                    // Draw path
                    poiPaths.push(new L.polyline(latlngs, pathOptions).addTo(map));
                    // Populate score metrics
                    poiMetrics.push([routeJSON['poiType'], findJSON['offset'] + routeJSON['distance'] + routeJSON['offset']]);
                    // If we are at the last POI ...
                    if (j == poiMetrics.length) {
                        // ... push trees ...
                        geoJSON = geoJSON.concat(findJSON['trees']);
                        // ... and redraw geoJSON markers
                        map.markerLayer.setGeoJSON(geoJSON);
                        // ... score ...
                        Score();
                    };
                });
            };
            // Score if no POI's are found
            if (poiIds.length == 0) {
                // ... push trees ...
                geoJSON = geoJSON.concat(findJSON['trees']);
                // ... redraw geoJSON markers
                map.markerLayer.setGeoJSON(geoJSON);
                // ... and score
                Score();
            };
        } else {
            // FIXME Declare that it wasn't found
            // Hide loading
            ShowLoading(false);
        };
    });
};

function SliderMove() {
    // If a query exists ...
    if (addressQuery) {
        // ... update score
        Score();
    };
};

function ResetScore() {
    // Reset score text
    document.getElementById('score').innerText = scoreText;
    // Reset score color
    $('#score').css('background-color', scoreColor);
    // Hide score
    $('#score').css('display', 'none');
    // Hide slider
    $('#slider').css('display', 'none');
};

function ResetMap() {
    // Clear address query
    addressQuery = null;
    // Clear POI paths
    for (var i = poiPaths.length; i > 0; i--) {
        poiPaths.pop().setLatLngs([]).redraw();
    };
    // Clear POI metrics
    poiMetrics = [];
    // Clear address, tree, and POI markers
    geoJSON = [];
    map.markerLayer.setGeoJSON(geoJSON);
    // Reset pan and zoom
    map.fitBounds(bounds);
};

function PawClick() {
    // Grab address box value
    var box = $('#address').val();
    // Reset map ...
    ResetMap();
    // ... and reset score ...
    ResetScore()
    // If it is not empty ...
    if (box != '' && box != null) {
        // ... and find and route
        FindAndRoute(box);
    };
};

function KeyPress(event) {
    // Grab address box value
    var box = $('#address').val();
    // If it is empty ...
    if (box == '' || box == null) {
        // ... reset map ...
        ResetMap();
        // ... and reset score ...
        ResetScore()
    } else {
        // ... otherwise, if [enter] was pressed
        if (13 == event.keyCode) {
            // ... reset map ...
            ResetMap();
            // ... and reset score ...
            ResetScore()
            // ... and find and route
            FindAndRoute(box);
        };
    };
};

function ShowLoading(showLoading) {
    if (showLoading) {
        $('#loading').css('visibility', 'visible');
    } else {
        $('#loading').css('visibility', 'hidden');
    };
};

function Load() {
    // Grab default score color
    scoreColor = $('#menu').css('background-color');
    // Grab default score text
    scoreText = document.getElementById('score').innerText;
    // Initialize MapBox map
    map = L.mapbox.map('map', mapId, {zoomControl : false}).fitBounds(bounds);
    // Move zoom controls to top-right
    new L.Control.Zoom({position : 'topright'}).addTo(map);
    // Customize marker drawing
    map.markerLayer.on('layeradd', function(e) {
        var marker = e.layer,
            feature = marker.feature;
        //
        marker.setIcon(L.icon(feature.properties.icon));
        //
        if (feature.properties.yelpUrl != undefined) {
            var popup = '' +
                        feature.properties.title + '';
            //
            marker.bindPopup(popup);
        };
    });
    // Debug
    if (false) {
        L.marker([37.74, -122.41], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/bar-24.svg'})}).addTo(map);
        L.marker([37.74, -122.42], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/circle-24.svg'})}).addTo(map);
        L.marker([37.74, -122.425], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/circle-24.svg'})}).addTo(map);
        L.marker([37.74, -122.43], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/park-24.svg'})}).addTo(map);
        L.marker([37.74, -122.44], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/restaurant-24.svg'})}).addTo(map);
        L.marker([37.74, -122.45], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/square-24.svg'})}).addTo(map);
        L.marker([37.74, -122.46], {icon:L.icon({iconSize : [48, 48], iconUrl : './static/img/star-24.svg'})}).addTo(map);
    };
};
<|endoftext|>


<commit_before>/**
 * build operation for Predator
 */

/**
 * module dependencies
 */
var glob = require('glob');
var util = require('./util');
var Hash = util.Hash;
var fmt = require('util').format;
var co = require('co');
var path = require('path');
var fs = require('fs');
var fse = require('fs-extra');
var UglifyJs = require('uglify-js');

/**
 * 只复制
 */
exports.buildCopy = function(globPatterns) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:copy');

  globPatterns.forEach(function(pattern) {
    var files = glob.sync(pattern, {
      cwd: cwd
    });

    files.forEach(function(f) {
      var src = self.home + '/app/' + f;
      var dest = self.buildDir + '/' + f;

      debug('copy %s -> %s', src, dest);
      util.copy(src, dest);
    });
  });
};

/**
 * 进行hash操作, 不引用其他的资源, 没有替换操作
 */
exports.buildStatic = function(globPatterns, rev) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:buildStatic');

  globPatterns.forEach(function(pattern) {

    var files = glob.sync(pattern, {
      cwd: cwd
    });

    files.forEach(function(f) {
      var original = f;
      var src = self.home + '/app/' + f;
      var hash = util.Hash.file(src);

      // setup rev map
      var parsed = path.parse(f);
      var hashed = fmt('%s/%s_%s%s', parsed.dir, parsed.name, hash, parsed.ext);
      debug('%s -> %s', original, hashed);
      rev[original] = hashed;

      // write file
      var dest = self.buildDir + '/' + hashed;
      fse.copySync(src, dest);
    });
  });
};

/**
 * less
 *
 * 处理less, 替换图片资源等
 */
exports.buildLessAsync = co.wrap(function * (globPatterns, rev) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:buildLessAsync');

  for (var i = 0; i < globPatterns.length; i++) {
    var pattern = globPatterns[i];
    var files = glob.sync(pattern, {
      cwd: cwd
    });

    for (var j = 0; j < files.length; j++) {
      var f = files[j];
      var original = f;

      // build hash
      var src = self.home + '/app/' + f;
      var content = yield self.renderLessAsync(src);
      content = util.processRev(content, rev);
      var hash = Hash.string(content);
      var parsed = path.parse(original);
      var hashed = fmt('%s/%s_%s%s', parsed.dir, parsed.name, hash, '.css');
      debug('%s -> %s', original, hashed);
      rev[original] = hashed;

      // write file
      var dest = self.buildDir + '/' + hashed;
      fse.outputFileSync(dest, content);
    };
  };
});

exports.buildJsAsync = co.wrap(function * (globPatterns, rev) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:buildJsAsync');

  for (var i = 0; i < globPatterns.length; i++) {
    var pattern = globPatterns[i];

    var files = glob.sync(pattern, {
      cwd: cwd
    });

    for (var j = 0; j < files.length; j++) {
      var f = files[j];
      if (f === 'global/js/main/index.json') { // hack on global js
        f = 'global/js/main/index.js'
      }
      var original = f;

      // build hash
      var src = self.home + '/app/' + f;

      // bundle
      var b = self.createBrowserify(src);
      var content = (yield b.bundleAsync()).toString('utf8');

      // process rev
      content = util.processRev(content, rev);

      // minify
      content = UglifyJs.minify(content, {
        fromString: true
      }).code;

      // do rev
      var hash = Hash.string(content);
      var parsed = path.parse(original);
      var hashed = fmt('%s/%s_%s%s', parsed.dir, parsed.name, hash, '.js');
      debug('%s -> %s', original, hashed);
      rev[original] = hashed;

      // write file
      var dest = self.buildDir + '/' + hashed;
      fse.outputFileSync(dest, content, 'utf8');
    }
  }
});

/**
 * 处理视图
 *
 * 只替换资源
 */
exports.buildView = function(globPatterns, rev) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:buildView');

  globPatterns.forEach(function(pattern) {
    var files = glob.sync(pattern, {
      cwd: cwd
    });

    files.forEach(function(f) {
      var file = self.home + '/app/' + f;
      var content = fs.readFileSync(file, 'utf8');
      content = util.processRev(content, rev);
      content = content.replace(/\/view(?=\/)/g, '/view_build');

      // write file
      var dest = file.replace(/\/view(?=\/)/, '/view_build');
      debug('%s -> %s', file, dest);
      fse.outputFileSync(dest, content, 'utf8');
    })
  });
};<commit_msg>build: add buildOtherJsCss<commit_after>/**
 * build operation for Predator
 */

/**
 * module dependencies
 */
var glob = require('glob');
var util = require('./util');
var Hash = util.Hash;
var fmt = require('util').format;
var co = require('co');
var path = require('path');
var fs = require('fs');
var fse = require('fs-extra');
var UglifyJs = require('uglify-js');

/**
 * 只复制
 */
exports.buildCopy = function(globPatterns) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:copy');

  globPatterns.forEach(function(pattern) {
    var files = glob.sync(pattern, {
      cwd: cwd
    });

    files.forEach(function(f) {
      var src = self.home + '/app/' + f;
      var dest = self.buildDir + '/' + f;

      debug('copy %s -> %s', src, dest);
      util.copy(src, dest);
    });
  });
};

/**
 * 进行hash操作, 不引用其他的资源, 没有替换操作
 */
exports.buildStatic = function(globPatterns, rev) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:buildStatic');

  globPatterns.forEach(function(pattern) {

    var files = glob.sync(pattern, {
      cwd: cwd
    });

    files.forEach(function(f) {
      var original = f;
      var src = self.home + '/app/' + f;
      var hash = util.Hash.file(src);

      // setup rev map
      var parsed = path.parse(f);
      var hashed = fmt('%s/%s_%s%s', parsed.dir, parsed.name, hash, parsed.ext);
      debug('%s -> %s', original, hashed);
      rev[original] = hashed;

      // write file
      var dest = self.buildDir + '/' + hashed;
      fse.copySync(src, dest);
    });
  });
};

/**
 * less
 *
 * 处理less, 替换图片资源等
 */
exports.buildLessAsync = co.wrap(function * (globPatterns, rev) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:buildLessAsync');

  for (var i = 0; i < globPatterns.length; i++) {
    var pattern = globPatterns[i];
    var files = glob.sync(pattern, {
      cwd: cwd
    });

    for (var j = 0; j < files.length; j++) {
      var f = files[j];
      var original = f;

      // build hash
      var src = self.home + '/app/' + f;
      var content = yield self.renderLessAsync(src);
      content = util.processRev(content, rev);
      var hash = Hash.string(content);
      var parsed = path.parse(original);
      var hashed = fmt('%s/%s_%s%s', parsed.dir, parsed.name, hash, '.css');
      debug('%s -> %s', original, hashed);
      rev[original] = hashed;

      // write file
      var dest = self.buildDir + '/' + hashed;
      fse.outputFileSync(dest, content);
    };
  };
});

exports.buildJsAsync = co.wrap(function * (globPatterns, rev) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:buildJsAsync');

  for (var i = 0; i < globPatterns.length; i++) {
    var pattern = globPatterns[i];

    var files = glob.sync(pattern, {
      cwd: cwd
    });

    for (var j = 0; j < files.length; j++) {
      var f = files[j];
      if (f === 'global/js/main/index.json') { // hack on global js
        f = 'global/js/main/index.js'
      }
      var original = f;

      // build hash
      var src = self.home + '/app/' + f;

      // bundle
      var b = self.createBrowserify(src);
      var content = (yield b.bundleAsync()).toString('utf8');

      // process rev
      content = util.processRev(content, rev);

      // minify
      content = UglifyJs.minify(content, {
        fromString: true
      }).code;

      // do rev
      var hash = Hash.string(content);
      var parsed = path.parse(original);
      var hashed = fmt('%s/%s_%s%s', parsed.dir, parsed.name, hash, '.js');
      debug('%s -> %s', original, hashed);
      rev[original] = hashed;

      // write file
      var dest = self.buildDir + '/' + hashed;
      fse.outputFileSync(dest, content, 'utf8');
    }
  }
});

/**
 * 处理视图
 *
 * 只替换资源
 */
exports.buildView = function(globPatterns, rev) {
  var self = this;
  var cwd = this.home + '/app';
  var debug = require('debug')('predator:build:buildView');

  globPatterns.forEach(function(pattern) {
    var files = glob.sync(pattern, {
      cwd: cwd
    });

    files.forEach(function(f) {
      var file = self.home + '/app/' + f;
      var content = fs.readFileSync(file, 'utf8');
      content = util.processRev(content, rev);
      content = content.replace(/\/view(?=\/)/g, '/view_build');

      // write file
      var dest = file.replace(/\/view(?=\/)/, '/view_build');
      debug('%s -> %s', file, dest);
      fse.outputFileSync(dest, content, 'utf8');
    })
  });
};

/**
 * 不带 main 的 js/css
 *
 */
exports.buildOtherJsCss = function(globPatterns, rev) {
  var cwd = this.home + '/app';
  var self = this;
  var debug = require('debug')('predator:build:buildOtherJsCss');

  globPatterns.forEach(function(pattern) {
    var files = glob.sync(pattern, {
      cwd: cwd
    });

    files.forEach(function(f) {
      // do rev
      var original = f;
      var src = cwd + '/' + f;
      var content = fs.readFileSync(src, 'utf8');
      content = util.processRev(content, rev);
      var hash = Hash.string(content);
      var parsed = path.parse(original);
      var hashed = fmt('%s/%s_%s%s', parsed.dir, parsed.name, hash, parsed.ext);
      rev[original] = hashed;
      debug('%s -> %s', original, hashed);

      // write file
      var dest = self.buildDir + '/' + hashed;
      fse.outputFileSync(dest, content);
    });
  });
};<|endoftext|>


<commit_before>var mouseState = false;
document.onmousedown = function(e) {
    mouseState = true;
}
document.onmouseup = function(e) {
    mouseState = false;
}

function flushThis(id){
   var msie = 'Microsoft Internet Explorer';
   var tmp = 0;
   var elementOnShow = document.getElementById(id);
   if (navigator.appName == msie){
      tmp = elementOnShow.parentNode.offsetTop  +  'px';
   } else {
      tmp = elementOnShow.offsetTop;
   }
}

function applyClass(klass) {

    /*
       Checks all the table elements,
       if they are selected, it removes the
       selected class (and all other classes)
       and applies the passed in class
    */

    $("#holiday-table")
        .find("td")
        .each(function () {
            if ($(this).hasClass("selected")) {
                $(this).removeClass();
                $(this).addClass(klass);
            }
        });
    return true;
}

function submit_all() {

    /*
       Submits all entries on the form

       Takes no parameters and returns true/false
       depending on success.
    */

    var successfully_completed = false;
    $("#holiday-table")
        .find(":button")
        .not("#submit_all, #btn_change_td")
        .each(function () {
            successfully_completed = submit_holidays($(this).attr("user_id"), true)
        });
    // refresh the table data
    setTimeout("change_table_data()", 1000);
    return successfully_completed;
}

function submit_holidays(user_id, mass) {
    /*
       En masse changes a set of holidays and
       takes a user_id as a parameter.

       Mass is true/false, if true it

       Returns true for success, false for error
    */

    if (!user_id) {
        return true;
    }

    // create a map to hold the holidays
    var holiday_map = JSON;

    // iterate through the table and check if it's
    // selected or not, if it's selected, ignore it.
    // else, add the number and the class to the map.
    $("#holiday-table")
        .find("td[usrid='"+user_id+"']")
        .each(function () {
            // remove the selected class off the element
            $(this).removeClass("selected");
            // get the bg colour of the td
            var current_class = $(this).attr('class');
            // this check is redundant but it helps if there
            // are any changes to the selection methods
            if (current_class !== "selected") {
                holiday_map[$(this).text()] = current_class;
            }
        });

    // setup our ajax properties
    $.ajaxSetup({
        type: 'POST',
        dataType: 'json'
    });

    $.ajax({
        url: '/ajax/',
        data: {
            'form_type': 'mass_holidays',
            'year': $("#holiday-table").attr("year"), // from the table header
            'month': $("#holiday-table").attr("month"),
            'holiday_data': JSON.stringify(holiday_map),
            'user_id': user_id
        },
        success: function(data) {
            if (data.success === true) {
                if (!mass) {
                    alert("Holidays updated successfully");
                }
            } else {
                alert(data.error);
            }
        },
        error: function(ajaxObj, textStatus, error) {
            alert(error);
        }
    });

    // return true so programmatic callers can
    // see we've completed
    return true;
}

function addFunctions () {

    "use strict";

    $("#holiday-table")
        .find(".job_code").each( function () {
            if ( $("#is_team_leader").attr("value") ) {
                $(this).text('');
            }
        });

    // all the daytype classes
    // are assigned a click handler which
    // swaps the colour depending on what
    // it currently is.
    $("#holiday-table")
        .find('.empty, .DAYOD, .TRAIN, '
            + '.WKDAY, .SICKD, .HOLIS, '
            + '.SPECI, .MEDIC, .PUABS, '
            + '.PUWRK, .SATUR, .RETRN, '
            + '.WKHOM, .OTHER, .ROVER  ')
        .not(":button")
        .attr("unselectable", "on")   // make it so you can't select text
        .mouseover(function (e) {
            if (mouseState) {

                if ($(this).hasClass("selected")) {
                    $(this).removeClass("selected");
                } else {
                    $(this).addClass("selected");
                }
                e.preventDefault();
                e.stopPropagation();
            }
        })
        .mousedown(function (e) {
            if ($(this).hasClass("selected")) {
                $(this).removeClass("selected");
            } else {
                $(this).addClass("selected");
            }
        });

    $("#year_select").val($("#holiday-table").attr("year"));
    $("#month_select").val($("#holiday-table").attr("month"));
    $("#process_select").val($("#holiday-table").attr("process"));
    $("#employees-select, #day_options").change(function () {
        retrieveComments();
    });
    $("#year_select, #month_select, #process_select").change(function () {
        change_table_data();
    });

    $("#holiday-table")
        .attr("border", "1")

    return true;
}

function change_table_data () {

    "use strict";

    /*
       Function which takes the values of the select boxes
       constructs an ajax call based on those and replaces
       the table with the data returned from the ajax call
    */

    var year = $("#year_select").val();
    var month = $("#month_select").val();
    var process = $("#process_select").val();

    if (process === "ALL") {
        process = "";
    }

    $.ajax({
        type: "GET",
        dataType: "HTML",
        url: "/holiday_planning/" + year + "/" + month + "/" + process,
        success: function(data) {

            $("#holiday-wrapper, #comments-wrapper").fadeTo(500, 0, function() {
                if ( $("#isie").attr("isie") === "true" ) {
                    $("#comments-wrapper").load(
                        "/holiday_planning/" + year + "/" + month + "/" + process + " #com-field"
                    );
                    $("#holiday-wrapper").load(
                        "/holiday_planning/" + year + "/" + month + "/" + process + " #holiday-table",
                        function() {
                            addFunctions();
                            retrieveComments();
                        }
                    );
                } else {
                    var holiday_html = $(data).find("#holiday-wrapper").html();
                    var comments_html = $(data).find("#comments-wrapper").html();
                    var table_year = $(data).find("#holiday-table").attr("year");
                    var table_month = $(data).find("#holiday-table").attr("month");

                    $("#com-field").html(comments_html);
                    $("#holiday-table").html(holiday_html);
                }
                flushThis("holiday-wrapper");
                $("#holiday-table").attr("year", table_year);
                $("#holiday-table").attr("month", table_month);
                addFunctions();
                $("#year_select").val(year);
                $("#month_select").val(month);
                if (process === "") {
                    $("#process_select").val("ALL");
                } else {
                    $("#process_select").val(process);
                }
                $("#holiday-wrapper, #comments-wrapper").fadeTo(500, 1);
            });
            checkTeamLeader();
        }
    });

    return true;
}

function removeComment() {
    "use strict";

    /*
      Function which removes a comment from the database for a specific
      tracking entry.
    */

    $.ajaxSetup({
        type: "POST",
        dataType: "json"
    });

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'remove_comment',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#user_select").val(),
            day: $("#day_options").val()
        },
        success: function (data) {
            if (data.success) {
                retrieveComments();
                change_table_data();
            } else {
                alert(data.error)
            }
        },
        error: function (data) {
            alert(data.error);
        }
    });

}

function insertComment() {

    "use strict";

    /*
      Function which inserts a comment into the database for a specific
      tracking entry.
    */

    $.ajaxSetup({
        type: "POST",
        dataType: "json"
    });

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'add_comment',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#user_select").val(),
            day: $("#day_options").val(),
            comment: $("#comments-field-comment").val()
        },
        success: function (data) {
            if (data.success) {
                retrieveComments();
                change_table_data();
            } else {
                alert(data.error)
            }
        },
        error: function (data) {
            alert(data.error);
        }
    });

}

function retrieveComments() {

    "use strict";

    /*
      Function which retrieves the comment associated with a tracking entry,
      this allows managers to apply a comment onto a field and edit the
      comments that they have already added onto a field by selecting the
      dates that they used it on.
    */

    $.ajaxSetup({
        type: "GET",
        dataType: "json"
    });

    $("#comments-field-comment").val('');

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'get_comments',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#user_select").val(),
            day: $("#day_options").val()
        },
        success: function (data) {
            if (data.success) {
                $("#comments-field-comment").val(data.comment);
            } else {
                alert(data.error)
            }
        },
        error: function(data) {
            alert(data.error);
        }
    });

    return true;

}

function checkTeamLeader() {

    /*
      Function which checks if the user is a team leader.

      If so, the field is removed
    */

    "use strict";

    var is_team_leader = $("#is_team_leader").attr("value");

    $("#holiday-table")
        .find(".job_code").each( function () {
            if ( is_team_leader ) {
                $(this).text('');
            }
            $(this).css("color", "black")
        });

    return true;
}

$(function () {
    addFunctions();
    checkTeamLeader();
});
<commit_msg>JSLint.<commit_after>var mouseState = false;
document.onmousedown = function (e) {
    mouseState = true;
}
document.onmouseup = function (e) {
    mouseState = false;
}

function flushThis(id){
   var msie = 'Microsoft Internet Explorer';
   var tmp = 0;
   var elementOnShow = document.getElementById(id);
   if (navigator.appName == msie){
      tmp = elementOnShow.parentNode.offsetTop  +  'px';
   } else {
      tmp = elementOnShow.offsetTop;
   }
}

function applyClass(klass) {

    /*
       Checks all the table elements,
       if they are selected, it removes the
       selected class (and all other classes)
       and applies the passed in class
    */

    $("#holiday-table")
        .find("td")
        .each(function () {
            if ($(this).hasClass("selected")) {
                $(this).removeClass();
                $(this).addClass(klass);
            }
        });
    return true;
}

function submit_all() {

    /*
       Submits all entries on the form

       Takes no parameters and returns true/false
       depending on success.
    */

    var successfully_completed = false;
    $("#holiday-table")
        .find(":button")
        .not("#submit_all, #btn_change_td")
        .each(function () {
            successfully_completed = submit_holidays($(this).attr("user_id"), true)
        });
    // refresh the table data
    setTimeout("change_table_data()", 1000);
    return successfully_completed;
}

function submit_holidays(user_id, mass) {
    /*
       En masse changes a set of holidays and
       takes a user_id as a parameter.

       Mass is true/false, if true it

       Returns true for success, false for error
    */

    if (!user_id) {
        return true;
    }

    // create a map to hold the holidays
    var holiday_map = JSON;

    // iterate through the table and check if it's
    // selected or not, if it's selected, ignore it.
    // else, add the number and the class to the map.
    $("#holiday-table")
        .find("td[usrid='"+user_id+"']")
        .each(function () {
            // remove the selected class off the element
            $(this).removeClass("selected");
            // get the bg colour of the td
            var current_class = $(this).attr('class');
            // this check is redundant but it helps if there
            // are any changes to the selection methods
            if (current_class !== "selected") {
                holiday_map[$(this).text()] = current_class;
            }
        });

    // setup our ajax properties
    $.ajaxSetup({
        type: 'POST',
        dataType: 'json'
    });

    $.ajax({
        url: '/ajax/',
        data: {
            'form_type': 'mass_holidays',
            'year': $("#holiday-table").attr("year"), // from the table header
            'month': $("#holiday-table").attr("month"),
            'holiday_data': JSON.stringify(holiday_map),
            'user_id': user_id
        },
        success: function(data) {
            if (data.success === true) {
                if (!mass) {
                    alert("Holidays updated successfully");
                }
            } else {
                alert(data.error);
            }
        },
        error: function(ajaxObj, textStatus, error) {
            alert(error);
        }
    });

    // return true so programmatic callers can
    // see we've completed
    return true;
}

function addFunctions () {

    "use strict";

    $("#holiday-table")
        .find(".job_code").each( function () {
            if ( $("#is_team_leader").attr("value") ) {
                $(this).text('');
            }
        });

    // all the daytype classes
    // are assigned a click handler which
    // swaps the colour depending on what
    // it currently is.
    $("#holiday-table")
        .find('.empty, .DAYOD, .TRAIN, '
            + '.WKDAY, .SICKD, .HOLIS, '
            + '.SPECI, .MEDIC, .PUABS, '
            + '.PUWRK, .SATUR, .RETRN, '
            + '.WKHOM, .OTHER, .ROVER  ')
        .not(":button")
        .attr("unselectable", "on")   // make it so you can't select text
        .mouseover(function (e) {
            if (mouseState) {

                if ($(this).hasClass("selected")) {
                    $(this).removeClass("selected");
                } else {
                    $(this).addClass("selected");
                }
                e.preventDefault();
                e.stopPropagation();
            }
        })
        .mousedown(function (e) {
            if ($(this).hasClass("selected")) {
                $(this).removeClass("selected");
            } else {
                $(this).addClass("selected");
            }
        });

    $("#year_select").val($("#holiday-table").attr("year"));
    $("#month_select").val($("#holiday-table").attr("month"));
    $("#process_select").val($("#holiday-table").attr("process"));
    $("#employees-select, #day_options").change(function () {
        retrieveComments();
    });
    $("#year_select, #month_select, #process_select").change(function () {
        change_table_data();
    });

    $("#holiday-table")
        .attr("border", "1")

    return true;
}

function change_table_data () {

    "use strict";

    /*
       Function which takes the values of the select boxes
       constructs an ajax call based on those and replaces
       the table with the data returned from the ajax call
    */

    var year = $("#year_select").val();
    var month = $("#month_select").val();
    var process = $("#process_select").val();

    if (process === "ALL") {
        process = "";
    }

    $.ajax({
        type: "GET",
        dataType: "HTML",
        url: "/holiday_planning/" + year + "/" + month + "/" + process,
        success: function(data) {

            $("#holiday-wrapper, #comments-wrapper").fadeTo(500, 0, function() {
                if ( $("#isie").attr("isie") === "true" ) {
                    $("#comments-wrapper").load(
                        "/holiday_planning/" + year + "/" + month + "/" + process + " #com-field"
                    );
                    $("#holiday-wrapper").load(
                        "/holiday_planning/" + year + "/" + month + "/" + process + " #holiday-table",
                        function() {
                            addFunctions();
                            retrieveComments();
                        }
                    );
                } else {
                    var holiday_html = $(data).find("#holiday-wrapper").html();
                    var comments_html = $(data).find("#comments-wrapper").html();
                    var table_year = $(data).find("#holiday-table").attr("year");
                    var table_month = $(data).find("#holiday-table").attr("month");

                    $("#com-field").html(comments_html);
                    $("#holiday-table").html(holiday_html);
                }
                flushThis("holiday-wrapper");
                $("#holiday-table").attr("year", table_year);
                $("#holiday-table").attr("month", table_month);
                addFunctions();
                $("#year_select").val(year);
                $("#month_select").val(month);
                if (process === "") {
                    $("#process_select").val("ALL");
                } else {
                    $("#process_select").val(process);
                }
                $("#holiday-wrapper, #comments-wrapper").fadeTo(500, 1);
            });
            checkTeamLeader();
        }
    });

    return true;
}

function removeComment() {
    "use strict";

    /*
      Function which removes a comment from the database for a specific
      tracking entry.
    */

    $.ajaxSetup({
        type: "POST",
        dataType: "json"
    });

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'remove_comment',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#user_select").val(),
            day: $("#day_options").val()
        },
        success: function (data) {
            if (data.success) {
                retrieveComments();
                change_table_data();
            } else {
                alert(data.error)
            }
        },
        error: function (data) {
            alert(data.error);
        }
    });

}

function insertComment() {

    "use strict";

    /*
      Function which inserts a comment into the database for a specific
      tracking entry.
    */

    $.ajaxSetup({
        type: "POST",
        dataType: "json"
    });

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'add_comment',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#user_select").val(),
            day: $("#day_options").val(),
            comment: $("#comments-field-comment").val()
        },
        success: function (data) {
            if (data.success) {
                retrieveComments();
                change_table_data();
            } else {
                alert(data.error)
            }
        },
        error: function (data) {
            alert(data.error);
        }
    });

}

function retrieveComments() {

    "use strict";

    /*
      Function which retrieves the comment associated with a tracking entry,
      this allows managers to apply a comment onto a field and edit the
      comments that they have already added onto a field by selecting the
      dates that they used it on.
    */

    $.ajaxSetup({
        type: "GET",
        dataType: "json"
    });

    $("#comments-field-comment").val('');

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'get_comments',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#user_select").val(),
            day: $("#day_options").val()
        },
        success: function (data) {
            if (data.success) {
                $("#comments-field-comment").val(data.comment);
            } else {
                alert(data.error)
            }
        },
        error: function(data) {
            alert(data.error);
        }
    });

    return true;

}

function checkTeamLeader() {

    /*
      Function which checks if the user is a team leader.

      If so, the field is removed
    */

    "use strict";

    var is_team_leader = $("#is_team_leader").attr("value");

    $("#holiday-table")
        .find(".job_code").each( function () {
            if ( is_team_leader ) {
                $(this).text('');
            }
            $(this).css("color", "black")
        });

    return true;
}

$(function () {
    addFunctions();
    checkTeamLeader();
});
<|endoftext|>


<commit_before>/*global System,process,global,require,module,__dirname*/
import { join as j } from "path";
import fs from "fs";
import { tmpdir } from "os";
import { execSync } from "child_process";
import { buildStages } from "./dependencies.js";
import { x, npmFallbackEnv } from "./util.js";

const dir = typeof __dirname !== "undefined"
        ? __dirname
        : System.decanonicalize("flatn/").replace("file://", ""),
      helperBinDir = j(dir, "bin"),
      nodeCentralPackageBin = j(helperBinDir, "node");

let _npmEnv;
function npmEnv() {
  return _npmEnv || (_npmEnv = (() => {
    let cacheFile = j(tmpdir(), "npm-env.json"), env;
    if (fs.existsSync(cacheFile)) {
      let cached = JSON.parse(String(fs.readFileSync(cacheFile)))
      if (Date.now() - cached.time < 1000*60) return cached.env;
    }
    try {
      var dir = j(tmpdir(), "npm-test-env-project");
      if (!fs.existsSync(dir)) fs.mkdirSync(dir);
      fs.writeFileSync(j(dir, "package.json"), `{"scripts": {"print-env": "${process.env.npm_node_execpath || "node"} ./print-env.js"}}`);
      fs.writeFileSync(j(dir, "print-env.js"), `console.log(JSON.stringify(process.env))`);
      let PATH = process.env.PATH.split(":").filter(ea => ea !== helperBinDir).join(":")
      env = JSON.parse(String(execSync(`npm --silent run print-env`, {cwd: dir, env: Object.assign({}, process.env, {PATH})})));
      for (let key in env)
        if (!key.toLowerCase().startsWith("npm") || key.toLowerCase().startsWith("npm_package"))
          delete env[key];
    } catch (err) {
      console.warn(`Cannot figure out real npm env, ${err}`);
      env = {};
    } finally {
      try {
        fs.unlinkSync(j(dir, "package.json"));
        fs.unlinkSync(j(dir, "print-env.js"));
        fs.rmdirSync(dir);
      } catch (err) {}
    }
    fs.writeFileSync(cacheFile, JSON.stringify({time: Date.now(), env}));
    return env;
  })());
}

function npmCreateEnvVars(configObj, env = {}, path = "npm_package") {
  if (Array.isArray(configObj))
    configObj.forEach((ea, i) => add(i, configObj[i]));
  else
    Object.keys(configObj).forEach(name => add(name, configObj[name]));
  return env;

  function add(key, val) {
    key = String(key).replace(/[-\.]/g, "_");
    if (typeof val === "object") npmCreateEnvVars(val, env, path + "_" + key);
    else env[path + "_" + key] = String(val);
  }

  return env;
}

function linkBins(packageSpecs, linkState = {}, verbose = false) {
  let linkLocation = j(tmpdir(), "npm-helper-bin-dir");
  if (!fs.existsSync(linkLocation)) fs.mkdirSync(linkLocation);
  packageSpecs.forEach(({bin, location}) => {
    if (location.startsWith("file://"))
      location = location.replace(/^file:\/\//, "")
    if (!bin) return;
    if (linkState[location]) return;
    for (let linkName in bin) {
      let realFile = bin[linkName];
      try {
        // fs.existsSync follows links, so broken links won't be reported as existing
        fs.lstatSync(j(linkLocation, linkName));
        fs.unlinkSync(j(linkLocation, linkName));
      } catch (err) {}
      verbose && console.log(`[flatn build] linking ${j(location, realFile)} => ${j(linkLocation, linkName)}`)
      fs.symlinkSync(j(location, realFile), j(linkLocation, linkName));
    }
    linkState[location] = true;
  });
  return linkLocation;
}

class BuildProcess {

  static for(packageSpec, packageMap, dependencyFields, forceBuild = false) {
    let stages = buildStages(packageSpec, packageMap, dependencyFields);
    return new this(stages, packageMap, forceBuild);
  }

  constructor(buildStages, packageMap, forceBuild, verbose = false) {
    this.buildStages = buildStages; // 2d list, package specs in sorted order
    this.packageMap = packageMap;
    this.builtPackages = [];
    this.binLinkState = {};
    this.binLinkLocation = "";
    this.forceBuild = forceBuild;
    this.verbose = verbose;
  }

  async run() {

    // let {buildStages, packageMap} = build
    let {buildStages, packageMap} = this,
        i = 1, n = buildStages.length;

    this.verbose && console.log(`[flatn] Running build stage ${i++}/${n}`)

    while (buildStages.length) {
      let stage = buildStages[0];
      if (!stage.length) {
        buildStages.shift();
        this.verbose && buildStages.length && console.log(`[flatn] Running build stage ${i++}/${n}`);
        continue;
      }
      let next = stage[0],
          [name, version] = next.split("@"),
          packageSpec = packageMap.lookup(name, version);
      if (!packageSpec) throw new Error(`[flatn build] package ${next} cannot be found in package map, skipping its build`);

      await this.build(packageSpec);
      stage.shift();
    }
  }

  normalizeScripts({scripts, location}) {
    if (!scripts || !scripts.install) {
      let hasBindingGyp = fs.existsSync(j(location, "binding.gyp"));
      if (hasBindingGyp) {
        scripts = Object.assign({install: "node-gyp rebuild"}, scripts)
      }
    }
    return scripts;
  }

  hasBuiltScripts(scripts) {
    return scripts && Object.keys(scripts).some(scriptName =>
      ["preinstall", "install", "postinstall"].includes(scriptName));
  }

  async build(packageSpec) {
    this.binLinkLocation = linkBins(
      this.builtPackages.concat([packageSpec]),
      this.binLinkState,
      this.verbose);

    let env = npmCreateEnvVars(await packageSpec.readConfig());
    let needsBuilt =
      this.forceBuild || packageSpec.isDevPackage || !(packageSpec.readLvInfo() || {}).build;

    if (needsBuilt) {
      let scripts = this.normalizeScripts(packageSpec);
      if (this.hasBuiltScripts(scripts)) {
        console.log(`[flatn] ${packageSpec.name} build starting`);
        await this.runScript(scripts, "preinstall",  packageSpec, env);
        await this.runScript(scripts, "install",     packageSpec, env);
        await this.runScript(scripts, "postinstall", packageSpec, env);
        await packageSpec.changeLvInfo(info => Object.assign({}, info, {build: true}));
        console.log(`[flatn] ${packageSpec.name} build done`);
      }
    }

    this.builtPackages.push(packageSpec);
  }

  async runScript(scripts, scriptName, {name, location}, env) {
    if (!scripts || !scripts[scriptName]) return false;
    this.verbose && console.log(`[flatn] build ${name}: running ${scriptName}`);

    let pathParts = process.env.PATH.split(":");
    pathParts.unshift(helperBinDir);
    pathParts.unshift(this.binLinkLocation);

    env = Object.assign({},
      process.env,
      npmFallbackEnv,
      npmEnv(),
      env,
      {
        npm_lifecycle_event: scriptName,
        npm_lifecycle_script: scripts[scriptName].split(" ")[0],
        PATH: pathParts.join(":")
      });

    try {
      return await x(`/bin/sh -c '${scripts[scriptName]}'`, {
        verbose: true,
        cwd: location.replace(/^file:\/\//, ""),
        env
      });

    } catch (err) {
      console.error(`[build ${name}] error running ${scripts[scriptName]}:\n${err}`);
      if (err.stdout || err.stderr) {
        console.log("The command output:");
        console.log(err.stdout);
        console.log(err.stderr);
      }
      throw err;
    }
  }

}

export { BuildProcess };
<commit_msg>keep npm_config_* env variables that existed before<commit_after>/*global System,process,global,require,module,__dirname*/
import { join as j } from "path";
import fs from "fs";
import { tmpdir } from "os";
import { execSync } from "child_process";
import { buildStages } from "./dependencies.js";
import { x, npmFallbackEnv } from "./util.js";

const dir = typeof __dirname !== "undefined"
        ? __dirname
        : System.decanonicalize("flatn/").replace("file://", ""),
      helperBinDir = j(dir, "bin"),
      nodeCentralPackageBin = j(helperBinDir, "node");

let _npmEnv;
function npmEnv() {
  return _npmEnv || (_npmEnv = (() => {
    let cacheFile = j(tmpdir(), "npm-env.json"), env = {};
    if (fs.existsSync(cacheFile)) {
      let cached = JSON.parse(String(fs.readFileSync(cacheFile)))
      if (Date.now() - cached.time < 1000*60) return cached.env;
    }
    try {
      var dir = j(tmpdir(), "npm-test-env-project");
      if (!fs.existsSync(dir)) fs.mkdirSync(dir);
      fs.writeFileSync(j(dir, "package.json"), `{"scripts": {"print-env": "${process.env.npm_node_execpath || "node"} ./print-env.js"}}`);
      fs.writeFileSync(j(dir, "print-env.js"), `console.log(JSON.stringify(process.env))`);
      let PATH = process.env.PATH.split(":").filter(ea => ea !== helperBinDir).join(":")
      Object.keys(process.env).forEach(ea => {
        if (ea.toLowerCase().startsWith("npm_config_"))
          env[ea] = process.env[ea];
      });
      env = Object.assign({},
        JSON.parse(String(execSync(`npm --silent run print-env`, {cwd: dir, env: Object.assign({}, process.env, {PATH})}))),
        env);
      for (let key in env)
        if (!key.toLowerCase().startsWith("npm") || key.toLowerCase().startsWith("npm_package"))
          delete env[key];
    } catch (err) {
      console.warn(`Cannot figure out real npm env, ${err}`);
      env = {};
    } finally {
      try {
        fs.unlinkSync(j(dir, "package.json"));
        fs.unlinkSync(j(dir, "print-env.js"));
        fs.rmdirSync(dir);
      } catch (err) {}
    }
    fs.writeFileSync(cacheFile, JSON.stringify({time: Date.now(), env}));
    return env;
  })());
}

function npmCreateEnvVars(configObj, env = {}, path = "npm_package") {
  if (Array.isArray(configObj))
    configObj.forEach((ea, i) => add(i, configObj[i]));
  else
    Object.keys(configObj).forEach(name => add(name, configObj[name]));
  return env;

  function add(key, val) {
    key = String(key).replace(/[-\.]/g, "_");
    if (typeof val === "object") npmCreateEnvVars(val, env, path + "_" + key);
    else env[path + "_" + key] = String(val);
  }

  return env;
}

function linkBins(packageSpecs, linkState = {}, verbose = false) {
  let linkLocation = j(tmpdir(), "npm-helper-bin-dir");
  if (!fs.existsSync(linkLocation)) fs.mkdirSync(linkLocation);
  packageSpecs.forEach(({bin, location}) => {
    if (location.startsWith("file://"))
      location = location.replace(/^file:\/\//, "")
    if (!bin) return;
    if (linkState[location]) return;
    for (let linkName in bin) {
      let realFile = bin[linkName];
      try {
        // fs.existsSync follows links, so broken links won't be reported as existing
        fs.lstatSync(j(linkLocation, linkName));
        fs.unlinkSync(j(linkLocation, linkName));
      } catch (err) {}
      verbose && console.log(`[flatn build] linking ${j(location, realFile)} => ${j(linkLocation, linkName)}`)
      fs.symlinkSync(j(location, realFile), j(linkLocation, linkName));
    }
    linkState[location] = true;
  });
  return linkLocation;
}

class BuildProcess {

  static for(packageSpec, packageMap, dependencyFields, forceBuild = false) {
    let stages = buildStages(packageSpec, packageMap, dependencyFields);
    return new this(stages, packageMap, forceBuild);
  }

  constructor(buildStages, packageMap, forceBuild, verbose = false) {
    this.buildStages = buildStages; // 2d list, package specs in sorted order
    this.packageMap = packageMap;
    this.builtPackages = [];
    this.binLinkState = {};
    this.binLinkLocation = "";
    this.forceBuild = forceBuild;
    this.verbose = verbose;
  }

  async run() {

    // let {buildStages, packageMap} = build
    let {buildStages, packageMap} = this,
        i = 1, n = buildStages.length;

    this.verbose && console.log(`[flatn] Running build stage ${i++}/${n}`)

    while (buildStages.length) {
      let stage = buildStages[0];
      if (!stage.length) {
        buildStages.shift();
        this.verbose && buildStages.length && console.log(`[flatn] Running build stage ${i++}/${n}`);
        continue;
      }
      let next = stage[0],
          [name, version] = next.split("@"),
          packageSpec = packageMap.lookup(name, version);
      if (!packageSpec) throw new Error(`[flatn build] package ${next} cannot be found in package map, skipping its build`);

      await this.build(packageSpec);
      stage.shift();
    }
  }

  normalizeScripts({scripts, location}) {
    if (!scripts || !scripts.install) {
      let hasBindingGyp = fs.existsSync(j(location, "binding.gyp"));
      if (hasBindingGyp) {
        scripts = Object.assign({install: "node-gyp rebuild"}, scripts)
      }
    }
    return scripts;
  }

  hasBuiltScripts(scripts) {
    return scripts && Object.keys(scripts).some(scriptName =>
      ["preinstall", "install", "postinstall"].includes(scriptName));
  }

  async build(packageSpec) {
    this.binLinkLocation = linkBins(
      this.builtPackages.concat([packageSpec]),
      this.binLinkState,
      this.verbose);

    let env = npmCreateEnvVars(await packageSpec.readConfig());
    let needsBuilt =
      this.forceBuild || packageSpec.isDevPackage || !(packageSpec.readLvInfo() || {}).build;

    if (needsBuilt) {
      let scripts = this.normalizeScripts(packageSpec);
      if (this.hasBuiltScripts(scripts)) {
        console.log(`[flatn] ${packageSpec.name} build starting`);
        await this.runScript(scripts, "preinstall",  packageSpec, env);
        await this.runScript(scripts, "install",     packageSpec, env);
        await this.runScript(scripts, "postinstall", packageSpec, env);
        await packageSpec.changeLvInfo(info => Object.assign({}, info, {build: true}));
        console.log(`[flatn] ${packageSpec.name} build done`);
      }
    }

    this.builtPackages.push(packageSpec);
  }

  async runScript(scripts, scriptName, {name, location}, env) {
    if (!scripts || !scripts[scriptName]) return false;
    this.verbose && console.log(`[flatn] build ${name}: running ${scriptName}`);

    let pathParts = process.env.PATH.split(":");
    pathParts.unshift(helperBinDir);
    pathParts.unshift(this.binLinkLocation);

    env = Object.assign({},
      process.env,
      npmFallbackEnv,
      npmEnv(),
      env,
      {
        npm_lifecycle_event: scriptName,
        npm_lifecycle_script: scripts[scriptName].split(" ")[0],
        PATH: pathParts.join(":")
      });

    try {
      return await x(`/bin/sh -c '${scripts[scriptName]}'`, {
        verbose: true,
        cwd: location.replace(/^file:\/\//, ""),
        env
      });

    } catch (err) {
      console.error(`[build ${name}] error running ${scripts[scriptName]}:\n${err}`);
      if (err.stdout || err.stderr) {
        console.log("The command output:");
        console.log(err.stdout);
        console.log(err.stderr);
      }
      throw err;
    }
  }

}

export { BuildProcess };
<|endoftext|>


<commit_before>module.exports = function (gulp, options) {

    var jshint = require('gulp-jshint'),
        del = require('del'),
        fs = require('fs'),
        path = require('path'),
        _ = require('lodash'),
        runSequence = require('run-sequence').use(gulp),
        browserify = require('browserify'),
        source = require('vinyl-source-stream'),
        streamify = require('gulp-streamify'),
        watchify = require('watchify'),
        gulpif = require('gulp-if'),
        babelify = require('babelify'),
        merge = require('merge-stream'),
        autoprefixer = require('gulp-autoprefixer'),
        minify = require('gulp-minify-css'),
        concat = require('gulp-concat'),
        embedlr = require('gulp-embedlr'),
        header = require('gulp-header'),
        rename = require('gulp-rename'),
        changed = require('gulp-changed'),
        minimist = require('minimist'),
        sass = require('gulp-sass'),
        plumber = require('gulp-plumber'),
        karma = require('karma').server,
        markdox = require('gulp-markdox'),
        uglify = require('gulp-uglify'),
        plato = require('plato'),
        express = require('express'),
        refresh = require('gulp-livereload'),
        async = require('async'),
        livereload = require('connect-livereload'),
        lrserver = require('tiny-lr')(),
        livereloadport = 35729,
        serverport = options.serverPort,
        server = express();

    var DIST_FOLDER = options.distribution,
        KARMA_CONFIG = '/karma.conf.js',
        BUNDLE_FILENAME = options.bundleFilename,
        watching = false,
        cwd = process.cwd(),
        currentVariant = getVariantOption("debug-main"),
        variantToRemove = "";

    if (!options.module) {
        server.use(express.static(getDistDirectory()));
        server.use(livereload({port: livereloadport}));

        server.all('/*', function (req, res) {
            res.sendfile('index.html', {root: getDistDirectory()});
        });
    }

    !options.module && gulp.task('build', ['clean', 'pre-build'], function () {
        var variants = [];
        if (watching) {
            variants = [currentVariant];
        } else if (currentVariant !== 'all' && currentVariant !== 'all-debug') {
            variants = [currentVariant];
        } else {
            variants = getDirectories(path.resolve(cwd, options.bootstrappers));
            variants = _.map(variants, function (variant) {
                return (currentVariant === 'all' ? 'release-' : 'debug-') + variant;
            });
        }
        async.mapSeries(variants, function (variant, callback) {
            currentVariant = variant;
            runSequence(['views', 'styles', 'images', 'assets', 'browserify'], 'post-build', callback);
        });
    });

    gulp.task('clean', function (done) {
        del([path.resolve(DIST_FOLDER, variantToRemove)], {force: true}, done);
    });

    gulp.task('lint', function () {
        gulp.src('scripts/*.js')
            .pipe(jshint())
            .pipe(jshint.reporter('default'));
    });

    gulp.task('doc', function () {
        return gulp.src(options.coverage + "*/*.js")
            .pipe(markdox())
            .pipe(concat("doc.md"))
            .pipe(gulp.dest("./doc"));
    });

    !options.module && gulp.task('styles', function () {
        return gulp.src(path.resolve(options.bootstrappers, getVariantPart(), 'bootstrapper.scss'))
            .pipe(concat(BUNDLE_FILENAME + '.css'))
            .pipe(plumber())
            .pipe(sass({
                includePaths: ['./'],
                onError: function (error) {
                    console.log(error)
                }
            }))
            .pipe(autoprefixer({browsers: options.autoprefixerRules}))
            .pipe(gulpif(isRelease(), minify()))
            .pipe(gulp.dest(getDistDirectory() + 'css/'))
            .pipe(gulpif(watching, refresh(lrserver)));
    });

    !options.module && gulp.task('browserify', function () {
        process.env.DEBUG = currentVariant.indexOf('debug') > -1;
        process.env.TARGET = getVariantPart();

        var browserifyOptions = {
            entries: [path.resolve(options.bootstrappers, getVariantPart(), 'bootstrapper.js')],
            noParse: _.map(options.bundleNoParse, function (package) {
                return require.resolve(package);
            }),
            basedir: cwd,
            debug: !isRelease(),
            cache: {},
            packageCache: {},
            fullPaths: true
        };

        var bundleStream = watching ? watchify(browserify(browserifyOptions)) :
            browserify(browserifyOptions);

        bundleStream = bundleStream.transform(babelify.configure({
            extensions: [".es6", ".es"],
            sourceMapRelative: '.'
        }));

        if (watching)
            bundleStream.on('update', rebundle);

        function rebundle() {
            return bundleStream.bundle()
                .on('error', function (err) {
                    console.log(err.message);
                    this.end();
                })
                .pipe(plumber())
                .pipe(source(BUNDLE_FILENAME + '.js'))
                .pipe(gulpif(isRelease(), streamify(uglify())))
                .pipe(gulpif(isRelease(), header('/*\n\n${name} : ${version}\n\n*/\n\n', {
                    name: options.projectPackage.name,
                    version: options.projectPackage.version
                })))
                .pipe(gulp.dest(getDistDirectory() + 'js'))
                .pipe(gulpif(watching, refresh(lrserver)));
        }

        return rebundle();
    });

    gulp.task('test', function (done) {
        karma.start({
            configFile: __dirname + KARMA_CONFIG,
            singleRun: !watching
        }, watching ? done : null);
    });

    !options.module && gulp.task('views', function () {
        var streams = [
            gulp.src(options.views + '/**/*.html')
                .pipe(changed(getDistDirectory() + options.views + '/'))
                .pipe(gulp.dest(getDistDirectory() + options.views + '/'))
                .pipe(gulpif(watching, refresh(lrserver)))];
        if (options.singlePage) {
            streams.push(
                gulp.src('index.html')
                    .pipe(gulpif(watching, embedlr()))
                    .pipe(gulp.dest(getDistDirectory())));
        }
        return merge(streams);
    });

    !options.module && gulp.task('images', function () {
        return gulp.src(options.images + '/**/*')
            .pipe(gulp.dest(getDistDirectory() + options.images + '/'));
    });

    !options.module && gulp.task('assets', function () {
        return gulp.src(options.assets + '/**/*')
            .pipe(gulp.dest(getDistDirectory() + options.assets + '/'));
    });

    !options.module && gulp.task('pre-build', function () {
        if (!options.preBuild.length) return;
        return merge(
            _.map(options.preBuild, function (action) {
                return gulp.src(action.source)
                    .pipe(gulpif(!!action.ext, rename(function (path) {
                        path.extname = "." + action.ext;
                    })))
                    .pipe(gulp.dest(action.dest));
            })
        );
    });

    !options.module && gulp.task('post-build', function () {
        if (!options.postBuild.length) return;
        return merge(
            _.map(options.postBuild, function (action) {
                return gulp.src(action.source)
                    .pipe(gulpif(!!action.ext, rename(function (path) {
                        path.extname = "." + action.ext;
                    })))
                    .pipe(gulp.dest(getDistDirectory() + action.dest));
            })
        );
    });

    !options.module && gulp.task('watch', function () {
        watching = true;
        currentVariant = getVariantOption("debug-main");
        variantToRemove = currentVariant;

        gulp.start('build', 'serve', function () {
            gulp.watch([path.resolve(options.bootstrappers, getVariantPart(), 'bootstrapper.scss'),
                    path.resolve(options.bootstrappers, 'base.scss'),
                    './' + options.styles + '/**/*.scss'], {maxListeners: 999},
                ['styles']);

            gulp.watch([options.views + '/**/*.html'], {maxListeners: 999}, ['views']);
        });
    });

    !options.module && gulp.task('watch-test', ['watch', 'test']);

    options.module && gulp.task('watch-test', function () {
        watching = true;
        gulp.start('test');
    });

    !options.module && gulp.task('serve', function () {
        if (!options.singlePage) return; //non single page application

        if (!currentVariant)
            currentVariant = getVariantOption("debug-main");

        server.listen(serverport);
        refresh.listen(livereloadport);
        console.log('Variant ' + currentVariant + ' listening on http://localhost:' + serverport);
    });

    gulp.task('analysis', function (done) {
        plato.inspect(options.analysis, options.analysisOutput, {
            recurse: true
        }, _.ary(done, 0));
    });

    gulp.task('default', [!options.module ? 'build' : 'test']);

    function getDirectories(rootDir) {
        var files = fs.readdirSync(rootDir),
            directories = [];
        _.forEach(files, function (file) {
            if (file[0] != '.') {
                var filePath = rootDir + '/' + file,
                    stat = fs.statSync(filePath);
                if (stat.isDirectory())
                    directories.push(file);
            }
        });
        return directories;
    }

    function isRelease() {
        return currentVariant.indexOf("release") > -1;
    }

    function getDistDirectory() {
        if (!options.singlePage)
            return path.resolve(DIST_FOLDER, getVariantPart()) + '/';
        return path.resolve(DIST_FOLDER, currentVariant) + '/';
    }

    function getVariantPart() {
        return currentVariant.slice(currentVariant.indexOf('-') + 1);
    }

    function getVariantOption(defaultOption) {
        return minimist(process.argv.slice(2), {
            string: 'variant',
            default: {variant: defaultOption || 'release-main'}
        }).variant;
    }
};<commit_msg>Watch-test always watches only tests<commit_after>module.exports = function (gulp, options) {

    var jshint = require('gulp-jshint'),
        del = require('del'),
        fs = require('fs'),
        path = require('path'),
        _ = require('lodash'),
        runSequence = require('run-sequence').use(gulp),
        browserify = require('browserify'),
        source = require('vinyl-source-stream'),
        streamify = require('gulp-streamify'),
        watchify = require('watchify'),
        gulpif = require('gulp-if'),
        babelify = require('babelify'),
        merge = require('merge-stream'),
        autoprefixer = require('gulp-autoprefixer'),
        minify = require('gulp-minify-css'),
        concat = require('gulp-concat'),
        embedlr = require('gulp-embedlr'),
        header = require('gulp-header'),
        rename = require('gulp-rename'),
        changed = require('gulp-changed'),
        minimist = require('minimist'),
        sass = require('gulp-sass'),
        plumber = require('gulp-plumber'),
        karma = require('karma').server,
        markdox = require('gulp-markdox'),
        uglify = require('gulp-uglify'),
        plato = require('plato'),
        express = require('express'),
        refresh = require('gulp-livereload'),
        async = require('async'),
        livereload = require('connect-livereload'),
        lrserver = require('tiny-lr')(),
        livereloadport = 35729,
        serverport = options.serverPort,
        server = express();

    var DIST_FOLDER = options.distribution,
        KARMA_CONFIG = '/karma.conf.js',
        BUNDLE_FILENAME = options.bundleFilename,
        watching = false,
        cwd = process.cwd(),
        currentVariant = getVariantOption("debug-main"),
        variantToRemove = "";

    if (!options.module) {
        server.use(express.static(getDistDirectory()));
        server.use(livereload({port: livereloadport}));

        server.all('/*', function (req, res) {
            res.sendfile('index.html', {root: getDistDirectory()});
        });
    }

    !options.module && gulp.task('build', ['clean', 'pre-build'], function () {
        var variants = [];
        if (watching) {
            variants = [currentVariant];
        } else if (currentVariant !== 'all' && currentVariant !== 'all-debug') {
            variants = [currentVariant];
        } else {
            variants = getDirectories(path.resolve(cwd, options.bootstrappers));
            variants = _.map(variants, function (variant) {
                return (currentVariant === 'all' ? 'release-' : 'debug-') + variant;
            });
        }
        async.mapSeries(variants, function (variant, callback) {
            currentVariant = variant;
            runSequence(['views', 'styles', 'images', 'assets', 'browserify'], 'post-build', callback);
        });
    });

    gulp.task('clean', function (done) {
        del([path.resolve(DIST_FOLDER, variantToRemove)], {force: true}, done);
    });

    gulp.task('lint', function () {
        gulp.src('scripts/*.js')
            .pipe(jshint())
            .pipe(jshint.reporter('default'));
    });

    gulp.task('doc', function () {
        return gulp.src(options.coverage + "*/*.js")
            .pipe(markdox())
            .pipe(concat("doc.md"))
            .pipe(gulp.dest("./doc"));
    });

    !options.module && gulp.task('styles', function () {
        return gulp.src(path.resolve(options.bootstrappers, getVariantPart(), 'bootstrapper.scss'))
            .pipe(concat(BUNDLE_FILENAME + '.css'))
            .pipe(plumber())
            .pipe(sass({
                includePaths: ['./'],
                onError: function (error) {
                    console.log(error)
                }
            }))
            .pipe(autoprefixer({browsers: options.autoprefixerRules}))
            .pipe(gulpif(isRelease(), minify()))
            .pipe(gulp.dest(getDistDirectory() + 'css/'))
            .pipe(gulpif(watching, refresh(lrserver)));
    });

    !options.module && gulp.task('browserify', function () {
        process.env.DEBUG = currentVariant.indexOf('debug') > -1;
        process.env.TARGET = getVariantPart();

        var browserifyOptions = {
            entries: [path.resolve(options.bootstrappers, getVariantPart(), 'bootstrapper.js')],
            noParse: _.map(options.bundleNoParse, function (package) {
                return require.resolve(package);
            }),
            basedir: cwd,
            debug: !isRelease(),
            cache: {},
            packageCache: {},
            fullPaths: true
        };

        var bundleStream = watching ? watchify(browserify(browserifyOptions)) :
            browserify(browserifyOptions);

        bundleStream = bundleStream.transform(babelify.configure({
            extensions: [".es6", ".es"],
            sourceMapRelative: '.'
        }));

        if (watching)
            bundleStream.on('update', rebundle);

        function rebundle() {
            return bundleStream.bundle()
                .on('error', function (err) {
                    console.log(err.message);
                    this.end();
                })
                .pipe(plumber())
                .pipe(source(BUNDLE_FILENAME + '.js'))
                .pipe(gulpif(isRelease(), streamify(uglify())))
                .pipe(gulpif(isRelease(), header('/*\n\n${name} : ${version}\n\n*/\n\n', {
                    name: options.projectPackage.name,
                    version: options.projectPackage.version
                })))
                .pipe(gulp.dest(getDistDirectory() + 'js'))
                .pipe(gulpif(watching, refresh(lrserver)));
        }

        return rebundle();
    });

    gulp.task('test', function (done) {
        karma.start({
            configFile: __dirname + KARMA_CONFIG,
            singleRun: !watching
        }, watching ? done : null);
    });

    !options.module && gulp.task('views', function () {
        var streams = [
            gulp.src(options.views + '/**/*.html')
                .pipe(changed(getDistDirectory() + options.views + '/'))
                .pipe(gulp.dest(getDistDirectory() + options.views + '/'))
                .pipe(gulpif(watching, refresh(lrserver)))];
        if (options.singlePage) {
            streams.push(
                gulp.src('index.html')
                    .pipe(gulpif(watching, embedlr()))
                    .pipe(gulp.dest(getDistDirectory())));
        }
        return merge(streams);
    });

    !options.module && gulp.task('images', function () {
        return gulp.src(options.images + '/**/*')
            .pipe(gulp.dest(getDistDirectory() + options.images + '/'));
    });

    !options.module && gulp.task('assets', function () {
        return gulp.src(options.assets + '/**/*')
            .pipe(gulp.dest(getDistDirectory() + options.assets + '/'));
    });

    !options.module && gulp.task('pre-build', function () {
        if (!options.preBuild.length) return;
        return merge(
            _.map(options.preBuild, function (action) {
                return gulp.src(action.source)
                    .pipe(gulpif(!!action.ext, rename(function (path) {
                        path.extname = "." + action.ext;
                    })))
                    .pipe(gulp.dest(action.dest));
            })
        );
    });

    !options.module && gulp.task('post-build', function () {
        if (!options.postBuild.length) return;
        return merge(
            _.map(options.postBuild, function (action) {
                return gulp.src(action.source)
                    .pipe(gulpif(!!action.ext, rename(function (path) {
                        path.extname = "." + action.ext;
                    })))
                    .pipe(gulp.dest(getDistDirectory() + action.dest));
            })
        );
    });

    !options.module && gulp.task('watch', function () {
        watching = true;
        currentVariant = getVariantOption("debug-main");
        variantToRemove = currentVariant;

        gulp.start('build', 'serve', function () {
            gulp.watch([path.resolve(options.bootstrappers, getVariantPart(), 'bootstrapper.scss'),
                    path.resolve(options.bootstrappers, 'base.scss'),
                    './' + options.styles + '/**/*.scss'], {maxListeners: 999},
                ['styles']);

            gulp.watch([options.views + '/**/*.html'], {maxListeners: 999}, ['views']);
        });
    });

    gulp.task('watch-test', function () {
        watching = true;
        gulp.start('test');
    });

    !options.module && gulp.task('serve', function () {
        if (!options.singlePage) return; //non single page application

        if (!currentVariant)
            currentVariant = getVariantOption("debug-main");

        server.listen(serverport);
        refresh.listen(livereloadport);
        console.log('Variant ' + currentVariant + ' listening on http://localhost:' + serverport);
    });

    gulp.task('analysis', function (done) {
        plato.inspect(options.analysis, options.analysisOutput, {
            recurse: true
        }, _.ary(done, 0));
    });

    gulp.task('default', [!options.module ? 'build' : 'test']);

    function getDirectories(rootDir) {
        var files = fs.readdirSync(rootDir),
            directories = [];
        _.forEach(files, function (file) {
            if (file[0] != '.') {
                var filePath = rootDir + '/' + file,
                    stat = fs.statSync(filePath);
                if (stat.isDirectory())
                    directories.push(file);
            }
        });
        return directories;
    }

    function isRelease() {
        return currentVariant.indexOf("release") > -1;
    }

    function getDistDirectory() {
        if (!options.singlePage)
            return path.resolve(DIST_FOLDER, getVariantPart()) + '/';
        return path.resolve(DIST_FOLDER, currentVariant) + '/';
    }

    function getVariantPart() {
        return currentVariant.slice(currentVariant.indexOf('-') + 1);
    }

    function getVariantOption(defaultOption) {
        return minimist(process.argv.slice(2), {
            string: 'variant',
            default: {variant: defaultOption || 'release-main'}
        }).variant;
    }
};<|endoftext|>