<commit_before>/**
 * Create a function from a string
 */
var evalFunction = (function () {
    // shadow global symbols
    var evalFunction;
    var createFunction;

    return function (contextSrc, functionSrc) {
        var src = '(function () {\n' +
                contextSrc +
                'return ' + functionSrc + ';' +
            '}())'

        return eval(src);
    };
}());

var createFunction = (function () {
    /**
     * Check that we can create a single function from the passed source and
     * return checked source.
     *
     * This function is intended to prevent this sort of thing:
     *     createFunction('function yo() { } foo()')
     * which would run foo in our context.
     *
     * This check is intended to find mistakes, not defend against malice.
     */
    function getCleanSource(src) {
        var newlineToken = '_!crlf!_';
        var newlineTokenPattern = new RegExp(newlineToken, 'g');
        var parsed, name, args, body;

        // parse the function source into name, arguments, and body
        // currently, names must by alphanumeric.
        parsed = src.replace(/\n/g, newlineToken).
            match(/^function\s+([a-zA-Z_]\w*)?\s*\(([^)]*)\)\s*\{(.*)\}$/);
        if (!parsed) {
            throw 'Cannot parse function: ' +
                src.replace(newlineTokenPattern, '\n');
        }
        name = parsed[1] || '';
        args = parsed[2].split(/\s*,\s*/);
        body = parsed[3].replace(newlineTokenPattern, '\n');

        var fn = Function.apply(null, args.concat(body));
        return ['function', name, '(', args.join(', '), ')', '{', body, '}'].join(' ');
    }

    function parseFunction(fnSource) {
        var context = {};
        var contextSource = '';

        if (fnSource instanceof Array) {
            context = fnSource[0];
            fnSource = fnSource[1];
        }

        for (var k in context) {
            contextSource += [
                'var', k, '=', JSON.stringify(context[k]) + ';\n'
            ].join(' ');
        }

        fnSource = getCleanSource(fnSource);

        return evalFunction(contextSource, fnSource);
    }

    return function (fn) {
        return fn ? parseFunction(fn) : void undefined;
    }
}());

// Due diligence to minimize side effects from createFunction
(function () {
var casper = require('casper');
var system = require('system');
var JsonRpcServer = require('./node_modules/tiny-jsonrpc/lib/tiny-jsonrpc').Server;

var server = new JsonRpcServer();

var instances = {};
var instanceCount = 0;
var nextInstanceId = 0;
function createInstance(options) {
    var id = nextInstanceId;
    nextInstanceId++;
    instanceCount++;

    for (var k in options) {
        if (k.indexOf('on') === 0) {
            options[k] = createFunction(options[k]);
        }
    }

    var instance = instances[id] = casper.create(options);
    instance.emit = function () {
        var args = [id].concat(Array.prototype.slice.apply(arguments));
        emit.apply(this, args);
        this.constructor.prototype.emit.apply(this, args.slice(1));
    };

    return {
        instance: id,
        methods: server.provides()
    };
}

/**
 * Create a new CasperJS instance and return its instance id.
 */
server.provide(function create(options) {
    return createInstance(options);
});

server.provide(function echo(message, style) {
    instance = instances[instance];

    instance.echo(message, style);

    return true;
});

server.provide(function run(instance, onComplete, time) {
    instance = instances[instance];

    instance.run(createFunction(onComplete), time);

    return true;
});

server.provide(function open(instance, location, settings) {
    instance = instances[instance];

    instance.open(location, settings);

    return true;
});

server.provide(function start(instance, url, then) {
    instance = instances[instance];

    instance.start(url, createFunction(then));

    return true;
});

server.provide(function then(instance, fn) {
    instance = instances[instance];

    instance.then(createFunction(fn));

    return true;
});

server.provide(function thenEvaluate(instance, fn, replacements) {
    instance = instances[instance];

    instance.thenEvaluate(createFunction(fn), replacements);

    return true;
});

server.provide(function waitFor(instance, testFn, then, onTimeout, timeout) {
    instance = instances[instance];

    instance.thenEvaluate(createFunction(testFn), createFunction(then), createFunction(onTimeout), timeout);

    return true;
});

function respond(response, code, body) {
    //console.log('< ' + code + ' ' + body);
    response.statusCode = code;
    response.write(body);
    response.close();
}

var port = 8080;
var arg;
for (var i = 1; i < system.args.length; i++) {
    arg = system.args[i];
    if (arg.indexOf('--port') === 0) {
        if (arg.indexOf('=') > -1) {
            port = arg.split('=')[1];
        } else {
            port = system.args[i + 1];
        }
        port = parseInt(port, 10);
        break;
    }
}

var service = require('webserver').create().listen(port, function (request, response) {
    //console.log('> ' + JSON.stringify(request));
    //console.log('> ' + request.post);
    if (request.method.toUpperCase() !== 'POST') {
        respond(response, 405, 'Requests must be POSTs');
        return;
    } else if (request.headers['Content-Type'] !== 'application/json' &&
        request.headers['content-type'] !== 'application/json'
    ) {
        respond(response, 415, 'Request entity must be JSON');
        return;
    }

    var result = JSON.parse(server.respond(request.post));

    if (result.error) {
        respond(response, 400, JSON.stringify(result));
    } else {
        respond(response, 200, JSON.stringify(result));
    }
});

function emit(id, event) {
    var args = Array.prototype.slice.call(arguments);

    console.log(JSON.stringify({
        jsonrpc: '2.0',
        method: 'emit',
        params: args
    }));
}

emit(null, 'ready');
//console.log(system.args.join(' '));
}());
<commit_msg>Fix copy pasta: waitFor should call waitFor<commit_after>/**
 * Create a function from a string
 */
var evalFunction = (function () {
    // shadow global symbols
    var evalFunction;
    var createFunction;

    return function (contextSrc, functionSrc) {
        var src = '(function () {\n' +
                contextSrc +
                'return ' + functionSrc + ';' +
            '}())'

        return eval(src);
    };
}());

var createFunction = (function () {
    /**
     * Check that we can create a single function from the passed source and
     * return checked source.
     *
     * This function is intended to prevent this sort of thing:
     *     createFunction('function yo() { } foo()')
     * which would run foo in our context.
     *
     * This check is intended to find mistakes, not defend against malice.
     */
    function getCleanSource(src) {
        var newlineToken = '_!crlf!_';
        var newlineTokenPattern = new RegExp(newlineToken, 'g');
        var parsed, name, args, body;

        // parse the function source into name, arguments, and body
        // currently, names must by alphanumeric.
        parsed = src.replace(/\n/g, newlineToken).
            match(/^function\s+([a-zA-Z_]\w*)?\s*\(([^)]*)\)\s*\{(.*)\}$/);
        if (!parsed) {
            throw 'Cannot parse function: ' +
                src.replace(newlineTokenPattern, '\n');
        }
        name = parsed[1] || '';
        args = parsed[2].split(/\s*,\s*/);
        body = parsed[3].replace(newlineTokenPattern, '\n');

        var fn = Function.apply(null, args.concat(body));
        return ['function', name, '(', args.join(', '), ')', '{', body, '}'].join(' ');
    }

    function parseFunction(fnSource) {
        var context = {};
        var contextSource = '';

        if (fnSource instanceof Array) {
            context = fnSource[0];
            fnSource = fnSource[1];
        }

        for (var k in context) {
            contextSource += [
                'var', k, '=', JSON.stringify(context[k]) + ';\n'
            ].join(' ');
        }

        fnSource = getCleanSource(fnSource);

        return evalFunction(contextSource, fnSource);
    }

    return function (fn) {
        return fn ? parseFunction(fn) : void undefined;
    }
}());

// Due diligence to minimize side effects from createFunction
(function () {
var casper = require('casper');
var system = require('system');
var JsonRpcServer = require('./node_modules/tiny-jsonrpc/lib/tiny-jsonrpc').Server;

var server = new JsonRpcServer();

var instances = {};
var instanceCount = 0;
var nextInstanceId = 0;
function createInstance(options) {
    var id = nextInstanceId;
    nextInstanceId++;
    instanceCount++;

    for (var k in options) {
        if (k.indexOf('on') === 0) {
            options[k] = createFunction(options[k]);
        }
    }

    var instance = instances[id] = casper.create(options);
    instance.emit = function () {
        var args = [id].concat(Array.prototype.slice.apply(arguments));
        emit.apply(this, args);
        this.constructor.prototype.emit.apply(this, args.slice(1));
    };

    return {
        instance: id,
        methods: server.provides()
    };
}

/**
 * Create a new CasperJS instance and return its instance id.
 */
server.provide(function create(options) {
    return createInstance(options);
});

server.provide(function echo(message, style) {
    instance = instances[instance];

    instance.echo(message, style);

    return true;
});

server.provide(function run(instance, onComplete, time) {
    instance = instances[instance];

    instance.run(createFunction(onComplete), time);

    return true;
});

server.provide(function open(instance, location, settings) {
    instance = instances[instance];

    instance.open(location, settings);

    return true;
});

server.provide(function start(instance, url, then) {
    instance = instances[instance];

    instance.start(url, createFunction(then));

    return true;
});

server.provide(function then(instance, fn) {
    instance = instances[instance];

    instance.then(createFunction(fn));

    return true;
});

server.provide(function thenEvaluate(instance, fn, replacements) {
    instance = instances[instance];

    instance.thenEvaluate(createFunction(fn), replacements);

    return true;
});

server.provide(function waitFor(instance, testFn, then, onTimeout, timeout) {
    instance = instances[instance];

    instance.waitFor(createFunction(testFn), createFunction(then), createFunction(onTimeout), timeout);

    return true;
});

function respond(response, code, body) {
    //console.log('< ' + code + ' ' + body);
    response.statusCode = code;
    response.write(body);
    response.close();
}

var port = 8080;
var arg;
for (var i = 1; i < system.args.length; i++) {
    arg = system.args[i];
    if (arg.indexOf('--port') === 0) {
        if (arg.indexOf('=') > -1) {
            port = arg.split('=')[1];
        } else {
            port = system.args[i + 1];
        }
        port = parseInt(port, 10);
        break;
    }
}

var service = require('webserver').create().listen(port, function (request, response) {
    //console.log('> ' + JSON.stringify(request));
    //console.log('> ' + request.post);
    if (request.method.toUpperCase() !== 'POST') {
        respond(response, 405, 'Requests must be POSTs');
        return;
    } else if (request.headers['Content-Type'] !== 'application/json' &&
        request.headers['content-type'] !== 'application/json'
    ) {
        respond(response, 415, 'Request entity must be JSON');
        return;
    }

    var result = JSON.parse(server.respond(request.post));

    if (result.error) {
        respond(response, 400, JSON.stringify(result));
    } else {
        respond(response, 200, JSON.stringify(result));
    }
});

function emit(id, event) {
    var args = Array.prototype.slice.call(arguments);

    console.log(JSON.stringify({
        jsonrpc: '2.0',
        method: 'emit',
        params: args
    }));
}

emit(null, 'ready');
//console.log(system.args.join(' '));
}());
<|endoftext|>


<commit_before>module.exports.deferred_callback_router = function (ctx, deferred) {
  var self = ctx;
  var handlers = {}
  handlers['output'] = defer_wrap(defer_output, ctx, deferred);
  handlers['execute_reply'] = defer_wrap(defer_exec_reply, ctx, deferred);
  return handlers;
}

