<commit_before>/*!
 * fengine
 * Version: 0.0.1
 * Date: 2016/8/2
 * https://github.com/Nuintun/fengine
 *
 * This is licensed under the MIT License (MIT).
 * For details, see: https://github.com/Nuintun/fengine/blob/master/LICENSE
 */

'use strict';

// lib
var os = require('os');
var fs = require('fs');
var url = require('url');
var path = require('path');
var http = require('http');
var util = require('./util');
var colors = require('colors');
var cluster = require('cluster');
var FileSend = require('file-send');
var Transform = require('./transform');

// variable declaration
var CWD = process.cwd();
var NUMCPUS = os.cpus().length;
var LOGLEVELS = {
  INFO: 'info',
  WARN: 'warn',
  ERROR: 'error'
};
var FAVICON = path.join(__dirname, '../favicon.ico');
var FAVICONSIZE = fs.lstatSync(FAVICON).size;

/**
 * date format
 * @param date
 * @param format
 * @returns {*}
 */
function dateFormat(date, format){
  if (!date instanceof Date) {
    throw new TypeError('param date must be a date.');
  }

  format = format || 'yyyy-MM-dd hh:mm:ss';

  var map = {
    'M': date.getMonth() + 1, // month
    'd': date.getDate(), // date
    'h': date.getHours(), // hours
    'm': date.getMinutes(), // minutes
    's': date.getSeconds(), // seconds
    'q': Math.floor((date.getMonth() + 3) / 3), // quarter
    'S': date.getMilliseconds() // milliseconds
  };

  format = format.replace(/([yMdhmsqS])+/g, function (all, t){
    var v = map[t];

    if (v !== undefined) {
      if (all.length > 1) {
        v = '0' + v;
        v = v.substr(v.length - 2);
      }

      return v;
    } else if (t === 'y') {
      return (date.getFullYear() + '').substr(4 - all.length);
    }

    return all;
  });

  return format;
}

/**
 * is out bound
 * @param path
 * @param root
 * @returns {boolean}
 */
function isOutBound(path, root){
  if (process.platform === 'win32') {
    path = path.toLowerCase();
    root = root.toLowerCase();
  }

  if (path.length < root.length) {
    return true;
  }

  return path.indexOf(root) !== 0;
}

/**
 * decode uri
 * @param uri
 * @returns {*}
 */
function decodeURI(uri){
  try {
    return decodeURIComponent(uri);
  } catch (err) {
    return -1;
  }
}

/**
 * converts a number to a string with
 * a given amount of leading characters.
 * @param {number} number Number to convert.
 * @param {number} width Amount of leading characters to prepend.
 * @param {string} [padding = '0'] leading character.
 * @throws Error
 * @returns {string}
 */
function pad(number, width, padding){
  // Convert number to string.
  var string = number.toString();

  // Return either the original number as string,
  // or the number with leading padding characters.
  if (!width || string.length >= width) {
    return string;
  }

  var leadingCharacters = new Array(width - string.length + 1).join(padding || '0');

  return leadingCharacters + string;
}

/**
 * Fengine
 * @param options
 * @constructor
 */
function Fengine(options){
  this.options = options;

  this.run();
}

/**
 *
 * @type {{
 *   dir: Fengine.dir,
 *   error: Fengine.error,
 *   log: Fengine.log,
 *   run: Fengine.run
 * }}
 */
Fengine.prototype = {
  dir: function (files, dir){
    var parent = util.normalize(path.join(dir, '../'));
    var html = '<!DOCTYPE html>\n'
      + '\n'
      + '  \n'
      + '    <meta name="renderer" content="webkit"/>\n'
      + '    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>\n'
      + '    <meta content="text/html; charset=utf-8" http-equiv="content-type"/>\n'
      + '    <title>' + dir + '</title>\n'
      + '    \n'
      + '  \n'
      + '  \n'
      + '
\n'
      + '
' + dir + '
  —\n'
      + '
up
\n'
      + '
\n';

    var width = (files.length + 1).toString().length;

    // + pad(++index, width) + ': '

    files.forEach(function (file, index){
      var href = dir + file;

      html += ''
        + '
\n'
        + '      ' + pad(++index, width) + ':'
        + '      ' + file + '
\n'
        + '
\n';
    });

    html += '  \n'
      + '\n';

    return html;
  },
  error: function (response, statusCode, next){
    var html = '<!DOCTYPE html>\n'
      + '\n'
      + '  \n'
      + '    <meta name="renderer" content="webkit"/>\n'
      + '    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>\n'
      + '    <meta content="text/html; charset=utf-8" http-equiv="content-type"/>\n'
      + '    <title>' + statusCode + '</title>\n'
      + '    \n'
      + '  \n'
      + '  \n'
      + '
' + statusCode + '
\n'
      + '
' + http.STATUS_CODES[statusCode] + '
\n'
      + '  \n'
      + '\n';

    if (util.fn(next)) {
      next(html);
    } else {
      response.statusCode = statusCode;

      response.setHeader('Content-Type', 'text/html; charset=UTF-8');
      response.end(html);
    }
  },
  log: function (data){
    var date = dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss');
    var message = colors.green.bold('[' + date + '] ');

    switch (data.type) {
      case LOGLEVELS.INFO:
        message += colors.cyan.bold(data.message);
        break;
      case LOGLEVELS.WARN:
        message += colors.yellow.bold(data.message);
        break;
      case LOGLEVELS.ERROR:
        message += colors.red.bold(data.message);
        break;
    }

    // log
    console.log(message);
  },
  send: function (requset, response, pathname){
    var context = this;
    var options = context.options;

    var send = new FileSend(requset, {
      root: options.root
    }).on('error', function (error, next){
      context.error(response, error.statusCode, next);
    }).on('dir', function (realpath, stats, next){
      // set Content-Type
      send.setHeader('Content-Type', 'text/html; charset=UTF-8');

      // read dir
      fs.readdir(realpath, function (error, files){
        if (error) {
          send.statError(response, error);
        } else {
          // response
          next(context.dir(files, pathname));
        }
      });
    }).pipe(response);

    return send;
  },
  transform: function (pathname, source, response){
    var context = this;
    var options = context.options;

    response.statusCode = 200;

    response.setHeader('Content-Type', 'text/html');

    // transform
    var transform = new Transform(pathname, source, {
      root: options.base,
      data: options.data,
      layout: options.layout,
      delimiter: options.delimiter
    });

    // data
    transform.on('data', function (data){
      response.write(data);
    });

    // error
    transform.on('error', function (event, file, command){
      var type;
      var message;

      switch (event) {
        case 'circle':
          type = 'warn';
          message = 'Found cyclic command \''
            + command + '\'\n  at file: /'
            + util.normalize(path.relative(options.root, file.src));
          break;
        case 'io':
          type = 'error';

          if (command) {
            message = 'File of command \''
              + command + '\' does not exist\n  at file: /'
              + util.normalize(path.relative(options.root, file.src));
          } else {
            message = 'The default layout file does not exist';
          }
          break;
      }

      // send message
      process.send({
        type: type,
        message: message
      })
    });

    // end
    transform.on('end', function (){
      response.end();
    });
  },
  run: function (){
    var context = this;
    var options = context.options;

    if (cluster.isMaster) {
      // worker
      var worker;

      // create thread
      for (var i = 0; i < NUMCPUS; i++) {
        // fork
        worker = cluster.fork();

        // listen event
        worker.on('message', context.log);
      }
    } else {
      // create server
      var server = http.createServer(function (requset, response){
        var parsed = requset.url;

        if (parsed === -1 || ~parsed.indexOf('\0')) {
          return context.error(response, 400);
        }

        parsed = url.parse(decodeURI(requset.url));

        var pathname = parsed.pathname;
        var extname = path.extname(pathname).toLowerCase();

        switch (extname) {
          case '.htm':
          case '.html':
            pathname = path.join(options.root, pathname);

            if (isOutBound(pathname, CWD)) {
              return context.error(response, 403);
            }

            if (!/^[.]+[/\\]/.test(path.relative(options.base, pathname))) {
              fs.readFile(pathname, function (error, source){
                if (error) {
                  return context.error(response, 404);
                }

                context.transform(pathname, source, response);
              });
            } else {
              context.send(requset, response, pathname);
            }
            break;
          default:
            if (pathname.toLowerCase() === '/favicon.ico') {
              pathname = path.join(options.root, pathname);

              fs.lstat(pathname, function (error){
                if (error) {
                  response.statusCode = 200;

                  response.setHeader('Content-Type', 'image/x-icon');
                  response.setHeader('Content-Length', FAVICONSIZE);

                  return fs.createReadStream(FAVICON).pipe(response);
                }

                context.send(requset, response, pathname);
              });
            } else {
              context.send(requset, response, pathname);
            }
            break;
        }
      });

      // start listening
      server.on('listening', function (){
        var server = this.address();

        options.data.server = server.address + ':' + server.port;

        // message
        process.send({
          type: 'info',
          message: 'Server thread ' + cluster.worker.id + ' runing at: ' + server.address + ':' + server.port
        });
      });

      // error
      server.on('error', function (error){
        // message
        process.send({
          type: 'error',
          message: 'Server thread ' + cluster.worker.id + ' failed to start: ' + error.message
        });

        // exit
        process.exit();
      });

      // close
      server.on('close', function (){
        // message
        process.send({
          type: 'info',
          message: 'Server thread ' + cluster.worker.id + ' closed'
        });

        // exit
        process.exit();
      });

      // listen
      server.listen(options.port, options.hostname);

      // return
      return server;
    }
  }
};

// exports
module.exports = Fengine;
<commit_msg>improve code<commit_after>/*!
 * fengine
 * Version: 0.0.1
 * Date: 2016/8/2
 * https://github.com/Nuintun/fengine
 *
 * This is licensed under the MIT License (MIT).
 * For details, see: https://github.com/Nuintun/fengine/blob/master/LICENSE
 */

'use strict';

// lib
var os = require('os');
var fs = require('fs');
var url = require('url');
var path = require('path');
var http = require('http');
var util = require('./util');
var colors = require('colors');
var cluster = require('cluster');
var FileSend = require('file-send');
var Transform = require('./transform');

// variable declaration
var CWD = process.cwd();
var NUMCPUS = os.cpus().length;
var LOGLEVELS = {
  INFO: 'info',
  WARN: 'warn',
  ERROR: 'error'
};
var FAVICON = path.join(__dirname, '../favicon.ico');
var FAVICONSIZE = fs.lstatSync(FAVICON).size;

/**
 * date format
 * @param date
 * @param format
 * @returns {*}
 */
function dateFormat(date, format){
  if (!date instanceof Date) {
    throw new TypeError('param date must be a date.');
  }

  format = format || 'yyyy-MM-dd hh:mm:ss';

  var map = {
    'M': date.getMonth() + 1, // month
    'd': date.getDate(), // date
    'h': date.getHours(), // hours
    'm': date.getMinutes(), // minutes
    's': date.getSeconds(), // seconds
    'q': Math.floor((date.getMonth() + 3) / 3), // quarter
    'S': date.getMilliseconds() // milliseconds
  };

  format = format.replace(/([yMdhmsqS])+/g, function (all, t){
    var v = map[t];

    if (v !== undefined) {
      if (all.length > 1) {
        v = '0' + v;
        v = v.substr(v.length - 2);
      }

      return v;
    } else if (t === 'y') {
      return (date.getFullYear() + '').substr(4 - all.length);
    }

    return all;
  });

  return format;
}

