<commit_before>var fs = require('fs')
var path = require('path')
var crypto = require('crypto')
var mkdirp = require('mkdirp')
var glob = require('glob')

var isWindows = process.platform === 'win32'
var pathSep   = path.sep

exports.hashTree = hashTree
function hashTree (fullPath) {
  // This function is used by the watcher. It makes the following guarantees:
  //
  // (1) It never throws an exception.
  //
  // (2) It does not miss changes. In other words, if after this function returns,
  // any part of the directory hierarchy changes, a subsequent call must
  // return a different hash.
  //
  // (1) and (2) hold even in the face of a constantly-changing file system.
  return hashStrings(keysForTree(fullPath))
}

function keysForTree (fullPath, options) {
  options = options || {}

  var _stack         = options._stack
  var _followSymlink = options._followSymlink
  var relativePath   = options.relativePath || '.'
  var stats
  var statKeys

  try {
    if (_followSymlink) {
      stats = fs.statSync(fullPath)
    } else {
      stats = fs.lstatSync(fullPath)
    }
  } catch (err) {
    console.warn('Warning: failed to stat ' + fullPath)
    // fullPath has probably ceased to exist. Leave `stats` undefined and
    // proceed hashing.
  }
  var childKeys = []
  if (stats) {
    statKeys = ['stats', stats.mode]
  } else {
    statKeys = ['stat failed']
  }
  if (stats && stats.isDirectory()) {
    var fileIdentity = stats.dev + '\x00' + stats.ino
    if (_stack != null && _stack.indexOf(fileIdentity) !== -1) {
      console.warn('Symlink directory loop detected at ' + fullPath + ' (note: loop detection may have false positives on Windows)')
    } else {
      if (_stack != null) _stack = _stack.concat([fileIdentity])
      var entries
      try {
        entries = fs.readdirSync(fullPath).sort()
      } catch (err) {
        console.warn('Warning: Failed to read directory ' + fullPath)
        console.warn(err.stack)
        childKeys = ['readdir failed']
        // That's all there is to say about this directory.
      }
      if (entries != null) {
        for (var i = 0; i < entries.length; i++) {

          var keys = keysForTree(path.join(fullPath, entries[i]), {
            _stack: _stack,
            relativePath: path.join(relativePath, entries[i])
          })
          childKeys = childKeys.concat(keys)
        }
      }
    }
  } else if (stats && stats.isSymbolicLink()) {
    if (_stack == null) {
      // From here on in the traversal, we need to guard against symlink
      // directory loops. _stack is kept null in the absence of symlinks to we
      // don't have to deal with Windows for now, as long as it doesn't use
      // symlinks.
      _stack = []
    }
    childKeys = keysForTree(fullPath, {_stack: _stack, relativePath: relativePath, _followSymlink: true}) // follow symlink
    statKeys.push(stats.mtime.getTime())
    statKeys.push(stats.size)
  } else if (stats && stats.isFile()) {
    statKeys.push(stats.mtime.getTime())
    statKeys.push(stats.size)
  }

  // Perhaps we should not use basename to infer the file name
  return ['path', relativePath]
    .concat(statKeys)
    .concat(childKeys)
}

exports.hashStats = hashStats
function hashStats (stats, path) {
  // Both stats and path can be null
  var keys = []
  if (stats != null) {
    keys.push(stats.mode, stats.size, stats.mtime.getTime())
  }
  if (path != null) {
    keys.push(path)
  }
  return hashStrings(keys)
}

exports.hashStrings = hashStrings
function hashStrings (strings) {
  var joinedStrings = strings.join('\x00')
  return crypto.createHash('md5').update(joinedStrings).digest('hex')
}

// If src is a file, dest is a file name. If src is a directory, dest is the
// directory that the contents of src will be copied into.
//
// This function refuses to overwrite files, but accepts if directories exist
// already.
//
// This function dereferences symlinks.
//
// Note that unlike cp(1), we do not special-case if dest is an existing
// directory, because relying on things to exist when we're in the middle of
// assembling a new tree is too brittle.
//
// This function is deprecated in favor of
// https://github.com/broccolijs/node-copy-dereference
//
// copy-dereference differs from copyRecursivelySync in that it won't call
// mkdirp to create the target directory (or the parent directory of the
// target file), which makes it stricter: (1) It's not OK for the target
// directory to exist already, and (2) missing parent directories will not
// automatically be created.
exports.copyRecursivelySync = copyRecursivelySync
function copyRecursivelySync (src, dest, _mkdirp) {
  if (_mkdirp == null) _mkdirp = true
  // Note: We could try readdir'ing and catching ENOTDIR exceptions, but that
  // is 3x slower than stat'ing in the common case that we have a file.
  var srcStats = fs.statSync(src)
  if (srcStats.isDirectory()) {
    mkdirp.sync(dest)
    var entries = fs.readdirSync(src).sort()
    for (var i = 0; i < entries.length; i++) {
      // Set _mkdirp to false when recursing to avoid extra mkdirp calls.
      copyRecursivelySync(src + '/' + entries[i], dest + '/' + entries[i], false)
    }
  } else {
    if (_mkdirp) {
      mkdirp.sync(path.dirname(dest))
    }
    copyPreserveSync(src, dest, srcStats)
  }
}

// This function is deprecated in favor of
// https://github.com/broccolijs/node-copy-dereference
//
// srcStats is optional; use it as an optimization to avoid double stats
// This function refuses to overwrite files.
exports.copyPreserveSync = copyPreserveSync
function copyPreserveSync (src, dest, srcStats) {
  if (srcStats == null) srcStats = fs.statSync(src)
  if (srcStats.isFile()) {
    var content = fs.readFileSync(src)
    fs.writeFileSync(dest, content, { flag: 'wx' })
    fs.utimesSync(dest, srcStats.atime, srcStats.mtime)
  } else {
    throw new Error('Unexpected file type for ' + src)
  }
}

exports.linkRecursivelySync = linkRecursivelySync
function linkRecursivelySync () {
  throw new Error('linkRecursivelySync has been removed; use copyRecursivelySync instead (note: it does not overwrite)')
}

exports.linkAndOverwrite = linkAndOverwrite
function linkAndOverwrite () {
  throw new Error('linkAndOverwrite has been removed; use copyPreserveSync instead (note: it does not overwrite)')
}

exports.assertAbsolutePaths = assertAbsolutePaths
function assertAbsolutePaths (paths) {
  for (var i = 0; i < paths.length; i++) {
    if (paths[i][0] !== '/') {
      throw new Error('Path must be absolute: "' + paths[i] + '"')
    }
  }
}

// Multi-glob with reasonable defaults, so APIs all behave the same
exports.multiGlob = multiGlob
function multiGlob (globs, globOptions) {
  if (!Array.isArray(globs)) {
    throw new TypeError("multiGlob's first argument must be an array");
  }
  var options = {
    nomount: true,
    strict: true
  }
  for (var key in globOptions) {
    if (globOptions.hasOwnProperty(key)) {
      options[key] = globOptions[key]
    }
  }

  var pathSet = {}
  var paths = []
  for (var i = 0; i < globs.length; i++) {
    if (options.nomount && globs[i][0] === '/') {
      throw new Error('Absolute paths not allowed (`nomount` is enabled): ' + globs[i])
    }
    var matches = glob.sync(globs[i], options)
    if (matches.length === 0) {
      throw new Error('Path or pattern "' + globs[i] + '" did not match any files')
    }
    for (var j = 0; j < matches.length; j++) {
      if (!pathSet[matches[j]]) {
        pathSet[matches[j]] = true
        paths.push(matches[j])
      }
    }
  }
  return paths
}

// This function is deprecated in favor of
// https://github.com/broccolijs/node-symlink-or-copy
exports.symlinkOrCopyPreserveSync = symlinkOrCopyPreserveSync
function symlinkOrCopyPreserveSync (sourcePath, destPath) {
  if (isWindows) {
    copyRecursivelySync(sourcePath, destPath)
  } else {
    if (fs.lstatSync(sourcePath).isSymbolicLink()) {
      // When we encounter symlinks, follow them. This prevents indirection
      // from growing out of control. Note: At the moment `realpath` on Node
      // is 70x slower than native: https://github.com/joyent/node/issues/7902
      sourcePath = fs.realpathSync(sourcePath)
    } else if (sourcePath[0] !== pathSep) {
      sourcePath = process.cwd() + pathSep + sourcePath
    }

    fs.symlinkSync(sourcePath, destPath)
  }
}
<commit_msg>Allow the usage of symlinks internally.<commit_after>var fs = require('fs')
var path = require('path')
var crypto = require('crypto')
var mkdirp = require('mkdirp')
var glob = require('glob')

var isWindows = process.platform === 'win32'
var pathSep   = path.sep

var keysForTreeWarningPrinted = false

exports.hashTree = hashTree
function hashTree (fullPath) {
  // This function is used by the watcher. It makes the following guarantees:
  //
  // (1) It never throws an exception.
  //
  // (2) It does not miss changes. In other words, if after this function returns,
  // any part of the directory hierarchy changes, a subsequent call must
  // return a different hash.
  //
  // (1) and (2) hold even in the face of a constantly-changing file system.
  return hashStrings(keysForTree(fullPath))
}

function keysForTree (fullPath, initialRelativePath) {
  var relativePath   = initialRelativePath || '.'
  var stats
  var statKeys

  try {
    stats = fs.statSync(fullPath)
  } catch (err) {
    if (!keysForTreeWarningPrinted) {
      console.warn('Warning: failed to stat ' + fullPath)
      keysForTreeWarningPrinted = true
    }
    // fullPath has probably ceased to exist. Leave `stats` undefined and
    // proceed hashing.
  }
  var childKeys = []
  if (stats) {
    statKeys = ['stats', stats.mode]
  } else {
    statKeys = ['stat failed']
  }
  if (stats && stats.isDirectory()) {
    var fileIdentity = stats.dev + '\x00' + stats.ino
    var entries
    try {
      entries = fs.readdirSync(fullPath).sort()
    } catch (err) {
      console.warn('Warning: Failed to read directory ' + fullPath)
      console.warn(err.stack)
      childKeys = ['readdir failed']
      // That's all there is to say about this directory.
    }
    if (entries != null) {
      for (var i = 0; i < entries.length; i++) {

        var keys = keysForTree(
          path.join(fullPath, entries[i]),
          path.join(relativePath, entries[i])
        )
        childKeys = childKeys.concat(keys)
      }
    }
  } else if (stats && stats.isFile()) {
    statKeys.push(stats.mtime.getTime())
    statKeys.push(stats.size)
  }

  // Perhaps we should not use basename to infer the file name
  return ['path', relativePath]
    .concat(statKeys)
    .concat(childKeys)
}

exports.hashStats = hashStats
function hashStats (stats, path) {
  // Both stats and path can be null
  var keys = []
  if (stats != null) {
    keys.push(stats.mode, stats.size, stats.mtime.getTime())
  }
  if (path != null) {
    keys.push(path)
  }
  return hashStrings(keys)
}

