<commit_before>var jsdom = require('jsdom');

var Filestube_API = (function() {
  // query.html is the page where the browser pings with search query
  var url = 'http://www.filestube.to/query.html?q=';
  // How many pages of results this search query has?
  var pages = 0;
  // Number of the page that is currently proceeded
  var currentPage = 1;
  // How many pages are we intrerested in? If we want just one link (getOne) we
  // don't need all the pages, one will be enough. In other cases we try to get
  // as many as possible
  var maxPages = Infinity;

  // Array with all the URLs that will be returned to the callback. That's not
  // the most clever name for the variable but it's 5AM and I worked for 20h
  // today so don't expect me to behave rationally now.
  var totalUrls = [];

  // Callback that is called after all the computation is done
  var mainCallback = function(e) { console.log('Sum tink rong', e); };

  var cssSelectors = {
    pagintion: '.pgr',
    result: '.r',
    resultsLink: '.rL',
    copyPasteLink: '#copy_paste_links'
  }
  var parsePage = function(url, cb) {
    jsdom.env({
      url: url,
      done: function(err, window) {
        var d = window.document;
        var urls = [];
        if (pages === 0) {
          if (d.querySelector(cssSelectors.pagination)) {
            pages = d.querySelector(cssSelectors.pagination).querySelectorAll('a').length;
            pages = Math.min(maxPages, pages);
          } else {
            pages = 1;
          }

        }

        var results = d.querySelectorAll(cssSelectors.result);

        for (var i = 0, j = results.length; i< j; i++) {
          var result = results[i];
          var link = result.querySelector(cssSelectors.resultsLink).href;
          link = 'http://www.filestube.to/' + link.split('/').pop();
          urls.push(link);

        }

        cb(urls);
      }
    });
  };

  var handlePageParsingResults = function(urls) {
    totalUrls = totalUrls.concat(urls);
    if (currentPage < pages) {
      currentPage++;
      parsePage(url + '&page=' + currentPage, handlePageParsingResults);
    } else {
      mainCallback(totalUrls);
    }
  };

  var getLinks = function(term, options, callback) {
    mainCallback = callback;
    pages = 0;
    currentPage = 1;
    url = 'http://www.filestube.to/query.html?q=';
    totalUrls = [];
    term = term.replace(/\s/g, '+');
    var reqOptions = '';

    if (options.type) {
      reqOptions += '&select=' + options.type;
    }

    if (options.size) {
      reqOptions += '&size=' + options.size;
    }

    url = url + term + reqOptions;
    parsePage(url, handlePageParsingResults);

  };

  var stripFinalLink = function(url, callback) {
    if (url) {
      jsdom.env({
        url: url,
        done: function(err, window) {
          var d = window.document;
          if (d.querySelector(cssSelectors.copyPasteLink)) {
            callback(d.querySelector(cssSelectors.copyPasteLink).textContent);
          } else {
            callback(0);
          }
        }
      });
    } else {
      callback(0);
    }
  };

  var getOne = function(phrase, options, callback){
    maxPages = 1;
    var currentLink = 0;
    getLinks(phrase, options, function(links){
      stripFinalLink(links[currentLink], function stripFinal_cb(resultLink){
        if (resultLink === 0 && links[currentLink]) {
          currentLink++;
          stripFinalLink(links[currentLink], stripFinal_cb);
        } else {
          if (resultLink !== 0) {
            resultLink = resultLink.split('\r\n').filter(function(element){
              if (element !== '')
                return element;
            });
          }
          callback(resultLink);
        }
      });
    });
  };

  var getAll = function(phrase, options, callback){
    var links = [];
    getLinks(phrase, options, function(links){
      links.forEach(function(singleLink){
        stripFinalLink(singleLink, function stripFinal_cb(resultLink){
          if (resultLink !== 0) {
            callback(resultLink.split('\r\n').filter(function(element) {
              if (element !== '')
                return element;
            }));
          }
        });
      });
    });
  };

  return {
    getOne: getOne,
    getAll: getAll
  };
})();

module.exports = Filestube_API;
<commit_msg>[FILESTUBE-CLIENT] - :roller_coaster: pagination code explained<commit_after>var jsdom = require('jsdom');

var Filestube_API = (function() {
  // query.html is the page where the browser pings with search query
  var url = 'http://www.filestube.to/query.html?q=';
  // How many pages of results this search query has?
  var pages = 0;
  // Number of the page that is currently proceeded
  var currentPage = 1;
  // How many pages are we intrerested in? If we want just one link (getOne) we
  // don't need all the pages, one will be enough. In other cases we try to get
  // as many as possible
  var maxPages = Infinity;

  // Array with all the URLs that will be returned to the callback. That's not
  // the most clever name for the variable but it's 5AM and I worked for 20h
  // today so don't expect me to behave rationally now.
  var totalUrls = [];

  // Callback that is called after all the computation is done
  var mainCallback = function(e) { console.log('Sum tink rong', e); };

  // Selectors (ids and classes) for the DOM element of filestube.to page.
  var cssSelectors = {
    pagintion: '.pgr',
    result: '.r',
    resultsLink: '.rL',
    copyPasteLink: '#copy_paste_links'
  }

  // This function parses the content of the main search page (the one with all
  // the search results)
  var parsePage = function(url, cb) {
    // Using jsdom we ask for the page on the given address.
    jsdom.env({
      url: url,
      done: function(err, window) {
        var d = window.document;
        // This Array will store all the urls we are interested in from
        // given site
        var urls = [];
        // If `pages` var is equal 0, than we've just started and we don't know
        // how many pages of results we have for our query
        if (pages === 0) {
          // If there is a pagination panel with page numbers, it means we have
          // more than 1 page of results
          if (d.querySelector(cssSelectors.pagination)) {
            // So let's calculate how many links (<a> elements) are in the
            // pagination panel
            pages = d.querySelector(cssSelectors.pagination).querySelectorAll('a').length;

            // If we don't want to parse all the pages of results (for
            // instance - we are interested just in one result), then let's
            // limit number of pages
            pages = Math.min(maxPages, pages);
          } else {
            // If pagination panel is not present in the ODM three of the
            // result page it means we have just one page of results
            pages = 1;
          }

        }

        // Code below will be executed for all the pages with results, not only
        // the first one (like the pagination code)

        // Let's grab all the results form the page...
        var results = d.querySelectorAll(cssSelectors.result);

        // ... and iterate through them.
        for (var i = 0, j = results.length; i< j; i++) {
          var result = results[i];
          var link = result.querySelector(cssSelectors.resultsLink).href;
          link = 'http://www.filestube.to/' + link.split('/').pop();
          urls.push(link);

        }

        cb(urls);
      }
    });
  };

  var handlePageParsingResults = function(urls) {
    totalUrls = totalUrls.concat(urls);
    if (currentPage < pages) {
      currentPage++;
      parsePage(url + '&page=' + currentPage, handlePageParsingResults);
    } else {
      mainCallback(totalUrls);
    }
  };

  var getLinks = function(term, options, callback) {
    mainCallback = callback;
    pages = 0;
    currentPage = 1;
    url = 'http://www.filestube.to/query.html?q=';
    totalUrls = [];
    term = term.replace(/\s/g, '+');
    var reqOptions = '';

    if (options.type) {
      reqOptions += '&select=' + options.type;
    }

    if (options.size) {
      reqOptions += '&size=' + options.size;
    }

    url = url + term + reqOptions;
    parsePage(url, handlePageParsingResults);

  };

  var stripFinalLink = function(url, callback) {
    if (url) {
      jsdom.env({
        url: url,
        done: function(err, window) {
          var d = window.document;
          if (d.querySelector(cssSelectors.copyPasteLink)) {
            callback(d.querySelector(cssSelectors.copyPasteLink).textContent);
          } else {
            callback(0);
          }
        }
      });
    } else {
      callback(0);
    }
  };

  var getOne = function(phrase, options, callback){
    maxPages = 1;
    var currentLink = 0;
    getLinks(phrase, options, function(links){
      stripFinalLink(links[currentLink], function stripFinal_cb(resultLink){
        if (resultLink === 0 && links[currentLink]) {
          currentLink++;
          stripFinalLink(links[currentLink], stripFinal_cb);
        } else {
          if (resultLink !== 0) {
            resultLink = resultLink.split('\r\n').filter(function(element){
              if (element !== '')
                return element;
            });
          }
          callback(resultLink);
        }
      });
    });
  };

  var getAll = function(phrase, options, callback){
    var links = [];
    getLinks(phrase, options, function(links){
      links.forEach(function(singleLink){
        stripFinalLink(singleLink, function stripFinal_cb(resultLink){
          if (resultLink !== 0) {
            callback(resultLink.split('\r\n').filter(function(element) {
              if (element !== '')
                return element;
            }));
          }
        });
      });
    });
  };

  return {
    getOne: getOne,
    getAll: getAll
  };
})();

module.exports = Filestube_API;
<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var cool = require('cool-ascii-faces');
var pg = require('pg');

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'))

app.get('/', function(request, response) {
  response.send('Hello World!')
});

app.get('/test', function(request, response) {
  var result = '';
  var times = process.env.TIMES || 5;
  for (i=0; i < times; i++) {
  	result += (cool() + "
");
  }
  response.send(result);
});

app.get('/db', function(request, response) {
	pg.connect(process.env.DATABASE_URL, function(err, client, done) {
		client.query('SELCT * FROM test_table', function(err, result) {
			done();
			iff (err) {
				console.error(err);
				response.send("Error " + error);
			} else {
				response.send(result.rows);
			}
		});
	});
});

app.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'))
});
<commit_msg>6 test<commit_after>var express = require('express');
var app = express();
var cool = require('cool-ascii-faces');
var pg = require('pg');

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'))

app.get('/', function(request, response) {
  response.send('Hello World!')
});

app.get('/test', function(request, response) {
  var result = '';
  var times = process.env.TIMES || 5;
  for (i=0; i < times; i++) {
  	result += (cool() + "
");
  }
  response.send(result);
});

// app.get('/db', function(request, response) {
// 	pg.connect(process.env.DATABASE_URL, function(err, client, done) {
// 		client.query('SELCT * FROM test_table', function(err, result) {
// 			done();
// 			iff (err) {
// 				console.error(err);
// 				response.send("Error " + error);
// 			} else {
// 				response.send(result.rows);
// 			}
// 		});
// 	});
// });

app.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'))
});
<|endoftext|>