/**
 * is out bound
 * @param path
 * @param root
 * @returns {boolean}
 */
function isOutBound(path, root){
  if (process.platform === 'win32') {
    path = path.toLowerCase();
    root = root.toLowerCase();
  }

  if (path.length < root.length) {
    return true;
  }

  return path.indexOf(root) !== 0;
}

/**
 * decode uri
 * @param uri
 * @returns {*}
 */
function decodeURI(uri){
  try {
    return decodeURIComponent(uri);
  } catch (err) {
    return -1;
  }
}

/**
 * converts a number to a string with
 * a given amount of leading characters.
 * @param {number} number Number to convert.
 * @param {number} width Amount of leading characters to prepend.
 * @param {string} [padding = '0'] leading character.
 * @throws Error
 * @returns {string}
 */
function pad(number, width, padding){
  // Convert number to string.
  var string = number.toString();

  // Return either the original number as string,
  // or the number with leading padding characters.
  if (!width || string.length >= width) {
    return string;
  }

  var leadingCharacters = new Array(width - string.length + 1).join(padding || '0');

  return leadingCharacters + string;
}

/**
 * Fengine
 * @param options
 * @constructor
 */
function Fengine(options){
  this.options = options;

  this.run();
}

/**
 *
 * @type {{
 *   dir: Fengine.dir,
 *   error: Fengine.error,
 *   log: Fengine.log,
 *   run: Fengine.run
 * }}
 */
Fengine.prototype = {
  dir: function (files, dir){
    var parent = util.normalize(path.join(dir, '../'));
    var html = '<!DOCTYPE html>\n'
      + '\n'
      + '  \n'
      + '    <meta name="renderer" content="webkit"/>\n'
      + '    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>\n'
      + '    <meta content="text/html; charset=utf-8" http-equiv="content-type"/>\n'
      + '    <title>' + dir + '</title>\n'
      + '    \n'
      + '  \n'
      + '  \n'
      + '
\n'
      + '
' + dir + '
  —\n'
      + '
up
\n'
      + '
\n';

    var width = (files.length + 1).toString().length;

    // + pad(++index, width) + ': '

    files.forEach(function (file, index){
      var href = dir + file;

      html += ''
        + '
\n'
        + '      ' + pad(++index, width) + ':'
        + '      ' + file + '
\n'
        + '
\n';
    });

    html += '  \n'
      + '\n';

    return html;
  },
  error: function (response, statusCode, next){
    var html = '<!DOCTYPE html>\n'
      + '\n'
      + '  \n'
      + '    <meta name="renderer" content="webkit"/>\n'
      + '    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>\n'
      + '    <meta content="text/html; charset=utf-8" http-equiv="content-type"/>\n'
      + '    <title>' + statusCode + '</title>\n'
      + '    \n'
      + '  \n'
      + '  \n'
      + '
' + statusCode + '
\n'
      + '
' + http.STATUS_CODES[statusCode] + '
\n'
      + '  \n'
      + '\n';

    if (util.fn(next)) {
      next(html);
    } else {
      response.statusCode = statusCode;

      response.setHeader('Content-Type', 'text/html; charset=UTF-8');
      response.end(html);
    }
  },
  log: function (data){
    var date = dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss');
    var message = colors.green.bold('[' + date + '] ');

    switch (data.type) {
      case LOGLEVELS.INFO:
        message += colors.cyan.bold(data.message);
        break;
      case LOGLEVELS.WARN:
        message += colors.yellow.bold(data.message);
        break;
      case LOGLEVELS.ERROR:
        message += colors.red.bold(data.message);
        break;
    }

    // log
    console.log(message);
  },
  send: function (requset, response, pathname){
    var context = this;
    var options = context.options;

    // file send
    var send = new FileSend(requset, {
      root: options.root
    }).on('error', function (error, next){
      context.error(response, error.statusCode, next);
    }).on('dir', function (realpath, stats, next){
      // set Content-Type
      send.setHeader('Content-Type', 'text/html; charset=UTF-8');

      // read dir
      fs.readdir(realpath, function (error, files){
        if (error) {
          send.statError(response, error);
        } else {
          // response
          next(context.dir(files, pathname));
        }
      });
    }).pipe(response);

    // send
    return send;
  },
  transform: function (pathname, source, response){
    var context = this;
    var options = context.options;

    // set status code
    response.statusCode = 200;

    // set Content-Type
    response.setHeader('Content-Type', 'text/html');

    // transform
    var transform = new Transform(pathname, source, {
      root: options.base,
      data: options.data,
      layout: options.layout,
      delimiter: options.delimiter
    });

    // data
    transform.on('data', function (data){
      response.write(data);
    });

    // error
    transform.on('error', function (event, file, command){
      var type;
      var message;

      switch (event) {
        case 'circle':
          type = 'warn';
          message = 'Found cyclic command \''
            + command + '\'\n  at file: /'
            + util.normalize(path.relative(options.root, file.src));
          break;
        case 'io':
          type = 'error';

          if (command) {
            message = 'File of command \''
              + command + '\' does not exist\n  at file: /'
              + util.normalize(path.relative(options.root, file.src));
          } else {
            message = 'The default layout file does not exist';
          }
          break;
      }

      // send message
      process.send({
        type: type,
        message: message
      })
    });

    // end
    transform.on('end', function (){
      response.end();
    });

    // transform
    return transform;
  },
  run: function (){
    var context = this;
    var options = context.options;

    // master thread
    if (cluster.isMaster) {
      // worker
      var worker;

      // create thread
      for (var i = 0; i < NUMCPUS; i++) {
        // fork
        worker = cluster.fork();

        // listen event
        worker.on('message', context.log);
      }
    } else {
      // create server
      var server = http.createServer(function (requset, response){
        var parsed = requset.url;

        if (parsed === -1 || ~parsed.indexOf('\0')) {
          return context.error(response, 400);
        }

        parsed = url.parse(decodeURI(requset.url));

        var pathname = parsed.pathname;
        var extname = path.extname(pathname).toLowerCase();

        switch (extname) {
          case '.htm':
          case '.html':
            pathname = path.join(options.root, pathname);

            if (isOutBound(pathname, CWD)) {
              return context.error(response, 403);
            }

            if (!/^[.]+[/\\]/.test(path.relative(options.base, pathname))) {
              fs.readFile(pathname, function (error, source){
                if (error) {
                  return context.error(response, 404);
                }

                context.transform(pathname, source, response);
              });
            } else {
              context.send(requset, response, pathname);
            }
            break;
          default:
            if (pathname.toLowerCase() === '/favicon.ico') {
              pathname = path.join(options.root, pathname);

              fs.lstat(pathname, function (error){
                if (error) {
                  response.statusCode = 200;

                  response.setHeader('Content-Type', 'image/x-icon');
                  response.setHeader('Content-Length', FAVICONSIZE);

                  return fs.createReadStream(FAVICON).pipe(response);
                }

                context.send(requset, response, pathname);
              });
            } else {
              context.send(requset, response, pathname);
            }
            break;
        }
      });

      // start listening
      server.on('listening', function (){
        var server = this.address();

        options.data.server = server.address + ':' + server.port;

        // message
        process.send({
          type: 'info',
          message: 'Server thread ' + cluster.worker.id + ' runing at: ' + server.address + ':' + server.port
        });
      });

      // error
      server.on('error', function (error){
        // message
        process.send({
          type: 'error',
          message: 'Server thread ' + cluster.worker.id + ' failed to start: ' + error.message
        });

        // exit
        process.exit();
      });

      // close
      server.on('close', function (){
        // message
        process.send({
          type: 'info',
          message: 'Server thread ' + cluster.worker.id + ' closed'
        });

        // exit
        process.exit();
      });

      // listen
      server.listen(options.port, options.hostname);

      // return
      return server;
    }
  }
};

// exports
module.exports = Fengine;
<|endoftext|>


<commit_before>var formatRelativeLocale = {
  lastWeek: "'el' eeee 'pasado a la' LT",
  yesterday: "'ayer a la' p",
  today: "'hoy a la' p",
  tomorrow: "'mañana a la' p",
  nextWeek: "eeee 'a la' p",
  other: 'P'
}

var formatRelativeLocalePlural = {
  lastWeek: "'el' eeee 'pasado a las' p",
  yesterday: "'ayer a las' p",
  today: "'hoy a las' p",
  tomorrow: "'mañana a las' p",
  nextWeek: "eeee 'a las' p",
  other: 'P'
}

export default function formatRelative (token, date, baseDate, options) {
  if (date.getHours() !== 1) {
    return formatRelativeLocalePlural[token]
  }
  return formatRelativeLocale[token]
}
<commit_msg>Use getISOHours in Spanish locale (closes #884) (#900)<commit_after>var formatRelativeLocale = {
  lastWeek: "'el' eeee 'pasado a la' LT",
  yesterday: "'ayer a la' p",
  today: "'hoy a la' p",
  tomorrow: "'mañana a la' p",
  nextWeek: "eeee 'a la' p",
  other: 'P'
}

var formatRelativeLocalePlural = {
  lastWeek: "'el' eeee 'pasado a las' p",
  yesterday: "'ayer a las' p",
  today: "'hoy a las' p",
  tomorrow: "'mañana a las' p",
  nextWeek: "eeee 'a las' p",
  other: 'P'
}

export default function formatRelative (token, date, baseDate, options) {
  if (date.getUTCHours() !== 1) {
    return formatRelativeLocalePlural[token]
  }
  return formatRelativeLocale[token]
}
<|endoftext|>


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