var defer_output = function (msg_type, content, metadata, context, deferred) {
  var data = {}
  data['msg_type'] = msg_type
  data['content'] = content
  data['metadata'] = metadata
  data['context'] = context
  deferred.resolve(data);
}

var defer_exec_reply = function (content, parent, context, deferred) {
  /*
   * Clean up if we didn't resolve with output.
   *
   * Note: exec_reply should come after output is flushed. So if there is
   * any output, defer_output should have already been called. This is to
   * handle code that doesn't result in output
   */
  var state = deferred.promise.inspect()['state'];
  if (state == 'pending') {
    deferred.resolve();
  }
}

var defer_wrap = function (func, ctx, _deferred) {
  var self = ctx;
  var deferred = _deferred;
  return function() {
    var context = self.context;
    [].push.call(arguments, context);
    [].push.call(arguments, deferred);
    return func.apply(self, arguments);
  }
}
<commit_msg>add a pause to help mitigate issues with #26 when execute_reply comes in before output<commit_after>module.exports.deferred_callback_router = function (ctx, deferred) {
  var self = ctx;
  var handlers = {}
  handlers['output'] = defer_wrap(defer_output, ctx, deferred);
  handlers['execute_reply'] = defer_wrap(defer_exec_reply, ctx, deferred);
  return handlers;
}

var defer_output = function (msg_type, content, metadata, context, deferred) {
  var data = {}
  data['msg_type'] = msg_type
  data['content'] = content
  data['metadata'] = metadata
  data['context'] = context
  deferred.resolve(data);
}

var defer_exec_reply = function (content, parent, context, _deferred) {
  /*
   * Clean up if we didn't resolve with output.
   *
   * Note: exec_reply should come after output is flushed. So if there is
   * any output, defer_output should have already been called. This is to
   * handle code that doesn't result in output
   */
  var deferred = _deferred;
  var state = deferred.promise.inspect()['state'];
  if (state == 'pending') {
    setTimeout(function() {
      deferred.resolve();
    }, 500)
  }
}

var defer_wrap = function (func, ctx, _deferred) {
  var self = ctx;
  var deferred = _deferred;
  return function() {
    var context = self.context;
    [].push.call(arguments, context);
    [].push.call(arguments, deferred);
    return func.apply(self, arguments);
  }
}
<|endoftext|>


<commit_before>var gdal = require("gdal")
  , util = require('util')
  , turf = require('turf')
  , path = require('path')
  , fs = require('fs-extra')
  , png = require('pngjs')
  , config = require('../../config.json');

  Math.radians = function(degrees) {
    return degrees * Math.PI / 180;
  };

  // Converts from radians to degrees.
  Math.degrees = function(radians) {
    return radians * 180 / Math.PI;
  };

  function tile2lon(x,z) {
    return (x/Math.pow(2,z)*360-180);
  }
  function tile2lat(y,z) {
    var n=Math.PI-2*Math.PI*y/Math.pow(2,z);
    return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
  }

  function tileBboxCalculator(x, y, z) {
    console.log('tile box calculator for ' + x + ' ' + y + ' ' + z);
    x = Number(x);
    y = Number(y);
    var tileBounds = {
      ul: {
        lat: tile2lat(y, z),
        lon: tile2lon(x, z)
      },
      lr: {
        lat: tile2lat(y+1, z),
        lon: tile2lon(x+1, z)
      }
    };

    return tileBounds;
  }

exports.process = function(source, callback) {
  console.log("geotiff");

  var ds = gdal.open(source.filePath);
  console.log("number of bands: " + ds.bands.count());
  var size = ds.rasterSize;
  console.log("width: " + ds.rasterSize.x);
  console.log("height: " + ds.rasterSize.y);
  var geotransform = ds.geoTransform;
  console.log('Origin = (' + geotransform[0] + ', ' + geotransform[3] + ')');
console.log('Pixel Size = (' + geotransform[1] + ', ' + geotransform[5] + ')');
console.log('GeoTransform =');
console.log(geotransform);
  console.log("srs: " + (ds.srs ? ds.srs.toPrettyWKT() : 'null'));

  // corners
var corners = {
	'Upper Left  ' : {x: 0, y: 0},
	'Upper Right ' : {x: size.x, y: 0},
	'Bottom Right' : {x: size.x, y: size.y},
	'Bottom Left ' : {x: 0, y: size.y}
};

var wgs84 = gdal.SpatialReference.fromEPSG(4326);
var coord_transform = new gdal.CoordinateTransformation(ds.srs, wgs84);

console.log("Corner Coordinates:")
var corner_names = Object.keys(corners);

var coordinateCorners = [];

corner_names.forEach(function(corner_name) {
	// convert pixel x,y to the coordinate system of the raster
	// then transform it to WGS84
	var corner      = corners[corner_name];
	var pt_orig     = {
		x: geotransform[0] + corner.x * geotransform[1] + corner.y * geotransform[2],
		y: geotransform[3] + corner.x * geotransform[4] + corner.y * geotransform[5]
	}
	var pt_wgs84    = coord_transform.transformPoint(pt_orig);
	var description = util.format('%s (%d, %d) (%s, %s)',
		corner_name,
		Math.floor(pt_orig.x * 100) / 100,
		Math.floor(pt_orig.y * 100) / 100,
		gdal.decToDMS(pt_wgs84.x, 'Long'),
		gdal.decToDMS(pt_wgs84.y, 'Lat')
	);
  coordinateCorners.push([pt_wgs84.x, pt_wgs84.y]);
	console.log(description);
});

  coordinateCorners.push([coordinateCorners[0][0], coordinateCorners[0][1]]);

  var polygon = turf.polygon([coordinateCorners]);
  console.log('created a polygon', polygon);

  source.geometry = polygon;
  source.save();

  ds.close();

  callback(null, source);
}

exports.getTile = function(source, z, x, y, callback) {
  console.log('get tile ' + z + '/' + x + '/' + y + '.png for source ' + source.name);

  var tileBbox = tileBboxCalculator(x, y, z);
  // does this intersect our image?
  var tilePoly = turf.bboxPolygon([tileBbox.ul.lon, tileBbox.lr.lat, tileBbox.lr.lon, tileBbox.ul.lat]);
  var intersection = turf.intersect(tilePoly, source.geometry);
  console.log('intersection for ' + z + '/' + x + '/' + y, intersection);
  if (!intersection){
    console.log("GeoTIFF does not intersect the requested tile");
    callback();
    return;
  }

  var ds = gdal.open(source.filePath);

  var tileDirectory = path.join(config.server.sourceDirectory.path, source.id, z, x);
  fs.mkdirsSync(tileDirectory);
  var tileFilename = path.join(tileDirectory, y + '.png');
  var size = ds.rasterSize;
  var geotransform = ds.geoTransform;

  // corners
var corners = {
  'Upper Left  ' : {x: 0, y: 0},
  'Upper Right ' : {x: size.x, y: 0},
  'Bottom Right' : {x: size.x, y: size.y},
  'Bottom Left ' : {x: 0, y: size.y}
};

var wgs84 = gdal.SpatialReference.fromEPSG(3857);
var coord_transform = new gdal.CoordinateTransformation(ds.srs, wgs84);

var xsize = ds.geoTransform[1];
var ysize = Math.abs(ds.geoTransform[5]);

var geotiffUpperLeft = {
  lat: ds.geoTransform[3],
  lon: ds.geoTransform[0]
};

var shift = {
  x: (tileBbox.ul.lon - geotiffUpperLeft.lon),
  y: (geotiffUpperLeft.lat - tileBbox.ul.lat)
};

var origin = {
  x: shift.x / xsize,
  y: shift.y / ysize
};

var lowerRight = {
  x: origin.x + ((tileBbox.lr.lon - tileBbox.ul.lon) / xsize),
  y: origin.y + ((tileBbox.ul.lat - tileBbox.lr.lat) / ysize)
};

console.log('geotiff', geotiffUpperLeft);
console.log("tile bbox", tileBbox);
console.log('origin', origin);
console.log('shift', shift);
console.log('lowerRight', lowerRight);
console.log('size', size);

var imageDataSizeRequestX = Math.min(lowerRight.x, size.x) - Math.max(origin.x, 0);
var imageDataSizeRequestY = Math.min(lowerRight.y, size.y) - Math.max(origin.y, 0);

var totalTileSizeX = lowerRight.x - origin.x;
var totalTileSizeY = lowerRight.y - origin.y;

var imageDataStartX = Math.max(0,origin.x * -1);
var imageDataStartY = Math.max(0,origin.y * -1);

var imageDataEndX = imageDataStartX + imageDataSizeRequestX;
var imageDataEndY = imageDataStartY + imageDataSizeRequestY;

var xRatioFromLeftEdge = (imageDataSizeRequestX == totalTileSizeX) ? 0 : imageDataStartX/totalTileSizeX;
var yRatioFromTopEdge = (imageDataSizeRequestY == totalTileSizeY) ? 0 : imageDataStartY/totalTileSizeY;

var xRatioFromRightEdge = (imageDataSizeRequestX == totalTileSizeX) ? 0 :(1-(imageDataEndX/totalTileSizeX));
var yRatioFromBottom = (imageDataSizeRequestY == totalTileSizeY) ? 0 : (1-((totalTileSizeY-ysize)/totalTileSizeY));
// var yRatioFromBottom = (imageDataSizeRequestY == totalTileSizeY) ? 0 : .08;//Math.abs(((imageDataEndY-lowerRight.y)/lowerRight.y));

console.log('image data x size request ', imageDataSizeRequestX);
console.log('image data y size request ', imageDataSizeRequestY);

console.log('total tile width ', totalTileSizeX);
console.log('total tile height ', totalTileSizeY);

console.log('image data start x ', imageDataStartX);
console.log('image data start y ', imageDataStartY);

console.log('image data end x ', imageDataEndX);
console.log('image data end y ', imageDataEndY);

console.log('xratioFromLeftEdge', xRatioFromLeftEdge);
console.log('yratioFromTop', yRatioFromTopEdge);
console.log('xratioFromRightEdge', xRatioFromRightEdge);
console.log('yratioFromBottom', yRatioFromBottom);

var realOrigin = {
  x: Math.max(0, origin.x),
  y: Math.max(0, origin.y)
}

var options = {};
options.buffer_width = Math.floor(256 * (1-(xRatioFromLeftEdge + xRatioFromRightEdge)));
options.buffer_height = Math.floor(256 * (1-(yRatioFromTopEdge + yRatioFromBottom)));

if (options.buffer_width <= 0 || options.buffer_height <= 0) {
  ds.close();
  return callback();
}

var finalDestination = {
  x:0,
  y:0
};

finalDestination.x = Math.floor(256 * xRatioFromLeftEdge);
finalDestination.y = Math.floor(256 * yRatioFromTopEdge);

// stupid hack to correct
if (xRatioFromRightEdge == 0) {
  finalDestination.x = 256-options.buffer_width;
}
if (yRatioFromBottom == 0) {
  finalDestination.y = 256-options.buffer_height;
}

console.log('options', options);
console.log('real origin', realOrigin);
console.log("final destination", finalDestination);

var pixelRegion1 = ds.bands.get(1).pixels.read(realOrigin.x, realOrigin.y, imageDataSizeRequestX, imageDataSizeRequestY, null, options);
var pixelRegion2 = ds.bands.get(2).pixels.read(realOrigin.x, realOrigin.y, imageDataSizeRequestX, imageDataSizeRequestY, null, options);
var pixelRegion3 = ds.bands.get(3).pixels.read(realOrigin.x, realOrigin.y, imageDataSizeRequestX, imageDataSizeRequestY, null, options);

var img = new png.PNG({
    width: options.buffer_width,
    height: options.buffer_height,
    filterType: 0
});
for (var i = 0; i < pixelRegion1.length; i++) {
  img.data[i*4] = pixelRegion1[i];
  img.data[(i*4)+1] = pixelRegion2[i];
  img.data[(i*4)+2] = pixelRegion3[i];
  img.data[(i*4)+3] = 255;
}

var finalImg = new png.PNG({
  width: 256,
  height: 256,
  filterType: 0
});

for (var i = 0; i < 256 * 256 * 4; i++) {
  finalImg.data[i] = 0;
}

console.log('dst.w ' + finalImg.width + " dst.h " + finalImg.height + " options ", options);
img.bitblt(finalImg, 0, 0, options.buffer_width, options.buffer_height, finalDestination.x, finalDestination.y);

callback(null, finalImg.pack());
// finalImg.pack().pipe(fs.createWriteStream(tileFilename)).on('finish', function(err) {
//   callback(err, tileFilename);
// });

ds.close();

}
<commit_msg>geotiffs work as long as the geotiff is in epsg3857.  we can assure this when the source is uploaded<commit_after>var gdal = require("gdal")
  , util = require('util')
  , turf = require('turf')
  , path = require('path')
  , fs = require('fs-extra')
  , png = require('pngjs')
  , config = require('../../config.json');

  Math.radians = function(degrees) {
    return degrees * Math.PI / 180;
  };

  // Converts from radians to degrees.
  Math.degrees = function(radians) {
    return radians * 180 / Math.PI;
  };

  function tile2lon(x,z) {
    return (x/Math.pow(2,z)*360-180);
  }
  function tile2lat(y,z) {
    var n=Math.PI-2*Math.PI*y/Math.pow(2,z);
    return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
  }

  function tileBboxCalculator(x, y, z) {
    console.log('tile box calculator for ' + x + ' ' + y + ' ' + z);
    x = Number(x);
    y = Number(y);
    var tileBounds = {
      north: tile2lat(y, z),
      east: tile2lon(x+1, z),
      south: tile2lat(y+1, z),
      west: tile2lon(x, z)
    };

    return tileBounds;
  }