<commit_before>const opts = require('minimist')(process.argv.slice(2));
const clc = require('cli-color');
const execSync = require('child_process').execSync;
const region = getAwsRegion();

const CF = require('aws-sdk/clients/cloudformation');
const cf = new CF({
    region: region
});
const LOGS = require('aws-sdk/clients/cloudwatchlogs');
const logs = new LOGS({
    region: region
});

if (!opts.stack || !opts.filter) {
    console.log(
        `Usage: lambda-logs --stack stackName --filter pattern [--region awsRegion] [--colorPattern pattern] [--color color] [--start timestamp] [--end timestamp] [--msgLength messageLength]`);
    return;
}

let stackName = opts.stack;
let filterPattern = opts.filter;
let colorPattern = opts.colorPattern || '';
let color = opts.color || 'yellow';
let startTime = getMsFromTimeString(opts.start) || Date.now() - 15 * 60 * 1000;
let endTime = getMsFromTimeString(opts.end) || Date.now();
let msgLength = typeof opts.msgLength === 'number' ? opts.msgLength : 350;

if (startTime >= endTime) {
    console.error(`Error: Start time '${opts.start}' may not be after end time '${opts.end}'! Please check your inputs.`);
    return;
}

let coloredClc = clc.yellow;
if (clc[color]) {
    coloredClc = clc[color];
}

// get all resources of the stack
cf.listStackResources({
    StackName: stackName
}).promise().then(data => {
    // filter out Lambdas from resources and retrieve their physical resource id's
    const resources = data.StackResourceSummaries;

    if (!resources) {
        console.log('No resources available.');
        return;
    }

    let lambdaFunctions = resources.filter(elem => {
        return elem.ResourceType === 'AWS::Lambda::Function';
    });

    return lambdaFunctions.map(elem => {
        return elem.PhysicalResourceId;
    });
}).then(resourceIds => {
    // now find all log groups related to the Lambdas
    let logPromises = [];
    resourceIds.forEach(resourceId => {
        logPromises.push(logs.describeLogGroups({
            logGroupNamePrefix: '/aws/lambda/' + resourceId
        }).promise());
    });
    return Promise.all(logPromises);
}).then(logGroups => {
    // now filter out all non-existent log groups
    let resultLogGroups = [];
    logGroups.forEach(elem => {
        if (elem.logGroups.length) {
            elem.logGroups.forEach(logGroup => {
                resultLogGroups.push(logGroup.logGroupName);
            });
        }
    });
    return resultLogGroups;
}).then(logGroups => {
    // now find all log events of a log group filtered by the specified filter pattern
    let logEventPromises = [];
    logGroups.forEach(logGroupName => {
        logEventPromises.push(logs.filterLogEvents({
            logGroupName: logGroupName,
            startTime: startTime,
            endTime: endTime,
            filterPattern: filterPattern
        }).promise());
    });
    return Promise.all(logEventPromises);
}).then(logEvents => {
    // now retrieve the actual message and its timestamp
    let outputMessages = [];
    if (logEvents && logEvents.length) {
        logEvents.forEach(logEvent => {
            if (logEvent && logEvent.events) {
                logEvent.events.forEach(event => {
                    outputMessages.push({
                        timestamp: event.timestamp,
                        message: event.message.trim()
                    });
                });
            }
        });
    }
    return outputMessages;
}).then(outputMessages => {
    // use the timestamp to sort the messages in the right order
    return outputMessages.sort((a, b) => {
        if (a.timestamp && b.timestamp) {
            return a.timestamp - b.timestamp;
        } else {
            return 0;
        }
    });
}).then(sortedMessages => {
    // print the messages in a pretty way
    sortedMessages.forEach(msg => {
        let messageString = msg.message;
        let beginning = '';

        if (colorPattern === '') {
            beginning = new Date(msg.timestamp);
        } else {
            let regex = new RegExp(colorPattern);
            let match = messageString.match(regex);
            let end = match.index + match[0].length;
            beginning = messageString.substring(0, end);
            messageString = messageString.substring(end + 1);
        }

        if (msgLength > 0) {
            messageString = messageString.substring(0, msgLength);
        }

        console.log(coloredClc(beginning) + ' ' + messageString);
    });
}).catch(err => {
    console.log('An unexpected error occurred while retrieving Lambda logs: ', err);
});

/**
 * Gets the AWS region to use for further calls. It's accessing the region configured in AWS CLI if no region parameter was set when calling this CLI tool.
 * Default: 'us-east-1'
 * @returns {string} an AWS region
 */
function getAwsRegion() {
    return opts.region || execSync('aws configure get region').toString().trim() || 'us-east-1';
}

/**
 * Converts time strings like '10s', '20m', '30h' or '4w' into milliseconds.
 * @param timeString
 * @returns {number} milliseconds of the given timeString
 */
function getMsFromTimeString(timeString) {
    if (!timeString) {
        return 0;
    }

    timeString = timeString.trim();
    let unitName = timeString.charAt(timeString.length - 1);
    let factor = timeString.substring(0, timeString.length);

    return Date.now() - (parseInt(factor) * getUnitInMs(unitName));
}

function getUnitInMs(name) {
    const ms = 1000;

    switch (name) {
        case 's':
            return ms;
        case 'm':
            return ms * 60;
        case 'h':
            return ms * 60 * 60;
        case 'd':
            return ms * 60 * 60 * 24;
        case 'w':
            return ms * 60 * 60 * 24 * 7;
    }
}<commit_msg>Added shebang<commit_after>#!/usr/bin/env node

const opts = require('minimist')(process.argv.slice(2));
const clc = require('cli-color');
const execSync = require('child_process').execSync;
const region = getAwsRegion();

const CF = require('aws-sdk/clients/cloudformation');
const cf = new CF({
    region: region
});
const LOGS = require('aws-sdk/clients/cloudwatchlogs');
const logs = new LOGS({
    region: region
});

if (!opts.stack || !opts.filter) {
    console.log(
        `Usage: lambda-logs --stack stackName --filter pattern [--region awsRegion] [--colorPattern pattern] [--color color] [--start timestamp] [--end timestamp] [--msgLength messageLength]`);
    return;
}

let stackName = opts.stack;
let filterPattern = opts.filter;
let colorPattern = opts.colorPattern || '';
let color = opts.color || 'yellow';
let startTime = getMsFromTimeString(opts.start) || Date.now() - 15 * 60 * 1000;
let endTime = getMsFromTimeString(opts.end) || Date.now();
let msgLength = typeof opts.msgLength === 'number' ? opts.msgLength : 350;

if (startTime >= endTime) {
    console.error(`Error: Start time '${opts.start}' may not be after end time '${opts.end}'! Please check your inputs.`);
    return;
}

let coloredClc = clc.yellow;
if (clc[color]) {
    coloredClc = clc[color];
}

// get all resources of the stack
cf.listStackResources({
    StackName: stackName
}).promise().then(data => {
    // filter out Lambdas from resources and retrieve their physical resource id's
    const resources = data.StackResourceSummaries;

    if (!resources) {
        console.log('No resources available.');
        return;
    }

    let lambdaFunctions = resources.filter(elem => {
        return elem.ResourceType === 'AWS::Lambda::Function';
    });

    return lambdaFunctions.map(elem => {
        return elem.PhysicalResourceId;
    });
}).then(resourceIds => {
    // now find all log groups related to the Lambdas
    let logPromises = [];
    resourceIds.forEach(resourceId => {
        logPromises.push(logs.describeLogGroups({
            logGroupNamePrefix: '/aws/lambda/' + resourceId
        }).promise());
    });
    return Promise.all(logPromises);
}).then(logGroups => {
    // now filter out all non-existent log groups
    let resultLogGroups = [];
    logGroups.forEach(elem => {
        if (elem.logGroups.length) {
            elem.logGroups.forEach(logGroup => {
                resultLogGroups.push(logGroup.logGroupName);
            });
        }
    });
    return resultLogGroups;
}).then(logGroups => {
    // now find all log events of a log group filtered by the specified filter pattern
    let logEventPromises = [];
    logGroups.forEach(logGroupName => {
        logEventPromises.push(logs.filterLogEvents({
            logGroupName: logGroupName,
            startTime: startTime,
            endTime: endTime,
            filterPattern: filterPattern
        }).promise());
    });
    return Promise.all(logEventPromises);
}).then(logEvents => {
    // now retrieve the actual message and its timestamp
    let outputMessages = [];
    if (logEvents && logEvents.length) {
        logEvents.forEach(logEvent => {
            if (logEvent && logEvent.events) {
                logEvent.events.forEach(event => {
                    outputMessages.push({
                        timestamp: event.timestamp,
                        message: event.message.trim()
                    });
                });
            }
        });
    }
    return outputMessages;
}).then(outputMessages => {
    // use the timestamp to sort the messages in the right order
    return outputMessages.sort((a, b) => {
        if (a.timestamp && b.timestamp) {
            return a.timestamp - b.timestamp;
        } else {
            return 0;
        }
    });
}).then(sortedMessages => {
    // print the messages in a pretty way
    sortedMessages.forEach(msg => {
        let messageString = msg.message;
        let beginning = '';

        if (colorPattern === '') {
            beginning = new Date(msg.timestamp);
        } else {
            let regex = new RegExp(colorPattern);
            let match = messageString.match(regex);
            let end = match.index + match[0].length;
            beginning = messageString.substring(0, end);
            messageString = messageString.substring(end + 1);
        }

        if (msgLength > 0) {
            messageString = messageString.substring(0, msgLength);
        }

        console.log(coloredClc(beginning) + ' ' + messageString);
    });
}).catch(err => {
    console.log('An unexpected error occurred while retrieving Lambda logs: ', err);
});

/**
 * Gets the AWS region to use for further calls. It's accessing the region configured in AWS CLI if no region parameter was set when calling this CLI tool.
 * Default: 'us-east-1'
 * @returns {string} an AWS region
 */