exports.hashStrings = hashStrings
function hashStrings (strings) {
  var joinedStrings = strings.join('\x00')
  return crypto.createHash('md5').update(joinedStrings).digest('hex')
}

// If src is a file, dest is a file name. If src is a directory, dest is the
// directory that the contents of src will be copied into.
//
// This function refuses to overwrite files, but accepts if directories exist
// already.
//
// This function dereferences symlinks.
//
// Note that unlike cp(1), we do not special-case if dest is an existing
// directory, because relying on things to exist when we're in the middle of
// assembling a new tree is too brittle.
//
// This function is deprecated in favor of
// https://github.com/broccolijs/node-copy-dereference
//
// copy-dereference differs from copyRecursivelySync in that it won't call
// mkdirp to create the target directory (or the parent directory of the
// target file), which makes it stricter: (1) It's not OK for the target
// directory to exist already, and (2) missing parent directories will not
// automatically be created.
exports.copyRecursivelySync = copyRecursivelySync
function copyRecursivelySync (src, dest, _mkdirp) {
  if (_mkdirp == null) _mkdirp = true
  // Note: We could try readdir'ing and catching ENOTDIR exceptions, but that
  // is 3x slower than stat'ing in the common case that we have a file.
  var srcStats = fs.statSync(src)
  if (srcStats.isDirectory()) {
    mkdirp.sync(dest)
    var entries = fs.readdirSync(src).sort()
    for (var i = 0; i < entries.length; i++) {
      // Set _mkdirp to false when recursing to avoid extra mkdirp calls.
      copyRecursivelySync(src + '/' + entries[i], dest + '/' + entries[i], false)
    }
  } else {
    if (_mkdirp) {
      mkdirp.sync(path.dirname(dest))
    }
    copyPreserveSync(src, dest, srcStats)
  }
}

// This function is deprecated in favor of
// https://github.com/broccolijs/node-copy-dereference
//
// srcStats is optional; use it as an optimization to avoid double stats
// This function refuses to overwrite files.
exports.copyPreserveSync = copyPreserveSync
function copyPreserveSync (src, dest, srcStats) {
  if (srcStats == null) srcStats = fs.statSync(src)
  if (srcStats.isFile()) {
    var content = fs.readFileSync(src)
    fs.writeFileSync(dest, content, { flag: 'wx' })
    fs.utimesSync(dest, srcStats.atime, srcStats.mtime)
  } else {
    throw new Error('Unexpected file type for ' + src)
  }
}

exports.linkRecursivelySync = linkRecursivelySync
function linkRecursivelySync () {
  throw new Error('linkRecursivelySync has been removed; use copyRecursivelySync instead (note: it does not overwrite)')
}

exports.linkAndOverwrite = linkAndOverwrite
function linkAndOverwrite () {
  throw new Error('linkAndOverwrite has been removed; use copyPreserveSync instead (note: it does not overwrite)')
}

exports.assertAbsolutePaths = assertAbsolutePaths
function assertAbsolutePaths (paths) {
  for (var i = 0; i < paths.length; i++) {
    if (paths[i][0] !== '/') {
      throw new Error('Path must be absolute: "' + paths[i] + '"')
    }
  }
}

// Multi-glob with reasonable defaults, so APIs all behave the same
exports.multiGlob = multiGlob
function multiGlob (globs, globOptions) {
  if (!Array.isArray(globs)) {
    throw new TypeError("multiGlob's first argument must be an array");
  }
  var options = {
    nomount: true,
    strict: true
  }
  for (var key in globOptions) {
    if (globOptions.hasOwnProperty(key)) {
      options[key] = globOptions[key]
    }
  }

  var pathSet = {}
  var paths = []
  for (var i = 0; i < globs.length; i++) {
    if (options.nomount && globs[i][0] === '/') {
      throw new Error('Absolute paths not allowed (`nomount` is enabled): ' + globs[i])
    }
    var matches = glob.sync(globs[i], options)
    if (matches.length === 0) {
      throw new Error('Path or pattern "' + globs[i] + '" did not match any files')
    }
    for (var j = 0; j < matches.length; j++) {
      if (!pathSet[matches[j]]) {
        pathSet[matches[j]] = true
        paths.push(matches[j])
      }
    }
  }
  return paths
}

// This function is deprecated in favor of
// https://github.com/broccolijs/node-symlink-or-copy
exports.symlinkOrCopyPreserveSync = symlinkOrCopyPreserveSync
function symlinkOrCopyPreserveSync (sourcePath, destPath) {
  if (isWindows) {
    copyRecursivelySync(sourcePath, destPath)
  } else {
    if (fs.lstatSync(sourcePath).isSymbolicLink()) {
      // When we encounter symlinks, follow them. This prevents indirection
      // from growing out of control. Note: At the moment `realpath` on Node
      // is 70x slower than native: https://github.com/joyent/node/issues/7902
      sourcePath = fs.realpathSync(sourcePath)
    } else if (sourcePath[0] !== pathSep) {
      sourcePath = process.cwd() + pathSep + sourcePath
    }

    fs.symlinkSync(sourcePath, destPath)
  }
}
<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var mysql = require('mysql');
//var mustache = require("mustache");
var app = express();
var port = 3700;

// statics
app.use(express.static(path.join(__dirname, 'public')));

// define usernames
var usernames = {};

// define rooms
var rooms = ['Calculus', 'Discrete Mathematics', 'Logic'];

var connection = mysql.createConnection({
  host     : '',
  user     : '',
  password : '',
  database : 'lath'
});

connection.connect();

// routes
app.get('/', function (req, res) {
    res.sendfile(__dirname + '/index.html');
});
//app.get('/log', function (req,res) {
//    var html = "";
//    connection.query('SELECT username, message FROM chat_log', function(err, rows, fields) {
//        if (err) throw err;
//        query = rows;
//        console.log(rows[0].username);
//        for (var row in rows) {
//            html += "
" + rows[row].username + ":" + rows[row].message + "
";
//        }
//
//        res.send(html);
//    });
//
//});

// socket
var io = require('socket.io').listen(app.listen(port));

// define events
io.sockets.on('connection', function (socket) {

    // when clients emit...

    socket.on('sendchat', function(data) {
        io.sockets.to(socket.room).emit('updatechat', socket.username, data);
        data = data.replace(/\\/g, '\\\\');
        connection.query('INSERT INTO chat_log(username, message, room) VALUES ("' + socket.username + '", "' + data + '", "' + socket.room + '")', function(err, rows, fields) {
          if (err) throw err;
        });

    });

    socket.on('adduser', function(username) {
        socket.username = username;
        if (usernames[socket.username]) {
            socket.emit('connect', true);
            return 0;
        }
        socket.room = 'Calculus';
        usernames[username] = username;
        socket.join('Calculus');
        socket.emit('updatechat', 'SERVER', 'You have connected to Calculus.');
        // broadcast to all users
        socket.broadcast.to('Calculus').emit('updatechat', 'SERVER', username + ' has connected.');
        // update list client side
        io.sockets.emit('updateusers', usernames);
        socket.emit('updaterooms', rooms, 'Calculus');
    });

    socket.on('switchroom', function (newroom) {
        socket.leave(socket.room);
        socket.join(newroom);
        socket.emit('updatechat', 'SERVER', 'You have connected to ' + newroom + '.');
        socket.broadcast.to(socket.room).emit('updatechat', 'SERVER', socket.username + ' has left the room.');
        socket.room = newroom;
        socket.broadcast.to(socket.room).emit('updatechat', 'SERVER', socket.username + ' has joined the room');
        socket.emit('updaterooms', rooms, newroom);

    });

    // sad panda is sad with this event
    socket.on('disconnect', function() {
        delete usernames[socket.username];
        io.sockets.emit('updateusers', usernames);
        // broadcast
        socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has disconnected.');
        socket.leave(socket.room);
    });

});

console.log('Listening...');
<commit_msg>Fix bug with mysql connection<commit_after>var express = require('express');
var path = require('path');
var mysql = require('mysql');
//var mustache = require("mustache");
var app = express();
var port = 3700;
var pool = mysql.createPool({
    host     : '',
    user     : '',
    password : '',
    database : 'lath'
});

// statics
app.use(express.static(path.join(__dirname, 'public')));

// define usernames
var usernames = {};

// define rooms
var rooms = ['Calculus', 'Discrete Mathematics', 'Logic'];

// var connection = mysql.createConnection({
//   host     : '',
//   user     : '',
//   password : '',
//   database : 'lath'
// });

// connection.connect();

// routes
app.get('/', function (req, res) {
    res.sendfile(__dirname + '/index.html');
});
//app.get('/log', function (req,res) {
//    var html = "";
//    connection.query('SELECT username, message FROM chat_log', function(err, rows, fields) {
//        if (err) throw err;
//        query = rows;
//        console.log(rows[0].username);
//        for (var row in rows) {
//            html += "
" + rows[row].username + ":" + rows[row].message + "
";
//        }
//
//        res.send(html);
//    });
//
//});

// socket
var io = require('socket.io').listen(app.listen(port));

// define events
io.sockets.on('connection', function (socket) {

    // when clients emit...

    socket.on('sendchat', function(data) {
        io.sockets.to(socket.room).emit('updatechat', socket.username, data);
        data = data.replace(/\\/g, '\\\\');

        pool.getConnection(function(err, connection) {
          // Use the connection
          connection.query('INSERT INTO chat_log(username, message, room) VALUES ("' + socket.username + '", "' + data + '", "' + socket.room + '")', function(err, rows) {
            // And done with the connection.
            connection.release();

            // Don't use the connection here, it has been returned to the pool.
          });
        });

        // connection.query('INSERT INTO chat_log(username, message, room) VALUES ("' + socket.username + '", "' + data + '", "' + socket.room + '")', function(err, rows, fields) {
        //   if (err) throw err;
        // });

    });

    socket.on('adduser', function(username) {
        socket.username = username;
        if (usernames[socket.username]) {
            socket.emit('connect', true);
            return 0;
        }
        socket.room = 'Calculus';
        usernames[username] = username;
        socket.join('Calculus');
        socket.emit('updatechat', 'SERVER', 'You have connected to Calculus.');
        // broadcast to all users
        socket.broadcast.to('Calculus').emit('updatechat', 'SERVER', username + ' has connected.');
        // update list client side
        io.sockets.emit('updateusers', usernames);
        socket.emit('updaterooms', rooms, 'Calculus');
    });

    socket.on('switchroom', function (newroom) {
        socket.leave(socket.room);
        socket.join(newroom);
        socket.emit('updatechat', 'SERVER', 'You have connected to ' + newroom + '.');
        socket.broadcast.to(socket.room).emit('updatechat', 'SERVER', socket.username + ' has left the room.');
        socket.room = newroom;
        socket.broadcast.to(socket.room).emit('updatechat', 'SERVER', socket.username + ' has joined the room');
        socket.emit('updaterooms', rooms, newroom);

    });

    // sad panda is sad with this event
    socket.on('disconnect', function() {
        delete usernames[socket.username];
        io.sockets.emit('updateusers', usernames);
        // broadcast
        socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has disconnected.');
        socket.leave(socket.room);
    });

});