function fix_pathes(files){
	return files.map(function(f){
		var p = f.replace(/\//g, '\\');
		return p.indexOf(' ') >= 0 ? '"' + p + '"' : p;
	});
}

function resolve(patterns){
	if (!patterns) return [];

	// static files
	var files = patterns.filter(function(p){
		return p.indexOf('*') < 0;
	});

	patterns = patterns.filter(function(p){ return p.indexOf('*') >= 0; });

	var matches = _.flatten(patterns.map(function(p){
		return glob(p, {mark: true, sync: true});
	}));

	files = matches.concat(files);
	return iswin() ? fix_pathes(files) : files;
}

function exclude(all, items){
	if (items.length == 0) return all;

	items.forEach(function(it){
		var i = all.indexOf(it);
		if (i >= 0){
			all.splice(i, 1);
		}
	});

	return all;
}

module.exports = function(patterns){
	if (!patterns){
		return [];
	}
	if (typeof patterns == 'string'){
		patterns = [patterns];
	}
	patterns = patterns.filter(_.identity);

	var excludes = patterns.filter(function(p){ return p.charAt(0) == '!'; });
	var includes = patterns.filter(function(p){ return p.charAt(0) != '!'; });

	var all_files = resolve(includes);
	var excluded_files = resolve(excludes.map(function(s){ return s.substr(1); }));
	var files = exclude(all_files, excluded_files);

	// quick hack to remove duplicate AssemblyInfo.cs files
	var count = 0;
	return files.filter(function(file){
		var name = path.basename(file);
		if (name.toLowerCase() == "assemblyinfo.cs"){
			if (count > 0) return false;
			count++;
		}
		return true;
	});
};
<commit_msg>removed hack<commit_after>// TODO make as separate npm package
// TODO implement both async and sync versions
var	glob = require('glob'),
	iswin = require('iswin');

function fix_pathes(files){
	return files.map(function(f){
		var p = f.replace(/\//g, '\\');
		return p.indexOf(' ') >= 0 ? '"' + p + '"' : p;
	});
}

function resolve(patterns){
	if (!patterns) return [];

	// static files
	var files = patterns.filter(function(p){
		return p.indexOf('*') < 0;
	});

	patterns = patterns.filter(function(p){ return p.indexOf('*') >= 0; });

	var matches = _.flatten(patterns.map(function(p){
		return glob(p, {mark: true, sync: true});
	}));

	files = matches.concat(files);
	return iswin() ? fix_pathes(files) : files;
}

function exclude(all, items){
	if (items.length == 0) return all;

	items.forEach(function(it){
		var i = all.indexOf(it);
		if (i >= 0){
			all.splice(i, 1);
		}
	});

	return all;
}

module.exports = function(patterns){
	if (!patterns){
		return [];
	}
	if (typeof patterns == 'string'){
		patterns = [patterns];
	}
	patterns = patterns.filter(_.identity);

	var excludes = patterns.filter(function(p){ return p.charAt(0) == '!'; });
	var includes = patterns.filter(function(p){ return p.charAt(0) != '!'; });

	var all_files = resolve(includes);
	var excluded_files = resolve(excludes.map(function(s){ return s.substr(1); }));
	return exclude(all_files, excluded_files);
};
<|endoftext|>


<commit_before>"use strict";

/*global nodeca, _*/

// fetch and prepare users info
// fired after each controllers
// list of user id should be prepared in controller
nodeca.filters.after('', {weight: 50}, function inject_users(params, next) {
  var env = this,
      user_id_list, user_in_fields, result, UserModel;

  if (_.isArray(this.data.users) && this.data.users.length > 0) {

    // There can be some garbage:
    // - empty ids (just because we push data without checks)
    // - duplicated ids(the same users from different objects)
    //
    // We remove dummy elements, let mongo filter unique values,
    // because it's more fast.
    user_id_list = _.compact(this.data.users);

    env.extras.puncher.start('Users join', { count: user_id_list.length });

    result = this.response.data.users = {};

// uncomment to imitate empty users (to check template & speed)
//    env.extras.puncher.stop();
//    return next();

    UserModel = nodeca.models.users.User;

    user_in_fields = {
      '_id': 1,
      'id': 1,
      '_uname': 1,
      '_uname_short': 1,
    };
    UserModel
        .where('_id').in(user_id_list)
        .select()
        .setOptions({ lean: true }).exec(function(err, user_list){

      user_list.forEach(function(user){
        // only registered users can see full name
        if (env.session.guest) {
          user._uname = user._uname_short;
        }
        result[user._id] = user;
      });

      env.extras.puncher.stop();

      next();
    });
  }
  else {
    next();
  }
});
<commit_msg>fixed users fields filtering<commit_after>"use strict";

/*global nodeca, _*/

var user_in_fields = {
  '_id': 1,
  'id': 1,
  '_uname': 1,
  '_uname_short': 1
};

// fetch and prepare users info
// fired after each controllers
// list of user id should be prepared in controller
nodeca.filters.after('', {weight: 50}, function inject_users(params, next) {
  var env = this,
      user_id_list, result, UserModel;

  if (_.isArray(this.data.users) && this.data.users.length > 0) {

    // There can be some garbage:
    // - empty ids (just because we push data without checks)
    // - duplicated ids(the same users from different objects)
    //
    // We remove dummy elements, let mongo filter unique values,
    // because it's more fast.
    user_id_list = _.compact(this.data.users);

    env.extras.puncher.start('Users join', { count: user_id_list.length });

    result = this.response.data.users = {};

// uncomment to imitate empty users (to check template & speed)
//    env.extras.puncher.stop();
//    return next();

    UserModel = nodeca.models.users.User;

    UserModel
        .where('_id').in(user_id_list)
        .select(user_in_fields)
        .setOptions({ lean: true }).exec(function(err, user_list){

      user_list.forEach(function(user){
        // only registered users can see full name
        if (env.session.guest) {
          user._uname = user._uname_short;
        }
        result[user._id] = user;
      });

      env.extras.puncher.stop();

      next();
    });
  }
  else {
    next();
  }
});
<|endoftext|>


<commit_before>exports['nl2br'] = function(text) {
	return require('./runtime').escape(text).replace(/\n/g, "
");
}
exports['cdata'] = function(text) {
	return "<![CDATA[\n" + text + "\n]]>";
}
exports['markdown'] = exports['md'] = function(text) {
	var markdownLib;
	var markdownLibs = ['markdown', 'discount', 'markdown-js', 'marked'];
	for(var i in markdownLibs)
	{
		try {
			markdownLib = require(markdownLibs[i]);
		}
		catch(e) {}
	}
	if(markdownLib == null)
		throw new Error("Blade cannot find a markdown library. Please install one. (i.e. `npm install markdown`)");
	return markdownLib.parse(text);
};
exports['coffeescript'] = exports['cs'] = function(text) {
	return '';
};
exports['javascript'] = exports['js'] = function(text, opts) {
	opts = opts || {};
	try {
		var uglify = require('uglify-js');
		var ast = uglifyjs.parser.parse(text),
			ugly = uglifyjs.uglify;
			if(opts.minify)
			{
				ast = ugly.ast_mangle(ast);
				ast = ugly.ast_squeeze(ast);
			}
			text = ugly.gen_code(ast, {'beautify': !opts.minify});
	}
	catch(e) {}
	return '';
};
exports['stylus'] = cssTemplate('stylus');
exports['less'] = cssTemplate('less');
function cssTemplate(lib) {
	return function(text, opts) {
		opts = opts || {};
		var ret = '';
		require(lib).render(text, opts, function(err, css) {
				if(err) throw err;
				ret = '';
			});
		return ret;
	};
};
exports['sass'] = function(text) {
	return '';
};

//Disable variable interpolation for a few filters
var noInterpolate = ['cs', 'stylus', 'less', 'sass'];
for(var i in noInterpolate)
	exports[noInterpolate[i]].interpolate = false;
<commit_msg>Fixed a bug in the :javascript filter Should have created a test file<commit_after>exports['nl2br'] = function(text) {
	return require('./runtime').escape(text).replace(/\n/g, "
");
}
exports['cdata'] = function(text) {
	return "<![CDATA[\n" + text + "\n]]>";
}
exports['markdown'] = exports['md'] = function(text) {
	var markdownLib;
	var markdownLibs = ['markdown', 'discount', 'markdown-js', 'marked'];
	for(var i in markdownLibs)
	{
		try {
			markdownLib = require(markdownLibs[i]);
		}
		catch(e) {}
	}
	if(markdownLib == null)
		throw new Error("Blade cannot find a markdown library. Please install one. (i.e. `npm install markdown`)");
	return markdownLib.parse(text);
};
exports['coffeescript'] = exports['cs'] = function(text) {
	return '';
};
exports['javascript'] = exports['js'] = function(text, opts) {
	opts = opts || {};
	try {
		var uglify = require('uglify-js');
		var ast = uglifyjs.parser.parse(text),
			ugly = uglifyjs.uglify;
			if(opts.minify)
			{
				ast = ugly.ast_mangle(ast);
				ast = ugly.ast_squeeze(ast);
			}
			text = ugly.gen_code(ast, {'beautify': !opts.minify});
	}
	catch(e) {}
	return '';
};
exports['stylus'] = cssTemplate('stylus');
exports['less'] = cssTemplate('less');
function cssTemplate(lib) {
	return function(text, opts) {
		opts = opts || {};
		var ret = '';
		require(lib).render(text, opts, function(err, css) {
				if(err) throw err;
				ret = '';
			});
		return ret;
	};
};
exports['sass'] = function(text) {
	return '';
};

//Disable variable interpolation for a few filters
var noInterpolate = ['cs', 'stylus', 'less', 'sass'];
for(var i in noInterpolate)
	exports[noInterpolate[i]].interpolate = false;
<|endoftext|>


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

/*
 * This controller handles the landing page and the contents of the panels on that page.
 */
angular.module('gromitSample').controller('aController', function($scope, $http, $window) {

    $scope.alerts = [];
    $scope.showMessage = function() {
        $scope.alerts.push({
            type: 'success',
            msg: 'See... no extra pound sign'
        })
    };

    $scope.closeAlert = function(index) {
        $scope.alerts.splice(index, 1);
    };

});<commit_msg>Fixed a JSHint error.<commit_after>/*******************************************************************************
 *
 * Copyright 2016 Gromit Soft Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/
 'use strict';

/*
 * This controller handles the landing page and the contents of the panels on that page.
 */
angular.module('gromitSample').controller('aController', function($scope, $http, $window) {

    $scope.alerts = [];
    $scope.showMessage = function() {
        $scope.alerts.push({
            type: 'success',
            msg: 'See... no extra pound sign'
        });
    };

    $scope.closeAlert = function(index) {
        $scope.alerts.splice(index, 1);
    };

});<|endoftext|>


<commit_before>
var tools = require('./tools'),
    debug = require('debug')('crud-mongoose:findAll'),
    specials = [ 'limit', 'offset', 'skip', 'page', 'perPage', 'sortBy',
                 'fields' ];

module.exports = exports = findAll;

function findAll(Model, projection) {
  return function (data, query, callback) {
    var keys = {},
        cursor, sort, sort_split, field_split, i, fields;

    debug('original query - %j', query);

    // gather special keys
    for (i = 0; i < specials.length; i++) {
      if (query.hasOwnProperty(specials[i])) {
        if (specials[i] !== 'sortBy' && specials[i] !== 'fields')
          keys[specials[i]] = parseInt(query[specials[i]]);
        else keys[specials[i]] = query[specials[i]];
        delete query[specials[i]];
      }
    }

    debug('special query params %j', keys);
    debug('going to find %j', query);

    cursor = Model.find(query);

    // modifying cursor for provided keys
    if (keys.hasOwnProperty('page')) {
      keys.skip = keys.skip || 0;
      keys.perPage = keys.perPage;
      keys.skip += keys.page * keys.perPage;
      keys.limit = Math.min(keys.limit || Infinity, keys.perPage);
      debug('page - %s\tperPage - %s', keys.page, keys.perPage);
    }

    if (keys.hasOwnProperty('limit')) {
      debug('limiting to %d records', keys.limit);
      cursor.limit(keys.limit);
    }

    if (keys.hasOwnProperty('skip')) {
      debug('skipping %d records', keys.skip);
      cursor.skip(keys.skip);
    }

    if (keys.hasOwnProperty('sortBy')) {
      sort = {};
      sort_split = keys.sortBy.split(',');
      for (i = 0; i < sort_split.length; i++) {
        sort[sort_split[i].split(':')[0]] =
          sort_split[i].split(':')[1] || 'asc';
      }
      debug('sorting: %j', sort);
      cursor.sort(sort);
    }

    if (keys.hasOwnProperty('fields')) {
      field_split = keys.fields.split(',');
      fields = [];
      for (i = 0; i < field_split.length; i++) {
        if (!projection || ~projection.indexOf(field_split[i]))
          fields.push(field_split[i]);
      }
      if (fields.length == 0) fields = projection;
      debug('selecting fields %s', fields);
      cursor.select(fields.join(' '));
    } else if (projection) {
      debug('selecting fields %s', projection);
      cursor.select(projection.join(' '));
    }

    cursor.lean().exec(callback);
  }
}

<commit_msg>Remove offset<commit_after>
var tools = require('./tools'),
    debug = require('debug')('crud-mongoose:findAll'),
    specials = [ 'limit', 'skip', 'page', 'perPage', 'sortBy',
                 'fields' ];

module.exports = exports = findAll;

function findAll(Model, projection) {
  return function (data, query, callback) {
    var keys = {},
        cursor, sort, sort_split, field_split, i, fields;

    debug('original query - %j', query);

    // gather special keys
    for (i = 0; i < specials.length; i++) {
      if (query.hasOwnProperty(specials[i])) {
        if (specials[i] !== 'sortBy' && specials[i] !== 'fields')
          keys[specials[i]] = parseInt(query[specials[i]]);
        else keys[specials[i]] = query[specials[i]];
        delete query[specials[i]];
      }
    }

    debug('special query params %j', keys);
    debug('going to find %j', query);

    cursor = Model.find(query);

    // modifying cursor for provided keys
    if (keys.hasOwnProperty('page')) {
      keys.skip = keys.skip || 0;
      keys.perPage = keys.perPage;
      keys.skip += keys.page * keys.perPage;
      keys.limit = Math.min(keys.limit || Infinity, keys.perPage);
      debug('page - %s\tperPage - %s', keys.page, keys.perPage);
    }

    if (keys.hasOwnProperty('limit')) {
      debug('limiting to %d records', keys.limit);
      cursor.limit(keys.limit);
    }

    if (keys.hasOwnProperty('skip')) {
      debug('skipping %d records', keys.skip);
      cursor.skip(keys.skip);
    }

    if (keys.hasOwnProperty('sortBy')) {
      sort = {};
      sort_split = keys.sortBy.split(',');
      for (i = 0; i < sort_split.length; i++) {
        sort[sort_split[i].split(':')[0]] =
          sort_split[i].split(':')[1] || 'asc';
      }
      debug('sorting: %j', sort);
      cursor.sort(sort);
    }

    if (keys.hasOwnProperty('fields')) {
      field_split = keys.fields.split(',');
      fields = [];
      for (i = 0; i < field_split.length; i++) {
        if (!projection || ~projection.indexOf(field_split[i]))
          fields.push(field_split[i]);
      }
      if (fields.length == 0) fields = projection;
      debug('selecting fields %s', fields);
      cursor.select(fields.join(' '));
    } else if (projection) {
      debug('selecting fields %s', projection);
      cursor.select(projection.join(' '));
    }

    cursor.lean().exec(callback);
  }
}

<|endoftext|>


<commit_before>var concat = require('./concat')
var fold = require('./fold')
var is = require('is')

/**
 * Flatten an given `array` until `max` depth is reached.
 *
 * @param {Array} array
 * @param {max} max Max depth
 * @return {Array} Flattened Array
 */

function flatten (array, max) {
  max = (is.number(max)) ? max : Infinity
  return _flatten(max, array, 1)
}

module.exports = flatten

function _flatten (max, array, depth) {
  if (depth > max) return array
  return fold([], each, array)
}

function each (acc, element) {
  if (!is.array(element)) return concat(acc, element)
  return concat(acc, _flatten(max, element, depth + 1))
}
<commit_msg>flatten: nest fold for simplicity<commit_after>var concat = require('./concat')
var fold = require('./fold')
var is = require('is')

/**
 * Flatten an given `array` until `max` depth is reached.
 *
 * @param {Array} array
 * @param {max} max Max depth
 * @return {Array} Flattened Array
 */

function flatten (array, max) {
  max = (is.number(max)) ? max : Infinity
  return _flatten(max, array, 1)
}

module.exports = flatten

function _flatten (max, array, depth) {
  if (depth > max) return array
  return fold([], function (acc, element) {
    if (!is.array(element)) return concat(acc, element)
    return concat(acc, _flatten(max, element, depth + 1))
  }, array)
}
<|endoftext|>


<commit_before>'use strict';

const render = require('debug')('gameboy:gpu:render');
const control = require('debug')('gameboy:gpu:control');
const EventEmitter = require('events').EventEmitter;
const Canvas = require('../shims/canvas');
const { LCDC, SCY, SCX, WY, WX, BGP, OBP0, OBP1 } = require('../registers');

require('../util/number');

// Non CGB gray shades

const GRAY_SHADES = [];

GRAY_SHADES[0] = [255, 255, 255];
GRAY_SHADES[1] = [192, 192, 192];
GRAY_SHADES[2] = [96, 96, 96];
GRAY_SHADES[3] = [0, 0, 0];

const FRAME_WIDTH = 160;
const FRAME_HEIGHT = 144;

class Gpu extends EventEmitter {
    constructor (video) {
        super();
        this._video = video;

        // Registers

        this._lcdc = 0;
        this._scy = 0;
        this._scx = 0;
        this._wy = 0;
        this._wx = 0;
        this._bgp = 0;
        this._obp0 = 0;
        this._obp1 = 0;

        // Display

        this._bgpal = null;
        this._objpal = [];

        // Canvas

        this._canvas = new Canvas(FRAME_WIDTH, FRAME_HEIGHT);
        this._ctx = this._canvas.getContext('2d');
        this._image = this._ctx.getImageData(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
        this._data = this._image.data;
    }

    readByte (addr) {
        switch (addr) {
            case LCDC: return this._lcdc;
            case SCY: return this._scy;
            case SCX: return this._scx;
            case BGP: return this._bgp;
            case OBP0: return this._obp0;
            case OBP1: return this._obp1;
            case WY: return this._wy;
            case WX: return this._wx;
        }

        throw new Error(`unmapped address 0x${addr.toString(16)}`);
    }

    writeByte (addr, val) {
        switch (addr) {
            case LCDC: return this._lcdc = val;
            case SCY: return this._scy = val;
            case SCX: return this._scx = val;
            case BGP:
                this._bgpal = this._createPalette(val);
                return this._bgp = val;
            case OBP0:
                this._objpal[0] = this._createPalette(val);
                return this._obp0 = val;
            case OBP1:
                this._objpal[1] = this._createPalette(val);
                return this._obp1 = val;
            case WY: return this._wy = val;
            case WX: return this._wx = val;
        }

        throw new Error(`unmapped address 0x${addr.toString(16)}`);
    }

    drawLine (line) {
        const data = this._lcdc >> 4 & 1;

        // Background

        if (this._lcdc & 1) {
            const map = this._lcdc >> 3 & 1;
            this._drawBackground(line, this._scx, this._scy, map, data);
        }

        // Window

        if (this._lcdc & 0x20 && line >= this._wy) {
            const map = this._lcdc >> 6 & 1;
            this._drawWindow(line, this._wx - 7, this._wy, map, data);
        }

        // Sprites

        if (this._lcdc & 2) {
            this._drawSprites(line);
        }
    }

    render () {
        render('frame');

        // LCD Display Enable

        control('%s', this._lcdc.toString(2));

        if (this._lcdc & 0x80 == 0) {
            this._ctx.fillStyle = 'white';
            this._ctx.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
        }

        this._ctx.putImageData(this._image, 0, 0);
        this._ctx.drawImage(this._canvas, 0, 0);

        this.emit('frame', this._canvas);
    }

    _createPalette (palette) {
        return [
            GRAY_SHADES[palette & 3],
            GRAY_SHADES[palette >> 2 & 3],
            GRAY_SHADES[palette >> 4 & 3],
            GRAY_SHADES[palette >> 6 & 3]
        ];
    }

    _drawBackground (line, offsetX, offsetY, mapSelect, dataSelect) {
        const map = this._video.bgMap[mapSelect];
        const y = offsetY + line;

        for (let i = 0; i < FRAME_WIDTH; i++) {
            const x = offsetX + i;

            const col = (x & 0xff) >> 3;
            const row = (y & 0xff) >> 3;

            const n = map[row * 32 + col];
            const tile = this._video.tiles[dataSelect ? n : 256 + n.signed()];
            const shade = this._bgpal[tile[y & 7][x & 7]];

            let offset = (line * FRAME_WIDTH + i) * 4;

            this._data[offset] = shade[0];
            this._data[++offset] = shade[1];
            this._data[++offset] = shade[2];
            this._data[++offset] = 255;
        }
    }

    _drawWindow (line, posX, posY, mapSelect, dataSelect) {
        const map = this._video.bgMap[mapSelect];
        const y = line - posY;

        for (let i = posX; i < FRAME_WIDTH; i++) {
            const x = i - posX;

            const col = x >> 3;
            const row = y >> 3;

            const n = map[row * 32 + col];
            const tile = this._video.tiles[dataSelect ? n : 256 + n.signed()];
            const shade = this._bgpal[tile[y & 7][x & 7]];

            let offset = (line * FRAME_WIDTH + i) * 4;

            this._data[offset] = shade[0];
            this._data[++offset] = shade[1];
            this._data[++offset] = shade[2];
            this._data[++offset] = 255;
        }
    }

    _drawSprites (line) {
        const height = this._lcdc & 4 ? 16 : 8;
        let count = 0;

        const sprites = this._video.sprites.sort((a, b) => a[1] - b[1]);
        for (let i = sprites.length - 1; i > -1; i--) {
            const sprite = sprites[i];

            // Position

            const sy = sprite[0] - 16;
            const sx = sprite[1] - 8;

            if (!(line >= sy && line < sy + height)) continue;
            if (sx >= FRAME_WIDTH || sy >= FRAME_HEIGHT) continue;
            if (++count > 10) continue;

            // Tile/Pattern Number

            const n = this._lcdc & 4 ? sprite[2] & 0xfe : sprite[2];

            // Attributes/Flags

            const attrs = sprite[3];

            const priority = attrs >> 7 & 1;
            const yflip = attrs >> 6 & 1;
            const xflip = attrs >> 5 & 1;
            const palette = this._objpal[attrs >> 4 & 1];

            // Draw

            const py = yflip ? (height - 1) - (line - sy) : line - sy;
            const data = this._data;

            for (let x = sx; x < sx + 8; x++) {
                if (x < 0) continue;

                const offset = (line * FRAME_WIDTH + x) * 4;

                if (priority &&
                    data[offset + 0] != 255 &&
                    data[offset + 1] != 255 &&
                    data[offset + 2] != 255
                ) continue;

                const tile = this._video.tiles[n + (py >> 3 & 1)];
                const color = tile[py & 7][xflip ? 7 - (x - sx) : x - sx];
                if (color == 0) continue;

                const shade = palette[color];

                data[offset + 0] = shade[0];
                data[offset + 1] = shade[1];
                data[offset + 2] = shade[2];
                data[offset + 3] = 255;
            }
        };
    }
}

module.exports = Gpu;
<commit_msg>revert sprite priorities<commit_after>'use strict';

const render = require('debug')('gameboy:gpu:render');
const control = require('debug')('gameboy:gpu:control');
const EventEmitter = require('events').EventEmitter;
const Canvas = require('../shims/canvas');
const { LCDC, SCY, SCX, WY, WX, BGP, OBP0, OBP1 } = require('../registers');

require('../util/number');

// Non CGB gray shades

const GRAY_SHADES = [];

GRAY_SHADES[0] = [255, 255, 255];
GRAY_SHADES[1] = [192, 192, 192];
GRAY_SHADES[2] = [96, 96, 96];
GRAY_SHADES[3] = [0, 0, 0];

const FRAME_WIDTH = 160;
const FRAME_HEIGHT = 144;

class Gpu extends EventEmitter {
    constructor (video) {
        super();
        this._video = video;

        // Registers

        this._lcdc = 0;
        this._scy = 0;
        this._scx = 0;
        this._wy = 0;
        this._wx = 0;
        this._bgp = 0;
        this._obp0 = 0;
        this._obp1 = 0;

        // Display

        this._bgpal = null;
        this._objpal = [];

        // Canvas

        this._canvas = new Canvas(FRAME_WIDTH, FRAME_HEIGHT);
        this._ctx = this._canvas.getContext('2d');
        this._image = this._ctx.getImageData(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
        this._data = this._image.data;
    }

    readByte (addr) {
        switch (addr) {
            case LCDC: return this._lcdc;
            case SCY: return this._scy;
            case SCX: return this._scx;
            case BGP: return this._bgp;
            case OBP0: return this._obp0;
            case OBP1: return this._obp1;
            case WY: return this._wy;
            case WX: return this._wx;
        }

        throw new Error(`unmapped address 0x${addr.toString(16)}`);
    }

    writeByte (addr, val) {
        switch (addr) {
            case LCDC: return this._lcdc = val;
            case SCY: return this._scy = val;
            case SCX: return this._scx = val;
            case BGP:
                this._bgpal = this._createPalette(val);
                return this._bgp = val;
            case OBP0:
                this._objpal[0] = this._createPalette(val);
                return this._obp0 = val;
            case OBP1:
                this._objpal[1] = this._createPalette(val);
                return this._obp1 = val;
            case WY: return this._wy = val;
            case WX: return this._wx = val;
        }

        throw new Error(`unmapped address 0x${addr.toString(16)}`);
    }

    drawLine (line) {
        const data = this._lcdc >> 4 & 1;

        // Background

        if (this._lcdc & 1) {
            const map = this._lcdc >> 3 & 1;
            this._drawBackground(line, this._scx, this._scy, map, data);
        }

        // Window

        if (this._lcdc & 0x20 && line >= this._wy) {
            const map = this._lcdc >> 6 & 1;
            this._drawWindow(line, this._wx - 7, this._wy, map, data);
        }

        // Sprites

        if (this._lcdc & 2) {
            this._drawSprites(line);
        }
    }

    render () {
        render('frame');

        // LCD Display Enable

        control('%s', this._lcdc.toString(2));

        if (this._lcdc & 0x80 == 0) {
            this._ctx.fillStyle = 'white';
            this._ctx.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
        }

        this._ctx.putImageData(this._image, 0, 0);
        this._ctx.drawImage(this._canvas, 0, 0);

        this.emit('frame', this._canvas);
    }

    _createPalette (palette) {
        return [
            GRAY_SHADES[palette & 3],
            GRAY_SHADES[palette >> 2 & 3],
            GRAY_SHADES[palette >> 4 & 3],
            GRAY_SHADES[palette >> 6 & 3]
        ];
    }

    _drawBackground (line, offsetX, offsetY, mapSelect, dataSelect) {
        const map = this._video.bgMap[mapSelect];
        const y = offsetY + line;

        for (let i = 0; i < FRAME_WIDTH; i++) {
            const x = offsetX + i;

            const col = (x & 0xff) >> 3;
            const row = (y & 0xff) >> 3;

            const n = map[row * 32 + col];
            const tile = this._video.tiles[dataSelect ? n : 256 + n.signed()];
            const shade = this._bgpal[tile[y & 7][x & 7]];

            let offset = (line * FRAME_WIDTH + i) * 4;

            this._data[offset] = shade[0];
            this._data[++offset] = shade[1];
            this._data[++offset] = shade[2];
            this._data[++offset] = 255;
        }
    }

    _drawWindow (line, posX, posY, mapSelect, dataSelect) {
        const map = this._video.bgMap[mapSelect];
        const y = line - posY;

        for (let i = posX; i < FRAME_WIDTH; i++) {
            const x = i - posX;

            const col = x >> 3;
            const row = y >> 3;

            const n = map[row * 32 + col];
            const tile = this._video.tiles[dataSelect ? n : 256 + n.signed()];
            const shade = this._bgpal[tile[y & 7][x & 7]];

            let offset = (line * FRAME_WIDTH + i) * 4;

            this._data[offset] = shade[0];
            this._data[++offset] = shade[1];
            this._data[++offset] = shade[2];
            this._data[++offset] = 255;
        }
    }

    _drawSprites (line) {
        const height = this._lcdc & 4 ? 16 : 8;
        let count = 0;

        const sprites = this._video.sprites;
        for (let i = 0; i < sprites.length; i++) {
            const sprite = sprites[i];

            // Position

            const sy = sprite[0] - 16;
            const sx = sprite[1] - 8;

            if (!(line >= sy && line < sy + height)) continue;
            if (sx >= FRAME_WIDTH || sy >= FRAME_HEIGHT) continue;
            if (count++ > 9) continue;

            // Tile/Pattern Number

            const n = this._lcdc & 4 ? sprite[2] & 0xfe : sprite[2];

            // Attributes/Flags

            const attrs = sprite[3];

            const priority = attrs >> 7 & 1;
            const yflip = attrs >> 6 & 1;
            const xflip = attrs >> 5 & 1;
            const palette = this._objpal[attrs >> 4 & 1];

            // Draw

            const py = yflip ? (height - 1) - (line - sy) : line - sy;
            const data = this._data;

            for (let x = sx; x < sx + 8; x++) {
                if (x < 0) continue;

                const offset = (line * FRAME_WIDTH + x) * 4;

                if (priority &&
                    data[offset + 0] != 255 &&
                    data[offset + 1] != 255 &&
                    data[offset + 2] != 255
                ) continue;

                const tile = this._video.tiles[n + (py >> 3 & 1)];
                const color = tile[py & 7][xflip ? 7 - (x - sx) : x - sx];
                if (color == 0) continue;

                const shade = palette[color];

                data[offset + 0] = shade[0];
                data[offset + 1] = shade[1];
                data[offset + 2] = shade[2];
                data[offset + 3] = 255;
            }
        };
    }
}

module.exports = Gpu;
<|endoftext|>


<commit_before>'use strict';

var _ = require('underscore');
var async = require('async');
var fs = require('fs');
var glob = require('glob');
var path = require('path');
var GraphWrapper = require('./graph-wrapper');
var QueryWrapper = require('./query-wrapper');
var PipelineWrapper = require('./pipeline-wrapper');

var Gremlin = module.exports = function(opts) {
    var java = require('java');

    opts = opts || {};
    opts.options = opts.options || [];
    opts.classpath = opts.classpath || [];

    //add default globbed lib/**/*.jar classpath
    opts.classpath.push(path.join(__dirname, '..', 'target', '**', '*.jar'));

    //add options
    java.options.push('-Djava.awt.headless=true');
    for (var i = 0; i < opts.options.length; i++) {
        java.options.push(opts.options[i]);
    }

    //add jar files
    for (var i = 0; i < opts.classpath.length; i++) {
        var pattern = opts.classpath[i];
        var filenames = glob.sync(pattern);
        for (var j = 0; j < filenames.length; j++) {
            java.classpath.push(filenames[j]);
        }
    }

    var GremlinGroovyScriptEngine = java.import('com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine');
    var GremlinPipeline = java.import('com.tinkerpop.gremlin.groovy.GremlinGroovyPipeline');
    var NULL = java.callStaticMethodSync('org.codehaus.groovy.runtime.NullObject', 'getNullObject');

    var JSONResultConverter = java.import('com.tinkerpop.rexster.gremlin.converter.JSONResultConverter');
    var JSONObject = java.import('org.json.JSONObject');
    var JSONArray = java.import('org.json.JSONArray');

    var Class = java.import('java.lang.Class');
    var ArrayList = java.import('java.util.ArrayList');
    var HashMap = java.import('java.util.HashMap');
    var Table = java.import('com.tinkerpop.pipes.util.structures.Table');
    var Tree = java.import('com.tinkerpop.pipes.util.structures.Tree');

    var Direction = java.import('com.tinkerpop.blueprints.Direction');
    var Tokens = java.import('com.tinkerpop.gremlin.Tokens$T');
    var Compare = java.import('com.tinkerpop.blueprints.Compare');
    var Contains = java.import('com.tinkerpop.blueprints.Contains');

    var ClassTypes = {
        'String': { 'class': Class.forNameSync('java.lang.String') },
        'Vertex': { 'class': java.getClassLoader().loadClassSync('com.tinkerpop.blueprints.Vertex') },
        'Edge': { 'class': java.getClassLoader().loadClassSync('com.tinkerpop.blueprints.Edge') },
        'Byte': { 'class': Class.forNameSync('java.lang.Byte') },
        'Character': { 'class': Class.forNameSync('java.lang.Character') },
        'Double': { 'class': Class.forNameSync('java.lang.Double') },
        'Float': { 'class': Class.forNameSync('java.lang.Float') },
        'Integer': { 'class': Class.forNameSync('java.lang.Integer') },
        'Long': { 'class': Class.forNameSync('java.lang.Long') },
        'Short': { 'class': Class.forNameSync('java.lang.Short') },
        'Number': { 'class': Class.forNameSync('java.lang.Number') },
        'BigDecimal': { 'class': Class.forNameSync('java.math.BigDecimal') },
        'BigInteger': { 'class': Class.forNameSync('java.math.BigInteger') }
    };

    var MAX_VALUE = java.newInstanceSync('java.lang.Long', 2147483647);
    var MIN_VALUE = 0;
    var _JSON = new JSONResultConverter(null, MIN_VALUE, MAX_VALUE, null);

    function isType(o, typeName) {
        if (!o._isType) {
            o._isType = {};
        }
        var res = o._isType[typeName];
        if (res === undefined) {
            try {
                res = java.instanceOf(o, typeName);
            } catch(err) {
                res = false;
            }
            o._isType[typeName] = res;
        }
        return res;
    }

    function toList(obj, callback) {
        if (_.isArray(obj)) {
            var list = new ArrayList();
            for (var i = 0; i < obj.length; i++) {
                list.addSync(obj[i]);
            }
            return callback(null, list);
        }
        if (obj.getClassSync().isArraySync()) {
            java.callStaticMethod('java.util.Arrays', 'asList', obj, callback);
            return;
        }
        java.callStaticMethod('com.google.common.collect.Lists', 'newArrayList', obj, callback);
    }

    function toListSync(obj) {
        if (_.isArray(obj)) {
            var list = new ArrayList();
            for (var i = 0; i < obj.length; i++) {
                list.addSync(obj[i]);
            }
            return list;
        }
        if (obj.getClassSync().isArraySync()) {
            return java.callStaticMethodSync('java.util.Arrays', 'asList', obj);
        }
        return java.callStaticMethodSync('com.google.common.collect.Lists', 'newArrayList', obj);
    }

    function toJSON(obj, callback) {
        _JSON.convert(obj, function(err, json) {
            if (err) return callback(err);
            try {
                json = JSON.parse(json.toString());
            } catch (e) {
                return callback(e);
            }
            return callback(null, json);
        });
    }

    function toJSONSync(obj) {
        var json = _JSON.convertSync(obj);
        json = JSON.parse(json.toString());
        return json;
    }

    function getEngine() {
        if (getEngine.engine) {
            return getEngine.engine;
        }
        getEngine.engine = new GremlinGroovyScriptEngine();
        return getEngine.engine;
    }

    function wrap(graph) {
        return new GraphWrapper(this, graph);
    }

    return {
        GremlinPipeline: GremlinPipeline,
        NULL: NULL,
        GraphWrapper: GraphWrapper,
        PipelineWrapper: PipelineWrapper,
        QueryWrapper: QueryWrapper,
        java: java,
        ClassTypes: ClassTypes,
        Tokens: Tokens,
        Compare: Compare,
        Contains: Contains,
        Direction: Direction,
        ArrayList: ArrayList,
        HashMap: HashMap,
        Table: Table,
        Tree: Tree,
        isType: isType,
        toList: toList,
        toListSync: toListSync,
        toJSON: toJSON,
        toJSONSync: toJSONSync,
        getEngine: getEngine,
        wrap: wrap
    };
};
<commit_msg> - get rid of strict warning<commit_after>'use strict';

var _ = require('underscore');
var async = require('async');
var fs = require('fs');
var glob = require('glob');
var path = require('path');
var GraphWrapper = require('./graph-wrapper');
var QueryWrapper = require('./query-wrapper');
var PipelineWrapper = require('./pipeline-wrapper');

var Gremlin = module.exports = function(opts) {
    var self = this;
    var java = require('java');

    opts = opts || {};
    opts.options = opts.options || [];
    opts.classpath = opts.classpath || [];

    //add default globbed lib/**/*.jar classpath
    opts.classpath.push(path.join(__dirname, '..', 'target', '**', '*.jar'));

    //add options
    java.options.push('-Djava.awt.headless=true');
    for (var i = 0; i < opts.options.length; i++) {
        java.options.push(opts.options[i]);
    }

    //add jar files
    for (var i = 0; i < opts.classpath.length; i++) {
        var pattern = opts.classpath[i];
        var filenames = glob.sync(pattern);
        for (var j = 0; j < filenames.length; j++) {
            java.classpath.push(filenames[j]);
        }
    }

    var GremlinGroovyScriptEngine = java.import('com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine');
    var GremlinPipeline = java.import('com.tinkerpop.gremlin.groovy.GremlinGroovyPipeline');
    var NULL = java.callStaticMethodSync('org.codehaus.groovy.runtime.NullObject', 'getNullObject');

    var JSONResultConverter = java.import('com.tinkerpop.rexster.gremlin.converter.JSONResultConverter');
    var JSONObject = java.import('org.json.JSONObject');
    var JSONArray = java.import('org.json.JSONArray');

    var Class = java.import('java.lang.Class');
    var ArrayList = java.import('java.util.ArrayList');
    var HashMap = java.import('java.util.HashMap');
    var Table = java.import('com.tinkerpop.pipes.util.structures.Table');
    var Tree = java.import('com.tinkerpop.pipes.util.structures.Tree');

    var Direction = java.import('com.tinkerpop.blueprints.Direction');
    var Tokens = java.import('com.tinkerpop.gremlin.Tokens$T');
    var Compare = java.import('com.tinkerpop.blueprints.Compare');
    var Contains = java.import('com.tinkerpop.blueprints.Contains');

    var ClassTypes = {
        'String': { 'class': Class.forNameSync('java.lang.String') },
        'Vertex': { 'class': java.getClassLoader().loadClassSync('com.tinkerpop.blueprints.Vertex') },
        'Edge': { 'class': java.getClassLoader().loadClassSync('com.tinkerpop.blueprints.Edge') },
        'Byte': { 'class': Class.forNameSync('java.lang.Byte') },
        'Character': { 'class': Class.forNameSync('java.lang.Character') },
        'Double': { 'class': Class.forNameSync('java.lang.Double') },
        'Float': { 'class': Class.forNameSync('java.lang.Float') },
        'Integer': { 'class': Class.forNameSync('java.lang.Integer') },
        'Long': { 'class': Class.forNameSync('java.lang.Long') },
        'Short': { 'class': Class.forNameSync('java.lang.Short') },
        'Number': { 'class': Class.forNameSync('java.lang.Number') },
        'BigDecimal': { 'class': Class.forNameSync('java.math.BigDecimal') },
        'BigInteger': { 'class': Class.forNameSync('java.math.BigInteger') }
    };

    var MAX_VALUE = java.newInstanceSync('java.lang.Long', 2147483647);
    var MIN_VALUE = 0;
    var _JSON = new JSONResultConverter(null, MIN_VALUE, MAX_VALUE, null);

    function isType(o, typeName) {
        if (!o._isType) {
            o._isType = {};
        }
        var res = o._isType[typeName];
        if (res === undefined) {
            try {
                res = java.instanceOf(o, typeName);
            } catch(err) {
                res = false;
            }
            o._isType[typeName] = res;
        }
        return res;
    }

    function toList(obj, callback) {
        if (_.isArray(obj)) {
            var list = new ArrayList();
            for (var i = 0; i < obj.length; i++) {
                list.addSync(obj[i]);
            }
            return callback(null, list);
        }
        if (obj.getClassSync().isArraySync()) {
            java.callStaticMethod('java.util.Arrays', 'asList', obj, callback);
            return;
        }
        java.callStaticMethod('com.google.common.collect.Lists', 'newArrayList', obj, callback);
    }

    function toListSync(obj) {
        if (_.isArray(obj)) {
            var list = new ArrayList();
            for (var i = 0; i < obj.length; i++) {
                list.addSync(obj[i]);
            }
            return list;
        }
        if (obj.getClassSync().isArraySync()) {
            return java.callStaticMethodSync('java.util.Arrays', 'asList', obj);
        }
        return java.callStaticMethodSync('com.google.common.collect.Lists', 'newArrayList', obj);
    }

    function toJSON(obj, callback) {
        _JSON.convert(obj, function(err, json) {
            if (err) return callback(err);
            try {
                json = JSON.parse(json.toString());
            } catch (e) {
                return callback(e);
            }
            return callback(null, json);
        });
    }

    function toJSONSync(obj) {
        var json = _JSON.convertSync(obj);
        json = JSON.parse(json.toString());
        return json;
    }

    function getEngine() {
        if (getEngine.engine) {
            return getEngine.engine;
        }
        getEngine.engine = new GremlinGroovyScriptEngine();
        return getEngine.engine;
    }

    function wrap(graph) {
        return new GraphWrapper(self, graph);
    }

    return {
        GremlinPipeline: GremlinPipeline,
        NULL: NULL,
        GraphWrapper: GraphWrapper,
        PipelineWrapper: PipelineWrapper,
        QueryWrapper: QueryWrapper,
        java: java,
        ClassTypes: ClassTypes,
        Tokens: Tokens,
        Compare: Compare,
        Contains: Contains,
        Direction: Direction,
        ArrayList: ArrayList,
        HashMap: HashMap,
        Table: Table,
        Tree: Tree,
        isType: isType,
        toList: toList,
        toListSync: toListSync,
        toJSON: toJSON,
        toJSONSync: toJSONSync,
        getEngine: getEngine,
        wrap: wrap
    };
};
<|endoftext|>


<commit_before>const utils = require('./utils')
const uploadS3 = require('./upload-s3')
const pgdump = require('./pgdump')
const decorateWithIamToken = require('./iam')

const encryption = require('./encryption')

const DEFAULT_CONFIG = require('./config')

async function backup(config) {
    if (!config.PGDATABASE) {
        throw new Error('PGDATABASE not provided in the event data')
    }
    if (!config.S3_BUCKET) {
        throw new Error('S3_BUCKET not provided in the event data')
    }

    const key = utils.generateBackupPath(
        config.PGDATABASE,
        config.ROOT
    )

    // spawn the pg_dump process
    let stream = await pgdump(config)
    if (config.ENCRYPT_KEY && encryption.validateKey(config.ENCRYPT_KEY)) {
        // if encryption is enabled, we generate an IV and store it in a separate file
        const iv = encryption.generateIv()
        const ivKey = key + '.iv'

        await uploadS3(iv.toString('hex'), config, ivKey)
        stream = encryption.encrypt(stream, config.ENCRYPT_KEY, iv)
    }
    // stream the backup to S3
    return uploadS3(stream, config, key)
}

async function handler(event) {
    const baseConfig = { ...DEFAULT_CONFIG, ...event }
    const config = event.USE_IAM_AUTH === true ? decorateWithIamToken(baseConfig) : baseConfig
    try {
        return await backup(config)
    }
    catch (error) {
        // log the error and rethrow for Lambda
        if (process.env.NODE_ENV !== 'test') {
            console.error(error)
        }
        throw error
    }
}

module.exports = handler, decorateWithIamToken
<commit_msg>formatting<commit_after>const utils = require('./utils')
const uploadS3 = require('./upload-s3')
const pgdump = require('./pgdump')
const decorateWithIamToken = require('./iam')
const encryption = require('./encryption')

const DEFAULT_CONFIG = require('./config')

async function backup(config) {
    if (!config.PGDATABASE) {
        throw new Error('PGDATABASE not provided in the event data')
    }
    if (!config.S3_BUCKET) {
        throw new Error('S3_BUCKET not provided in the event data')
    }

    const key = utils.generateBackupPath(
        config.PGDATABASE,
        config.ROOT
    )

    // spawn the pg_dump process
    let stream = await pgdump(config)
    if (config.ENCRYPT_KEY && encryption.validateKey(config.ENCRYPT_KEY)) {
        // if encryption is enabled, we generate an IV and store it in a separate file
        const iv = encryption.generateIv()
        const ivKey = key + '.iv'

        await uploadS3(iv.toString('hex'), config, ivKey)
        stream = encryption.encrypt(stream, config.ENCRYPT_KEY, iv)
    }
    // stream the backup to S3
    return uploadS3(stream, config, key)
}

async function handler(event) {
    const baseConfig = { ...DEFAULT_CONFIG, ...event }
    const config = event.USE_IAM_AUTH === true ? decorateWithIamToken(baseConfig) : baseConfig
    try {
        return await backup(config)
    }
    catch (error) {
        // log the error and rethrow for Lambda
        if (process.env.NODE_ENV !== 'test') {
            console.error(error)
        }
        throw error
    }
}

module.exports = handler, decorateWithIamToken
<|endoftext|>


<commit_before>const { BrowserPool, PlaywrightPlugin } = require('browser-pool');
const { chromium } = require('playwright-core');
const debug = require('debug')('express-dom');
const clone = require('clone');

const plugins = require('./plugins');
const helpers = require('./helpers');
const tracker = require('./tracker');
const Deferred = require('./deferred');
const asyncEmit = require('./async-emit');

let browserPool;

class RequestTracker extends Deferred {
	#count = 0;

	constructor(page) {
		super();
		page.on('request', () => this.creates());
		page.on('requestfinished', () => this.completes());
		page.on('requestfailed', () => this.completes());
	}
	creates() {
		this.#count++;
	}
	completes() {
		if (--this.#count == 0) setImmediate(this.resolve);
	}
}

module.exports = class Handler {
	static pool = {
		max: 20
	};
	static plugins = plugins;
	static helpers = helpers;
	static settings = {
		helpers: [
			helpers.view,
			helpers.prioritize
		],
		prepare: {
			plugins: [
				plugins.hide,
				plugins.noreq,
				plugins.html
			]
		},
		load: {
			disable: Boolean(process.env.DEVELOP),
			plugins: [
				plugins.hide,
				plugins.nomedia,
				plugins.prerender,
				plugins.redirect,
				plugins.referrer,
				plugins.html
			]
		},
		console: process.env.NODE_ENV != "production",
		stall: 15000,
		allow: "same-origin",
		navigation: false,
		verbose: true
	};

	constructor(view, ...helpers) {
		const h = this;
		if (typeof view == "function") {
			helpers.unshift(view);
			view = null;
		} else {
			h.view = view;
		}
		debug("new handler", view);
		h.settings = emptySettings(Handler.settings);
		h.settings.helpers = helpers.concat(Handler.settings.helpers);
		h.settings.prepare = emptySettings(Handler.settings, true);
		h.settings.load = emptySettings(Handler.settings, true);

		h.chain = (...args) => h.middleware(...args);
		h.chain.load = (...args) => h.load(...args);
		h.chain.prepare = (...args) => h.prepare(...args);
	}
	#init(settings, defaults, opts, args) {
		if (!browserPool) browserPool = new BrowserPool({
			browserPlugins: [new PlaywrightPlugin(chromium, {
				maxOpenPagesPerBrowser: Handler.pool.max,
				retireBrowserAfterPageCount: Handler.pool.maxloads,
				useIncognitoPages: true, // each page can have its cookies
				launchOptions: {
					channel: 'chrome',
					timeout: 5000
				}
			})],
		});
		if (typeof opts == "function") opts = null;
		else args.shift();
		let plugins = settings.plugins;
		Object.assign(settings, defaults, opts);
		if ((!opts || !opts.plugins) && plugins.length) settings.plugins = plugins;
		else plugins = settings.plugins;
		if (typeof plugins == "function") plugins = [plugins];
		settings.plugins = args.concat(plugins);
	}

	static async destroy() {
		await browserPool.destroy();
		browserPool = null;
	}
	clone() {
		const h = new Handler(this.view);
		h.settings = clone(this.settings);
		return h;
	}
	prepare(opts) {
		this.#init(
			this.settings.prepare,
			Handler.settings.prepare,
			opts,
			Array.from(arguments)
		);
		return this.chain;
	}

	load(opts) {
		this.#init(
			this.settings.load,
			Handler.settings.load,
			opts,
			Array.from(arguments)
		);
		return this.chain;
	}
	async middleware(req, res, next) {
		const manual = {};
		if (typeof req == "string") {
			debug("Called in manual mode");
			const loc = new URL(req);
			req = {
				headers: {
					host: loc.host
				},
				protocol: loc.protocol,
				url: loc.path
			};
			req.get = function (key) {
				return this.headers[key];
			}.bind(req);
			res = { statusCode: 200 };
			res.sendStatus = function (status) {
				res.statusCode = manual.status = status;
			};
			res.send = function (str) {
				manual.body = str;
			};
			res.status = res.sendStatus;
			req.res = res;
		}
		// per request settings
		const rh = this.clone();
		try {
			await rh.runMiddleware(req, res);
			if (!next) {
				return manual;
			}
		} catch (err) {
			if (next) next(err);
			else throw err;
		}
	}

	async runMiddleware(req, res) {
		const { settings } = this;

		const loc = settings.location = new URL(
			req.url,
			(req.get('X-Forwarded-Proto') ?? req.protocol) + '://' + req.headers.host
		);
		if (req.headers.cookie) loc.headers = {
			cookie: req.headers.cookie
		};

		for (const helper of settings.helpers) {
			await helper(this, settings, req, res);
		}

		debug('view loaded for', loc.pathname, "with", settings.prepare.plugins.length, "prepare plugins, and", settings.load.plugins.length, "load plugins");

		if (!settings.prepare.disable && settings.prepare.plugins.length > 0) {
			await this.runMethod('prepare', settings, req, res);
		}

		if (!settings.load.disable && settings.load.plugins.length > 0) {
			await this.runMethod('load', settings, req, res);
		}

		let data = settings.input;
		// hopefully free faster that memory
		delete settings.input;
		if (res.get && !res.get('Content-Type')) {
			res.set('Content-Type', "text/html");
		}
		let status = res.statusCode;
		if (data === false) {
			debug("data handled by plugin");
			return;
		}
		if (!data) {
			if (!settings.prepare && !settings.load) {
				return res.sendStatus(501);
			} else {
				return res.sendStatus(404);
			}
		}
		let isPath = true, isStream = false;
		if (data instanceof Error) {
			isPath = false;
			data = null;
		} else if (Buffer.isBuffer(data)) {
			isPath = false;
		} else if (typeof data.pipe == "function") {
			isPath = false;
			isStream = true;
		} else if (typeof data != "string") {
			data = data.toString();
		}
		if (isPath && data.startsWith('<')) {
			isPath = false;
		}
		if (isPath) {
			try {
				res.sendFile(data);
			} catch (ex) {
				// eslint-disable-next-line no-console
				console.error("express-dom thought input was a file path", data);
				status = 500;
				isPath = false;
			}
		}
		if (!isPath) {
			if (status) res.status(status);
			if (isStream) {
				data.once('error', (err) => {
					res.emit('error', err);
					data.unpipe(res);
				});
				data.pipe(res);
			} else {
				res.send(data);
			}
		}
	}

	async runMethod(method, settings, req, res) {
		const page = await browserPool.newPage();
		asyncEmit(page);
		const mSettings = Object.assign({}, settings, settings[method]);
		mSettings.location = settings.location;
		const plugins = mSettings.plugins;
		delete mSettings.plugins;
		for (const plugin of plugins) {
			await plugin(page, mSettings, req, res);
		}

		settings.location = mSettings.location;
		settings.input = mSettings.input;
		delete mSettings.location;
		delete mSettings.input;
		const url = settings.location.toString();
		debug(method, url);

		page.route(url, route => {
			route.fulfill({
				body: settings.input,
				contentType: 'text/html'
			});
		});

		page.on('console', msg => {
			console.error(msg.text());
		});
		page.on('pageerror', err => {
			// TODO cancel all other promises, return early
			console.error(err);
		});
		const reqTrack = new RequestTracker(page);

		const fnid = 'signal' + Math.floor(Math.random() * 10000000);
		await page.addInitScript(tracker, fnid);
		try {
			await page.goto(url, {
				waitUntil: 'domcontentloaded'
			});
			debug("page loaded");
			await reqTrack;
			debug("page requests finished");
			const event = await page.evaluate(id => window[id], fnid);
			debug("page idle");
			if (event == "idle") {
				await asyncEmit(page, 'idle');
				debug("async emit done");
			} else {
				console.warn("Unknown event", event);
			}
		} catch (ex) {
			console.error(ex);
		}

		if (mSettings.output !== undefined) {
			settings.input = mSettings.output;
		}
		await page.close();
	}
};

function emptySettings(defaults, withArrays) {
	// use defaults but not .load, .prepare sub global settings
	let obj = Object.assign({}, defaults);
	delete obj.load;
	delete obj.prepare;
	obj = clone(obj);
	if (withArrays) {
		if (!obj.filters) obj.filters = [];
		if (!obj.plugins) obj.plugins = [];
		if (!obj.scripts) obj.scripts = [];
	}
	return obj;
}

<commit_msg>Right console method<commit_after>const { BrowserPool, PlaywrightPlugin } = require('browser-pool');
const { chromium } = require('playwright-core');
const debug = require('debug')('express-dom');
const clone = require('clone');

const plugins = require('./plugins');
const helpers = require('./helpers');
const tracker = require('./tracker');
const Deferred = require('./deferred');
const asyncEmit = require('./async-emit');

let browserPool;

class RequestTracker extends Deferred {
	#count = 0;

	constructor(page) {
		super();
		page.on('request', () => this.creates());
		page.on('requestfinished', () => this.completes());
		page.on('requestfailed', () => this.completes());
	}
	creates() {
		this.#count++;
	}
	completes() {
		if (--this.#count == 0) setImmediate(this.resolve);
	}
}

module.exports = class Handler {
	static pool = {
		max: 20
	};
	static plugins = plugins;
	static helpers = helpers;
	static settings = {
		helpers: [
			helpers.view,
			helpers.prioritize
		],
		prepare: {
			plugins: [
				plugins.hide,
				plugins.noreq,
				plugins.html
			]
		},
		load: {
			disable: Boolean(process.env.DEVELOP),
			plugins: [
				plugins.hide,
				plugins.nomedia,
				plugins.prerender,
				plugins.redirect,
				plugins.referrer,
				plugins.html
			]
		},
		console: process.env.NODE_ENV != "production",
		stall: 15000,
		allow: "same-origin",
		navigation: false,
		verbose: true
	};

	constructor(view, ...helpers) {
		const h = this;
		if (typeof view == "function") {
			helpers.unshift(view);
			view = null;
		} else {
			h.view = view;
		}
		debug("new handler", view);
		h.settings = emptySettings(Handler.settings);
		h.settings.helpers = helpers.concat(Handler.settings.helpers);
		h.settings.prepare = emptySettings(Handler.settings, true);
		h.settings.load = emptySettings(Handler.settings, true);

		h.chain = (...args) => h.middleware(...args);
		h.chain.load = (...args) => h.load(...args);
		h.chain.prepare = (...args) => h.prepare(...args);
	}
	#init(settings, defaults, opts, args) {
		if (!browserPool) browserPool = new BrowserPool({
			browserPlugins: [new PlaywrightPlugin(chromium, {
				maxOpenPagesPerBrowser: Handler.pool.max,
				retireBrowserAfterPageCount: Handler.pool.maxloads,
				useIncognitoPages: true, // each page can have its cookies
				launchOptions: {
					channel: 'chrome',
					timeout: 5000
				}
			})],
		});
		if (typeof opts == "function") opts = null;
		else args.shift();
		let plugins = settings.plugins;
		Object.assign(settings, defaults, opts);
		if ((!opts || !opts.plugins) && plugins.length) settings.plugins = plugins;
		else plugins = settings.plugins;
		if (typeof plugins == "function") plugins = [plugins];
		settings.plugins = args.concat(plugins);
	}

	static async destroy() {
		await browserPool.destroy();
		browserPool = null;
	}
	clone() {
		const h = new Handler(this.view);
		h.settings = clone(this.settings);
		return h;
	}
	prepare(opts) {
		this.#init(
			this.settings.prepare,
			Handler.settings.prepare,
			opts,
			Array.from(arguments)
		);
		return this.chain;
	}

	load(opts) {
		this.#init(
			this.settings.load,
			Handler.settings.load,
			opts,
			Array.from(arguments)
		);
		return this.chain;
	}
	async middleware(req, res, next) {
		const manual = {};
		if (typeof req == "string") {
			debug("Called in manual mode");
			const loc = new URL(req);
			req = {
				headers: {
					host: loc.host
				},
				protocol: loc.protocol,
				url: loc.path
			};
			req.get = function (key) {
				return this.headers[key];
			}.bind(req);
			res = { statusCode: 200 };
			res.sendStatus = function (status) {
				res.statusCode = manual.status = status;
			};
			res.send = function (str) {
				manual.body = str;
			};
			res.status = res.sendStatus;
			req.res = res;
		}
		// per request settings
		const rh = this.clone();
		try {
			await rh.runMiddleware(req, res);
			if (!next) {
				return manual;
			}
		} catch (err) {
			if (next) next(err);
			else throw err;
		}
	}

	async runMiddleware(req, res) {
		const { settings } = this;

		const loc = settings.location = new URL(
			req.url,
			(req.get('X-Forwarded-Proto') ?? req.protocol) + '://' + req.headers.host
		);
		if (req.headers.cookie) loc.headers = {
			cookie: req.headers.cookie
		};

		for (const helper of settings.helpers) {
			await helper(this, settings, req, res);
		}

		debug('view loaded for', loc.pathname, "with", settings.prepare.plugins.length, "prepare plugins, and", settings.load.plugins.length, "load plugins");

		if (!settings.prepare.disable && settings.prepare.plugins.length > 0) {
			await this.runMethod('prepare', settings, req, res);
		}

		if (!settings.load.disable && settings.load.plugins.length > 0) {
			await this.runMethod('load', settings, req, res);
		}

		let data = settings.input;
		// hopefully free faster that memory
		delete settings.input;
		if (res.get && !res.get('Content-Type')) {
			res.set('Content-Type', "text/html");
		}
		let status = res.statusCode;
		if (data === false) {
			debug("data handled by plugin");
			return;
		}
		if (!data) {
			if (!settings.prepare && !settings.load) {
				return res.sendStatus(501);
			} else {
				return res.sendStatus(404);
			}
		}
		let isPath = true, isStream = false;
		if (data instanceof Error) {
			isPath = false;
			data = null;
		} else if (Buffer.isBuffer(data)) {
			isPath = false;
		} else if (typeof data.pipe == "function") {
			isPath = false;
			isStream = true;
		} else if (typeof data != "string") {
			data = data.toString();
		}
		if (isPath && data.startsWith('<')) {
			isPath = false;
		}
		if (isPath) {
			try {
				res.sendFile(data);
			} catch (ex) {
				// eslint-disable-next-line no-console
				console.error("express-dom thought input was a file path", data);
				status = 500;
				isPath = false;
			}
		}
		if (!isPath) {
			if (status) res.status(status);
			if (isStream) {
				data.once('error', (err) => {
					res.emit('error', err);
					data.unpipe(res);
				});
				data.pipe(res);
			} else {
				res.send(data);
			}
		}
	}

	async runMethod(method, settings, req, res) {
		const page = await browserPool.newPage();
		asyncEmit(page);
		const mSettings = Object.assign({}, settings, settings[method]);
		mSettings.location = settings.location;
		const plugins = mSettings.plugins;
		delete mSettings.plugins;
		for (const plugin of plugins) {
			await plugin(page, mSettings, req, res);
		}

		settings.location = mSettings.location;
		settings.input = mSettings.input;
		delete mSettings.location;
		delete mSettings.input;
		const url = settings.location.toString();
		debug(method, url);

		page.route(url, route => {
			route.fulfill({
				body: settings.input,
				contentType: 'text/html'
			});
		});

		if (mSettings.verbose) page.on('console', msg => {
			// eslint-disable-next-line no-console
			console[msg.type()](msg.text());
		});
		page.on('pageerror', err => {
			// TODO cancel all other promises, return early
			console.error(err);
		});
		const reqTrack = new RequestTracker(page);

		const fnid = 'signal' + Math.floor(Math.random() * 10000000);
		await page.addInitScript(tracker, fnid);
		try {
			await page.goto(url, {
				waitUntil: 'domcontentloaded'
			});
			debug("page loaded");
			await reqTrack;
			debug("page requests finished");
			const event = await page.evaluate(id => window[id], fnid);
			debug("page idle");
			if (event == "idle") {
				await asyncEmit(page, 'idle');
				debug("async emit done");
			} else {
				console.warn("Unknown event", event);
			}
		} catch (ex) {
			console.error(ex);
		}

		if (mSettings.output !== undefined) {
			settings.input = mSettings.output;
		}
		await page.close();
	}
};

function emptySettings(defaults, withArrays) {
	// use defaults but not .load, .prepare sub global settings
	let obj = Object.assign({}, defaults);
	delete obj.load;
	delete obj.prepare;
	obj = clone(obj);
	if (withArrays) {
		if (!obj.filters) obj.filters = [];
		if (!obj.plugins) obj.plugins = [];
		if (!obj.scripts) obj.scripts = [];
	}
	return obj;
}

<|endoftext|>


<commit_before>'use strict'

var keyMap = require('./key_map')
var retainElement = keyMap.retainElement
var hasMutationObserver = typeof MutationObserver !== 'undefined'
var hasDocument = typeof document !== 'undefined'

module.exports = {
  setDefault: setDefault,
  bindEvents: bindEvents,
  animate: animate,
  flow: flow,

  // Alias for flow.
  chain: flow
}

function setDefault (node, value) {
  return value != null ? value : void 0
}

function bindEvents (events, useCapture) {
  var listeners = {}

  if (useCapture === void 0) useCapture = false

  return function (node, value, previousValue, path) {
    var key

    if (value == null)
      for (key in events)
        node.removeEventListener(key, listeners[key], useCapture)
    else if (previousValue == null)
      for (key in events) {
        listeners[key] = makeEventListener(events[key], path)
        node.addEventListener(key, listeners[key], useCapture)
      }
  }

  function makeEventListener (fn, path) {
    return function eventListener (event) {
      return fn(event, path)
    }
  }
}

function animate (insertClass, mutateClass, removeClass, retainTime) {
  return function (node, value, previousValue) {
    var observer

    if (!('classList' in node)) return void 0

    if (value == null) {
      if (insertClass) node.classList.remove(insertClass)
      if (removeClass) node.classList.add(removeClass)
      if (retainTime) {
        setTimeout(function () {
          node.parentNode.removeChild(node)
        }, retainTime)

        return retainElement
      }
    }
    else if (value != null && previousValue != null && mutateClass) {
      if (node.classList.contains(mutateClass)) {
        node.classList.remove(mutateClass)

        // Hack to trigger reflow.
        void node.offsetWidth
      }

      node.classList.add(mutateClass)
    }
    else if (previousValue == null && insertClass)
      // Trigger class addition after the element is inserted.
      if (hasMutationObserver && hasDocument &&
        !document.documentElement.contains(node)) {
        observer = new MutationObserver(function (mutations) {
          var i, j, k, l, mutation, addedNode

          for (i = 0, j = mutations.length; i < j; i++) {
            mutation = mutations[i]

            for (k = 0, l = mutation.addedNodes.length; k < l; k++) {
              addedNode = mutation.addedNodes[k]

              if (addedNode === node) {
                // Hack to trigger reflow.
                void node.offsetWidth

                node.classList.add(insertClass)
                observer.disconnect()
              }
            }
          }
        })

        observer.observe(document.documentElement, {
          childList: true, subtree: true
        })
      }
      else node.classList.add(insertClass)

    return void 0
  }
}

function flow () {
  var args = arguments

  return function (node, value, previousValue, path) {
    var i, returnValue, result

    for (i = 0; i < args.length; i++) {
      returnValue = args[i](node, value, previousValue, path)
      if (returnValue !== void 0) result = returnValue
    }

    return result
  }
}
<commit_msg>add comment on removeEventListener<commit_after>'use strict'

var keyMap = require('./key_map')
var retainElement = keyMap.retainElement
var hasMutationObserver = typeof MutationObserver !== 'undefined'
var hasDocument = typeof document !== 'undefined'

module.exports = {
  setDefault: setDefault,
  bindEvents: bindEvents,
  animate: animate,
  flow: flow,

  // Alias for flow.
  chain: flow
}

function setDefault (node, value) {
  return value != null ? value : void 0
}

function bindEvents (events, useCapture) {
  var listeners = {}

  if (useCapture === void 0) useCapture = false

  return function (node, value, previousValue, path) {
    var key

    if (value == null)
      for (key in events)
        // The point of removing event listeners here is not manual memory
        // management, but to ensure that after the value has been unset, it
        // no longer triggers events.
        node.removeEventListener(key, listeners[key], useCapture)
    else if (previousValue == null)
      for (key in events) {
        listeners[key] = makeEventListener(events[key], path)
        node.addEventListener(key, listeners[key], useCapture)
      }
  }

  function makeEventListener (fn, path) {
    return function eventListener (event) {
      return fn(event, path)
    }
  }
}

function animate (insertClass, mutateClass, removeClass, retainTime) {
  return function (node, value, previousValue) {
    var observer

    if (!('classList' in node)) return void 0

    if (value == null) {
      if (insertClass) node.classList.remove(insertClass)
      if (removeClass) node.classList.add(removeClass)
      if (retainTime) {
        setTimeout(function () {
          node.parentNode.removeChild(node)
        }, retainTime)

        return retainElement
      }
    }
    else if (value != null && previousValue != null && mutateClass) {
      if (node.classList.contains(mutateClass)) {
        node.classList.remove(mutateClass)

        // Hack to trigger reflow.
        void node.offsetWidth
      }

      node.classList.add(mutateClass)
    }
    else if (previousValue == null && insertClass)
      // Trigger class addition after the element is inserted.
      if (hasMutationObserver && hasDocument &&
        !document.documentElement.contains(node)) {
        observer = new MutationObserver(function (mutations) {
          var i, j, k, l, mutation, addedNode

          for (i = 0, j = mutations.length; i < j; i++) {
            mutation = mutations[i]

            for (k = 0, l = mutation.addedNodes.length; k < l; k++) {
              addedNode = mutation.addedNodes[k]

              if (addedNode === node) {
                // Hack to trigger reflow.
                void node.offsetWidth

                node.classList.add(insertClass)
                observer.disconnect()
              }
            }
          }
        })

        observer.observe(document.documentElement, {
          childList: true, subtree: true
        })
      }
      else node.classList.add(insertClass)

    return void 0
  }
}

function flow () {
  var args = arguments

  return function (node, value, previousValue, path) {
    var i, returnValue, result

    for (i = 0; i < args.length; i++) {
      returnValue = args[i](node, value, previousValue, path)
      if (returnValue !== void 0) result = returnValue
    }

    return result
  }
}
<|endoftext|>