function getAwsRegion() {
    return opts.region || execSync('aws configure get region').toString().trim() || 'us-east-1';
}

/**
 * Converts time strings like '10s', '20m', '30h' or '4w' into milliseconds.
 * @param timeString
 * @returns {number} milliseconds of the given timeString
 */
function getMsFromTimeString(timeString) {
    if (!timeString) {
        return 0;
    }

    timeString = timeString.trim();
    let unitName = timeString.charAt(timeString.length - 1);
    let factor = timeString.substring(0, timeString.length);

    return Date.now() - (parseInt(factor) * getUnitInMs(unitName));
}

function getUnitInMs(name) {
    const ms = 1000;

    switch (name) {
        case 's':
            return ms;
        case 'm':
            return ms * 60;
        case 'h':
            return ms * 60 * 60;
        case 'd':
            return ms * 60 * 60 * 24;
        case 'w':
            return ms * 60 * 60 * 24 * 7;
    }
}<|endoftext|>


<commit_before>var Fs = require('fire-fs');
var Path = require('fire-path');
var PathWatcher = require('pathwatcher');
var Gulp = require('gulp');
var EventStream = require ('event-stream');
var Util = require ('util');
var Events = require ('events');

var commandPriority = { delete: 0, new: 1, change: 2 };
var globalDiff = process.platform === 'win32';

function _dbgPrintResults ( results ) {
    for ( var p in results ) {
        console.log( "%s: %s", results[p].command, results[p].path );
    }
}

function _addResult ( results, command, path, isDirectory ) {
    var result = results[path];
    if ( result ) {
        if ( result.isDirectory !== isDirectory ) {
            throw new Error("We not support file and directory share the same path " + path );
        }

        if ( commandPriority[result.command] > commandPriority[command] ) {
            result.command = command;
        }

        return;
    }

    results[path] = {
        command: command,
        path: path,
        isDirectory: isDirectory
    };
}

function _watch ( fireWatcher ) {
    if ( globalDiff ) {
        return EventStream.through(function (file) {
            fireWatcher.files[file.path] = { file: file, children: [] };

            var parent = fireWatcher.files[Path.dirname(file.path)];
            parent.children.push( file.path );

            if ( file.stat.isDirectory() ) {
                fireWatcher.changes[file.path] = { command: "change", path: file.path };
            }

            this.push(file);
        });
    }

    return EventStream.through(function (file) {
        fireWatcher.files[file.path] = { file: file, children: [] };

        var parent = fireWatcher.files[Path.dirname(file.path)];
        parent.children.push( file.path );

        var pathWatcher = PathWatcher.watch( file.path, function ( event, path ) {
            // console.log("DEBUG: %s, %s, %s", event, file.path, path);

            if ( event === "delete" ) {
                pathWatcher.close();
            }
            fireWatcher.changes[file.path] = { command: event, path: file.path, relatedPath: path };
            // TODO: _cooldown(fireWatcher);
        } );

        this.push(file);
    });
}

function _cooldown ( fireWatcher ) {
    clearTimeout(fireWatcher.timer);
    fireWatcher.timer = setTimeout(function () {
        _flush(fireWatcher);
    }, 500);
}

function _flush ( fireWatcher ) {
    var sortedChanges = [];
    for ( var k in fireWatcher.changes ) {
        sortedChanges.push(fireWatcher.changes[k]);
    }
    fireWatcher.changes = {};

    //
    sortedChanges.sort( function ( a, b ) {
        return a.path.localeCompare(b.path);
    });
    var results = _computeResults( fireWatcher.files, sortedChanges );

    //
    fireWatcher.emit( 'changed', results );

}

function _computeResults ( files, changes ) {
    function getFiles ( path ) {
        if ( !Fs.existsSync(path) )
            return [];

        return Fs.readdirSync(path)
        .filter( function ( name ) {
            return name[0] !== ".";
        })
        .map( function ( name ) {
            return Path.join( path, name );
        })
        ;
    }
    function fastRemove ( array, nth, len ) {
        array[nth] = array[len-1];
    }

    var results = {};

    for ( var i = 0; i < changes.length; ++i ) {
        var info = changes[i];
        var fileInfo = files[info.path];

        if ( !fileInfo ) {
            _addResult( results, 'new', info.path, Fs.statSync(info.path).isDirectory() );
            continue;
        }

        // get file
        var file = fileInfo.file;
        var path, stat, stat2;

        // if changed file is folder
        if ( file.stat.isDirectory() ) {
            var oldFiles = fileInfo.children.slice();
            var newFiles = getFiles( file.path );
            var sameFiles = [];
            var oldLen = oldFiles.length;
            var newLen = newFiles.length;
            var j, jj;

            for ( j = 0; j < newLen; ++j ) {
                for ( jj = 0; jj < oldLen; ++jj ) {
                    var newpath = newFiles[j];
                    var oldpath = oldFiles[jj];

                    if ( newpath === oldpath ) {
                        sameFiles.push(newpath);

                        fastRemove( newFiles, j, newLen );
                        newLen -= 1; --j;

                        fastRemove( oldFiles, jj, oldLen );
                        oldLen -= 1; --jj;

                        break;
                    }
                }
            }

            for ( j = 0; j < newLen; ++j ) {
                path = newFiles[j];
                stat = Fs.statSync(path);
                _addResult( results, 'new', path, stat.isDirectory() );
            }

            for ( j = 0; j < oldLen; ++j ) {
                path = oldFiles[j];
                stat = files[path].file.stat;
                _addResult( results, 'delete', path, stat.isDirectory() );
            }

            for ( j = 0; j < sameFiles.length; ++j ) {
                path = sameFiles[j];
                stat = files[path].file.stat;
                stat2 = Fs.statSync(path);
                if ( stat.isFile() && stat.mtime.getTime() !== stat2.mtime.getTime() ) {
                    _addResult( results, 'change', path, false );
                }
            }
        }
        else {
            if ( info.command === "change" ) {
                _addResult( results, 'change', info.path, false );
            }
            else if ( info.command === "rename" ) {
                if ( !Fs.existsSync(info.path) ) {
                    _addResult( results, 'delete', info.path, false );
                }
                else {
                    _addResult( results, 'change', info.path, false );
                }

                if ( Path.contains( file.base, info.relatedPath ) ) {
                    _addResult( results, 'new', info.relatedPath, false );
                }
            }
            else if ( info.command === "delete" ) {
                if ( !Fs.existsSync(info.path) ) {
                    _addResult( results, 'delete', info.path, false );
                }
                else {
                    _addResult( results, 'change', info.path, false );
                }
            }
        }
    }

    var resultList = [];
    for ( var p in results ) {
        resultList.push(results[p]);
    }
    resultList.sort( function ( a, b ) {
        var compareCommand = commandPriority[a.command] - commandPriority[b.command];
        if ( compareCommand !== 0 ) {
            return compareCommand;
        }

        return a.path.localeCompare(b.path);
    } );

    var lastDirectory = null;
    resultList = resultList.filter( function ( r ) {
        if ( lastDirectory &&
             lastDirectory.command === r.command &&
             Path.contains( lastDirectory.path, r.path ) )
        {
            return false;
        }

        if ( r.isDirectory ) {
            lastDirectory = r;
        }
        return true;
    } );
    return resultList;
}

function FireWatch () {
    Events.EventEmitter.call(this);

    this.files = {};
    this.changes = {};
    this.timer = null;
}

Util.inherits( FireWatch, Events.EventEmitter );

FireWatch.prototype.stop = function ( cb ) {
    //
    setTimeout( function () {
        PathWatcher.closeAllWatchers();
        clearTimeout(this.timer);

        _flush(this);
        this.files = {};

        if ( cb ) cb();
    }.bind(this), 100 );
};

FireWatch.start = function ( root, cb ) {
    root = Path.normalize(root);
    var fireWatcher = new FireWatch();
    fireWatcher.files[Path.dirname(root)] = { file: null, children: [] };

    Gulp.src( [root, Path.join(root,"**/*")], { cwd: root, base: root, read: false } )
        .pipe ( _watch(fireWatcher) ).on( "end", function () {
            if ( cb ) cb ();

            // DEBUG
            // console.log(PathWatcher.getWatchedPaths());
        })
        ;

    return fireWatcher;
};

module.exports = FireWatch;
<commit_msg>add protection for undefined error<commit_after>var Fs = require('fire-fs');
var Path = require('fire-path');
var PathWatcher = require('pathwatcher');
var Gulp = require('gulp');
var EventStream = require ('event-stream');
var Util = require ('util');
var Events = require ('events');

var commandPriority = { delete: 0, new: 1, change: 2 };
var globalDiff = process.platform === 'win32';

function _dbgPrintResults ( results ) {
    for ( var p in results ) {
        console.log( "%s: %s", results[p].command, results[p].path );
    }
}

function _addResult ( results, command, path, isDirectory ) {
    var result = results[path];
    if ( result ) {
        if ( result.isDirectory !== isDirectory ) {
            throw new Error("We not support file and directory share the same path " + path );
        }

        if ( commandPriority[result.command] > commandPriority[command] ) {
            result.command = command;
        }

        return;
    }

    results[path] = {
        command: command,
        path: path,
        isDirectory: isDirectory
    };
}

function _watch ( fireWatcher ) {
    if ( globalDiff ) {
        return EventStream.through(function (file) {
            fireWatcher.files[file.path] = { file: file, children: [] };

            var parent = fireWatcher.files[Path.dirname(file.path)];
            parent.children.push( file.path );

            if ( file.stat.isDirectory() ) {
                fireWatcher.changes[file.path] = { command: "change", path: file.path };
            }

            this.push(file);
        });
    }

    return EventStream.through(function (file) {
        fireWatcher.files[file.path] = { file: file, children: [] };

        var parent = fireWatcher.files[Path.dirname(file.path)];
        if ( !parent ) {
            console.error('Watch failed: Can not find path: %s', Path.dirname(file.path) );
            return;
        }

        parent.children.push( file.path );

        var pathWatcher = PathWatcher.watch( file.path, function ( event, path ) {
            // console.log("DEBUG: %s, %s, %s", event, file.path, path);

            if ( event === "delete" ) {
                pathWatcher.close();
            }
            fireWatcher.changes[file.path] = { command: event, path: file.path, relatedPath: path };
            // TODO: _cooldown(fireWatcher);
        } );

        this.push(file);
    });
}