exports.process = function(source, callback) {
  console.log("geotiff");

  var ds = gdal.open(source.filePath);
  console.log("number of bands: " + ds.bands.count());
  var size = ds.rasterSize;
  console.log("width: " + ds.rasterSize.x);
  console.log("height: " + ds.rasterSize.y);
  var geotransform = ds.geoTransform;
  console.log('Origin = (' + geotransform[0] + ', ' + geotransform[3] + ')');
console.log('Pixel Size = (' + geotransform[1] + ', ' + geotransform[5] + ')');
console.log('GeoTransform =');
console.log(geotransform);
  console.log("srs: " + (ds.srs ? ds.srs.toPrettyWKT() : 'null'));

  // corners
var corners = {
	'Upper Left  ' : {x: 0, y: 0},
	'Upper Right ' : {x: size.x, y: 0},
	'Bottom Right' : {x: size.x, y: size.y},
	'Bottom Left ' : {x: 0, y: size.y}
};

var wgs84 = gdal.SpatialReference.fromEPSG(4326);
var coord_transform = new gdal.CoordinateTransformation(ds.srs, wgs84);

console.log("Corner Coordinates:")
var corner_names = Object.keys(corners);

var coordinateCorners = [];

corner_names.forEach(function(corner_name) {
	// convert pixel x,y to the coordinate system of the raster
	// then transform it to WGS84
	var corner      = corners[corner_name];
	var pt_orig     = {
		x: geotransform[0] + corner.x * geotransform[1] + corner.y * geotransform[2],
		y: geotransform[3] + corner.x * geotransform[4] + corner.y * geotransform[5]
	}
	var pt_wgs84    = coord_transform.transformPoint(pt_orig);
	var description = util.format('%s (%d, %d) (%s, %s)',
		corner_name,
		Math.floor(pt_orig.x * 100) / 100,
		Math.floor(pt_orig.y * 100) / 100,
		gdal.decToDMS(pt_wgs84.x, 'Long'),
		gdal.decToDMS(pt_wgs84.y, 'Lat')
	);
  coordinateCorners.push([pt_wgs84.x, pt_wgs84.y]);
	console.log(description);
});

  coordinateCorners.push([coordinateCorners[0][0], coordinateCorners[0][1]]);

  var polygon = turf.polygon([coordinateCorners]);
  source.geometry = polygon;
  source.save();

  ds.close();

  callback(null, source);
}

// direct port from gdal2tiles.py
function tileRasterBounds(ds, ulx, uly, lrx, lry) {

  var gt = ds.geoTransform;
  var rx = Math.floor((ulx - gt[0]) / gt[1] + 0.001);
  var ry = Math.floor((uly - gt[3]) / gt[5] + 0.001);
  var rxsize = Math.floor((lrx - ulx) / gt[1] + 0.5);
  var rysize = Math.floor((lry - uly) / gt[5] + 0.5);

  var wxsize = rxsize;
  var wysize = rysize;

  var wx = 0;
  if (rx < 0) {
    var rxshift = Math.abs(rx);
    wx = Math.floor(wxsize * (rxshift / rxsize));
    wxsize = wxsize - wx;
    rxsize = rxsize - Math.floor(rxsize * (rxshift / rxsize));
    rx = 0;
  }
  if ((rx + rxsize) > ds.rasterSize.x) {
    wxsize = Math.floor(wxsize * ((ds.rasterSize.x - rx) / rxsize));
    rxsize = ds.rasterSize.x - rx;
  }
  var wy = 0;
  if (ry < 0) {
    var ryshift = Math.abs(ry);
    wy = Math.floor(wysize * (ryshift / rysize));
    wysize = wysize - wy;
    rysize = rysize - Math.floor(rysize * (ryshift / rysize));
    ry = 0;
  }
  if ((ry + rysize) > ds.rasterSize.y) {
    wysize = Math.floor(wysize * ((ds.rasterSize.y - ry)/ rysize));
    rysize = ds.rasterSize.y - ry;
  }

  return {
    rx: rx,
    ry: ry,
    rxsize: rxsize,
    rysize: rysize,
    wx: wx,
    wy: wy,
    wxsize: wxsize,
    wysize: wysize
  };
}

exports.getTile = function(source, z, x, y, callback) {
  console.log('get tile ' + z + '/' + x + '/' + y + '.png for source ' + source.name);

  var tileEnvelope = tileBboxCalculator(x, y, z);
  var tilePoly = turf.bboxPolygon([tileEnvelope.west, tileEnvelope.south, tileEnvelope.east, tileEnvelope.north]);
  var intersection = turf.intersect(tilePoly, source.geometry);
  if (!intersection){
    console.log("GeoTIFF does not intersect the requested tile");
    callback();
    return;
  }

  var ds = gdal.open(source.filePath);

  // we are assuming that the output SRS is the same as the input SRS.  This will
  // normally not be the case so we will have to reproject at some point

  var out_srs = gdal.SpatialReference.fromEPSG(3857);
  var out_ds = ds;

  var out_gt = out_ds.geoTransform;

  if (out_gt[2] != 0 || out_gt[4] != 0) {
    console.log("error the geotiff is skewed, need to warp first");
    callback();
  }

  // output bounds - coordinates in the output SRS
  var ominx = out_gt[0];
  var omaxx = out_gt[0] + out_ds.rasterSize.x * out_gt[1];
  var omaxy = out_gt[3];
  var ominy = out_gt[3] - out_ds.rasterSize.y * out_gt[1];

  console.log("Bounds (output srs): " + ominx + ", " + ominy + ", " + omaxx + ", " + omaxy);

  var coord_transform = new gdal.CoordinateTransformation(gdal.SpatialReference.fromEPSG(4326), out_srs);
  var ul = coord_transform.transformPoint(tileEnvelope.west, tileEnvelope.north);
  var lr = coord_transform.transformPoint(tileEnvelope.east, tileEnvelope.south);
  var tminx = ul.x;
  var tmaxx = lr.x;
  var tminy = lr.y;
  var tmaxy = ul.y;

  // these represent the bounds of the tile in the output SRS.  They could be bigger or smaller than the actual image
  console.log("Tile Bounds (output srs): " + tminx + ", " + tminy + ", " + tmaxx + ", " + tmaxy);

  var ctminx = tminx;
  var ctmaxx = tmaxx;
  var ctminy = tminy;
  var ctmaxy = tmaxy;
  if (tminx < ominx) ctminx = ominx;
  if (tmaxx > omaxx) ctmaxx = omaxx;
  if (tminy < ominy) ctminy = ominy;
  if (tmaxy > omaxy) ctmaxy = omaxy;

  console.log("Corrected Tile Bounds (output srs): " + ctminx + ", " + ctminy + ", " + ctmaxx + ", " + ctmaxy);

  var tb = tileRasterBounds(out_ds, tminx, tmaxy, tmaxx, tminy);

  console.log("Tile Raster Bounds", tb);

  var options = {
    buffer_width: tb.wxsize,
    buffer_height: tb.wysize
  };

  var options = {
    buffer_width: Math.floor(256*Math.min(1,(ctmaxx-ctminx)/(tmaxx-tminx))),
    buffer_height: Math.floor(256*Math.min(1,(ctmaxy-ctminy)/(tmaxy-tminy)))
  };

  console.log('width %', (tmaxx-tminx)/(omaxx-ominx));
  console.log('height %', (tmaxy-tminy)/(omaxy-ominy));

  console.log('tile width', (tmaxx-tminx));
  console.log('tile height', (tmaxy-tminy));

  console.log('output width', (omaxx-ominx));
  console.log('output height', (omaxy-ominy));

  var pixelRegion1 = out_ds.bands.get(1).pixels.read(tb.rx, tb.ry, tb.rxsize, tb.rysize, null, options);
  var pixelRegion2 = out_ds.bands.get(2).pixels.read(tb.rx, tb.ry, tb.rxsize, tb.rysize, null, options);
  var pixelRegion3 = out_ds.bands.get(3).pixels.read(tb.rx, tb.ry, tb.rxsize, tb.rysize, null, options);

  var img = new png.PNG({
      width: options.buffer_width,
      height: options.buffer_height,
      filterType: 0
  });
  for (var i = 0; i < pixelRegion1.length; i++) {
    img.data[i*4] = pixelRegion1[i];
    img.data[(i*4)+1] = pixelRegion2[i];
    img.data[(i*4)+2] = pixelRegion3[i];
    img.data[(i*4)+3] = 255;
  }

  var finalImg = new png.PNG({
    width: 256,
    height: 256,
    filterType: 0
  });

  for (var i = 0; i < 256 * 256 * 4; i++) {
    finalImg.data[i] = 200;
  }

  var finalDestination = {
    x: Math.floor(256*(ctminx - tminx)/(tmaxx-tminx)),
    y: Math.floor(256*(ctmaxy - tmaxy)/(tmaxy-tminy))
  };

  console.log('final destination', finalDestination);

  img.bitblt(finalImg, 0, 0, options.buffer_width, options.buffer_height, finalDestination.x, finalDestination.y);
  callback(null, finalImg.pack());

  out_ds.close();
}