console.log('Listening...');
<|endoftext|>


<commit_before>'use strict';
var clc = require("cli-color");

var logLevels = {
    'debug': 1,
    'log': 1, //to handle the logType easier
    'info': 2,
    'warn': 3,
    'warning': 3,
    'error': 4
};

clc.nocolor = function (args) {
    return args;
};
//global nodelog configuration
var nodelog = {
    global: {
        logLevel: logLevels.warning,
    },
    console: {},
    default: {
        color: {
            log: clc.nocolor,
            debug: clc.nocolor,
            info: clc.magenta,
            warn: clc.yellow,
            error: clc.red,
            important: clc.white
        }
    }
};

//flag which helps to detect an existing initialization
nodelog.console.ExtensionsInitialized = false;

module.exports = function (options, enableConsole) {
    options = options || {};

    //for performance we analyze strings only if they are given
    if (options.level) {
        //default log level is warning
        options.level = options.level || 'debug';
        //for the first call we have to analyze the string :-/
        switch (options.level.toLowerCase()) {
        case 'all':
        case 'debug':
        case 'log':
        case 'verbose':
            options.logLevel = logLevels.debug;
            break;
        case 'info':
            options.logLevel = logLevels.info;
            break;
        case 'warning':
        case 'warn':
            options.logLevel = logLevels.warn;
            break;
        case 'error' || 'exception':
            options.logLevel = logLevels.error;
            break;
        default:
            console.log('using default log level');
            if (options.logLevel != nodelog.default.logLevel)
                options.logLevel = logLevels.debug;
        }
    }
    options.logLevel = options.logLevel || nodelog.global.logLevel;
    //copy back, because its the new default for later instances
    nodelog.global.logLevel = options.logLevel;

    if (!options.color) {
        //simple, just use te default
        options.color = options.color || nodelog.default.color;
    } else {
        //some colors are specified by the user, so figure out which
        options.color.log = options.color.log || options.color.debug || nodelog.default.color.log || nodelog.default.color.log;
        options.color.debug = options.color.log;
        options.color.info = options.color.info || nodelog.default.color.info;
        options.color.warn = options.color.warn || nodelog.default.color.warn;
        options.color.error = options.color.error || nodelog.default.color.error;
        options.color.important = options.color.important || nodelog.default.color.importantx;
    }
    //set default prefix
    //use options, if hat is not set a configured global,
    //if that is not set use our defualt
    options.prefix = options.prefix || nodelog.global.prefix || function (logType) {
        if (logType) logType = '(' + logType + ')\t';
        else logType = '';
        return logType + new Date().toISOString();
    };

    //if there is no public prefix, use the configured one
    nodelog.global.prefix = nodelog.global.prefix || options.prefix;

    //save the options to public if they are not there
    //TODO P2: use option by option
    nodelog.default = nodelog.default || options;

    //initialization
    (function () {

        if (nodelog.console.ExtensionsInitialized) return;

        if (options.logLevel <= logLevels.debug)
            console.log("initialize logger");

        if (enableConsole) {
            if (options.logLevel <= logLevels.debug)
                console.log("initialize console.log extension");
            nodelog.console.ExtensionsInitialized = true;
            ['log', 'info', 'warn', 'error'].forEach(function (logType) {
                var org = console[logType].bind(console);
                console[logType] = function () {

                    //analyze og levels
                    if (logLevels[logType] < nodelog.global.logLevel) return;

                    arguments[0] = options.color[logType](nodelog.global.prefix(logType)) + ' - ' + arguments[0];
                    org.apply(console, arguments);
                };
            });
        }
    }());

    var log = {
        options: options,

        //publish loglevels on log object
        logLevels: logLevels,
        //in the case that console.log should not be modified, we support log....() funcitons with colors

        setPrefix: function (func) {
            options.prefix = func;
            //if (!nodelog.console.ExtensionsInitialized)
            nodelog.global.prefix = func;
        },

        setColor: function (loglevel, color) {
            options.color[loglevel] = color;
        },

        getColor: function (loglevel) {
            return options.color[loglevel];
        },

        //TODO P1: Set LogLevel + SetColors

        writeLine: function (logType, args) {
            //fallback for unknown logTypes
            if (!options.color[logType]) logType = 'debug';
            if (logLevels[logType] < options.logLevel) return;

            //we have to set the colors here if the console command is not modified
            if (!nodelog.console.ExtensionsInitialized) {
                args[0] = options.color[logType](options.prefix(logType)) + ' - ' + args[0];
            }
            switch (logType) {
            case 'info':
                console.info.apply(console, args);
                break;
            case 'warn':
                console.warn.apply(console, args);
                break;
            case 'error':
                console.error.apply(console, args);
                break;
            default:
                console.log.apply(console, args);
            }
        },
        debug: function () {
            this.writeLine('debug', arguments);
        },
        info: function () {
            this.writeLine('info', arguments);
        },
        warning: function () {
            this.writeLine('warn', arguments);
        },
        error: function () {
            this.writeLine('error', arguments);
        },
        important: function () {
            arguments[0] = nodelog.default.color.important(' --> ' +
                arguments[0] + ' <--');
            console.log.apply(console, arguments);
        }
    };
    return log;
};
<commit_msg>fix jslint issues and reduce global objects<commit_after>/*jslint node: true */
(function () {
    'use strict';
    var clc = require("cli-color");

    clc.nocolor = function (args) {
        return args;
    };
    //global nodelog configuration
    var nodelog = {
        logLevels: {
            'debug': 1,
            'log': 1, //to handle the logType easier
            'info': 2,
            'warn': 3,
            'warning': 3,
            'error': 4
        },
        global: {
            //default log level is warning
            logLevel: 3,
        },
        console: {
            ExtensionsInitialized: false
        },
        default: {
            color: {
                log: clc.nocolor,
                debug: clc.nocolor,
                info: clc.magenta,
                warn: clc.yellow,
                error: clc.red,
                important: clc.white
            }
        }
    };

    //flag which helps to detect an existing initialization
    //nodelog.console.ExtensionsInitialized = false;

    module.exports = function (options, enableConsole) {
        options = options || {};

        //for performance we analyze strings only if they are given
        if (options.level) {
            //default log level is warning
            options.level = options.level || 'debug';
            //for the first call we have to analyze the string :-/
            switch (options.level.toLowerCase()) {
            case 'all':
            case 'debug':
            case 'log':
            case 'verbose':
                options.logLevel = nodelog.logLevels.debug;
                break;
            case 'info':
                options.logLevel = nodelog.logLevels.info;
                break;
            case 'warning':
            case 'warn':
                options.logLevel = nodelog.logLevels.warn;
                break;
            case 'error' || 'exception':
                options.logLevel = nodelog.logLevels.error;
                break;
            default:
                console.log('using default log level');
                if (options.logLevel != nodelog.default.logLevel) {
                    options.logLevel = nodelog.logLevels.debug;
                }
            }
        }
        options.logLevel = options.logLevel || nodelog.global.logLevel;
        //copy back, because its the new default for later instances
        nodelog.global.logLevel = options.logLevel;

        if (!options.color) {
            //simple, just use te default
            options.color = options.color || nodelog.default.color;
        } else {
            //some colors are specified by the user, so figure out which
            options.color.log = options.color.log || options.color.debug || nodelog.default.color.log || nodelog.default.color.log;
            options.color.debug = options.color.log;
            options.color.info = options.color.info || nodelog.default.color.info;
            options.color.warn = options.color.warn || nodelog.default.color.warn;
            options.color.error = options.color.error || nodelog.default.color.error;
            options.color.important = options.color.important || nodelog.default.color.importantx;
        }
        //set default prefix
        //use options, if hat is not set a configured global,
        //if that is not set use our defualt
        options.prefix = options.prefix || nodelog.global.prefix || function (logType) {
            if (logType) {
                logType = '(' + logType + ')\t';
            } else {
                logType = '';
            }
            return logType + new Date().toISOString();
        };

        //if there is no public prefix, use the configured one
        nodelog.global.prefix = nodelog.global.prefix || options.prefix;

        //save the options to public if they are not there
        //TODO P2: use option by option
        nodelog.default = nodelog.default || options;

        //initialization
        (function () {

            if (nodelog.console.ExtensionsInitialized) {
                return;
            }

            if (options.logLevel <= nodelog.logLevels.debug) {
                console.log("initialize logger");
            }

            if (enableConsole) {
                if (options.logLevel <= nodelog.logLevels.debug) {
                    console.log("initialize console.log extension");
                }
                nodelog.console.ExtensionsInitialized = true;
            ['log', 'info', 'warn', 'error'].forEach(function (logType) {
                    var org = console[logType].bind(console);
                    console[logType] = function () {

                        //analyze og levels
                        if (nodelog.logLevels[logType] < nodelog.global.logLevel) {
                            return;
                        }

                        arguments[0] = options.color[logType](nodelog.global.prefix(logType)) + ' - ' + arguments[0];
                        org.apply(console, arguments);
                    };
                });
            }
        }());

        var log = {
            options: options,

            //publish loglevels on log object
            logLevels: nodelog.logLevels,
            //in the case that console.log should not be modified, we support log....() funcitons with colors

            setPrefix: function (func) {
                options.prefix = func;
                //if (!nodelog.console.ExtensionsInitialized)
                nodelog.global.prefix = func;
            },

            setColor: function (loglevel, color) {
                options.color[loglevel] = color;
            },

            getColor: function (loglevel) {
                return options.color[loglevel];
            },

            writeLine: function (logType, args) {
                //fallback for unknown logTypes
                if (!options.color[logType]) {
                    logType = 'debug';
                }
                if (nodelog.logLevels[logType] < options.logLevel) {
                    return;
                }

                //we have to set the colors here if the console command is not modified
                if (!nodelog.console.ExtensionsInitialized) {
                    args[0] = options.color[logType](options.prefix(logType)) + ' - ' + args[0];
                }
                switch (logType) {
                case 'info':
                    console.info.apply(console, args);
                    break;
                case 'warn':
                    console.warn.apply(console, args);
                    break;
                case 'error':
                    console.error.apply(console, args);
                    break;
                default:
                    console.log.apply(console, args);
                }
            },
            debug: function () {
                this.writeLine('debug', arguments);
            },
            info: function () {
                this.writeLine('info', arguments);
            },
            warning: function () {
                this.writeLine('warn', arguments);
            },
            error: function () {
                this.writeLine('error', arguments);
            },
            important: function () {
                arguments[0] = nodelog.default.color.important(' --> ' +
                    arguments[0] + ' <--');
                console.log.apply(console, arguments);
            }
        };

        return log;
    };
})();<|endoftext|>


<commit_before>/*jshint node:true */

"use strict";

var through = require('through');