function _cooldown ( fireWatcher ) {
    clearTimeout(fireWatcher.timer);
    fireWatcher.timer = setTimeout(function () {
        _flush(fireWatcher);
    }, 500);
}

function _flush ( fireWatcher ) {
    var sortedChanges = [];
    for ( var k in fireWatcher.changes ) {
        sortedChanges.push(fireWatcher.changes[k]);
    }
    fireWatcher.changes = {};

    //
    sortedChanges.sort( function ( a, b ) {
        return a.path.localeCompare(b.path);
    });
    var results = _computeResults( fireWatcher.files, sortedChanges );

    //
    fireWatcher.emit( 'changed', results );

}

function _computeResults ( files, changes ) {
    function getFiles ( path ) {
        if ( !Fs.existsSync(path) )
            return [];

        return Fs.readdirSync(path)
        .filter( function ( name ) {
            return name[0] !== ".";
        })
        .map( function ( name ) {
            return Path.join( path, name );
        })
        ;
    }
    function fastRemove ( array, nth, len ) {
        array[nth] = array[len-1];
    }

    var results = {};

    for ( var i = 0; i < changes.length; ++i ) {
        var info = changes[i];
        var fileInfo = files[info.path];

        if ( !fileInfo ) {
            _addResult( results, 'new', info.path, Fs.statSync(info.path).isDirectory() );
            continue;
        }

        // get file
        var file = fileInfo.file;
        var path, stat, stat2;

        // if changed file is folder
        if ( file.stat.isDirectory() ) {
            var oldFiles = fileInfo.children.slice();
            var newFiles = getFiles( file.path );
            var sameFiles = [];
            var oldLen = oldFiles.length;
            var newLen = newFiles.length;
            var j, jj;

            for ( j = 0; j < newLen; ++j ) {
                for ( jj = 0; jj < oldLen; ++jj ) {
                    var newpath = newFiles[j];
                    var oldpath = oldFiles[jj];

                    if ( newpath === oldpath ) {
                        sameFiles.push(newpath);

                        fastRemove( newFiles, j, newLen );
                        newLen -= 1; --j;

                        fastRemove( oldFiles, jj, oldLen );
                        oldLen -= 1; --jj;

                        break;
                    }
                }
            }

            for ( j = 0; j < newLen; ++j ) {
                path = newFiles[j];
                stat = Fs.statSync(path);
                _addResult( results, 'new', path, stat.isDirectory() );
            }

            for ( j = 0; j < oldLen; ++j ) {
                path = oldFiles[j];
                stat = files[path].file.stat;
                _addResult( results, 'delete', path, stat.isDirectory() );
            }

            for ( j = 0; j < sameFiles.length; ++j ) {
                path = sameFiles[j];
                stat = files[path].file.stat;
                stat2 = Fs.statSync(path);
                if ( stat.isFile() && stat.mtime.getTime() !== stat2.mtime.getTime() ) {
                    _addResult( results, 'change', path, false );
                }
            }
        }
        else {
            if ( info.command === "change" ) {
                _addResult( results, 'change', info.path, false );
            }
            else if ( info.command === "rename" ) {
                if ( !Fs.existsSync(info.path) ) {
                    _addResult( results, 'delete', info.path, false );
                }
                else {
                    _addResult( results, 'change', info.path, false );
                }

                if ( Path.contains( file.base, info.relatedPath ) ) {
                    _addResult( results, 'new', info.relatedPath, false );
                }
            }
            else if ( info.command === "delete" ) {
                if ( !Fs.existsSync(info.path) ) {
                    _addResult( results, 'delete', info.path, false );
                }
                else {
                    _addResult( results, 'change', info.path, false );
                }
            }
        }
    }

    var resultList = [];
    for ( var p in results ) {
        resultList.push(results[p]);
    }
    resultList.sort( function ( a, b ) {
        var compareCommand = commandPriority[a.command] - commandPriority[b.command];
        if ( compareCommand !== 0 ) {
            return compareCommand;
        }

        return a.path.localeCompare(b.path);
    } );

    var lastDirectory = null;
    resultList = resultList.filter( function ( r ) {
        if ( lastDirectory &&
             lastDirectory.command === r.command &&
             Path.contains( lastDirectory.path, r.path ) )
        {
            return false;
        }

        if ( r.isDirectory ) {
            lastDirectory = r;
        }
        return true;
    } );
    return resultList;
}

function FireWatch () {
    Events.EventEmitter.call(this);

    this.files = {};
    this.changes = {};
    this.timer = null;
}

Util.inherits( FireWatch, Events.EventEmitter );

FireWatch.prototype.stop = function ( cb ) {
    //
    setTimeout( function () {
        PathWatcher.closeAllWatchers();
        clearTimeout(this.timer);

        _flush(this);
        this.files = {};

        if ( cb ) cb();
    }.bind(this), 100 );
};

FireWatch.start = function ( root, cb ) {
    root = Path.normalize(root);
    var fireWatcher = new FireWatch();
    fireWatcher.files[Path.dirname(root)] = { file: null, children: [] };

    Gulp.src( [root, Path.join(root,"**/*")], { cwd: root, base: root, read: false } )
        .pipe ( _watch(fireWatcher) ).on( "end", function () {
            if ( cb ) cb ();

            // DEBUG
            // console.log(PathWatcher.getWatchedPaths());
        })
        ;

    return fireWatcher;
};

module.exports = FireWatch;
<|endoftext|>


<commit_before>var isDomain = require('is-valid-domain')
var rx = require('ip-regex')({exact: true})
var isIP = rx.test.bind(rx)

var isInteger = Number.isInteger

function isString(s) {
  return 'string' === typeof s
}

var isLink = exports.isLink =
  function (data) {
    return isString(data) && /^(@|%|&)[A-Za-z0-9\/+]{43}=\.[\w\d]+$/.test(data)
  }

var isFeedId = exports.isFeed = exports.isFeedId =
  function (data) {
    return isString(data) && /^@[A-Za-z0-9\/+]{43}=\.(?:sha256|ed25519)$/.test(data)
  }

var isMsgId = exports.isMsg = exports.isMsgId =
  function (data) {
    return isString(data) && /^%[A-Za-z0-9\/+]{43}=\.sha256$/.test(data)
  }

var isBlobId = exports.isBlob = exports.isBlobId =
  function (data) {
    return isString(data) && /^&[A-Za-z0-9\/+]{43}=\.sha256$/.test(data)
  }

var isAddress = exports.isAddress =
  function (data) {
    if(!isString(data)) return false
  var parts = data.split(':')

  return (
    parts.length === 3
    && isFeedId(parts[2])
    && isInteger(+parts[1])
    && (
      isIP(parts[0])
      || isDomain(parts[0])
      || parts[0] === 'localhost'
    )
  )
}

var isInvite = exports.isInvite =
  function (data) {
    if(!isString(data)) return false
    var parts = data.split('~')
    //console.log(parts, isAddress(parts[0]), /^[A-Za-z0-9\/+]{43}=$/.test(parts[1]))
    return parts.length == 2 && isAddress(parts[0]) && /^[A-Za-z0-9\/+]{43}=$/.test(parts[1])
  }

exports.type =
  function (id) {
    if(!isString(id)) return false
    var c = id.charAt(0)
    if (c == '@' && isFeedId(id))
      return 'feed'
    else if (c == '%' && isMsgId(id))
      return 'msg'
    else if (c == '&' && isBlobId(id))
      return 'blob'
    else if(isAddress(id)) return 'address'
    else if(isInvite(id)) return 'invite'
    else
    return false
  }
<commit_msg>handle ipv6 addresses<commit_after>var isDomain = require('is-valid-domain')
var rx = require('ip-regex')({exact: true})
var isIP = rx.test.bind(rx)

var isInteger = Number.isInteger

function isString(s) {
  return 'string' === typeof s
}

var isLink = exports.isLink =
  function (data) {
    return isString(data) && /^(@|%|&)[A-Za-z0-9\/+]{43}=\.[\w\d]+$/.test(data)
  }

var isFeedId = exports.isFeed = exports.isFeedId =
  function (data) {
    return isString(data) && /^@[A-Za-z0-9\/+]{43}=\.(?:sha256|ed25519)$/.test(data)
  }

var isMsgId = exports.isMsg = exports.isMsgId =
  function (data) {
    return isString(data) && /^%[A-Za-z0-9\/+]{43}=\.sha256$/.test(data)
  }

var isBlobId = exports.isBlob = exports.isBlobId =
  function (data) {
    return isString(data) && /^&[A-Za-z0-9\/+]{43}=\.sha256$/.test(data)
  }

var isAddress = exports.isAddress =
  function (data) {
    if(!isString(data)) return false
  var parts = data.split(':')
  var id = parts.pop(), port = parts.pop(), addr = parts.join(':')
  return (
    isFeedId(id) && isInteger(+port)
    && (isIP(addr) || isDomain(addr) || addr === 'localhost')
  )
}

var isInvite = exports.isInvite =
  function (data) {
    if(!isString(data)) return false
    var parts = data.split('~')
    //console.log(parts, isAddress(parts[0]), /^[A-Za-z0-9\/+]{43}=$/.test(parts[1]))
    return parts.length == 2 && isAddress(parts[0]) && /^[A-Za-z0-9\/+]{43}=$/.test(parts[1])
  }

exports.type =
  function (id) {
    if(!isString(id)) return false
    var c = id.charAt(0)
    if (c == '@' && isFeedId(id))
      return 'feed'
    else if (c == '%' && isMsgId(id))
      return 'msg'
    else if (c == '&' && isBlobId(id))
      return 'blob'
    else if(isAddress(id)) return 'address'
    else if(isInvite(id)) return 'invite'
    else
    return false
  }
<|endoftext|>


<commit_before>var Db = function(prefix) {
    if (!(this instanceof Db)) {
        return new Db(prefix);
    }

    var self = this;
    self.prefix = prefix;
    self.storage = global.localStorage;
};