function gdalInfo(ds) {
  console.log("number of bands: " + ds.bands.count());
  var size = ds.rasterSize;
  console.log("width: " + ds.rasterSize.x);
  console.log("height: " + ds.rasterSize.y);
  var geotransform = ds.geoTransform;
  console.log('Origin = (' + geotransform[0] + ', ' + geotransform[3] + ')');
  console.log('Pixel Size = (' + geotransform[1] + ', ' + geotransform[5] + ')');
  console.log('GeoTransform =');
  console.log(geotransform);
  console.log("srs: " + (ds.srs ? ds.srs.toPrettyWKT() : 'null'));

  // corners
  var corners = {
  	'Upper Left  ' : {x: 0, y: 0},
  	'Upper Right ' : {x: size.x, y: 0},
  	'Bottom Right' : {x: size.x, y: size.y},
  	'Bottom Left ' : {x: 0, y: size.y}
  };

  var wgs84 = gdal.SpatialReference.fromEPSG(4326);
  var coord_transform = new gdal.CoordinateTransformation(ds.srs, wgs84);

  console.log("Corner Coordinates:")
  var corner_names = Object.keys(corners);

  var coordinateCorners = [];

  corner_names.forEach(function(corner_name) {
  	// convert pixel x,y to the coordinate system of the raster
  	// then transform it to WGS84
  	var corner      = corners[corner_name];
  	var pt_orig     = {
  		x: geotransform[0] + corner.x * geotransform[1] + corner.y * geotransform[2],
  		y: geotransform[3] + corner.x * geotransform[4] + corner.y * geotransform[5]
  	}
  	var pt_wgs84    = coord_transform.transformPoint(pt_orig);
  	var description = util.format('%s (%d, %d) (%s, %s)',
  		corner_name,
  		Math.floor(pt_orig.x * 100) / 100,
  		Math.floor(pt_orig.y * 100) / 100,
  		gdal.decToDMS(pt_wgs84.x, 'Long'),
  		gdal.decToDMS(pt_wgs84.y, 'Lat')
  	);
    coordinateCorners.push([pt_wgs84.x, pt_wgs84.y]);
  	console.log(description);
  });
}
<|endoftext|>


<commit_before>"use strict";

/* eslint no-process-exit:0 */

var parseDiff = require("../parse-diff");
var _ = require("lodash");
var async = require("async");
var fs = require("fs");
var minimatch = require("minimatch");

var git = require("../git");
var todos = require("../todos");
var config = require("../config");

exports.config = function (opts) {
  return opts
    .string("r")
    .default("r", "origin")
    .alias("r", "remote")
    .describe("r", "Remote to which the push is being done")
    .string("R")
    .alias("R", "range")
    .describe("R", "Commits range to analyze, will expect git-hook data from standard input otherwise");
};

exports.run = function (argv, opts, conf) {
  conf = _.merge({}, config.defaults, conf);

  if (process.env.DRY_RUN) {
    console.log("[Github-Todos] DRY_RUN set: no modifications to filesystem, no calls to Github API");
  }

  if (!checkRemote(conf.remotes, argv.remote)) {
    console.log("[Github-Todos] Hook disabled for remote '" + argv.remote + "' (you may check option 'remotes')");
    return;
  }

  checkBranch(conf.branches, function (err, enabled, branch) {
    if (err) {
      throw err;
    }

    if (enabled) {
      main(argv, conf);
    } else {
      console.log("[Github-Todos] Hook disabled for branch '" + branch + "' (you may check option 'branches')");
    }
  });
};

// Check if hook is enabled for requested remote
// String, String → Boolean
function checkRemote (remotes, remote) {
  if (remotes === "ALL") {
    return true;
  }

  if (!_.isArray(remotes)) {
    remotes = _.invoke(remotes.split(","), "trim");
  }

  return _.any(remotes, _.partial(minimatch, remote));
}

// Check if hook is enabled on current branch
// String ~→ Boolean
function checkBranch (branches, cb) {
  if (branches === "ALL") {
    return cb(null, true);
  }

  if (!_.isArray(branches)) {
    branches = _.invoke(branches.split(","), "trim");
  }

  git.currentBranch(function (err, branch) {
    if (err) {
      return cb(err);
    }

    cb(null, _.any(branches, _.partial(minimatch, branch)), branch);
  });
}

// Main process
// Object, Object → void
function main (argv, conf) {
  if (!conf.repo) {
    console.error("[Github-Todos] Mandatory option 'repo' not set, where am I supposed to create issues?");
    console.error("[Github-Todos] Run 'github-todos config repo \"<GITHUB USER OR ORG>/<REPOSITORY>\"' to enable hook");
    process.exit(1);
  }

  if (argv.range) {

    // Extract target SHA
    var targetCommit = _.last(argv.range.split(".."));
    git.run("rev-parse '" + targetCommit + "'", function (err, sha) {
      if (err) {
        throw err;
      }

      analyzeRange(argv.range, sha.trim(), conf);
    });

  } else {

    // Receive git-hook data from stdin
    process.stdin.on("data", function (chunk) {
      var info = chunk.toString("utf8").split(/\s+/);
      onCommitRange(info[1], info[3], conf);
    });

  }
}

// String, Sha, String, Sha → void
function onCommitRange (localSha, remoteSha, conf) {
  var range = localSha; // all local commits until localSha
  if (localSha.match(/^0+$/)) {
    // Delete branch: skip
    return;
  } else if (!remoteSha.match(/^0+$/)) {
    // Remote branch exists: build range
    range = remoteSha + ".." + localSha;
  }

  analyzeRange(range, localSha, conf);
}

// Sha..Sha, Sha → void
function analyzeRange (range, targetSha, conf) {
  git.run("diff -u " + range, function (err, diff) {
    if (err) {
      throw err;
    }

    var allowedFiles = conf.files;
    if (!_.isArray(allowedFiles)) {
      allowedFiles = _.invoke(allowedFiles.split(","), "trim");
    }

    analyzeDiff(_.filter(parseDiff(diff), function (file) {
      return _.any(allowedFiles, _.partial(minimatch, file));
    }), targetSha, conf);
  });
}

// String, Sha → void
function analyzeDiff (diff, sha, conf) {
  todos.fromDiff(conf.repo, diff, sha, _.merge({
    "onProgress": function onProgress (err, result, todo) {
      if (err) {
        console.error("[Github-Todos] Error", err);
      } else if (result && result.type === "comment") {
        console.log("[Github-Todos] Added comment to issue #%s (%s) - %s", result.issue, todo.title, result.url);
      } else if (result && result.type === "issue") {
        console.log("[Github-Todos] Created issue #%s (%s) - %s", result.number, todo.title, result.url);
      } else if (!result) {
        console.log("[Github-Todos] Aborted - %s", todo.title);
      } else {
        console.error("[Github-Todos] Unknown result", result);
      }
    }
  }, conf), function (err, results, todos) {
    if (err) {
      throw err;
    }

    if (conf["inject-issue"]) {
      console.log("[Github-Todos] Injecting issue numbers to files…");

      git.dirty(function (err, dirty) {
        if (err) {
          console.error("[Github-Todos] Warning: could not check if repository is dirty");
        }

        var injects = generateInjects(todos, results);

        async.series([
          fail(err),
          stash(dirty),
          injectIssues(injects),
          add,
          commit,
          unstash(dirty)
        ], function (err) {
          if (err) {
            console.error("[Github-Todos] Warning: failed injecting issues, you may need to do it manually in following files:");
            console.errro("[Github-Todos] %s", err);
            _.each(injects, function (inject) {
              console.log("[Github-Todos]  * %s, line %s: Issue #%s", inject.file, inject.line, inject.issue);
            });
          }
        });
      });
    }
  });
}

function generateInjects (todos, results) {
  return _.map(todos, function (todo, i) {
    var result = results[i];
    var issue = (result.type === "issue") ? result.number : result.issue;

    return {
      "file":     todo.file,
      "line":     todo.line,
      "title":    todo.title,
      "issue":    issue
    };
  });
}

function fail (err) {
  return function (cb) {
    if (process.env.DRY_RUN) {
      return cb(new Error("Simulated execution (DRY_RUN set)"));
    }

    cb(err);
  };
}

function stash (dirty) {
  return function (cb) {
    if (dirty) {
      git.stash.save(cb);
    } else {
      cb();
    }
  };
}

function injectIssues (injects) {
  return function (cb) {
    async.map(injects, injectIssue, cb);
  };
}