module.exports = function (doit, child) {
	if (!child) {
		throw new Error('gulp-if: child action is required');
	}
	if (doit) {
		return child;
	} else {
		// noop
		return through(function(data){
			this.emit('data', data);
		});
	}
};
<commit_msg>Be able to use a boolean function<commit_after>/*jshint node:true */

"use strict";

var through = require('through');

module.exports = function (doit, child) {
	if (!child) {
		throw new Error('gulp-if: child action is required');
	}

	// if doit is a boolean function
	if(typeof doit === 'function') {
		var _write = function(file) {

		    if(!!doit.call(null, file)) {

		            var get_this = this;

		            var detour = through()
		                    .pipe(child)
		                    .through(function(data) {get_this.emit('data', data);});

		            return detour.write(file);

		    } else {
		        // pass along
		        return this.emit('data' file);
		    }

		}

		return through(_write);
	}

	if (doit) {
		return child;
	} else {
		// noop
		return through(function(data){
			this.emit('data', data);
		});
	}
};
<|endoftext|>


<commit_before>/**
 *
 * Contructor variation
 *
 * ```js
 * // normal
 * var url = new Url('http://example.com/path/a/');
 *
 * // function type
 * var url = Url('http://example.com/path/a/');
 *
 * // with url string
 * var url = Url('http://example.com/path/a/');
 *
 * // with url object
 * var nodeUrl = require('url');
 * var nodeUrlObj = nodeUrl.parse('http://example.com/path/a/');
 * var url = Url(nodeUrlObj);
 *
 * ```
 *
 * ┌─────────────────────────────────────────────────────────────────────────────┐
 * │                                    href                                     │
 * ├──────────┬┬───────────┬─────────────────┬───────────────────────────┬───────┤
 * │ protocol ││   auth    │      host       │           path            │ hash  │
 * │          ││           ├──────────┬──────┼──────────┬────────────────┤       │
 * │          ││           │ hostname │ port │ pathname │     search     │       │
 * │          ││           │          │      │          ├─┬──────────────┤       │
 * │          ││           │          │      │          │ │    query     │       │
 * "  http:   // user:pass @ host.com : 8080   /p/a/t/h  ?  query=string   #hash "
 * │          ││           │          │      │          │ │              │       │
 * └──────────┴┴───────────┴──────────┴──────┴──────────┴─┴──────────────┴───────┘
 * (all spaces in the "" line should be ignored -- they're purely for formatting)
 *
 */
'use strict';

var url = require('url');
//var path = require('path');
var _ = require('lodash');

var defaults = {};

var slice = function(array, begin, end){
	return Array.prototype.slice.call(array, begin, end);
};
var slash = '/';
var resolve = function(start){
	return slice(arguments, 1).reduce(function(a, b){
		a = a.split(slash);
		b = b.split(slash);
		var el;
		while((el = b.shift()) != undefined) {
			if (el === '..') a.pop();
			else if (el === '.') continue;
			else a.push(el);

			if (a.length <= 0) return '';
		}
		return a.join(slash);
	}, start);
};

var Url = function(urlObj, parseQueryString, slashesDenoteHost){
	if (!(this instanceof Url)) return new Url(urlObj, parseQueryString, slashesDenoteHost);

	if (typeof urlObj === 'string') urlObj = url.parse(urlObj, parseQueryString, slashesDenoteHost);

	if (typeof urlObj != 'object') throw new Error('a type of 1st argument should be string or object.');

	this._url = urlObj;
};

Url.parse = function(urlString){
	return Url(urlString);
};
Url.format = function(urlObj){
	return url.format(urlObj);
};

Url.prototype.resolve = function(next){
	var resolved = url.resolve(this._url.href, next);
	return Url(resolved);
};
Url.prototype.cd = function(pathname){
	var resolved = resolve(this._url.pathname, pathname);
	this.pathname = resolved;
	return this;
};
Url.prototype.format = function(){
	return this._url.href;
};
Url.prototype._refresh = function(){
	this._url = url.parse(url.format(this._url));
};
Object.defineProperties(Url.prototype, {
	"href": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.href;
		},
		set: function(val) {
			this._url = url.parse(val);
		}
	},
	"protocol": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.protocol;
		},
		set: function(val) {
			this._url.protocol = val;
			this._refresh();
		}
	},
	"host": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.host;
		},
		set: function(val) {
			this._url.host = val;
			this._refresh();
		}
	},
	"auth": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.auth;
		},
		set: function(val) {
			this._url.auth = val;
			this._refresh();
		}
	},
	"hostname": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.hostname;
		},
		set: function(val) {
			this._url.hostname = val;
			delete this._url.host;
			this._refresh();
		}
	},
	"port": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.port;
		},
		set: function(val) {
			this._url.port = val;
			delete this._url.host;
			this._refresh();
		}
	},
	"path": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.path;
		},
		set: function(val) {
			if (!/^\//.test(val)) val = '/' + val;
			this.href = url.resolve(this._url.href, val);
		}
	},
	"pathname": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.pathname;
		},
		set: function(val) {
			this._url.pathname = val;
			this._refresh();
		}
	},
	"search": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.search;
		},
		set: function(val) {
			this._url.search = val;
			this._refresh();
		}
	},
	"query": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.query;
		},
		set: function(val) {
			this._url.query = val;
			delete this._url.search;
			this._refresh();
		}
	},
	"hash": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.hash;
		},
		set: function(val) {
			this._url.hash = val;
			this._refresh();
		}
	}
});

module.exports = Url;
<commit_msg>change != to !==<commit_after>/**
 *
 * Contructor variation
 *
 * ```js
 * // normal
 * var url = new Url('http://example.com/path/a/');
 *
 * // function type
 * var url = Url('http://example.com/path/a/');
 *
 * // with url string
 * var url = Url('http://example.com/path/a/');
 *
 * // with url object
 * var nodeUrl = require('url');
 * var nodeUrlObj = nodeUrl.parse('http://example.com/path/a/');
 * var url = Url(nodeUrlObj);
 *
 * ```
 *
 * ┌─────────────────────────────────────────────────────────────────────────────┐
 * │                                    href                                     │
 * ├──────────┬┬───────────┬─────────────────┬───────────────────────────┬───────┤
 * │ protocol ││   auth    │      host       │           path            │ hash  │
 * │          ││           ├──────────┬──────┼──────────┬────────────────┤       │
 * │          ││           │ hostname │ port │ pathname │     search     │       │
 * │          ││           │          │      │          ├─┬──────────────┤       │
 * │          ││           │          │      │          │ │    query     │       │
 * "  http:   // user:pass @ host.com : 8080   /p/a/t/h  ?  query=string   #hash "
 * │          ││           │          │      │          │ │              │       │
 * └──────────┴┴───────────┴──────────┴──────┴──────────┴─┴──────────────┴───────┘
 * (all spaces in the "" line should be ignored -- they're purely for formatting)
 *
 */
'use strict';

var url = require('url');
//var path = require('path');
var _ = require('lodash');

var defaults = {};

var slice = function(array, begin, end){
	return Array.prototype.slice.call(array, begin, end);
};
var slash = '/';
var resolve = function(start){
	return slice(arguments, 1).reduce(function(a, b){
		a = a.split(slash);
		b = b.split(slash);
		var el;
		while((el = b.shift()) !== undefined) {
			if (el === '..') a.pop();
			else if (el === '.') continue;
			else a.push(el);

			if (a.length <= 0) return '';
		}
		return a.join(slash);
	}, start);
};

var Url = function(urlObj, parseQueryString, slashesDenoteHost){
	if (!(this instanceof Url)) return new Url(urlObj, parseQueryString, slashesDenoteHost);

	if (typeof urlObj === 'string') urlObj = url.parse(urlObj, parseQueryString, slashesDenoteHost);

	if (typeof urlObj !== 'object') throw new Error('a type of 1st argument should be string or object.');

	this._url = urlObj;
};

Url.parse = function(urlString){
	return Url(urlString);
};
Url.format = function(urlObj){
	return url.format(urlObj);
};

Url.prototype.resolve = function(next){
	var resolved = url.resolve(this._url.href, next);
	return Url(resolved);
};
Url.prototype.cd = function(pathname){
	var resolved = resolve(this._url.pathname, pathname);
	this.pathname = resolved;
	return this;
};
Url.prototype.format = function(){
	return this._url.href;
};
Url.prototype._refresh = function(){
	this._url = url.parse(url.format(this._url));
};
Object.defineProperties(Url.prototype, {
	"href": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.href;
		},
		set: function(val) {
			this._url = url.parse(val);
		}
	},
	"protocol": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.protocol;
		},
		set: function(val) {
			this._url.protocol = val;
			this._refresh();
		}
	},
	"host": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.host;
		},
		set: function(val) {
			this._url.host = val;
			this._refresh();
		}
	},
	"auth": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.auth;
		},
		set: function(val) {
			this._url.auth = val;
			this._refresh();
		}
	},
	"hostname": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.hostname;
		},
		set: function(val) {
			this._url.hostname = val;
			delete this._url.host;
			this._refresh();
		}
	},
	"port": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.port;
		},
		set: function(val) {
			this._url.port = val;
			delete this._url.host;
			this._refresh();
		}
	},
	"path": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.path;
		},
		set: function(val) {
			if (!/^\//.test(val)) val = '/' + val;
			this.href = url.resolve(this._url.href, val);
		}
	},
	"pathname": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.pathname;
		},
		set: function(val) {
			this._url.pathname = val;
			this._refresh();
		}
	},
	"search": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.search;
		},
		set: function(val) {
			this._url.search = val;
			this._refresh();
		}
	},
	"query": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.query;
		},
		set: function(val) {
			this._url.query = val;
			delete this._url.search;
			this._refresh();
		}
	},
	"hash": {
		configurable: true,
		enumerable: true,
		get: function() {
			return this._url.hash;
		},
		set: function(val) {
			this._url.hash = val;
			this._refresh();
		}
	}
});

module.exports = Url;
<|endoftext|>


<commit_before>'use strict';

/**
 * Parse the input string with options.
 *
 * @param {String} str The string to parse.
 * @param {Object?} opts
 *        @param {Boolean?} opts.loose Whether to tolerate ambiguous delimiters. Default: false
 *        @param {String?} opts.lang The name of the parser to use if opts.parsers is not a function. Default: 'yaml'
 *        @param {(String|Array)?} opts.delims Custom delimiter(s). Default: '---' or ['---', '---']
 *        @param {(Function|Object.<String, Function>)?} opts.parsers Custom parser(s). Default: {'yaml':yaml,'toml':toml}
 * @return {Object} result
 *         @param {String} result.src The original input string.
 *         @param {String} result.body The input string without front matter.
 *         @param {Mixed} result.data The data returned from the parsers. Default: null
 */