Db.prototype.clear = function(cb) {
    var self = this;
    var storage = self.storage;
    var prefix = self._prefix('');

    try {
        for (var idx=0 ; idx<storage.length ; ++idx) {
            var key = storage.key(idx);
            if (key.indexOf(prefix) != 0) {
                continue;
            }
            storage.removeItem(key);
        }
    } catch (err) {
        return cb(err);
    }

    cb();
};

Db.prototype.set = function(key, val, cb) {
    var self = this;
    key = self._prefix(key);
    try {
        val = JSON.stringify(val);
        self.storage.setItem(key, val);
    } catch (err) {
        return cb(err);
    }

    cb();
};

Db.prototype.get = function(key, cb) {
    var self = this;
    key = self._prefix(key);
    try {
        var item = self.storage.getItem(key);
        item = JSON.parse(item);
        cb(null, item);
    } catch (err) {
        return cb(err);
    }
};

Db.prototype.remove = function(key, cb) {
    var self = this;
    key = self._prefix(key);
    try {
        self.storage.removeItem(key);
    } catch (err) {
        return cb(err);
    }

    cb();
};

Db.prototype.length = function(cb) {
    var self = this;

    var storage = self.storage;
    var prefix = self._prefix('');
    var count = 0;
    for (var idx=0 ; idx<storage.length ; ++idx) {
        var key = storage.key(idx);
        if (key.indexOf(prefix) != 0) {
            continue;
        }
        count++;
    }

    cb(null, count);
};

Db.prototype.key = function(idx, cb) {
    var self = this;
    cb(null, self.storage.key(idx));
};

Db.prototype._prefix = function(key) {
    var self = this;
    return (self.prefix ? self.prefix + '.' : '') + key;
};

module.exports = Db;
<commit_msg>take callback out of try/catch for .get<commit_after>var Db = function(prefix) {
    if (!(this instanceof Db)) {
        return new Db(prefix);
    }

    var self = this;
    self.prefix = prefix;
    self.storage = global.localStorage;
};

Db.prototype.clear = function(cb) {
    var self = this;
    var storage = self.storage;
    var prefix = self._prefix('');

    try {
        for (var idx=0 ; idx<storage.length ; ++idx) {
            var key = storage.key(idx);
            if (key.indexOf(prefix) != 0) {
                continue;
            }
            storage.removeItem(key);
        }
    } catch (err) {
        return cb(err);
    }

    cb();
};

Db.prototype.set = function(key, val, cb) {
    var self = this;
    key = self._prefix(key);
    try {
        val = JSON.stringify(val);
        self.storage.setItem(key, val);
    } catch (err) {
        return cb(err);
    }

    cb();
};

Db.prototype.get = function(key, cb) {
    var self = this;
    key = self._prefix(key);
    var item;
    try {
        item = JSON.parse(self.storage.getItem(key));
    } catch (err) {
        return cb(err);
    }
    cb(null, item);
};

Db.prototype.remove = function(key, cb) {
    var self = this;
    key = self._prefix(key);
    try {
        self.storage.removeItem(key);
    } catch (err) {
        return cb(err);
    }

    cb();
};

Db.prototype.length = function(cb) {
    var self = this;

    var storage = self.storage;
    var prefix = self._prefix('');
    var count = 0;
    for (var idx=0 ; idx<storage.length ; ++idx) {
        var key = storage.key(idx);
        if (key.indexOf(prefix) != 0) {
            continue;
        }
        count++;
    }

    cb(null, count);
};

Db.prototype.key = function(idx, cb) {
    var self = this;
    cb(null, self.storage.key(idx));
};

Db.prototype._prefix = function(key) {
    var self = this;
    return (self.prefix ? self.prefix + '.' : '') + key;
};

module.exports = Db;
<|endoftext|>


<commit_before>var BracketData = require('bracket-data');
var BracketValidator = require('bracket-validator');
var _extend = require('lodash/object/assign');
var _defaults = require('lodash/object/defaults');
var _pick = require('lodash/object/pick');
var _find = require('lodash/collection/find');
var _each = require('lodash/collection/forEach');
var _map = require('lodash/collection/map');
var _isNumber = require('lodash/lang/isNumber');
var _values = require('lodash/object/values');
var bracketData;
var teamNameMatches = function (team1, team2) {
    return team1 && team1.name && team2 && team2.name && team1.name.toLowerCase() === team2.name.toLowerCase();
};
var seedMatches = function (team1, team2) {
    return team1 && team2 && parseInt(team1.seed) === parseInt(team2.seed);
};
var flatten = function (bracket) {
    var flattenedBracket = '';
    _each(bracket, function (bracketRegion) {
        var regionString = _map(bracketRegion.rounds, function (round, roundIndex) {
            if (roundIndex === 0) return '';
            return _map(round, function (roundGame) {
                if (roundGame === null) return bracketData.constants.UNPICKED_MATCH;
                if (_isNumber(roundGame) || !isNaN(roundGame)) return roundGame;
                if (bracketRegion.id === bracketData.constants.FINAL_ID) return roundGame.fromRegion;
                return roundGame.seed;
            }).join('');
        }).join('')
        .replace(new RegExp(bracketData.order.join(''), 'g'), '')
        .replace(new RegExp(_values(bracketData.constants.REGION_IDS).join(''), 'g'), '');
        flattenedBracket += bracketRegion.id + regionString;
    });
    return flattenedBracket;
};

function Updater(options) {
    bracketData = new BracketData({
        sport: options.sport,
        year: options.year,
        props: ['constants', 'order']
    });

    this.validator = new BracketValidator({
        sport: options.sport,
        year: options.year
    });

    return this.reset(options);
}

Updater.prototype.reset = function (options) {
    _defaults(options || {}, {
        winner: {},
        loser: {},
        fromRegion: ''
    });

    if (typeof options.winner === 'number' || !isNaN(options.winner)) options.winner = {seed: parseInt(options.winner, 10)};
    if (typeof options.loser === 'number' || !isNaN(options.loser)) options.loser = {seed: parseInt(options.loser, 10)};
    if (typeof options.winner === 'string' && isNaN(options.winner)) options.winner = {name: options.winner};
    if (typeof options.loser === 'string' && isNaN(options.loser)) options.loser = {name: options.loser};

    // If we got passed in null or something, set the properties we need to not break
    if (!options.winner) options.winner = {};
    if (!options.loser) options.loser = {};
    if (!options.winner.name) options.winner.name = '';
    if (!options.loser.name) options.loser.name = '';

    _extend(this, _pick(options, 'winner', 'loser', 'fromRegion', 'currentMaster'));

    return this;
};

Updater.prototype.hasWinner = function () {
    return !!(this.winner && (this.winner.name || this.winner.seed));
};

Updater.prototype.hasLoser = function () {
    return !!(this.loser && (this.loser.name || this.loser.seed));
};

Updater.prototype.isFinal = function () {
    var finalName = bracketData.constants.FINAL_NAME.toLowerCase(),
        finalId = bracketData.constants.FINAL_ID.toLowerCase(),
        region = this.fromRegion.toLowerCase();

    return region === finalName || region === finalId;
};

Updater.prototype.isChampionship = function () {
    return (/((National )?Championship( Game)?|NCG)/i).test(this.fromRegion);
};

Updater.prototype.teamMatches = function (team1, team2) {
    if (this.isFinal()) {
        return teamNameMatches(team1, team2);
    } else {
        return seedMatches(team1, team2);
    }
};

Updater.prototype.gameMatches = function (winner, loser) {
    return this.teamMatches(winner, this.winner) && this.teamMatches(loser, this.loser);
};

Updater.prototype.getSeed = function (winner) {
    if (this.isFinal()) {
        var finalTeams = this.validated[bracketData.constants.FINAL_ID].rounds[0];
        var finalTeam = _find(finalTeams, function (team) {
            return teamNameMatches(team, winner);
        }, this);
        return {fromRegion: finalTeam.fromRegion};
    } else {
        return {seed: winner.seed};
    }
};

Updater.prototype.update = function (options) {
    options && this.reset(options);
    var validated = this.validator.validate(this.currentMaster);
    if (validated instanceof Error) return validated;
    this.validated = validated;

    if (this.isChampionship()) {
        this.fromRegion = bracketData.constants.FINAL_ID;
    }

    var region = validated[this.fromRegion] || _find(validated, function (item) {
        return item.name.toLowerCase() === this.fromRegion.toLowerCase();
    }, this);

    if (!region) return new Error('No region');
    if (!this.hasWinner()) return new Error('Supply at least winning team');

    var regionRoundIndex = null;
    var nextRoundGameIndex = null;
    var i, ii, m, mm, round, roundGame, otherTeam;

    roundLoop:
    for (i = region.rounds.length; i-- > 0;) {
        round = region.rounds[i];
        for (ii = round.length; ii-- > 0;) {
            roundGame = round[ii],
            otherTeam = round[(ii % 2 === 0) ? ii + 1 : ii - 1];

            if (roundGame !== null) {
                if (this.hasWinner() && this.hasLoser() && this.gameMatches(roundGame, otherTeam)) {
                    // If we have a winner and a loser look for the game that matches both
                    // Place winner into the next round
                    regionRoundIndex = i + 1;
                    nextRoundGameIndex = Math.floor(ii / 2);
                    break roundLoop;
                } else {
                    // If there is no other team, it means we want to use the winner of the latest game they appear
                    // So if a user is picking a bracket, a winner can be picked without an opponent
                    if (this.teamMatches(roundGame, this.winner) && !this.hasLoser()) {
                        regionRoundIndex = i + 1;
                        nextRoundGameIndex = Math.floor(ii / 2);
                        otherTeam && (this.loser = otherTeam);
                        break roundLoop;
                    }
                }
            }
        }
    }

    if (regionRoundIndex !== null && nextRoundGameIndex !== null) {
        var hasRound = !!region.rounds[regionRoundIndex];
        if (hasRound) {
            region.rounds[regionRoundIndex][nextRoundGameIndex] = this.getSeed(this.winner);
            for (i = regionRoundIndex, m = region.rounds.length; i < m; i++) {
                round = region.rounds[i];
                for (ii = 0, mm = round.length; ii < mm; ii++) {
                    roundGame = round[ii],
                    otherTeam = round[(ii % 2 === 0) ? ii + 1 : ii - 1];
                    // The losing team might have already advanced in the bracket
                    // Such as when someone is picking a bracket and changed their mind
                    // We need to remove all of the losing team from the rest of the rounds
                    if (this.hasLoser() && roundGame !== null && this.teamMatches(roundGame, this.loser)) {
                        round[ii] = null;
                    }
                }
            }
        }
    }

    // Clear losing teams from final four also
    var isFinalRegion = this.fromRegion === bracketData.constants.FINAL_ID;
    if (this.hasLoser() && (!isFinalRegion || (isFinalRegion && regionRoundIndex === 1))) {
        var fin = validated[bracketData.constants.FINAL_ID];
        _each(fin.rounds, function (round, i) {
            if (i > 0) {
                _each(round, function (game, ii) {
                    if (game && teamNameMatches(game, this.loser)) {
                        validated[bracketData.constants.FINAL_ID].rounds[i][ii] = null;
                    }
                }, this);
            }
        }, this);
    }

    this.currentMaster = flatten(validated);
    return this.currentMaster;
};