function injectIssue (inject, cb) {
  fs.readFile(inject.file, {encoding: "utf8"}, function (err, content) {
    if (err) {
      return cb(err);
    }

    var lines = content.split("\n");
    var line = lines[inject.line - 1];
    var index = line.indexOf(inject.title);
    if (index === -1) {
      return cb();
    }

    var head = line.substring(0, index);
    var matchIssue = head.match(/#(\d+)(\s+)$/);
    if (matchIssue && String(inject.issue) === matchIssue[1]) {
      // Already added
      return cb();
    }

    var rest = line.substring(index);
    line = head + "#" + inject.issue + " " + rest;
    lines[inject.line - 1] = line;
    content = lines.join("\n");
    fs.writeFile(inject.file, content, cb);
  });
}

function add (cb) {
  git.run("add .", cb);
}

function commit (cb) {
  git.run("commit -m '[Github-Todos] Inject issue numbers'", function (err) {
    if (err) {
      console.error("[Github-Todos] Failed to commit");
      cb(err);
    } else {
      console.log("[Github-Todos] Added a commit containing issue injections");
      cb();
    }
  });
}

function unstash (dirty) {
  return function (cb) {
    if (dirty) {
      git.stash.pop(function (err) {
        if (err) {
          console.error("[Github-Todos] Warning: could not run 'git stash pop'");
          console.error("[Github-Todos]          %s", err);
          console.error("[Github-Todos] You may want to remove commit (`git reset --soft HEAD~1`) and clean conflicts before running `git stash pop` manually");
        }
        cb();
      });
    } else {
      cb();
    }
  };
}
<commit_msg>show ignored files in debug mode<commit_after>"use strict";

/* eslint no-process-exit:0 */

var parseDiff = require("../parse-diff");
var _ = require("lodash");
var async = require("async");
var fs = require("fs");
var minimatch = require("minimatch");
var debug = require("debug")("github-todos");

var git = require("../git");
var todos = require("../todos");
var config = require("../config");

exports.config = function (opts) {
  return opts
    .string("r")
    .default("r", "origin")
    .alias("r", "remote")
    .describe("r", "Remote to which the push is being done")
    .string("R")
    .alias("R", "range")
    .describe("R", "Commits range to analyze, will expect git-hook data from standard input otherwise");
};

exports.run = function (argv, opts, conf) {
  conf = _.merge({}, config.defaults, conf);

  if (process.env.DRY_RUN) {
    console.log("[Github-Todos] DRY_RUN set: no modifications to filesystem, no calls to Github API");
  }

  if (!checkRemote(conf.remotes, argv.remote)) {
    console.log("[Github-Todos] Hook disabled for remote '" + argv.remote + "' (you may check option 'remotes')");
    return;
  }

  checkBranch(conf.branches, function (err, enabled, branch) {
    if (err) {
      throw err;
    }

    if (enabled) {
      main(argv, conf);
    } else {
      console.log("[Github-Todos] Hook disabled for branch '" + branch + "' (you may check option 'branches')");
    }
  });
};

// Check if hook is enabled for requested remote
// String, String → Boolean
function checkRemote (remotes, remote) {
  if (remotes === "ALL") {
    return true;
  }

  if (!_.isArray(remotes)) {
    remotes = _.invoke(remotes.split(","), "trim");
  }

  return _.any(remotes, _.partial(minimatch, remote));
}

// Check if hook is enabled on current branch
// String ~→ Boolean
function checkBranch (branches, cb) {
  if (branches === "ALL") {
    return cb(null, true);
  }

  if (!_.isArray(branches)) {
    branches = _.invoke(branches.split(","), "trim");
  }

  git.currentBranch(function (err, branch) {
    if (err) {
      return cb(err);
    }

    cb(null, _.any(branches, _.partial(minimatch, branch)), branch);
  });
}

// Main process
// Object, Object → void
function main (argv, conf) {
  if (!conf.repo) {
    console.error("[Github-Todos] Mandatory option 'repo' not set, where am I supposed to create issues?");
    console.error("[Github-Todos] Run 'github-todos config repo \"<GITHUB USER OR ORG>/<REPOSITORY>\"' to enable hook");
    process.exit(1);
  }

  if (argv.range) {

    // Extract target SHA
    var targetCommit = _.last(argv.range.split(".."));
    git.run("rev-parse '" + targetCommit + "'", function (err, sha) {
      if (err) {
        throw err;
      }

      analyzeRange(argv.range, sha.trim(), conf);
    });

  } else {

    // Receive git-hook data from stdin
    process.stdin.on("data", function (chunk) {
      var info = chunk.toString("utf8").split(/\s+/);
      onCommitRange(info[1], info[3], conf);
    });

  }
}

// String, Sha, String, Sha → void
function onCommitRange (localSha, remoteSha, conf) {
  var range = localSha; // all local commits until localSha
  if (localSha.match(/^0+$/)) {
    // Delete branch: skip
    return;
  } else if (!remoteSha.match(/^0+$/)) {
    // Remote branch exists: build range
    range = remoteSha + ".." + localSha;
  }

  analyzeRange(range, localSha, conf);
}

// Sha..Sha, Sha → void
function analyzeRange (range, targetSha, conf) {
  git.run("diff -u " + range, function (err, diff) {
    if (err) {
      throw err;
    }

    var allowedFiles = conf.files;
    if (!_.isArray(allowedFiles)) {
      allowedFiles = _.invoke(allowedFiles.split(","), "trim");
    }

    analyzeDiff(_.filter(parseDiff(diff), function (file) {
      var ignored = !_.any(allowedFiles, _.partial(minimatch, file.to));
      if (ignored) {
        debug("Ignore", file.to);
      }
      return !ignored;
    }), targetSha, conf);
  });
}

// String, Sha → void
function analyzeDiff (diff, sha, conf) {
  todos.fromDiff(conf.repo, diff, sha, _.merge({
    "onProgress": function onProgress (err, result, todo) {
      if (err) {
        console.error("[Github-Todos] Error", err);
      } else if (result && result.type === "comment") {
        console.log("[Github-Todos] Added comment to issue #%s (%s) - %s", result.issue, todo.title, result.url);
      } else if (result && result.type === "issue") {
        console.log("[Github-Todos] Created issue #%s (%s) - %s", result.number, todo.title, result.url);
      } else if (!result) {
        console.log("[Github-Todos] Aborted - %s", todo.title);
      } else {
        console.error("[Github-Todos] Unknown result", result);
      }
    }
  }, conf), function (err, results, todos) {
    if (err) {
      throw err;
    }

    if (conf["inject-issue"]) {
      console.log("[Github-Todos] Injecting issue numbers to files…");

      git.dirty(function (err, dirty) {
        if (err) {
          console.error("[Github-Todos] Warning: could not check if repository is dirty");
        }

        var injects = generateInjects(todos, results);

        async.series([
          fail(err),
          stash(dirty),
          injectIssues(injects),
          add,
          commit,
          unstash(dirty)
        ], function (err) {
          if (err) {
            console.error("[Github-Todos] Warning: failed injecting issues, you may need to do it manually in following files:");
            console.errro("[Github-Todos] %s", err);
            _.each(injects, function (inject) {
              console.log("[Github-Todos]  * %s, line %s: Issue #%s", inject.file, inject.line, inject.issue);
            });
          }
        });
      });
    }
  });
}

function generateInjects (todos, results) {
  return _.map(todos, function (todo, i) {
    var result = results[i];
    var issue = (result.type === "issue") ? result.number : result.issue;

    return {
      "file":     todo.file,
      "line":     todo.line,
      "title":    todo.title,
      "issue":    issue
    };
  });
}

function fail (err) {
  return function (cb) {
    if (process.env.DRY_RUN) {
      return cb(new Error("Simulated execution (DRY_RUN set)"));
    }

    cb(err);
  };
}

function stash (dirty) {
  return function (cb) {
    if (dirty) {
      git.stash.save(cb);
    } else {
      cb();
    }
  };
}

function injectIssues (injects) {
  return function (cb) {
    async.map(injects, injectIssue, cb);
  };
}

function injectIssue (inject, cb) {
  fs.readFile(inject.file, {encoding: "utf8"}, function (err, content) {
    if (err) {
      return cb(err);
    }

    var lines = content.split("\n");
    var line = lines[inject.line - 1];
    var index = line.indexOf(inject.title);
    if (index === -1) {
      return cb();
    }

    var head = line.substring(0, index);
    var matchIssue = head.match(/#(\d+)(\s+)$/);
    if (matchIssue && String(inject.issue) === matchIssue[1]) {
      // Already added
      return cb();
    }

    var rest = line.substring(index);
    line = head + "#" + inject.issue + " " + rest;
    lines[inject.line - 1] = line;
    content = lines.join("\n");
    fs.writeFile(inject.file, content, cb);
  });
}

function add (cb) {
  git.run("add .", cb);
}

function commit (cb) {
  git.run("commit -m '[Github-Todos] Inject issue numbers'", function (err) {
    if (err) {
      console.error("[Github-Todos] Failed to commit");
      cb(err);
    } else {
      console.log("[Github-Todos] Added a commit containing issue injections");
      cb();
    }
  });
}

function unstash (dirty) {
  return function (cb) {
    if (dirty) {
      git.stash.pop(function (err) {
        if (err) {
          console.error("[Github-Todos] Warning: could not run 'git stash pop'");
          console.error("[Github-Todos]          %s", err);
          console.error("[Github-Todos] You may want to remove commit (`git reset --soft HEAD~1`) and clean conflicts before running `git stash pop` manually");
        }
        cb();
      });
    } else {
      cb();
    }
  };
}
<|endoftext|>


<commit_before>"use strict";

(function (window, document, bs, undefined) {

    var socket = bs.socket;
    var uiOptions = {
        bs: {}
    };

    socket.on("ui:connection", function (options) {

        uiOptions = options;

        bs.socket.emit("ui:history:connected", {
            href: window.location.href,
            location: window.location
        });
    });

    socket.on("ui:element:remove", function (data) {
        if (data.id) {
            var elem = document.getElementById(data.id);
            if (elem) {
                removeElement(elem);
            }
        }
    });

    socket.on("highlight", function () {
        var id = "__browser-sync-highlight__";
        var elem = document.getElementById(id);
        if (elem) {
            return removeElement(elem);
        }
        (function (e) {
            e.style.position = "fixed";
            e.style.zIndex = "1000";
            e.style.width = "100%";
            e.style.height = "100%";
            e.style.borderWidth = "5px";
            e.style.borderColor = "red";
            e.style.borderStyle = "solid";
            e.style.top = "0";
            e.style.left = "0";
            e.setAttribute("id", id);
            document.getElementsByTagName("body")[0].appendChild(e);
        })(document.createElement("div"));
    });

    socket.on("ui:element:add", function (data) {

        var elem = document.getElementById(data.id);

        if (!elem) {
            if (data.type === "css") {
                addCss(data);
            }
            if (data.type === "js") {
                addJs(data);
            }
        }
    });

    function addJs(data) {
        (function (e) {
            e.setAttribute("src", getAbsoluteUrl(data.src));
            e.setAttribute("id", data.id);
            document.getElementsByTagName("body")[0].appendChild(e);
        })(document.createElement("script"));
    }

    function addCss(data) {
        (function (e) {
            e.setAttribute("rel",  "stylesheet");
            e.setAttribute("type", "text/css");
            e.setAttribute("id",   data.id);
            e.setAttribute("media", "all");
            e.setAttribute("href", getAbsoluteUrl(data.src));
            document.getElementsByTagName("head")[0].appendChild(e);
        })(document.createElement("link"));
    }

    function removeElement(element) {
        if (element && element.parentNode) {
            element.parentNode.removeChild(element);
        }
    }

    function getAbsoluteUrl(path) {
        if (path.match(/^h/)) {
            return path;
        }
        return [window.location.protocol, "//", getHost(), path].join("");
    }

    function getHost () {
        return uiOptions.bs.mode === "snippet" ? window.location.hostname + ":" + uiOptions.bs.port : window.location.host;
    }

})(window, document, ___browserSync___);<commit_msg>fix(client): don't send window.location re: https://github.com/BrowserSync/browser-sync/issues/445<commit_after>"use strict";

(function (window, document, bs, undefined) {

    var socket = bs.socket;
    var uiOptions = {
        bs: {}
    };

    socket.on("ui:connection", function (options) {

        uiOptions = options;

        bs.socket.emit("ui:history:connected", {
            href: window.location.href
        });
    });

    socket.on("ui:element:remove", function (data) {
        if (data.id) {
            var elem = document.getElementById(data.id);
            if (elem) {
                removeElement(elem);
            }
        }
    });

    socket.on("highlight", function () {
        var id = "__browser-sync-highlight__";
        var elem = document.getElementById(id);
        if (elem) {
            return removeElement(elem);
        }
        (function (e) {
            e.style.position = "fixed";
            e.style.zIndex = "1000";
            e.style.width = "100%";
            e.style.height = "100%";
            e.style.borderWidth = "5px";
            e.style.borderColor = "red";
            e.style.borderStyle = "solid";
            e.style.top = "0";
            e.style.left = "0";
            e.setAttribute("id", id);
            document.getElementsByTagName("body")[0].appendChild(e);
        })(document.createElement("div"));
    });

    socket.on("ui:element:add", function (data) {

        var elem = document.getElementById(data.id);

        if (!elem) {
            if (data.type === "css") {
                addCss(data);
            }
            if (data.type === "js") {
                addJs(data);
            }
        }
    });

    function addJs(data) {
        (function (e) {
            e.setAttribute("src", getAbsoluteUrl(data.src));
            e.setAttribute("id", data.id);
            document.getElementsByTagName("body")[0].appendChild(e);
        })(document.createElement("script"));
    }

    function addCss(data) {
        (function (e) {
            e.setAttribute("rel",  "stylesheet");
            e.setAttribute("type", "text/css");
            e.setAttribute("id",   data.id);
            e.setAttribute("media", "all");
            e.setAttribute("href", getAbsoluteUrl(data.src));
            document.getElementsByTagName("head")[0].appendChild(e);
        })(document.createElement("link"));
    }

    function removeElement(element) {
        if (element && element.parentNode) {
            element.parentNode.removeChild(element);
        }
    }

    function getAbsoluteUrl(path) {
        if (path.match(/^h/)) {
            return path;
        }
        return [window.location.protocol, "//", getHost(), path].join("");
    }

    function getHost () {
        return uiOptions.bs.mode === "snippet" ? window.location.hostname + ":" + uiOptions.bs.port : window.location.host;
    }

})(window, document, ___browserSync___);<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const stackTrace = require('stack-trace');
const asyncEach = require('async-each');
const hljs = require('highlight.js');
const sep = require('path').sep;
const errorView = require('./template/errorView.js');
const instanceRecycler = require('./instanceRecycler.js');
const templateProcessor = require('./templateProcessor.js');

const renderedSPAs = {};

hljs.configure({
	tabReplace: '  ',
	lineNodes: true
});

module.exports = ((environment, logger, languageLoader, appFactory) => {
	appFactory();

	function _displayDetails(err, req, res) {
		let callstack = stackTrace.parse(err);
		let fileIndex = 1;

		logger.error('The application crashed due to an uncaught exception', { err });

		asyncEach(callstack, (stackFrame, cb) => {
			// exclude core node modules and node modules
			if (
				!stackFrame.fileName ||
				!stackFrame.fileName.includes(sep) ||
				/node_modules/.test(stackFrame.fileName) ||
				/internal/.test(stackFrame.fileName)
			) {
				return cb();
			}

			fs.readFile(stackFrame.fileName, 'utf-8', (err, content) => {
				if (err) {
					return cb(err);
				}

				content = hljs.highlight('javascript', content);

				// start a few lines before the error or at the beginning of
				// the file
				let start = Math.max(stackFrame.lineNumber - 11, 0);
				let lines = content.value.split('\n').map(
					line => `<span class="line">${line}</span>`
				);
				// end a few lines after the error or the last line of the file
				let end = Math.min(stackFrame.lineNumber + 10, lines.length);
				let snippet = lines.slice(start, end);
				// array starts at 0 but lines numbers begin with 1, so we have
				// to subtract 1 to get the error line position in the array
				let errLine = stackFrame.lineNumber - start - 1;

				snippet[errLine] = snippet[errLine].replace(
					'',
					''
				);

				stackFrame.content = snippet.join('\n');
				stackFrame.errLine = errLine;
				stackFrame.startLine = start;
				stackFrame.id = 'file-' + fileIndex;

				fileIndex++;

				cb(null, stackFrame);
			});
		}, (error, callstack) => {
			if (!Array.isArray(callstack)) {
				callstack = [];
			}

			callstack = callstack.filter(item => !!item);

			// if something bad happened while processing the stacktrace make
			// sure to return something useful
			if (error) {
				logger.error('Failed to display error page', { error });
				res.send(err.stack);
			} else {
				res.send(errorView(err, callstack));
			}
		});
	}

	function _initApp(req, res, appMain) {
		let bootConfig = _getBootConfig(req, res);
		let app = instanceRecycler.getInstance();

		Object.assign(
			bootConfig,
			appMain.getInitialAppConfigFunctions(),
			appMain.ima.getInitialPluginConfig(),
			appMain.ima.getInitialImaConfigFunctions()
		);
		app.bootstrap
			.run(bootConfig);

		return app;
	}

	function showStaticErrorPage(error, req, res) {
		logger.error(
			'Failed to display error page, displaying the static error page',
			{ error }
		);

		return new Promise((resolve, reject) => {
			const filePath = './build/static/html/error.html';
			fs.readFile(filePath, 'utf-8', (error, content) => {
				let status = 500;
				res.status(status);

				if (error) {
					res.send('500');
					reject(error);
				}

				res.send(content);

				resolve({ content, status, error });
			});
		});
	}

	function showStaticSPAPage(req, res) {
		let bootConfig = _getBootConfig(req, res);
		let status = 200;

		let cacheKey = [
			bootConfig.settings.$Protocol,
			bootConfig.settings.$Language,
			bootConfig.settings.$Host,
			bootConfig.settings.$Root,
			bootConfig.settings.$LanguagePartPath
		].join('|');
		if (renderedSPAs[cacheKey]) {
			res.status(status);
			res.send(renderedSPAs[cacheKey]);

			return Promise.resolve({
				content: renderedSPAs[cacheKey],
				pageState: {},
				status,
				SPA: true
			});
		}

		return new Promise((resolve, reject) => {
			const filePath = './build/static/html/spa.html';
			fs.readFile(filePath, 'utf-8', (error, content) => {
				if (error) {
					showStaticErrorPage(error, req, res);
					reject(error);
					return;
				}

				content = templateProcessor(content, bootConfig.settings);

				renderedSPAs[cacheKey] = content;

				res.status(status);
				res.send(content);

				resolve({ content, status, SPA: true, error: null });
			});
		});
	}

	function _hasToServeSPA(req, app) {
		let userAgent = req.headers['user-agent'] || '';
		let spaConfig = environment.$Server.serveSPA;
		let isAllowedServeSPA = spaConfig.allow;
		let isServerBusy = instanceRecycler.hasReachedMaxConcurrentRequests();
		let isAllowedUserAgent = !spaConfig.blackListReg.test(userAgent);
		let canBeRouteServeAsSPA = true;
		let routeInfo = _getRouteInfo(app);

		if (routeInfo && routeInfo.route.getOptions().allowSPA === false) {
			canBeRouteServeAsSPA = false;
		}

		return isAllowedServeSPA &&
			isServerBusy &&
			isAllowedUserAgent &&
			canBeRouteServeAsSPA;
	}

	function _getBootConfig(req, res) {
		let language = res.locals.language;
		let languagePartPath = res.locals.languagePartPath;
		let host = res.locals.host;
		let root = res.locals.root;
		let urlPath = res.locals.path;
		let protocol = res.locals.protocol;

		let dictionary = languageLoader(language);

		let bootConfig = {

			services: {
				request: req,
				response: res,
				$IMA: {},
				dictionary: {
					$Language: language,
					dictionary: dictionary
				},
				router: {
					$Protocol: protocol,
					$Host: host,
					$Path: urlPath,
					$Root: root,
					$LanguagePartPath: languagePartPath
				}
			},
			settings: {
				$Debug: environment.$Debug,
				$Env: environment.$Env,
				$Version: environment.$Version,
				$App: environment.$App || {},
				$Protocol: protocol,
				$Language: language,
				$Host: host,
				$Path: urlPath,
				$Root: root,
				$LanguagePartPath: languagePartPath
			}
		};

		return bootConfig;
	}

	function _applyError(error, req, res, app) {
		let promise;

		try {
			promise = app.oc.get('$Router')
				.handleError({ error })
				.then((response) => {
					instanceRecycler.clearInstance(app);

					return response;
				})
				.catch((fatalError) => {
					showStaticErrorPage(fatalError, req, res);
					instanceRecycler.clearInstance(app);

					return Promise.reject(fatalError);
				});
		} catch (e) {
			showStaticErrorPage(e, req, res);
			instanceRecycler.clearInstance(app);
			promise = Promise.reject(e);
		}

		return promise;
	}

	function _applyNotFound(error, req, res, app) {
		let promise;

		try {
			promise = app.oc.get('$Router')
				.handleNotFound({ error })
				.then((response) => {
					instanceRecycler.clearInstance(app);

					return response;
				})
				.catch((error) => {
					return _applyError(error, req, res, app);
				});
		} catch (e) {
			promise = _applyError(e, req, res, app);
		}

		return promise;
	}

	function _applyRedirect(error, req, res, app) {
		let promise;

		try {
			app.oc.get('$Router').redirect(
				error.getParams().url,
				{ httpStatus: error.getHttpStatus() }
			);
			instanceRecycler.clearInstance(app);
			promise = Promise.resolve({
				content: null,
				pageState: {},
				status: error.getHttpStatus(),
				error: error
			});
		} catch (e) {
			promise = _applyError(e, req, res, app);
		}

		return promise;
	}

	function _importAppMain() {
		return $IMA.Loader
			.import('app/main')
			.then(appMain => {
				if (!instanceRecycler.isInitialized()) {
					instanceRecycler.init(
						appMain.ima.createImaApp,
						environment.$Server.concurrency
					);
				}

				return appMain;
			});
	}

	function errorHandler(error, req, res, app) {
		let returnPromise;

		if (environment.$Debug) {
			if (app) {
				instanceRecycler.clearInstance(app);
			}

			returnPromise = Promise.reject(error);
			_displayDetails(error, req, res);
		} else {
			let appPromise = Promise.resolve(app);

			if (!app) {
				appPromise = _importAppMain()
					.then((appMain) => {
						return _initApp(req, res, appMain);
					});
			}

			returnPromise = appPromise
				.then((app) => {
					let router = app.oc.get('$Router');
					app.oc.get('$Cache').clear();

					if (router.isClientError(error)) {
						return _applyNotFound(error, req, res, app);
					} else if (router.isRedirection(error)) {
						return _applyRedirect(error, req, res, app);
					} else {
						return _applyError(error, req, res, app);
					}
				})
				.catch((e) => {
					showStaticErrorPage(e, req, res);

					instanceRecycler.clearInstance(app);
					returnPromise = Promise.reject(e);
				});
		}

		return returnPromise;
	}

	function _getRouteInfo(app) {
		let router = app.oc.get('$Router');
		let routeInfo = null;

		try {
			routeInfo = router.getCurrentRouteInfo();
		} catch (e) {
			logger.warn('Failed to retrieve current route info', { error: e });
		}

		return routeInfo;
	}

	function _addImaToResponse(req, res, app) {
		let routeName = 'other';
		let routeInfo = _getRouteInfo(app);

		if (routeInfo) {
			routeName = routeInfo.route.getName();
		}

		res.$IMA = res.$IMA || { routeName };
	}

	function _generateResponse(req, res, app) {
		let returnPromise;
		let router = app.oc.get('$Router');

		try {
			returnPromise = router
				.route(router.getPath())
				.then((response) => {
					instanceRecycler.clearInstance(app);

					return response;
				})
				.catch((error) => {
					return errorHandler(error, req, res, app);
				});
		} catch (e) {
			returnPromise = errorHandler(e, req, res, app);
		}

		return returnPromise;
	}

	function requestHandler(req, res) {
		if (environment.$Env === 'dev') {
			appFactory();
			instanceRecycler.clear();
		}

		return _importAppMain()
			.then((appMain) => {
				let app = _initApp(req, res, appMain);
				_addImaToResponse(req, res, app);

				if (_hasToServeSPA(req, app)) {
					instanceRecycler.clearInstance(app);
					return showStaticSPAPage(req, res);
				}

				return _generateResponse(req, res, app);
			});
	}

	return {
		errorHandler,
		requestHandler,
		showStaticErrorPage,
		showStaticSPAPage
	};
});
<commit_msg>#! fix bug with memory leaks for dev environment<commit_after>'use strict';

const fs = require('fs');
const stackTrace = require('stack-trace');
const asyncEach = require('async-each');
const hljs = require('highlight.js');
const sep = require('path').sep;
const errorView = require('./template/errorView.js');
const instanceRecycler = require('./instanceRecycler.js');
const templateProcessor = require('./templateProcessor.js');

const renderedSPAs = {};

hljs.configure({
	tabReplace: '  ',
	lineNodes: true
});

module.exports = ((environment, logger, languageLoader, appFactory) => {
	appFactory();

	function _displayDetails(err, req, res) {
		let callstack = stackTrace.parse(err);
		let fileIndex = 1;

		logger.error('The application crashed due to an uncaught exception', { err });

		asyncEach(callstack, (stackFrame, cb) => {
			// exclude core node modules and node modules
			if (
				!stackFrame.fileName ||
				!stackFrame.fileName.includes(sep) ||
				/node_modules/.test(stackFrame.fileName) ||
				/internal/.test(stackFrame.fileName)
			) {
				return cb();
			}

			fs.readFile(stackFrame.fileName, 'utf-8', (err, content) => {
				if (err) {
					return cb(err);
				}

				content = hljs.highlight('javascript', content);

				// start a few lines before the error or at the beginning of
				// the file
				let start = Math.max(stackFrame.lineNumber - 11, 0);
				let lines = content.value.split('\n').map(
					line => `<span class="line">${line}</span>`
				);
				// end a few lines after the error or the last line of the file
				let end = Math.min(stackFrame.lineNumber + 10, lines.length);
				let snippet = lines.slice(start, end);
				// array starts at 0 but lines numbers begin with 1, so we have
				// to subtract 1 to get the error line position in the array
				let errLine = stackFrame.lineNumber - start - 1;

				snippet[errLine] = snippet[errLine].replace(
					'',
					''
				);

				stackFrame.content = snippet.join('\n');
				stackFrame.errLine = errLine;
				stackFrame.startLine = start;
				stackFrame.id = 'file-' + fileIndex;

				fileIndex++;

				cb(null, stackFrame);
			});
		}, (error, callstack) => {
			if (!Array.isArray(callstack)) {
				callstack = [];
			}

			callstack = callstack.filter(item => !!item);

			// if something bad happened while processing the stacktrace make
			// sure to return something useful
			if (error) {
				logger.error('Failed to display error page', { error });
				res.send(err.stack);
			} else {
				res.send(errorView(err, callstack));
			}
		});
	}

	function _initApp(req, res, appMain) {
		let bootConfig = _getBootConfig(req, res);
		let app = instanceRecycler.getInstance();

		Object.assign(
			bootConfig,
			appMain.getInitialAppConfigFunctions(),
			appMain.ima.getInitialPluginConfig(),
			appMain.ima.getInitialImaConfigFunctions()
		);
		app.bootstrap
			.run(bootConfig);

		return app;
	}

	function showStaticErrorPage(error, req, res) {
		logger.error(
			'Failed to display error page, displaying the static error page',
			{ error }
		);

		return new Promise((resolve, reject) => {
			const filePath = './build/static/html/error.html';
			fs.readFile(filePath, 'utf-8', (error, content) => {
				let status = 500;
				res.status(status);

				if (error) {
					res.send('500');
					reject(error);
				}

				res.send(content);

				resolve({ content, status, error });
			});
		});
	}

	function showStaticSPAPage(req, res) {
		let bootConfig = _getBootConfig(req, res);
		let status = 200;

		let cacheKey = [
			bootConfig.settings.$Protocol,
			bootConfig.settings.$Language,
			bootConfig.settings.$Host,
			bootConfig.settings.$Root,
			bootConfig.settings.$LanguagePartPath
		].join('|');
		if (renderedSPAs[cacheKey]) {
			res.status(status);
			res.send(renderedSPAs[cacheKey]);

			return Promise.resolve({
				content: renderedSPAs[cacheKey],
				pageState: {},
				status,
				SPA: true
			});
		}

		return new Promise((resolve, reject) => {
			const filePath = './build/static/html/spa.html';
			fs.readFile(filePath, 'utf-8', (error, content) => {
				if (error) {
					showStaticErrorPage(error, req, res);
					reject(error);
					return;
				}

				content = templateProcessor(content, bootConfig.settings);

				renderedSPAs[cacheKey] = content;

				res.status(status);
				res.send(content);

				resolve({ content, status, SPA: true, error: null });
			});
		});
	}

	function _hasToServeSPA(req, app) {
		let userAgent = req.headers['user-agent'] || '';
		let spaConfig = environment.$Server.serveSPA;
		let isAllowedServeSPA = spaConfig.allow;
		let isServerBusy = instanceRecycler.hasReachedMaxConcurrentRequests();
		let isAllowedUserAgent = !spaConfig.blackListReg.test(userAgent);
		let canBeRouteServeAsSPA = true;
		let routeInfo = _getRouteInfo(app);

		if (routeInfo && routeInfo.route.getOptions().allowSPA === false) {
			canBeRouteServeAsSPA = false;
		}

		return isAllowedServeSPA &&
			isServerBusy &&
			isAllowedUserAgent &&
			canBeRouteServeAsSPA;
	}

	function _getBootConfig(req, res) {
		let language = res.locals.language;
		let languagePartPath = res.locals.languagePartPath;
		let host = res.locals.host;
		let root = res.locals.root;
		let urlPath = res.locals.path;
		let protocol = res.locals.protocol;

		let dictionary = languageLoader(language);

		let bootConfig = {

			services: {
				request: req,
				response: res,
				$IMA: {},
				dictionary: {
					$Language: language,
					dictionary: dictionary
				},
				router: {
					$Protocol: protocol,
					$Host: host,
					$Path: urlPath,
					$Root: root,
					$LanguagePartPath: languagePartPath
				}
			},
			settings: {
				$Debug: environment.$Debug,
				$Env: environment.$Env,
				$Version: environment.$Version,
				$App: environment.$App || {},
				$Protocol: protocol,
				$Language: language,
				$Host: host,
				$Path: urlPath,
				$Root: root,
				$LanguagePartPath: languagePartPath
			}
		};

		return bootConfig;
	}

	function _applyError(error, req, res, app) {
		let promise;

		try {
			promise = app.oc.get('$Router')
				.handleError({ error })
				.then((response) => {
					instanceRecycler.clearInstance(app);

					return response;
				})
				.catch((fatalError) => {
					showStaticErrorPage(fatalError, req, res);
					instanceRecycler.clearInstance(app);

					return Promise.reject(fatalError);
				});
		} catch (e) {
			showStaticErrorPage(e, req, res);
			instanceRecycler.clearInstance(app);
			promise = Promise.reject(e);
		}

		return promise;
	}

	function _applyNotFound(error, req, res, app) {
		let promise;

		try {
			promise = app.oc.get('$Router')
				.handleNotFound({ error })
				.then((response) => {
					instanceRecycler.clearInstance(app);

					return response;
				})
				.catch((error) => {
					return _applyError(error, req, res, app);
				});
		} catch (e) {
			promise = _applyError(e, req, res, app);
		}

		return promise;
	}

	function _applyRedirect(error, req, res, app) {
		let promise;

		try {
			app.oc.get('$Router').redirect(
				error.getParams().url,
				{ httpStatus: error.getHttpStatus() }
			);
			instanceRecycler.clearInstance(app);
			promise = Promise.resolve({
				content: null,
				pageState: {},
				status: error.getHttpStatus(),
				error: error
			});
		} catch (e) {
			promise = _applyError(e, req, res, app);
		}

		return promise;
	}

	function _importAppMain() {
		return $IMA.Loader
			.import('app/main')
			.then(appMain => {
				if (!instanceRecycler.isInitialized()) {
					instanceRecycler.init(
						appMain.ima.createImaApp,
						environment.$Server.concurrency
					);
				}

				return appMain;
			});
	}

	function errorHandler(error, req, res, app) {
		let returnPromise;

		if (environment.$Debug) {
			if (app) {
				instanceRecycler.clearInstance(app);
			}

			returnPromise = Promise.reject(error);
			_displayDetails(error, req, res);
		} else {
			let appPromise = Promise.resolve(app);

			if (!app) {
				appPromise = _importAppMain()
					.then((appMain) => {
						return _initApp(req, res, appMain);
					});
			}

			returnPromise = appPromise
				.then((app) => {
					let router = app.oc.get('$Router');
					app.oc.get('$Cache').clear();

					if (router.isClientError(error)) {
						return _applyNotFound(error, req, res, app);
					} else if (router.isRedirection(error)) {
						return _applyRedirect(error, req, res, app);
					} else {
						return _applyError(error, req, res, app);
					}
				})
				.catch((e) => {
					showStaticErrorPage(e, req, res);

					instanceRecycler.clearInstance(app);
					returnPromise = Promise.reject(e);
				});
		}

		return returnPromise;
	}

	function _getRouteInfo(app) {
		let router = app.oc.get('$Router');
		let routeInfo = null;

		try {
			routeInfo = router.getCurrentRouteInfo();
		} catch (e) {
			logger.warn('Failed to retrieve current route info', { error: e });
		}

		return routeInfo;
	}

	function _addImaToResponse(req, res, app) {
		let routeName = 'other';
		let routeInfo = _getRouteInfo(app);

		if (routeInfo) {
			routeName = routeInfo.route.getName();
		}

		res.$IMA = res.$IMA || { routeName };
	}

	function _generateResponse(req, res, app) {
		let returnPromise;
		let router = app.oc.get('$Router');

		try {
			returnPromise = router
				.route(router.getPath())
				.then((response) => {
					instanceRecycler.clearInstance(app);

					return response;
				})
				.catch((error) => {
					return errorHandler(error, req, res, app);
				});
		} catch (e) {
			returnPromise = errorHandler(e, req, res, app);
		}

		return returnPromise;
	}

	function requestHandler(req, res) {
		if (environment.$Env === 'dev') {
			instanceRecycler.clear();
			$IMA.Loader.modules = {};
			appFactory();
		}

		return _importAppMain()
			.then((appMain) => {
				let app = _initApp(req, res, appMain);
				_addImaToResponse(req, res, app);

				if (_hasToServeSPA(req, app)) {
					instanceRecycler.clearInstance(app);
					return showStaticSPAPage(req, res);
				}

				return _generateResponse(req, res, app);
			});
	}

	return {
		errorHandler,
		requestHandler,
		showStaticErrorPage,
		showStaticSPAPage
	};
});
<|endoftext|>


<commit_before>(function(global) {
    'use strict';

    var rendy;

    if (typeof module === 'object' && module.exports) {
        rendy               = require('rendy');
        module.exports      = new CloudFuncProto();
    } else {
        rendy               = window.rendy;
        global.CloudFunc    = new CloudFuncProto();
    }

    function CloudFuncProto() {
        var CloudFunc               = this,
            Entity                  = new entityProto(),
            FS;

        /* КОНСТАНТЫ (общие для клиента и сервера)*/

        /* название программы */
        this.NAME                   = 'Cloud Commander';

        /* если в ссылке будет эта строка - в браузере js отключен */
        this.FS    =   FS           = '/fs';

        this.apiURL                 = '/api/v1';
        this.MAX_FILE_SIZE          = 500 * 1024;
        this.Entity                 = Entity;

        function entityProto() {
            var Entities = {
                ' ': ' ',
                '<'  : '<',
                '>'   : '>'
            };

            this.encode = function(str) {
                Object.keys(Entities).forEach(function(code) {
                    var char    = Entities[code],
                        reg     = RegExp(char, 'g');

                    str = str.replace(reg, code);
                });

                return str;
            };

            this.decode = function(str) {
                Object.keys(Entities).forEach(function(code) {
                    var char    = Entities[code],
                        reg     = RegExp(code, 'g');

                    str = str.replace(reg, char);
                });

                return str;
            };
        }

        this.formatMsg              = function(msg, name, status) {
            if (!status)
                status = 'ok';

            if (name)
                name = '("' + name + '")';
            else
                name = '';

            msg = msg + ': ' + status + name;

            return msg;
        };

        /** Функция возвращает заголовок веб страницы
         * @pPath
         */
        this.getTitle               = function(pPath) {
            if (!CloudFunc.Path)
                CloudFunc.Path = '/';

            return  CloudFunc.NAME + ' - ' + (pPath || CloudFunc.Path);

        };

        /** Функция получает адреса каждого каталога в пути
         * возвращаеться массив каталогов
         * @param url -  адрес каталога
         */
        function getPathLink(url, prefix, template) {
            var namesRaw, names, length,
                pathHTML    = '',
                path        = '/';

            if (!url)
                throw Error('url could not be empty!');

            if (!template)
                throw Error('template could not be empty!');

            namesRaw    = url.split('/')
                             .slice(1, -1),

            names       = [].concat('/', namesRaw),

            length      = names.length - 1;

            names.forEach(function(name, index) {
                var slash       = '',
                    isLast      = index === length;

                if (index)
                    path        += name + '/';

                if (index && isLast) {
                    pathHTML    += name + '/';
                } else {
                    if (index)
                        slash = '/';

                    pathHTML    += rendy(template, {
                        path: path,
                        name: name,
                        slash: slash,
                        prefix: prefix
                    });
                }
            });

            return pathHTML;
        }

        /**
         * Функция строит таблицу файлв из JSON-информации о файлах
         * @param params - информация о файлах
         *
         */
        this.buildFromJSON          = function(params) {
            var file, i, n, type, attribute, size, date, owner, mode,
                dotDot, link, dataName,
                linkResult,
                prefix          = params.prefix,
                template        = params.template,
                templateFile    = template.file,
                templateLink    = template.link,
                json            = params.data,
                files           = json.files,
                path            = json.path,

                /*
                 * Строим путь каталога в котором мы находимся
                 * со всеми подкаталогами
                 */
                htmlPath        = getPathLink(path, prefix, template.pathLink),

                fileTable       = rendy(template.path, {
                    link        : prefix + FS + path,
                    fullPath    : path,
                    path        : htmlPath
                }),

                header         = rendy(templateFile, {
                    tag         : 'div',
                    attribute   : '',
                    className   : 'fm-header',
                    type        : '',
                    name        : 'name',
                    size        : 'size',
                    date        : 'date',
                    owner       : 'owner',
                    mode        : 'mode'
                });

            fileTable          += header;

            /* сохраняем путь */
            CloudFunc.Path      = path;

            fileTable           += '
';
            /* Если мы не в корне */
            if (path !== '/') {
                /* убираем последний слеш и каталог в котором мы сейчас находимся*/
                dotDot          = path.substr(path, path.lastIndexOf('/'));
                dotDot          = dotDot.substr(dotDot, dotDot.lastIndexOf('/'));
                /* Если предыдущий каталог корневой */
                if (dotDot === '')
                    dotDot = '/';

                link            = prefix + FS + dotDot;

                linkResult      = rendy(template.link, {
                    link        : link,
                    title       : '..',
                    name        : '..'
                });

                dataName        = 'data-name="js-file-.." ',
                attribute       = 'draggable="true" ' + dataName,
                /* Сохраняем путь к каталогу верхнего уровня*/
                fileTable += rendy(template.file, {
                    tag         : 'li',
                    attribute   : attribute,
                    className   : '',
                    type        : 'directory',
                    name        : linkResult,
                    size        : '<dir>',
                    date        : '.',
                    owner       : '.',
                    mode        : '--- --- ---'
                });
            }

            n = files.length;
            for (i = 0; i < n; i++) {
                file            = files[i];
                link            = prefix + FS + path + file.name;

                if (file.size === 'dir') {
                    type        = 'directory';
                    attribute   = '';
                    size        = '<dir>';
                } else {
                    type        = 'text-file';
                    attribute   = 'target="_blank" ';
                    size        = file.size;
                }

                date    = file.date;
                owner   = file.owner || 'root';
                mode    = file.mode;

                linkResult  = rendy(templateLink, {
                    link        : link,
                    title       : file.name,
                    name        : Entity.encode(file.name),
                    attribute   : attribute
                });

                dataName        = 'data-name="js-file-' + file.name + '" ';
                attribute       = 'draggable="true" ' + dataName;

                fileTable += rendy(templateFile, {
                    tag         : 'li',
                    attribute   : attribute,
                    className   : '',
                    /* Если папка - выводим пиктограмму папки   *
                     * В противоположном случае - файла         */
                    type        : type,
                    name        : linkResult,
                    size        : size,
                    date        : date,
                    owner       : owner,
                    mode        : mode
                });
            }

            fileTable          += '
';

            return fileTable;
        };
     }
})(this);
<commit_msg>fix(cloudfunc) when no date use --.--.----<commit_after>(function(global) {
    'use strict';

    var rendy;

    if (typeof module === 'object' && module.exports) {
        rendy               = require('rendy');
        module.exports      = new CloudFuncProto();
    } else {
        rendy               = window.rendy;
        global.CloudFunc    = new CloudFuncProto();
    }

    function CloudFuncProto() {
        var CloudFunc               = this,
            Entity                  = new entityProto(),
            FS;

        /* КОНСТАНТЫ (общие для клиента и сервера)*/

        /* название программы */
        this.NAME                   = 'Cloud Commander';

        /* если в ссылке будет эта строка - в браузере js отключен */
        this.FS    =   FS           = '/fs';

        this.apiURL                 = '/api/v1';
        this.MAX_FILE_SIZE          = 500 * 1024;
        this.Entity                 = Entity;

        function entityProto() {
            var Entities = {
                ' ': ' ',
                '<'  : '<',
                '>'   : '>'
            };

            this.encode = function(str) {
                Object.keys(Entities).forEach(function(code) {
                    var char    = Entities[code],
                        reg     = RegExp(char, 'g');

                    str = str.replace(reg, code);
                });

                return str;
            };

            this.decode = function(str) {
                Object.keys(Entities).forEach(function(code) {
                    var char    = Entities[code],
                        reg     = RegExp(code, 'g');

                    str = str.replace(reg, char);
                });

                return str;
            };
        }

        this.formatMsg              = function(msg, name, status) {
            if (!status)
                status = 'ok';

            if (name)
                name = '("' + name + '")';
            else
                name = '';

            msg = msg + ': ' + status + name;

            return msg;
        };

        /** Функция возвращает заголовок веб страницы
         * @pPath
         */
        this.getTitle               = function(pPath) {
            if (!CloudFunc.Path)
                CloudFunc.Path = '/';

            return  CloudFunc.NAME + ' - ' + (pPath || CloudFunc.Path);

        };

        /** Функция получает адреса каждого каталога в пути
         * возвращаеться массив каталогов
         * @param url -  адрес каталога
         */
        function getPathLink(url, prefix, template) {
            var namesRaw, names, length,
                pathHTML    = '',
                path        = '/';

            if (!url)
                throw Error('url could not be empty!');

            if (!template)
                throw Error('template could not be empty!');

            namesRaw    = url.split('/')
                             .slice(1, -1),

            names       = [].concat('/', namesRaw),

            length      = names.length - 1;

            names.forEach(function(name, index) {
                var slash       = '',
                    isLast      = index === length;

                if (index)
                    path        += name + '/';

                if (index && isLast) {
                    pathHTML    += name + '/';
                } else {
                    if (index)
                        slash = '/';

                    pathHTML    += rendy(template, {
                        path: path,
                        name: name,
                        slash: slash,
                        prefix: prefix
                    });
                }
            });

            return pathHTML;
        }

        /**
         * Функция строит таблицу файлв из JSON-информации о файлах
         * @param params - информация о файлах
         *
         */
        this.buildFromJSON          = function(params) {
            var file, i, n, type, attribute, size, date, owner, mode,
                dotDot, link, dataName,
                linkResult,
                prefix          = params.prefix,
                template        = params.template,
                templateFile    = template.file,
                templateLink    = template.link,
                json            = params.data,
                files           = json.files,
                path            = json.path,

                /*
                 * Строим путь каталога в котором мы находимся
                 * со всеми подкаталогами
                 */
                htmlPath        = getPathLink(path, prefix, template.pathLink),

                fileTable       = rendy(template.path, {
                    link        : prefix + FS + path,
                    fullPath    : path,
                    path        : htmlPath
                }),

                header         = rendy(templateFile, {
                    tag         : 'div',
                    attribute   : '',
                    className   : 'fm-header',
                    type        : '',
                    name        : 'name',
                    size        : 'size',
                    date        : 'date',
                    owner       : 'owner',
                    mode        : 'mode'
                });

            fileTable          += header;

            /* сохраняем путь */
            CloudFunc.Path      = path;

            fileTable           += '
';
            /* Если мы не в корне */
            if (path !== '/') {
                /* убираем последний слеш и каталог в котором мы сейчас находимся*/
                dotDot          = path.substr(path, path.lastIndexOf('/'));
                dotDot          = dotDot.substr(dotDot, dotDot.lastIndexOf('/'));
                /* Если предыдущий каталог корневой */
                if (dotDot === '')
                    dotDot = '/';

                link            = prefix + FS + dotDot;

                linkResult      = rendy(template.link, {
                    link        : link,
                    title       : '..',
                    name        : '..'
                });

                dataName        = 'data-name="js-file-.." ',
                attribute       = 'draggable="true" ' + dataName,
                /* Сохраняем путь к каталогу верхнего уровня*/
                fileTable += rendy(template.file, {
                    tag         : 'li',
                    attribute   : attribute,
                    className   : '',
                    type        : 'directory',
                    name        : linkResult,
                    size        : '<dir>',
                    date        : '--.--.----',
                    owner       : '.',
                    mode        : '--- --- ---'
                });
            }

            n = files.length;
            for (i = 0; i < n; i++) {
                file            = files[i];
                link            = prefix + FS + path + file.name;

                if (file.size === 'dir') {
                    type        = 'directory';
                    attribute   = '';
                    size        = '<dir>';
                } else {
                    type        = 'text-file';
                    attribute   = 'target="_blank" ';
                    size        = file.size;
                }

                date    = file.date || '--.--.----;
                owner   = file.owner || 'root';
                mode    = file.mode;

                linkResult  = rendy(templateLink, {
                    link        : link,
                    title       : file.name,
                    name        : Entity.encode(file.name),
                    attribute   : attribute
                });

                dataName        = 'data-name="js-file-' + file.name + '" ';
                attribute       = 'draggable="true" ' + dataName;

                fileTable += rendy(templateFile, {
                    tag         : 'li',
                    attribute   : attribute,
                    className   : '',
                    /* Если папка - выводим пиктограмму папки   *
                     * В противоположном случае - файла         */
                    type        : type,
                    name        : linkResult,
                    size        : size,
                    date        : date,
                    owner       : owner,
                    mode        : mode
                });
            }

            fileTable          += '
';

            return fileTable;
        };
     }
})(this);
<|endoftext|>