function matter(str, opts) {

  str = formatString(str);
  opts = formatOptions(opts);
  var result = {src: str, data: null, body: str};
  if (!str) {
    return result;
  }

  var strict = !opts.loose;
  var header = opts.delims[0];
  var footer = opts.delims[1];
  var dataStart, dataEnd;
  // Front matter must start from the first byte.
  if (str.substr(0, header.length) !== header ||
      // Whether the delimiter is followed by a strange character.
      (!opts.loose && header.length < str.length &&
          str[header.length] !== '\n' &&
          str[header.length] === header[header.length-1]) ||
      // Metadata and delimiters should be separated with linefeeds.
      (dataStart = str.indexOf('\n', header.length)) < 0 ||
      (dataEnd = str.indexOf('\n' + footer, dataStart)) < 0) {
    return result;
  }
  var bodyStart = dataEnd + 1 + footer.length;
  // Whether the delimiter is followed by strange characters.
  if (strict && bodyStart < str.length) {
    if (str[bodyStart] !== '\n' && str[bodyStart] === footer[footer.length-1]) {
      return result;
    }
    while (bodyStart < str.length && str[bodyStart] !== '\n') {
      if (/^[^\s]$/.test(str[bodyStart])) {
        return result;
      }
      bodyStart++;
    }
  }  // else: Tolerate the case that a linefeed is missing: <end-delimiter><body>
  if (str[bodyStart] === '\r') { bodyStart++; }
  if (str[bodyStart] === '\n') { bodyStart++; }
  var data;
  if (dataStart < dataEnd &&
      (data = str.substr(dataStart, dataEnd - dataStart).trim())) {
    var lang = str.substr(header.length, dataStart - header.length)
                  .trim().toLowerCase() || opts.lang;
    var parse;
    if (typeof opts.parsers === 'function') {
      parse = opts.parsers;
    } else if (opts.parsers != null && opts.parsers[lang]) {
      parse = opts.parsers[lang];
    } else {
      parse = matter.parsers[lang];
    }
    if (typeof parse === 'function') {
      result.data = parse(data, {loose: opts.loose});
    } else {
      throw new Error(message('No parser found for the language: ' + lang));
    }
  }
  result.body = result.body.substr(bodyStart);

  return result;
}

/**
 * Test if the input string contains front matter.
 *
 * @param {String} str The input string.
 * @param {Options} opts
 *        @param {Boolean} opts.loose Whether to tolerate ambiguous delimiters.
 *        @param {(String|Array)?} opts.delims Custom delimiter(s). Default: '---' or ['---', '---']
 * @return {Boolean}
 */
matter.test = function (str, opts) {
  if ((typeof str !== 'string') || !str) {
    return false;
  }
  opts = (opts != null ? opts : {});
  var delims = formatDelimiters(opts.delims, true);
  if (!delims) {
    return false;
  }
  var header = delims[0];
  var footer = delims[1];
  var strict = !opts.loose;
  var dataStart, dataEnd;
  // Front matter must start from the first byte.
  if (str.substr(0, header.length) !== header ||
      // Whether the delimiter is followed by a strange character.
      (strict && header.length < str.length &&
          str[header.length] !== '\n' &&
          str[header.length] === header[header.length-1]) ||
      // Metadata and delimiters should be separated with linefeeds.
      (dataStart = str.indexOf('\n', header.length)) < 0 ||
      (dataEnd = str.indexOf('\n' + footer, dataStart)) < 0) {
    return false;
  }
  var bodyStart = dataEnd + 1 + footer.length;
  // Whether the delimiter is followed by strange characters.
  if (strict && bodyStart < str.length) {
    if (str[bodyStart] !== '\n' && str[bodyStart] === footer[footer.length-1]) {
      return false;
    }
    while (bodyStart < str.length && str[bodyStart] !== '\n') {
      if (/^[^\s]$/.test(str[bodyStart])) {
        return false;
      }
      bodyStart++;
    }
  }  // else: Tolerate the case that a linefeed is missing: <end-delimiter><body>
  return true;
};

/**
 * Read and parse the file synchronously.
 *
 * @param {String} path The path to the file.
 * @param {Object?} opts Options to parse to matter().
 * @return {Object} result The result from matter().
 */
matter.readFileSync = function (path, opts) {
  opts = formatOptions(opts);
  var fs = require('fs');
  var content = fs.readFileSync(path, {encoding: 'utf8'});
  var result = matter(content, opts);
  result.path = fs.realpathSync(path);
  return result;
};

/**
 * Read and parse the file asynchronously.
 *
 * @param {String} path The path to the file.
 * @param {Object?} opts Options to parse to matter().
 * @param {Function} result The result from matter().
 */
matter.readFile = function (path, opts, callback) {
  // Options are optional, and callback function can take the place of it.
  if (typeof opts === 'function') {
    callback = opts;
    opts = null
  }
  if (typeof callback !== 'function') {
    throw new Error(message('matter.readFile needs a callback function.'));
  }
  opts = formatOptions(opts);
  var fs = require('fs');
  fs.readFile(path, {encoding: 'utf8'}, function (err, content) {
    if (err) {
      callback(err, null);
    }
    var result = matter(content, opts);
    result.path = fs.realpathSync(path);
    callback(err, result);
  });
};

function formatString(str) {
  if (typeof str !== 'string') {
    throw new Error(message('The first argument of matter() must be of type String.'));
  }
  if (str.charCodeAt(0) === 0xFEFF) {
    // Remove the optional byte-order mark.
    return str.substr(1);
  }
  return str;
}

function formatDelimiters(delims, nothrow) {
  if (!Array.isArray(delims)) {
    delims = [delims];
  } else {
    delims = delims.slice(0);  // shallow-clone
  }
  delims[0] = delims[0] != null ?
      delims[0] : (delims[1] != null ? delims[1] : '---');
  delims[1] = delims[1] != null ?
      delims[1] : (delims[0] != null ? delims[0] : '---');
  if ((typeof delims[0] !== 'string') || (typeof delims[1] !== 'string')) {
    if (!nothrow) {
      throw new Error(message('The option "delims" is invalid.'));
    }
    return null;
  }
  return delims;
}

function formatOptions(opts) {
  if (opts == null) {
    return {
      loose: false,
      lang: 'yaml',
      delims: ['---', '---'],
      parsers: null
    };
  } else {  // shallow-clone
    opts = {
      loose: opts.loose,
      lang: opts.lang,
      delims: opts.delims,
      parsers: opts.parsers
    };
  }
  opts.lang = (opts.lang != null) ? opts.lang : 'yaml';
  if (typeof opts.lang !== 'string') {
    throw new Error(message('The option "lang" must be a string.'));
  }
  opts.lang = opts.lang.trim().toLowerCase();
  opts.delims = formatDelimiters(opts.delims);
  opts.parsers = (opts.parsers != null ? opts.parsers : null);
  opts.loose = Boolean(opts.loose);
  return opts;
}

function message(msg) {
  return '[matter]: ' + msg;
}

/**
 * Expose modules required by matter().
 */
var fm_yaml, fm_toml;
matter.modules = {
  get yaml() { return fm_yaml || (fm_yaml = require('js-yaml')); },
  get toml() { return fm_toml || (fm_toml = require('toml')); },
};

matter.parsers = {
  /**
   * @param {Object} opts
   *        @param {Boolean} opts.loose Whether to ignore errors.
   * @return {Mixed}
   */
  yaml: function (str, opts) {
    opts = (opts == null ? {} : opts);
    var parser = fm_yaml || (fm_yaml = require('js-yaml'));
    try {
      return parser.safeLoad(str);
    } catch (err) {
      return null;
    }
  },
  /**
   * @param {Object} opts
   *        @param {Boolean} opts.loose Whether to ignore errors.
   * @return {Mixed}
   */
  toml: function (str, opts) {
    var parser = fm_toml || (fm_toml = require('toml'));
    try {
      return parser.parse(str);
    } catch (err) {
      return null;
    }
  }
};

module.exports = matter;
<commit_msg>Fix builtin YAML parser, for consistency with general configurations<commit_after>'use strict';

/**
 * Parse the input string with options.
 *
 * @param {String} str The string to parse.
 * @param {Object?} opts
 *        @param {Boolean?} opts.loose Whether to tolerate ambiguous delimiters. Default: false
 *        @param {String?} opts.lang The name of the parser to use if opts.parsers is not a function. Default: 'yaml'
 *        @param {(String|Array)?} opts.delims Custom delimiter(s). Default: '---' or ['---', '---']
 *        @param {(Function|Object.<String, Function>)?} opts.parsers Custom parser(s). Default: {'yaml':yaml,'toml':toml}
 * @return {Object} result
 *         @param {String} result.src The original input string.
 *         @param {String} result.body The input string without front matter.
 *         @param {Mixed} result.data The data returned from the parsers. Default: null
 */
function matter(str, opts) {

  str = formatString(str);
  opts = formatOptions(opts);
  var result = {src: str, data: null, body: str};
  if (!str) {
    return result;
  }

  var strict = !opts.loose;
  var header = opts.delims[0];
  var footer = opts.delims[1];
  var dataStart, dataEnd;
  // Front matter must start from the first byte.
  if (str.substr(0, header.length) !== header ||
      // Whether the delimiter is followed by a strange character.
      (!opts.loose && header.length < str.length &&
          str[header.length] !== '\n' &&
          str[header.length] === header[header.length-1]) ||
      // Metadata and delimiters should be separated with linefeeds.
      (dataStart = str.indexOf('\n', header.length)) < 0 ||
      (dataEnd = str.indexOf('\n' + footer, dataStart)) < 0) {
    return result;
  }
  var bodyStart = dataEnd + 1 + footer.length;
  // Whether the delimiter is followed by strange characters.
  if (strict && bodyStart < str.length) {
    if (str[bodyStart] !== '\n' && str[bodyStart] === footer[footer.length-1]) {
      return result;
    }
    while (bodyStart < str.length && str[bodyStart] !== '\n') {
      if (/^[^\s]$/.test(str[bodyStart])) {
        return result;
      }
      bodyStart++;
    }
  }  // else: Tolerate the case that a linefeed is missing: <end-delimiter><body>
  if (str[bodyStart] === '\r') { bodyStart++; }
  if (str[bodyStart] === '\n') { bodyStart++; }
  var data;
  if (dataStart < dataEnd &&
      (data = str.substr(dataStart, dataEnd - dataStart).trim())) {
    var lang = str.substr(header.length, dataStart - header.length)
                  .trim().toLowerCase() || opts.lang;
    var parse;
    if (typeof opts.parsers === 'function') {
      parse = opts.parsers;
    } else if (opts.parsers != null && opts.parsers[lang]) {
      parse = opts.parsers[lang];
    } else {
      parse = matter.parsers[lang];
    }
    if (typeof parse === 'function') {
      result.data = parse(data, {loose: opts.loose});
    } else {
      throw new Error(message('No parser found for the language: ' + lang));
    }
  }
  result.body = result.body.substr(bodyStart);

  return result;
}