module.exports = Updater;
<commit_msg>fix state outside scope<commit_after>var BracketData = require('bracket-data');
var BracketValidator = require('bracket-validator');
var _extend = require('lodash/object/assign');
var _defaults = require('lodash/object/defaults');
var _pick = require('lodash/object/pick');
var _find = require('lodash/collection/find');
var _each = require('lodash/collection/forEach');
var _map = require('lodash/collection/map');
var _isNumber = require('lodash/lang/isNumber');
var _values = require('lodash/object/values');

var teamNameMatches = function (team1, team2) {
    return team1 && team1.name && team2 && team2.name && team1.name.toLowerCase() === team2.name.toLowerCase();
};
var seedMatches = function (team1, team2) {
    return team1 && team2 && parseInt(team1.seed) === parseInt(team2.seed);
};

function Updater(options) {
    this.bracketData = new BracketData({
        sport: options.sport,
        year: options.year,
        props: ['constants', 'order']
    });

    this.validator = new BracketValidator({
        sport: options.sport,
        year: options.year
    });

    return this.reset(options);
}

Updater.prototype.reset = function (options) {
    _defaults(options || {}, {
        winner: {},
        loser: {},
        fromRegion: ''
    });

    if (typeof options.winner === 'number' || !isNaN(options.winner)) options.winner = {seed: parseInt(options.winner, 10)};
    if (typeof options.loser === 'number' || !isNaN(options.loser)) options.loser = {seed: parseInt(options.loser, 10)};
    if (typeof options.winner === 'string' && isNaN(options.winner)) options.winner = {name: options.winner};
    if (typeof options.loser === 'string' && isNaN(options.loser)) options.loser = {name: options.loser};

    // If we got passed in null or something, set the properties we need to not break
    if (!options.winner) options.winner = {};
    if (!options.loser) options.loser = {};
    if (!options.winner.name) options.winner.name = '';
    if (!options.loser.name) options.loser.name = '';

    _extend(this, _pick(options, 'winner', 'loser', 'fromRegion', 'currentMaster'));

    return this;
};

Updater.prototype.hasWinner = function () {
    return !!(this.winner && (this.winner.name || this.winner.seed));
};

Updater.prototype.hasLoser = function () {
    return !!(this.loser && (this.loser.name || this.loser.seed));
};

Updater.prototype.isFinal = function () {
    var finalName = this.bracketData.constants.FINAL_NAME.toLowerCase(),
        finalId = this.bracketData.constants.FINAL_ID.toLowerCase(),
        region = this.fromRegion.toLowerCase();

    return region === finalName || region === finalId;
};

Updater.prototype.isChampionship = function () {
    return (/((National )?Championship( Game)?|NCG)/i).test(this.fromRegion);
};

Updater.prototype.teamMatches = function (team1, team2) {
    if (this.isFinal()) {
        return teamNameMatches(team1, team2);
    } else {
        return seedMatches(team1, team2);
    }
};

Updater.prototype.gameMatches = function (winner, loser) {
    return this.teamMatches(winner, this.winner) && this.teamMatches(loser, this.loser);
};

Updater.prototype.getSeed = function (winner) {
    if (this.isFinal()) {
        var finalTeams = this.validated[this.bracketData.constants.FINAL_ID].rounds[0];
        var finalTeam = _find(finalTeams, function (team) {
            return teamNameMatches(team, winner);
        }, this);
        return {fromRegion: finalTeam.fromRegion};
    } else {
        return {seed: winner.seed};
    }
};

Updater.prototype.flatten = function (bracket) {
    var self = this;
    var flattenedBracket = '';
    _each(bracket, function (bracketRegion) {
        var regionString = _map(bracketRegion.rounds, function (round, roundIndex) {
            if (roundIndex === 0) return '';
            return _map(round, function (roundGame) {
                if (roundGame === null) return self.bracketData.constants.UNPICKED_MATCH;
                if (_isNumber(roundGame) || !isNaN(roundGame)) return roundGame;
                if (bracketRegion.id === self.bracketData.constants.FINAL_ID) return roundGame.fromRegion;
                return roundGame.seed;
            }).join('');
        }).join('')
        .replace(new RegExp(self.bracketData.order.join(''), 'g'), '')
        .replace(new RegExp(_values(self.bracketData.constants.REGION_IDS).join(''), 'g'), '');
        flattenedBracket += bracketRegion.id + regionString;
    });
    return flattenedBracket;
};

Updater.prototype.update = function (options) {
    options && this.reset(options);
    var validated = this.validator.validate(this.currentMaster);
    if (validated instanceof Error) return validated;
    this.validated = validated;

    if (this.isChampionship()) {
        this.fromRegion = this.bracketData.constants.FINAL_ID;
    }

    var region = validated[this.fromRegion] || _find(validated, function (item) {
        return item.name.toLowerCase() === this.fromRegion.toLowerCase();
    }, this);

    if (!region) return new Error('No region');
    if (!this.hasWinner()) return new Error('Supply at least winning team');

    var regionRoundIndex = null;
    var nextRoundGameIndex = null;
    var i, ii, m, mm, round, roundGame, otherTeam;

    roundLoop:
    for (i = region.rounds.length; i-- > 0;) {
        round = region.rounds[i];
        for (ii = round.length; ii-- > 0;) {
            roundGame = round[ii],
            otherTeam = round[(ii % 2 === 0) ? ii + 1 : ii - 1];

            if (roundGame !== null) {
                if (this.hasWinner() && this.hasLoser() && this.gameMatches(roundGame, otherTeam)) {
                    // If we have a winner and a loser look for the game that matches both
                    // Place winner into the next round
                    regionRoundIndex = i + 1;
                    nextRoundGameIndex = Math.floor(ii / 2);
                    break roundLoop;
                } else {
                    // If there is no other team, it means we want to use the winner of the latest game they appear
                    // So if a user is picking a bracket, a winner can be picked without an opponent
                    if (this.teamMatches(roundGame, this.winner) && !this.hasLoser()) {
                        regionRoundIndex = i + 1;
                        nextRoundGameIndex = Math.floor(ii / 2);
                        otherTeam && (this.loser = otherTeam);
                        break roundLoop;
                    }
                }
            }
        }
    }

    if (regionRoundIndex !== null && nextRoundGameIndex !== null) {
        var hasRound = !!region.rounds[regionRoundIndex];
        if (hasRound) {
            region.rounds[regionRoundIndex][nextRoundGameIndex] = this.getSeed(this.winner);
            for (i = regionRoundIndex, m = region.rounds.length; i < m; i++) {
                round = region.rounds[i];
                for (ii = 0, mm = round.length; ii < mm; ii++) {
                    roundGame = round[ii],
                    otherTeam = round[(ii % 2 === 0) ? ii + 1 : ii - 1];
                    // The losing team might have already advanced in the bracket
                    // Such as when someone is picking a bracket and changed their mind
                    // We need to remove all of the losing team from the rest of the rounds
                    if (this.hasLoser() && roundGame !== null && this.teamMatches(roundGame, this.loser)) {
                        round[ii] = null;
                    }
                }
            }
        }
    }

    // Clear losing teams from final four also
    var isFinalRegion = this.fromRegion === this.bracketData.constants.FINAL_ID;
    if (this.hasLoser() && (!isFinalRegion || (isFinalRegion && regionRoundIndex === 1))) {
        var fin = validated[this.bracketData.constants.FINAL_ID];
        _each(fin.rounds, function (round, i) {
            if (i > 0) {
                _each(round, function (game, ii) {
                    if (game && teamNameMatches(game, this.loser)) {
                        validated[this.bracketData.constants.FINAL_ID].rounds[i][ii] = null;
                    }
                }, this);
            }
        }, this);
    }

    this.currentMaster = this.flatten(validated);
    return this.currentMaster;
};

module.exports = Updater;
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;

var browserResolve = require('browser-resolve');
var nodeResolve = require('resolve');
var detective = require('detective');
var through = require('through2');
var concat = require('concat-stream');
var parents = require('parents');
var combine = require('stream-combiner');
var duplexer = require('duplexer2');

var inherits = require('inherits');
var Readable = require('readable-stream').Readable;

module.exports = Deps;
inherits(Deps, Readable);

function Deps (mains, opts) {
    var self = this;
    if (!(this instanceof Deps)) return new Deps(mains, opts);
    Readable.call(this, { objectMode: true });

    if (!opts) opts = {};
    if (!Array.isArray(mains)) mains = [ mains ].filter(Boolean);

    this.basedir = opts.basedir || process.cwd();
    this.cache = opts.cache;
    this.pkgCache = opts.packageCache || {};
    this.pkgFileCache = {};
    this.pkgFileCachePending = {};
    this.visited = {};

    this.paths = opts.paths || process.env.NODE_PATH;
    if (typeof this.paths === 'string') {
        this.paths = process.env.NODE_PATH.split(':');
    }
    if (!this.paths) this.paths = [];
    this.entries = [];
    this.mains = [];

    this.transforms = [].concat(opts.transform).filter(Boolean);
    this.resolver = opts.resolve || browserResolve;
    this.options = opts;
    this.pending = 0;
    this.top = { id: '/', filename: '/', paths: this.paths };

    mains.forEach(function (file) { self.add(file) });
}

Deps.prototype._read = function () {
    if (this._started) return;
    this._started = true;
    this._start();
};

Deps.prototype._start = function () {
    var self = this;

    for (var i = 0; i < this.entries.length; i++) {
        var main = this.mains[i];
        var file = this.entries[i];

        this.lookupPackage(file, function (err, pkg) {
            if (err) return self.emit('error', err)
            else start(main, file, pkg)
        });
    }

    function start (main, file, pkg) {
        if (!pkg) pkg = {};
        if (!pkg.__dirname) pkg.__dirname = path.dirname(file);

        if (typeof main === 'object') {
            self.walk({ stream: main, file: file }, main);
        }
        else self.walk(main, self.top);
    }
};

Deps.prototype.add = function (main) {
    var self = this;

    var file;
    if (typeof main.pipe === 'function') {
        var n = Math.floor(Math.pow(16,8) * Math.random()).toString(16);
        file = path.join(this.basedir, 'fake_' + n + '.js');
        if (typeof main.read !== 'function') {
            main = Readable().wrap(main);
        }
    }
    else file = main;
    file = path.resolve(file);
    this.mains.push(main);
    this.entries.push(file);
};

Deps.prototype.resolve = function (id, parent, cb) {
    var self = this;
    var opts = self.options;

    if (typeof id === 'object') {
        id.stream.pipe(concat(function (body) {
            var src = body.toString('utf8');
            var pkgfile = path.join(self.basedir, 'package.json');
            fs.readFile(pkgfile, function (err, pkgsrc) {
                var pkg = {};
                if (!err) {
                    try { pkg = JSON.parse(pkgsrc) }
                    catch (e) {};
                }
                var trx = getTransform(pkg);
                applyTransforms(id.file, trx, src, pkg);
            });
        }));
        if (cb) cb(false);
        return;
    }

    var c = this.cache && this.cache[parent.id];
    var resolver = c && typeof c === 'object'
    && !Buffer.isBuffer(c) && c.deps[id]
        ? function (xid, xparent, fn) {
            var file = self.cache[parent.id].deps[id];
            fn(null, file, self.pkgCache && self.pkgCache[file]);
        }
        : self.resolver
    ;

    var pkgdir;
    parent.packageFilter = function (p, x) {
        pkgdir = x;
        if (opts.packageFilter) return opts.packageFilter(p, x);
        else return p;
    };

    if (opts.extensions) parent.extensions = opts.extensions;
    if (opts.modules) parent.modules = opts.modules;

    self.resolver(id, parent, function onresolve (err, file, pkg) {
        if (err) return cb(err);
        if (!file) return cb(new Error(
            'module not found: "' + id + '" from file '
            + parent.filename
        ));

        if (pkg && pkgdir) pkg.__dirname = pkgdir;
        if (!pkg || !pkg.__dirname) {
            self.lookupPackage(file, function (err, p) {
                if (err) return cb(err);
                if (!p) p = {};
                if (!p.__dirname) p.__dirname = path.dirname(file);
                self.pkgCache[file] = p;
                onresolve(err, file, opts.packageFilter
                    ? opts.packageFilter(p, p.__dirname) : p
                );
            });
        }
        else cb(err, file, pkg);
    });
};

Deps.prototype.readFile = function (file, pkg) {
    if (this.cache && this.cache[file]) {
        var tr = through();
        tr.push(this.cache[file]);
        return tr;
    }
    var rs = fs.createReadStream(file);
    rs.on('error', function (err) { tr.emit('error', err) });
    return rs.pipe(this.getTransforms(file, pkg));
};

Deps.prototype.getTransforms = function (file, pkg) {
    var self = this;
    var isTopLevel = this.entries.some(function (main) {
        var m = path.relative(path.dirname(main), file);
        return m.split('/').indexOf('node_modules') < 0;
    });

    var transforms = [].concat(isTopLevel ? this.transforms : [])
        .concat(getTransforms(pkg, this.options))
    ;
    if (transforms.length === 0) return through();

    var pending = transforms.length;
    var streams = [];
    var input = through();
    var output = through();
    var dup = duplexer(input, output);

    for (var i = 0; i < transforms.length; i++) {
        makeTransform(transforms[i], function (err, trs) {
            if (err) return dup.emit('error', err)
            streams.push(trs);
            if (-- pending === 0) done();
        });
    }
    return dup;

    function done () {
        var middle = combine.apply(null, streams);
        input.pipe(middle).pipe(output);
    }

    function makeTransform (tr, cb) {
        var trOpts = {};
        if (Array.isArray(tr)) {
            trOpts = tr[1];
            tr = tr[0];
        }
        if (typeof tr === 'function') {
            var t = tr(file, trOpts);
            self.emit('transform', t, file);
            nextTick(cb, null, t);
        }
        else {
            loadTransform(tr, trOpts, function (err, trs) {
                self.emit('transform', t, file);
                cb(null, trs);
            });
        }
    }

    function loadTransform (file, trOpts, cb) {
        var params = { basedir: path.dirname(file) };
        nodeResolve(file, params, function nr (err, res, again) {
            if (err && again) return cb(err);

            if (err) {
                params.basedir = process.cwd();
                return nodeResolve(file, params, function (e, r) {
                    nr(e, r, true)
                });
            }

            if (!res) return cb(new Error(
                'cannot find transform module ' + tr
                + ' while transforming ' + file
            ));

            var r = require(res);
            if (typeof r !== 'function') {
                return cb(new Error('transform not a function'));
            }

            var trs = r(file, trOpts);
            self.emit('transform', trs, file);
            cb(null, trs);
        });
    }
};

Deps.prototype.walk = function (id, parent, cb) {
    var self = this;
    var opts = self.options;
    this.pending ++;

    if (id && typeof id === 'object' && id.stream) {
        return id.stream.pipe(concat(function (body) {
            var src = body.toString('utf8');
            var deps = self.parseDeps(id.file, src);
            self.lookupPackage(id.file, function (err, pkg) {
                fromDeps(id.file, src, pkg || {}, deps);
            });
        }));
    }

    self.resolve(id, parent, function (err, file, pkg) {
        if (err) return self.emit('error', err);
        self.readFile(file).pipe(concat(function (body) {
            var src = body.toString('utf8');
            var deps = self.parseDeps(file, src);
            fromDeps(file, src, pkg, deps);
        }));
    });

    function fromDeps (file, src, pkg, deps) {
        var p = deps.length;
        var current = {
            id: file,
            filename: file,
            paths: self.paths,
            package: pkg
        };
        var resolved = {};

        deps.forEach(function (id) {
            if (opts.filter && !opts.filter(id)) {
                resolved[id] = false;
                if (--p === 0) done();
                return;
            }
            self.walk(id, current, function (err, r) {
                resolved[id] = r;
                if (--p === 0) done();
            });
        });
        if (deps.length === 0) done();

        function done () {
            var rec = {
                id: file,
                source: src,
                deps: resolved
            };
            if (self.entries.indexOf(file) >= 0) {
                rec.entry = true;
            }
            self.push(rec);

            if (cb) cb(null, file);
            if (-- self.pending === 0) self.push(null);
        }
    }
};

Deps.prototype.parseDeps = function (file, src, cb) {
    if (this.options.noParse === true) return [];
    if (/\.json$/.test(file)) return [];

    if (Array.isArray(this.options.noParse)
    && this.options.noParse.indexOf(file) >= 0) {
        return [];
    }

    try { var deps = detective(src) }
    catch (ex) {
        return
        var message = ex && ex.message ? ex.message : ex;
        return output.emit('error', new Error(
            'Parsing file ' + file + ': ' + message
        ));
    }
    return deps;
};

Deps.prototype.lookupPackage = function (file, cb) {
    var self = this;

    var id = path.resolve(this.basedir, file);
    var cached = this.pkgCache[id];
    if (cached) return process.nextTick(function () { cb(null, cached) });

    var dirs = parents(path.dirname(file));
    (function next () {
        if (dirs.length === 0) return cb(null, undefined);
        var dir = dirs.shift();
        var pkgfile = path.join(dir, 'package.json');

        var cached = self.pkgFileCachePending[pkgfile];
        if (cached) return cached.push(onpkg);
        cached = self.pkgFileCachePending[pkgfile] = [];

        fs.readFile(pkgfile, function (err, src) {
            if (err) return onpkg();
            try { var pkg = JSON.parse(src) }
            catch (err) {
                return onpkg(new Error([
                    err + ' while parsing json file ' + pkgfile
                ].join('')))
            }
            pkg.__dirname = dir;

            self.pkgCache[id] = pkg;
            onpkg(null, pkg);
        });

        function onpkg (err, pkg) {
            if (self.pkgFileCachePending[pkgfile]) {
                var fns = self.pkgFileCachePending[pkgfile];
                delete self.pkgFileCachePending[pkgfile];
                fns.forEach(function (f) { f(err, pkg) });
            }
            if (err) cb(err)
            else if (pkg) cb(null, pkg)
            else next()
        }
    })();
};

function getTransforms (pkg, opts) {
    var trx = [];
    if (opts.transformKey) {
        var n = pkg;
        var keys = opts.transformKey;
        for (var i = 0; i < keys.length; i++) {
            if (n && typeof n === 'object') n = n[keys[i]];
            else break;
        }
        if (i === keys.length) {
            trx = [].concat(n).filter(Boolean);
        }
    }
    return trx.concat(opts.globalTransform || []);
}

function nextTick (cb) {
    var args = [].slice.call(arguments, 1);
    process.nextTick(function () { cb.apply(null, args) });
}
<commit_msg>fixed the stream test by checking for .path<commit_after>var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;

var browserResolve = require('browser-resolve');
var nodeResolve = require('resolve');
var detective = require('detective');
var through = require('through2');
var concat = require('concat-stream');
var parents = require('parents');
var combine = require('stream-combiner');
var duplexer = require('duplexer2');

var inherits = require('inherits');
var Readable = require('readable-stream').Readable;

module.exports = Deps;
inherits(Deps, Readable);