/**
 * Test if the input string contains front matter.
 *
 * @param {String} str The input string.
 * @param {Options} opts
 *        @param {Boolean} opts.loose Whether to tolerate ambiguous delimiters.
 *        @param {(String|Array)?} opts.delims Custom delimiter(s). Default: '---' or ['---', '---']
 * @return {Boolean}
 */
matter.test = function (str, opts) {
  if ((typeof str !== 'string') || !str) {
    return false;
  }
  opts = (opts != null ? opts : {});
  var delims = formatDelimiters(opts.delims, true);
  if (!delims) {
    return false;
  }
  var header = delims[0];
  var footer = delims[1];
  var strict = !opts.loose;
  var dataStart, dataEnd;
  // Front matter must start from the first byte.
  if (str.substr(0, header.length) !== header ||
      // Whether the delimiter is followed by a strange character.
      (strict && header.length < str.length &&
          str[header.length] !== '\n' &&
          str[header.length] === header[header.length-1]) ||
      // Metadata and delimiters should be separated with linefeeds.
      (dataStart = str.indexOf('\n', header.length)) < 0 ||
      (dataEnd = str.indexOf('\n' + footer, dataStart)) < 0) {
    return false;
  }
  var bodyStart = dataEnd + 1 + footer.length;
  // Whether the delimiter is followed by strange characters.
  if (strict && bodyStart < str.length) {
    if (str[bodyStart] !== '\n' && str[bodyStart] === footer[footer.length-1]) {
      return false;
    }
    while (bodyStart < str.length && str[bodyStart] !== '\n') {
      if (/^[^\s]$/.test(str[bodyStart])) {
        return false;
      }
      bodyStart++;
    }
  }  // else: Tolerate the case that a linefeed is missing: <end-delimiter><body>
  return true;
};

/**
 * Read and parse the file synchronously.
 *
 * @param {String} path The path to the file.
 * @param {Object?} opts Options to parse to matter().
 * @return {Object} result The result from matter().
 */
matter.readFileSync = function (path, opts) {
  opts = formatOptions(opts);
  var fs = require('fs');
  var content = fs.readFileSync(path, {encoding: 'utf8'});
  var result = matter(content, opts);
  result.path = fs.realpathSync(path);
  return result;
};

/**
 * Read and parse the file asynchronously.
 *
 * @param {String} path The path to the file.
 * @param {Object?} opts Options to parse to matter().
 * @param {Function} result The result from matter().
 */
matter.readFile = function (path, opts, callback) {
  // Options are optional, and callback function can take the place of it.
  if (typeof opts === 'function') {
    callback = opts;
    opts = null
  }
  if (typeof callback !== 'function') {
    throw new Error(message('matter.readFile needs a callback function.'));
  }
  opts = formatOptions(opts);
  var fs = require('fs');
  fs.readFile(path, {encoding: 'utf8'}, function (err, content) {
    if (err) {
      callback(err, null);
    }
    var result = matter(content, opts);
    result.path = fs.realpathSync(path);
    callback(err, result);
  });
};

function formatString(str) {
  if (typeof str !== 'string') {
    throw new Error(message('The first argument of matter() must be of type String.'));
  }
  if (str.charCodeAt(0) === 0xFEFF) {
    // Remove the optional byte-order mark.
    return str.substr(1);
  }
  return str;
}

function formatDelimiters(delims, nothrow) {
  if (!Array.isArray(delims)) {
    delims = [delims];
  } else {
    delims = delims.slice(0);  // shallow-clone
  }
  delims[0] = delims[0] != null ?
      delims[0] : (delims[1] != null ? delims[1] : '---');
  delims[1] = delims[1] != null ?
      delims[1] : (delims[0] != null ? delims[0] : '---');
  if ((typeof delims[0] !== 'string') || (typeof delims[1] !== 'string')) {
    if (!nothrow) {
      throw new Error(message('The option "delims" is invalid.'));
    }
    return null;
  }
  return delims;
}

function formatOptions(opts) {
  if (opts == null) {
    return {
      loose: false,
      lang: 'yaml',
      delims: ['---', '---'],
      parsers: null
    };
  } else {  // shallow-clone
    opts = {
      loose: opts.loose,
      lang: opts.lang,
      delims: opts.delims,
      parsers: opts.parsers
    };
  }
  opts.lang = (opts.lang != null) ? opts.lang : 'yaml';
  if (typeof opts.lang !== 'string') {
    throw new Error(message('The option "lang" must be a string.'));
  }
  opts.lang = opts.lang.trim().toLowerCase();
  opts.delims = formatDelimiters(opts.delims);
  opts.parsers = (opts.parsers != null ? opts.parsers : null);
  opts.loose = Boolean(opts.loose);
  return opts;
}

function message(msg) {
  return '[matter]: ' + msg;
}

/**
 * Expose modules required by matter().
 */
var fm_yaml, fm_toml;
matter.modules = {
  get yaml() { return fm_yaml || (fm_yaml = require('js-yaml')); },
  get toml() { return fm_toml || (fm_toml = require('toml')); },
};

matter.parsers = {
  /**
   * @param {Object} opts
   *        @param {Boolean} opts.loose Whether to ignore errors.
   * @return {Mixed}
   */
  yaml: function (str, opts) {
    opts = (opts == null ? {} : opts);
    var parser = fm_yaml || (fm_yaml = require('js-yaml'));
    try {
      var data = parser.safeLoad(str);
      return data !== undefined ? data : {};
    } catch (err) {
      return null;
    }
  },
  /**
   * @param {Object} opts
   *        @param {Boolean} opts.loose Whether to ignore errors.
   * @return {Mixed}
   */
  toml: function (str, opts) {
    var parser = fm_toml || (fm_toml = require('toml'));
    try {
      return parser.parse(str);
    } catch (err) {
      return null;
    }
  }
};

module.exports = matter;
<|endoftext|>


<commit_before>'use strict';

var MongooseError = require('mongoose/lib/error');
var regex = /index:\s*.+?\.\$(\S*)\s*dup key:\s*\{.*?:\s*"(.*)"\s*\}/;

/**
 * Beautifies an E11000 or 11001 (unique constraint fail) Mongo error
 * by turning it into a validation error
 *
 * @param {MongoError} err Error to beautify
 * @param {Object} collection Collection for the associated model
 * @param {Object} map Map fields -> unique error messages
 * @param {function} callback Called with the beautified error
 * @return {null}
 */
function beautify(err, collection, map, callback) {
    var matches = regex.exec(err.message), props;

    if (matches && typeof matches[1] === 'string') {
        collection.indexInformation(function (dbErr, indexes) {
            var valError = new MongooseError.ValidationError(err),
                index = indexes && indexes[matches[1]];

            if (!dbErr && index) {
                // populate validation error with the fields
                // contained in the index
                index.forEach(function (item) {
                    props = {
                        type: 'Duplicate value',
                        path: item[0],
                        value: matches[2]
                    };

                    if (typeof map[item[0]] === 'string') {
                        props.message = map[item[0]];
                    }

                    valError.errors[item[0]] =
                        new MongooseError.ValidatorError(props);
                });

                callback(valError);
                return;
            }

            callback(dbErr);
        });
    }
}

module.exports = function (schema) {
    var tree = schema.tree, key, map = {};

    // fetch error messages defined in the
    // 'unique' field, and replace them with 'true'
    for (key in tree) {
        if (tree.hasOwnProperty(key)) {
            if (tree[key] && tree[key].unique) {
                map[key] = tree[key].unique;
                tree[key].unique = true;
            }
        }
    }

    schema.methods.trySave = function (callback) {
        var collection = this.collection;

        this.save(function (err, doc) {
            // we have a native E11000 error, lets beautify it
            if (err && err.name === 'MongoError' && (err.code === 11000 || err.code === 11001)) {
                beautify(err, collection, map, function (newErr) {
                    callback(newErr, doc);
                });
                return;
            }

            callback(err, doc);
        });
    };
};
<commit_msg>:bulb: Promisify the "trySave" method<commit_after>'use strict';

var MongooseError = require('mongoose/lib/error');
var regex = /index:\s*.+?\.\$(\S*)\s*dup key:\s*\{.*?:\s*"(.*)"\s*\}/;

/**
 * Beautifies an E11000 or 11001 (unique constraint fail) Mongo error
 * by turning it into a validation error
 *
 * @param {MongoError} err Error to beautify
 * @param {Object} collection Collection for the associated model
 * @param {Object} map Map fields -> unique error messages
 * @param {function} callback Called with the beautified error
 * @return {null}
 */
function beautify(err, collection, map, callback) {
    var matches = regex.exec(err.message), props;

    if (matches && typeof matches[1] === 'string') {
        collection.indexInformation(function (dbErr, indexes) {
            var valError = new MongooseError.ValidationError(err),
                index = indexes && indexes[matches[1]];

            if (!dbErr && index) {
                // populate validation error with the fields
                // contained in the index
                index.forEach(function (item) {
                    props = {
                        type: 'Duplicate value',
                        path: item[0],
                        value: matches[2]
                    };

                    if (typeof map[item[0]] === 'string') {
                        props.message = map[item[0]];
                    }

                    valError.errors[item[0]] =
                        new MongooseError.ValidatorError(props);
                });

                callback(valError);
                return;
            }

            callback(dbErr);
        });
    }
}

module.exports = function (schema) {
    var tree = schema.tree, key, map = {};

    // fetch error messages defined in the
    // 'unique' field, and replace them with 'true'
    for (key in tree) {
        if (tree.hasOwnProperty(key)) {
            if (tree[key] && tree[key].unique) {
                map[key] = tree[key].unique;
                tree[key].unique = true;
            }
        }
    }

    schema.methods.trySave = function (callback) {
        var _this = this;
        var args = [].slice.call(arguments);
        var lastArg = args.pop();
        var collection = this.collection;

        var proxyFn = function (resolve, handler) {
            return function (err, doc) {
                // we have a native E11000 error, lets beautify it
                if (err && err.name === 'MongoError' && (err.code === 11000 || err.code === 11001)) {
                    beautify(err, collection, map, function (newErr) {
                        handler(newErr, doc);
                    });
                    return;
                }

                if (resolve != null && err == null) {
                    resolve(doc);
                    return;
                }

                handler(err, doc);
            }
        }

        if ('function' === typeof lastArg) {
            _this.save(proxyFn(null, callback));
        } else {
            return new Promise(function(resolve, reject){
                _this.save(proxyFn(resolve, reject));
            });
        }

    };
};
<|endoftext|>


<commit_before>/**
 * @file gulp fontmin
 * @author junmer
 */

/* eslint-env node */

'use strict';
var path = require('path');
var gutil = require('gulp-util');
var through = require('through2-concurrent');
var assign = require('object-assign');
var prettyBytes = require('pretty-bytes');
var chalk = require('chalk');
var Fontmin = require('fontmin');

/**
 * rename
 *
 * @param  {Object} opts opts
 * @return {stream.Transform}      rename transform
 */
function rename(opts) {
    opts = opts || {};

    return through.obj(function (file, enc, cb) {
        file.path = opts.path;
        cb(null, file);
    });
}

/**
 * fontmin transform
 *
 * @param  {Object} opts opts
 * @return {stream.Transform}      fontmin transform
 */
module.exports = function (opts) {
    opts = assign({
        // TODO: remove this when gulp get's a real logger with levels
        verbose: process.argv.indexOf('--verbose') !== -1
    }, opts);

    var totalFiles = 0;
    var validExts = ['.ttf'];

    function printMsg(originalFile, optimizedFile, verbose) {
        var originalSize = originalFile.contents.length;
        var optimizedSize = optimizedFile.contents.length;
        var saved = originalSize - optimizedSize;
        var percent = originalSize > 0 ? (saved / originalSize) * 100 : 0;
        var savedMsg = 'saved ' + prettyBytes(saved) + ' - ' + percent.toFixed(1).replace(/\.0$/, '') + '%';
        var msg = saved > 0 ? savedMsg : 'already optimized';

        var optimizedType = (path.extname(optimizedFile.path) || path.extname(originalFile.path)).toLowerCase();

        if (verbose) {
            msg = chalk.green('✔ ') + originalFile.relative + ' -> ' + optimizedType + chalk.gray(' (' + msg + ')');
            gutil.log('gulp-fontmin:', msg);
        }

    }

    return through.obj(function (file, enc, cb) {
        if (file.isNull()) {
            cb(null, file);
            return;
        }

        if (file.isStream()) {
            cb(new gutil.PluginError('gulp-fontmin', 'Streaming not supported'));
            return;
        }

        if (validExts.indexOf(path.extname(file.path).toLowerCase()) === -1) {
            if (opts.verbose) {
                gutil.log('gulp-fontmin: Skipping unsupported font ' + chalk.blue(file.relative));
            }

            cb(null, file);
            return;
        }

        var text = opts.text || '';

        if (text && opts.chineseOnly) {
            text = text.replace(/[^\u4e00-\u9fa5]/g, '');
        }

        var fontmin = new Fontmin()
            .src(file.contents)
            .use(rename({
                path: file.path
            }))
            .use(Fontmin.glyph({
                text: text
            }))
            .use(Fontmin.ttf2eot())
            .use(Fontmin.ttf2woff())
            .use(Fontmin.ttf2svg())
            .use(Fontmin.css(opts));

        if (opts.use) {
            opts.use.forEach(fontmin.use.bind(fontmin));
        }

        var fileStream = this;

        fontmin.run(function (err, files) {
            if (err) {
                cb(new gutil.PluginError('gulp-fontmin:', err, {fileName: file.path}));
                return;
            }

            var gulpFile;

            files.forEach(function (optimizedFile, index) {

                if (index === 0) {  // ttf
                    file.contents = optimizedFile.contents;
                }
                else {              // other
                    gulpFile = file.clone();
                    gulpFile.path = gulpFile.path.replace(/.ttf$/, path.extname(optimizedFile.path));
                    gulpFile.contents = optimizedFile.contents;
                    fileStream.push(gulpFile);
                }

                printMsg(file, optimizedFile, opts.verbose);

            });

            totalFiles++;

            cb(null, file);
        });

    }, function (cb) {
        var msg = 'Minified ' + totalFiles + ' ';

        msg += totalFiles === 1 ? 'font' : 'fonts';

        gutil.log('gulp-fontmin:', msg);
        cb();
    });
};
<commit_msg>add glyph opts<commit_after>/**
 * @file gulp fontmin
 * @author junmer
 */

/* eslint-env node */

'use strict';
var path = require('path');
var gutil = require('gulp-util');
var through = require('through2-concurrent');
var assign = require('object-assign');
var prettyBytes = require('pretty-bytes');
var chalk = require('chalk');
var Fontmin = require('fontmin');

/**
 * rename
 *
 * @param  {Object} opts opts
 * @return {stream.Transform}      rename transform
 */
function rename(opts) {
    opts = opts || {};

    return through.obj(function (file, enc, cb) {
        file.path = opts.path;
        cb(null, file);
    });
}

/**
 * fontmin transform
 *
 * @param  {Object} opts opts
 * @return {stream.Transform}      fontmin transform
 */
module.exports = function (opts) {
    opts = assign({
        // TODO: remove this when gulp get's a real logger with levels
        verbose: process.argv.indexOf('--verbose') !== -1
    }, opts);

    var totalFiles = 0;
    var validExts = ['.ttf'];

    function printMsg(originalFile, optimizedFile, verbose) {
        var originalSize = originalFile.contents.length;
        var optimizedSize = optimizedFile.contents.length;
        var saved = originalSize - optimizedSize;
        var percent = originalSize > 0 ? (saved / originalSize) * 100 : 0;
        var savedMsg = 'saved ' + prettyBytes(saved) + ' - ' + percent.toFixed(1).replace(/\.0$/, '') + '%';
        var msg = saved > 0 ? savedMsg : 'already optimized';

        var optimizedType = (path.extname(optimizedFile.path) || path.extname(originalFile.path)).toLowerCase();

        if (verbose) {
            msg = chalk.green('✔ ') + originalFile.relative + ' -> ' + optimizedType + chalk.gray(' (' + msg + ')');
            gutil.log('gulp-fontmin:', msg);
        }

    }

    return through.obj(function (file, enc, cb) {
        if (file.isNull()) {
            cb(null, file);
            return;
        }

        if (file.isStream()) {
            cb(new gutil.PluginError('gulp-fontmin', 'Streaming not supported'));
            return;
        }

        if (validExts.indexOf(path.extname(file.path).toLowerCase()) === -1) {
            if (opts.verbose) {
                gutil.log('gulp-fontmin: Skipping unsupported font ' + chalk.blue(file.relative));
            }

            cb(null, file);
            return;
        }

        var text = opts.text || '';

        if (text && opts.chineseOnly) {
            text = text.replace(/[^\u4e00-\u9fa5]/g, '');
        }

        opts.text = text;

        var fontmin = new Fontmin()
            .src(file.contents)
            .use(rename({
                path: file.path
            }))
            .use(Fontmin.glyph(opts))
            .use(Fontmin.ttf2eot())
            .use(Fontmin.ttf2woff())
            .use(Fontmin.ttf2svg())
            .use(Fontmin.css(opts));

        if (opts.use) {
            opts.use.forEach(fontmin.use.bind(fontmin));
        }

        var fileStream = this;

        fontmin.run(function (err, files) {
            if (err) {
                cb(new gutil.PluginError('gulp-fontmin:', err, {fileName: file.path}));
                return;
            }

            var gulpFile;

            files.forEach(function (optimizedFile, index) {

                if (index === 0) {  // ttf
                    file.contents = optimizedFile.contents;
                }
                else {              // other
                    gulpFile = file.clone();
                    gulpFile.path = gulpFile.path.replace(/.ttf$/, path.extname(optimizedFile.path));
                    gulpFile.contents = optimizedFile.contents;
                    fileStream.push(gulpFile);
                }

                printMsg(file, optimizedFile, opts.verbose);

            });

            totalFiles++;

            cb(null, file);
        });

    }, function (cb) {
        var msg = 'Minified ' + totalFiles + ' ';

        msg += totalFiles === 1 ? 'font' : 'fonts';

        gutil.log('gulp-fontmin:', msg);
        cb();
    });
};
<|endoftext|>


<commit_before>var fs = require('fs-extra');
var path = require('path');
var express = require('express');
var multer = require('multer');
var bodyParser = require('body-parser');
var JSONStream = require('jsonstream');
var ndjson = require('ndjson');
var cors = require('cors');
var request = require('request');
var crypto = require('crypto');
var geojsonhint = require('geojsonhint');
var basicAuth = require('basic-auth');
var app = express();
var diff = require('./lib/diff');
var auth = require('./lib/auth');
var db = require('./lib/db');
var current = require('./lib/current');
var validators = require('./lib/validators');
var config = require(process.env.HISTOGRAPH_CONFIG);
var coreApiUrl = 'http://' + config.core.traversal.host + ':' + config.core.traversal.port + '/';

app.use(bodyParser.json({
  type: 'application/json'
}));

app.use(bodyParser.text({
  type: 'application/x-ndjson'
}));

app.use(cors());

function send200(res) {
  res.status(200).send({
    message: 'ok'
  });
}

function send201(res) {
  res.status(201).send({
    message: 'ok'
  });
}

function send404(res, type, id) {
  res.status(404).send({
    message: type + ' \'' + id + '\' not found'
  });
}

function send409(res, type, id) {
  res.status(409).send({
    message: type + ' \'' + id + '\' already exists'
  });
}

app.get('/sources', function(req, res) {
  db.getSources(res, function(data) {
    res.send(data);
  });
});

app.post('/sources',
  auth.owner,
  function(req, res) {
    var source = req.body;
    if (validators.source(source)) {
      db.getSource(res, source.id, function(data) {
        if (data) {
          send409(res, 'Source', source.id);
        } else {
          var owner = basicAuth(req);
          db.createSource(res, source, owner.name, function() {
            current.createDir(source.id);
            send201(res);
          });
        }
      });
    } else {
      res.status(422).send({
        message: validators.source.errors
      });
    }
  }

);

app.patch('/sources/:source',
  db.sourceExists,
  auth.ownerForSource,
  function(req, res) {
    var source = req.body;

    if (source.id == req.params.source || source.id === undefined) {
      if (validators.source(source)) {
        db.updateSource(res, source, function() {
          send200(res);
        });
      } else {
        res.status(422).send({
          message: validators.source.errors
        });
      }
    } else {
      res.status(422).send({
        message: 'Source ID in URL must match source ID in JSON body'
      });
    }
  }

);

app.delete('/sources/:source',
  db.sourceExists,
  auth.ownerForSource,
  function(req, res) {
    db.deleteSource(res, req.params.source, function() {
      send200(res);

      fs.closeSync(fs.openSync(current.getFilename(req.params.source, 'pits'), 'w'));
      fs.closeSync(fs.openSync(current.getFilename(req.params.source, 'relations'), 'w'));

      diff.fileChanged(req.params.source, 'pits', function() {
        diff.fileChanged(req.params.source, 'relations', function() {
          fs.removeSync(path.join(config.api.dataDir, 'sources', req.params.source));
        });
      });
    });
  }

);

app.get('/sources/:source', function(req, res) {
  db.getSource(res, req.params.source, function(data) {
    if (data) {
      res.send(data);
    } else {
      send404(res, 'Source', req.params.source);
    }
  });
});

app.get('/sources/:source/rejected_relations',
  db.sourceExists,
  function(req, res) {
    var uri = coreApiUrl + 'rejected?sourceid=' + req.params.source;
    request.get(uri)
      .pipe(JSONStream.parse('rejected_relations.*'))
      .pipe(JSONStream.stringify())
      .pipe(res);
  }

);