function Deps (mains, opts) {
    var self = this;
    if (!(this instanceof Deps)) return new Deps(mains, opts);
    Readable.call(this, { objectMode: true });

    if (!opts) opts = {};
    if (!Array.isArray(mains)) mains = [ mains ].filter(Boolean);

    this.basedir = opts.basedir || process.cwd();
    this.cache = opts.cache;
    this.pkgCache = opts.packageCache || {};
    this.pkgFileCache = {};
    this.pkgFileCachePending = {};
    this.visited = {};

    this.paths = opts.paths || process.env.NODE_PATH;
    if (typeof this.paths === 'string') {
        this.paths = process.env.NODE_PATH.split(':');
    }
    if (!this.paths) this.paths = [];
    this.entries = [];
    this.mains = [];

    this.transforms = [].concat(opts.transform).filter(Boolean);
    this.resolver = opts.resolve || browserResolve;
    this.options = opts;
    this.pending = 0;
    this.top = { id: '/', filename: '/', paths: this.paths };

    mains.forEach(function (file) { self.add(file) });
}

Deps.prototype._read = function () {
    if (this._started) return;
    this._started = true;
    this._start();
};

Deps.prototype._start = function () {
    var self = this;

    for (var i = 0; i < this.entries.length; i++) {
        var main = this.mains[i];
        var file = this.entries[i];

        this.lookupPackage(file, function (err, pkg) {
            if (err) return self.emit('error', err)
            else start(main, file, pkg)
        });
    }

    function start (main, file, pkg) {
        if (!pkg) pkg = {};
        if (!pkg.__dirname) pkg.__dirname = path.dirname(file);

        if (typeof main === 'object') {
            self.walk({ stream: main, file: main.path || file }, main);
        }
        else self.walk(main, self.top);
    }
};

Deps.prototype.add = function (main) {
    var self = this;

    var file;
    if (typeof main.pipe === 'function') {
        var n = Math.floor(Math.pow(16,8) * Math.random()).toString(16);
        file = path.join(this.basedir, 'fake_' + n + '.js');
        if (typeof main.read !== 'function') {
            var old = main;
            main = Readable().wrap(main);
            if (old.path) main.path = old.path;
        }
    }
    else file = main;
    file = path.resolve(file);
    this.mains.push(main);
    this.entries.push(file);
};

Deps.prototype.resolve = function (id, parent, cb) {
    var self = this;
    var opts = self.options;

    var c = this.cache && this.cache[parent.id];
    var resolver = c && typeof c === 'object'
    && !Buffer.isBuffer(c) && c.deps[id]
        ? function (xid, xparent, fn) {
            var file = self.cache[parent.id].deps[id];
            fn(null, file, self.pkgCache && self.pkgCache[file]);
        }
        : self.resolver
    ;

    var pkgdir;
    parent.packageFilter = function (p, x) {
        pkgdir = x;
        if (opts.packageFilter) return opts.packageFilter(p, x);
        else return p;
    };

    if (opts.extensions) parent.extensions = opts.extensions;
    if (opts.modules) parent.modules = opts.modules;

    self.resolver(id, parent, function onresolve (err, file, pkg) {
        if (err) return cb(err);
        if (!file) return cb(new Error(
            'module not found: "' + id + '" from file '
            + parent.filename
        ));

        if (pkg && pkgdir) pkg.__dirname = pkgdir;
        if (!pkg || !pkg.__dirname) {
            self.lookupPackage(file, function (err, p) {
                if (err) return cb(err);
                if (!p) p = {};
                if (!p.__dirname) p.__dirname = path.dirname(file);
                self.pkgCache[file] = p;
                onresolve(err, file, opts.packageFilter
                    ? opts.packageFilter(p, p.__dirname) : p
                );
            });
        }
        else cb(err, file, pkg);
    });
};

Deps.prototype.readFile = function (file, pkg) {
    if (this.cache && this.cache[file]) {
        var tr = through();
        tr.push(this.cache[file]);
        return tr;
    }
    var rs = fs.createReadStream(file);
    rs.on('error', function (err) { tr.emit('error', err) });
    return rs.pipe(this.getTransforms(file, pkg));
};

Deps.prototype.getTransforms = function (file, pkg) {
    var self = this;
    var isTopLevel = this.entries.some(function (main) {
        var m = path.relative(path.dirname(main), file);
        return m.split('/').indexOf('node_modules') < 0;
    });

    var transforms = [].concat(isTopLevel ? this.transforms : [])
        .concat(getTransforms(pkg, this.options))
    ;
    if (transforms.length === 0) return through();

    var pending = transforms.length;
    var streams = [];
    var input = through();
    var output = through();
    var dup = duplexer(input, output);

    for (var i = 0; i < transforms.length; i++) {
        makeTransform(transforms[i], function (err, trs) {
            if (err) return dup.emit('error', err)
            streams.push(trs);
            if (-- pending === 0) done();
        });
    }
    return dup;

    function done () {
        var middle = combine.apply(null, streams);
        input.pipe(middle).pipe(output);
    }

    function makeTransform (tr, cb) {
        var trOpts = {};
        if (Array.isArray(tr)) {
            trOpts = tr[1];
            tr = tr[0];
        }
        if (typeof tr === 'function') {
            var t = tr(file, trOpts);
            self.emit('transform', t, file);
            nextTick(cb, null, t);
        }
        else {
            loadTransform(tr, trOpts, function (err, trs) {
                self.emit('transform', t, file);
                cb(null, trs);
            });
        }
    }

    function loadTransform (file, trOpts, cb) {
        var params = { basedir: path.dirname(file) };
        nodeResolve(file, params, function nr (err, res, again) {
            if (err && again) return cb(err);

            if (err) {
                params.basedir = process.cwd();
                return nodeResolve(file, params, function (e, r) {
                    nr(e, r, true)
                });
            }

            if (!res) return cb(new Error(
                'cannot find transform module ' + tr
                + ' while transforming ' + file
            ));

            var r = require(res);
            if (typeof r !== 'function') {
                return cb(new Error('transform not a function'));
            }

            var trs = r(file, trOpts);
            self.emit('transform', trs, file);
            cb(null, trs);
        });
    }
};

Deps.prototype.walk = function (id, parent, cb) {
    var self = this;
    var opts = self.options;
    this.pending ++;

    if (id && typeof id === 'object' && id.stream) {
        return id.stream.pipe(concat(function (body) {
            var src = body.toString('utf8');
            var deps = self.parseDeps(id.file, src);
            self.lookupPackage(id.file, function (err, pkg) {
                fromDeps(id.file, src, pkg || {}, deps);
            });
        }));
    }

    self.resolve(id, parent, function (err, file, pkg) {
        if (err) return self.emit('error', err);
        self.readFile(file).pipe(concat(function (body) {
            var src = body.toString('utf8');
            var deps = self.parseDeps(file, src);
            fromDeps(file, src, pkg, deps);
        }));
    });

    function fromDeps (file, src, pkg, deps) {
        var p = deps.length;
        var current = {
            id: file,
            filename: file,
            paths: self.paths,
            package: pkg
        };
        var resolved = {};

        deps.forEach(function (id) {
            if (opts.filter && !opts.filter(id)) {
                resolved[id] = false;
                if (--p === 0) done();
                return;
            }
            self.walk(id, current, function (err, r) {
                resolved[id] = r;
                if (--p === 0) done();
            });
        });
        if (deps.length === 0) done();

        function done () {
            var rec = {
                id: file,
                source: src,
                deps: resolved
            };
            if (self.entries.indexOf(file) >= 0) {
                rec.entry = true;
            }
            self.push(rec);

            if (cb) cb(null, file);
            if (-- self.pending === 0) self.push(null);
        }
    }
};

Deps.prototype.parseDeps = function (file, src, cb) {
    if (this.options.noParse === true) return [];
    if (/\.json$/.test(file)) return [];

    if (Array.isArray(this.options.noParse)
    && this.options.noParse.indexOf(file) >= 0) {
        return [];
    }

    try { var deps = detective(src) }
    catch (ex) {
        return
        var message = ex && ex.message ? ex.message : ex;
        return output.emit('error', new Error(
            'Parsing file ' + file + ': ' + message
        ));
    }
    return deps;
};

Deps.prototype.lookupPackage = function (file, cb) {
    var self = this;

    var id = path.resolve(this.basedir, file);
    var cached = this.pkgCache[id];
    if (cached) return process.nextTick(function () { cb(null, cached) });

    var dirs = parents(path.dirname(file));
    (function next () {
        if (dirs.length === 0) return cb(null, undefined);
        var dir = dirs.shift();
        var pkgfile = path.join(dir, 'package.json');

        var cached = self.pkgFileCachePending[pkgfile];
        if (cached) return cached.push(onpkg);
        cached = self.pkgFileCachePending[pkgfile] = [];

        fs.readFile(pkgfile, function (err, src) {
            if (err) return onpkg();
            try { var pkg = JSON.parse(src) }
            catch (err) {
                return onpkg(new Error([
                    err + ' while parsing json file ' + pkgfile
                ].join('')))
            }
            pkg.__dirname = dir;

            self.pkgCache[id] = pkg;
            onpkg(null, pkg);
        });

        function onpkg (err, pkg) {
            if (self.pkgFileCachePending[pkgfile]) {
                var fns = self.pkgFileCachePending[pkgfile];
                delete self.pkgFileCachePending[pkgfile];
                fns.forEach(function (f) { f(err, pkg) });
            }
            if (err) cb(err)
            else if (pkg) cb(null, pkg)
            else next()
        }
    })();
};

function getTransforms (pkg, opts) {
    var trx = [];
    if (opts.transformKey) {
        var n = pkg;
        var keys = opts.transformKey;
        for (var i = 0; i < keys.length; i++) {
            if (n && typeof n === 'object') n = n[keys[i]];
            else break;
        }
        if (i === keys.length) {
            trx = [].concat(n).filter(Boolean);
        }
    }
    return trx.concat(opts.globalTransform || []);
}

function nextTick (cb) {
    var args = [].slice.call(arguments, 1);
    process.nextTick(function () { cb.apply(null, args) });
}
<|endoftext|>