app.get('/sources/:source/:file(pits|relations)',
  db.sourceExists,
  function(req, res) {
    var filename = current.getCurrentFilename(req.params.source, req.params.file);
    fs.exists(filename, function(exists) {
      if (exists) {
        var stat = fs.statSync(filename);

        res.writeHead(200, {
          'Content-Type': 'text/plain',
          'Content-Length': stat.size
        });
        fs.createReadStream(filename).pipe(res);
      } else {
        res.send('');
      }
    });
  }

);

app.put('/sources/:source/:file(pits|relations)',
  db.sourceExists,
  auth.ownerForSource,
  multer({
    dest: path.join(config.api.dataDir, 'uploads')
  }),
  function(req, res) {
    // TODO this path should fail when content-type is different
    req.accepts('application/x-ndjson');

    var uploadedFilename;

    if (req.files && Object.keys(req.files).length > 0) {
      // File upload, multipart/form-data in req.files

      // TODO: make sure to only accept one file at a time
      uploadedFilename = path.join(config.api.dataDir, 'uploads', req.files.file.name);
    } else {
      // JSON POST data in req.body

      var currentDate = (new Date()).valueOf().toString();
      var random = Math.random().toString();

      uploadedFilename = path.join(config.api.dataDir, 'uploads', crypto.createHash('sha1').update(currentDate + random).digest('hex') + '.ndjson');
      var contents;

      // Apparently, req.body == {} when JSON POST data is empty
      if (typeof req.body == 'object' && Object.keys(req.body).length === 0) {
        contents = '';
      } else {
        contents = req.body;
      }

      var file = fs.openSync(uploadedFilename, 'w');
      fs.writeSync(file, contents);
    }

    if (uploadedFilename) {
      var newFilename = path.join(config.api.dataDir, 'sources', req.params.source, req.params.file + '.ndjson');

      var responseError = {
        error: 'NDJSON does not comply to schema',
        details: []
      };

      var finished = false;
      var allValid = true;
      var lineNr = 1;

      fs.createReadStream(uploadedFilename)
        .pipe(ndjson.parse())
        .on('data', function(obj) {
          var errors;
          var jsonValid = validators[req.params.file](obj);
          var thisValid = true;

          if (!jsonValid) {
            errors = validators[req.params.file].errors;
            thisValid = false;
          } else if (req.params.file === 'pits' && obj.geometry) {
            var geojsonErrors = geojsonhint.hint(obj.geometry);
            if (geojsonErrors.length > 0) {
              errors = geojsonErrors;
              thisValid = false;
            }
          }

          if (!thisValid) {
            if (responseError.details.length < 10) {
              responseError.details.push({
                line: lineNr,
                errors: errors
              });
            }

            allValid = false;
          }

          lineNr += 1;
        })
        .on('error', function(err) {
          allValid = false;
          if (responseError.details.length < 10) {
            responseError.details.push({
              line: lineNr,
              errors: err.message
            });
          }

          finished = true;
          res.status(422).send(responseError);
          fs.unlinkSync(uploadedFilename);

          lineNr += 1;
        })
        .on('end', function() {
          if (allValid) {
            send200(res);

            fs.renameSync(uploadedFilename, newFilename);

            // TODO: use lock? make sure dest is not overwritten
            // when diff processes file
            diff.fileChanged(req.params.source, req.params.file);
          } else if (!finished) {
            res.status(422).send(responseError);
            fs.unlinkSync(uploadedFilename);
          }
        });

    } else {
      res.status(422).send({
        error: 'No data received'
      });
    }
  }

);

fs.mkdirsSync(path.join(config.api.dataDir, 'sources'));
fs.mkdirsSync(path.join(config.api.dataDir, 'uploads'));

// app.listen(config.io.port, function() {
//   console.log('Histograph IO listening on port ' + config.io.port);
// });

module.exports = app;
<commit_msg>only send response once on error<commit_after>var fs = require('fs-extra');
var path = require('path');
var express = require('express');
var multer = require('multer');
var bodyParser = require('body-parser');
var JSONStream = require('jsonstream');
var ndjson = require('ndjson');
var cors = require('cors');
var request = require('request');
var crypto = require('crypto');
var geojsonhint = require('geojsonhint');
var basicAuth = require('basic-auth');
var app = express();
var diff = require('./lib/diff');
var auth = require('./lib/auth');
var db = require('./lib/db');
var current = require('./lib/current');
var validators = require('./lib/validators');
var config = require(process.env.HISTOGRAPH_CONFIG);
var coreApiUrl = 'http://' + config.core.traversal.host + ':' + config.core.traversal.port + '/';

app.use(bodyParser.json({
  type: 'application/json'
}));

app.use(bodyParser.text({
  type: 'application/x-ndjson'
}));

app.use(cors());

function send200(res) {
  res.status(200).send({
    message: 'ok'
  });
}

function send201(res) {
  res.status(201).send({
    message: 'ok'
  });
}

function send404(res, type, id) {
  res.status(404).send({
    message: type + ' \'' + id + '\' not found'
  });
}

function send409(res, type, id) {
  res.status(409).send({
    message: type + ' \'' + id + '\' already exists'
  });
}

app.get('/sources', function(req, res) {
  db.getSources(res, function(data) {
    res.send(data);
  });
});

app.post('/sources',
  auth.owner,
  function(req, res) {
    var source = req.body;
    if (validators.source(source)) {
      db.getSource(res, source.id, function(data) {
        if (data) {
          send409(res, 'Source', source.id);
        } else {
          var owner = basicAuth(req);
          db.createSource(res, source, owner.name, function() {
            current.createDir(source.id);
            send201(res);
          });
        }
      });
    } else {
      res.status(422).send({
        message: validators.source.errors
      });
    }
  }

);

app.patch('/sources/:source',
  db.sourceExists,
  auth.ownerForSource,
  function(req, res) {
    var source = req.body;

    if (source.id == req.params.source || source.id === undefined) {
      if (validators.source(source)) {
        db.updateSource(res, source, function() {
          send200(res);
        });
      } else {
        res.status(422).send({
          message: validators.source.errors
        });
      }
    } else {
      res.status(422).send({
        message: 'Source ID in URL must match source ID in JSON body'
      });
    }
  }

);

app.delete('/sources/:source',
  db.sourceExists,
  auth.ownerForSource,
  function(req, res) {
    db.deleteSource(res, req.params.source, function() {
      send200(res);

      fs.closeSync(fs.openSync(current.getFilename(req.params.source, 'pits'), 'w'));
      fs.closeSync(fs.openSync(current.getFilename(req.params.source, 'relations'), 'w'));

      diff.fileChanged(req.params.source, 'pits', function() {
        diff.fileChanged(req.params.source, 'relations', function() {
          fs.removeSync(path.join(config.api.dataDir, 'sources', req.params.source));
        });
      });
    });
  }

);

app.get('/sources/:source', function(req, res) {
  db.getSource(res, req.params.source, function(data) {
    if (data) {
      res.send(data);
    } else {
      send404(res, 'Source', req.params.source);
    }
  });
});

app.get('/sources/:source/rejected_relations',
  db.sourceExists,
  function(req, res) {
    var uri = coreApiUrl + 'rejected?sourceid=' + req.params.source;
    request.get(uri)
      .pipe(JSONStream.parse('rejected_relations.*'))
      .pipe(JSONStream.stringify())
      .pipe(res);
  }

);

app.get('/sources/:source/:file(pits|relations)',
  db.sourceExists,
  function(req, res) {
    var filename = current.getCurrentFilename(req.params.source, req.params.file);
    fs.exists(filename, function(exists) {
      if (exists) {
        var stat = fs.statSync(filename);

        res.writeHead(200, {
          'Content-Type': 'text/plain',
          'Content-Length': stat.size
        });
        fs.createReadStream(filename).pipe(res);
      } else {
        res.send('');
      }
    });
  }

);

app.put('/sources/:source/:file(pits|relations)',
  db.sourceExists,
  auth.ownerForSource,
  multer({
    dest: path.join(config.api.dataDir, 'uploads')
  }),
  function(req, res) {
    // TODO this path should fail when content-type is different
    req.accepts('application/x-ndjson');

    var uploadedFilename;

    if (req.files && Object.keys(req.files).length > 0) {
      // File upload, multipart/form-data in req.files

      // TODO: make sure to only accept one file at a time
      uploadedFilename = path.join(config.api.dataDir, 'uploads', req.files.file.name);
    } else {
      // JSON POST data in req.body

      var currentDate = (new Date()).valueOf().toString();
      var random = Math.random().toString();

      uploadedFilename = path.join(config.api.dataDir, 'uploads', crypto.createHash('sha1').update(currentDate + random).digest('hex') + '.ndjson');
      var contents;

      // Apparently, req.body == {} when JSON POST data is empty
      if (typeof req.body == 'object' && Object.keys(req.body).length === 0) {
        contents = '';
      } else {
        contents = req.body;
      }

      var file = fs.openSync(uploadedFilename, 'w');
      fs.writeSync(file, contents);
    }

    if (uploadedFilename) {
      var newFilename = path.join(config.api.dataDir, 'sources', req.params.source, req.params.file + '.ndjson');

      var responseError = {
        error: 'NDJSON does not comply to schema',
        details: []
      };

      var finished = false;
      var allValid = true;
      var lineNr = 1;

      fs.createReadStream(uploadedFilename)
        .pipe(ndjson.parse())
        .on('data', function(obj) {
          var errors;
          var jsonValid = validators[req.params.file](obj);
          var thisValid = true;

          if (!jsonValid) {
            errors = validators[req.params.file].errors;
            thisValid = false;
          } else if (req.params.file === 'pits' && obj.geometry) {
            var geojsonErrors = geojsonhint.hint(obj.geometry);
            if (geojsonErrors.length > 0) {
              errors = geojsonErrors;
              thisValid = false;
            }
          }

          if (!thisValid) {
            if (responseError.details.length < 10) {
              responseError.details.push({
                line: lineNr,
                errors: errors
              });
            }

            allValid = false;
          }

          lineNr += 1;
        })
        .on('error', function(err) {

          allValid = false;
          if (responseError.details.length < 10) {
            responseError.details.push({
              line: lineNr,
              errors: err.message
            });
          }

          if (!finished) {
            res.status(422).send(responseError);
            fs.unlinkSync(uploadedFilename);
          }

          finished = true;

          lineNr += 1;
        })
        .on('end', function() {
          if (allValid) {
            send200(res);

            fs.renameSync(uploadedFilename, newFilename);

            // TODO: use lock? make sure dest is not overwritten
            // when diff processes file
            diff.fileChanged(req.params.source, req.params.file);
          } else if (!finished) {
            res.status(422).send(responseError);
            fs.unlinkSync(uploadedFilename);
          }
        });

    } else {
      res.status(422).send({
        error: 'No data received'
      });
    }
  }

);

fs.mkdirsSync(path.join(config.api.dataDir, 'sources'));
fs.mkdirsSync(path.join(config.api.dataDir, 'uploads'));

// app.listen(config.io.port, function() {
//   console.log('Histograph IO listening on port ' + config.io.port);
// });

module.exports = app;
<|endoftext|>