<commit_before>var TokenBucket = require('./tokenBucket');

/**
 * A generic rate limiter. Underneath the hood, this uses a token bucket plus
 * an additional check to limit how many tokens we can remove each interval.
 * @author John Hurliman <jhurliman@jhurliman.org>
 *
 * @param {Number} tokensPerInterval Maximum number of tokens that can be
 *  removed at any given moment and over the course of one interval.
 * @param {String|Number} interval The interval length in milliseconds, or as
 *  one of the following strings: 'second', 'minute', 'hour', day'.
 * @param {Boolean} fireImmediately Optional. Whether or not the callback
 *  will fire immediately when rate limiting is in effect (default is false).
 */
var RateLimiter = function(tokensPerInterval, interval, fireImmediately) {
  this.tokenBucket = new TokenBucket(tokensPerInterval, tokensPerInterval,
    interval, null);

  // Fill the token bucket to start
  this.tokenBucket.content = tokensPerInterval;

  this.curIntervalStart = +new Date();
  this.tokensThisInterval = 0;
  this.fireImmediately = fireImmediately;
};

RateLimiter.prototype = {
  tokenBucket: null,
  curIntervalStart: 0,
  tokensThisInterval: 0,
  fireImmediately: false,

  /**
   * Remove the requested number of tokens and fire the given callback. If the
   * rate limiter contains enough tokens and we haven't spent too many tokens
   * in this interval already, this will happen immediately. Otherwise, the
   * removal and callback will happen when enough tokens become available.
   * @param {Number} count The number of tokens to remove.
   * @param {Function} callback(err, remainingTokens)
   * @returns {Boolean} True if the callback was fired immediately, otherwise
   *  false.
   */
  removeTokens: function(count, callback) {
    // Make sure the request isn't for more than we can handle
    if (count > this.tokenBucket.bucketSize) {
      process.nextTick(callback.bind(null, 'Requested tokens ' + count +
        ' exceeds maximum tokens per interval ' + this.tokenBucket.bucketSize,
        null));
      return false;
    }

    var self = this;
    var now = Date.now();

    // Advance the current interval and reset the current interval token count
    // if needed
    if (now - this.curIntervalStart >= this.tokenBucket.interval) {
      this.curIntervalStart = now;
      this.tokensThisInterval = 0;
    }

    // If we don't have enough tokens left in this interval, wait until the
    // next interval
    if (count > this.tokenBucket.tokensPerInterval - this.tokensThisInterval) {
      if (this.fireImmediately) {
        process.nextTick(callback.bind(null, null, -1));
      } else {
        var waitInterval = Math.ceil(
          this.curIntervalStart + this.tokenBucket.interval - now);

        setTimeout(function() {
          self.tokenBucket.removeTokens(count, afterTokensRemoved);
        }, waitInterval);
      }
      return false;
    }

    // Remove the requested number of tokens from the token bucket
    return this.tokenBucket.removeTokens(count, afterTokensRemoved);

    function afterTokensRemoved(err, tokensRemaining) {
      if (err) return callback(err, null);

      self.tokensThisInterval += count;
      callback(null, tokensRemaining);
    }
  },

  /**
   * Attempt to remove the requested number of tokens and return immediately.
   * If the bucket (and any parent buckets) contains enough tokens and we
   * haven't spent too many tokens in this interval already, this will return
   * true. Otherwise, false is returned.
   * @param {Number} count The number of tokens to remove.
   * @param {Boolean} True if the tokens were successfully removed, otherwise
   *  false.
   */
  tryRemoveTokens: function(count) {
    // Make sure the request isn't for more than we can handle
    if (count > this.tokenBucket.bucketSize)
      return false;

    var now = Date.now();

    // Advance the current interval and reset the current interval token count
    // if needed
    if (now - this.curIntervalStart >= this.tokenBucket.interval) {
      this.curIntervalStart = now;
      this.tokensThisInterval = 0;
    }

    // If we don't have enough tokens left in this interval, return false
    if (count > this.tokenBucket.tokensPerInterval - this.tokensThisInterval)
      return false;

    // Try to remove the requested number of tokens from the token bucket
    return this.tokenBucket.tryRemoveTokens(count);
  },

  /**
   * Returns the number of tokens remaining in the TokenBucket.
   * @returns {Number} The number of tokens remaining.
   */
  getTokensRemaining: function () {
    this.tokenBucket.drip();
    return this.tokenBucket.content;
  }
};

module.exports = RateLimiter;
<commit_msg>increment tokensThisInterval in tryRemoveTokens<commit_after>var TokenBucket = require('./tokenBucket');

/**
 * A generic rate limiter. Underneath the hood, this uses a token bucket plus
 * an additional check to limit how many tokens we can remove each interval.
 * @author John Hurliman <jhurliman@jhurliman.org>
 *
 * @param {Number} tokensPerInterval Maximum number of tokens that can be
 *  removed at any given moment and over the course of one interval.
 * @param {String|Number} interval The interval length in milliseconds, or as
 *  one of the following strings: 'second', 'minute', 'hour', day'.
 * @param {Boolean} fireImmediately Optional. Whether or not the callback
 *  will fire immediately when rate limiting is in effect (default is false).
 */
var RateLimiter = function(tokensPerInterval, interval, fireImmediately) {
  this.tokenBucket = new TokenBucket(tokensPerInterval, tokensPerInterval,
    interval, null);

  // Fill the token bucket to start
  this.tokenBucket.content = tokensPerInterval;

  this.curIntervalStart = +new Date();
  this.tokensThisInterval = 0;
  this.fireImmediately = fireImmediately;
};

RateLimiter.prototype = {
  tokenBucket: null,
  curIntervalStart: 0,
  tokensThisInterval: 0,
  fireImmediately: false,

  /**
   * Remove the requested number of tokens and fire the given callback. If the
   * rate limiter contains enough tokens and we haven't spent too many tokens
   * in this interval already, this will happen immediately. Otherwise, the
   * removal and callback will happen when enough tokens become available.
   * @param {Number} count The number of tokens to remove.
   * @param {Function} callback(err, remainingTokens)
   * @returns {Boolean} True if the callback was fired immediately, otherwise
   *  false.
   */
  removeTokens: function(count, callback) {
    // Make sure the request isn't for more than we can handle
    if (count > this.tokenBucket.bucketSize) {
      process.nextTick(callback.bind(null, 'Requested tokens ' + count +
        ' exceeds maximum tokens per interval ' + this.tokenBucket.bucketSize,
        null));
      return false;
    }

    var self = this;
    var now = Date.now();

    // Advance the current interval and reset the current interval token count
    // if needed
    if (now - this.curIntervalStart >= this.tokenBucket.interval) {
      this.curIntervalStart = now;
      this.tokensThisInterval = 0;
    }

    // If we don't have enough tokens left in this interval, wait until the
    // next interval
    if (count > this.tokenBucket.tokensPerInterval - this.tokensThisInterval) {
      if (this.fireImmediately) {
        process.nextTick(callback.bind(null, null, -1));
      } else {
        var waitInterval = Math.ceil(
          this.curIntervalStart + this.tokenBucket.interval - now);

        setTimeout(function() {
          self.tokenBucket.removeTokens(count, afterTokensRemoved);
        }, waitInterval);
      }
      return false;
    }

    // Remove the requested number of tokens from the token bucket
    return this.tokenBucket.removeTokens(count, afterTokensRemoved);

    function afterTokensRemoved(err, tokensRemaining) {
      if (err) return callback(err, null);

      self.tokensThisInterval += count;
      callback(null, tokensRemaining);
    }
  },

  /**
   * Attempt to remove the requested number of tokens and return immediately.
   * If the bucket (and any parent buckets) contains enough tokens and we
   * haven't spent too many tokens in this interval already, this will return
   * true. Otherwise, false is returned.
   * @param {Number} count The number of tokens to remove.
   * @param {Boolean} True if the tokens were successfully removed, otherwise
   *  false.
   */
  tryRemoveTokens: function(count) {
    // Make sure the request isn't for more than we can handle
    if (count > this.tokenBucket.bucketSize)
      return false;

    var now = Date.now();

    // Advance the current interval and reset the current interval token count
    // if needed
    if (now - this.curIntervalStart >= this.tokenBucket.interval) {
      this.curIntervalStart = now;
      this.tokensThisInterval = 0;
    }

    // If we don't have enough tokens left in this interval, return false
    if (count > this.tokenBucket.tokensPerInterval - this.tokensThisInterval)
      return false;

    // Try to remove the requested number of tokens from the token bucket
    var removed = this.tokenBucket.tryRemoveTokens(count);
    if (removed) {
      this.tokensThisInterval += count;
    }
    return removed;
  },

  /**
   * Returns the number of tokens remaining in the TokenBucket.
   * @returns {Number} The number of tokens remaining.
   */
  getTokensRemaining: function () {
    this.tokenBucket.drip();
    return this.tokenBucket.content;
  }
};

module.exports = RateLimiter;
<|endoftext|>


<commit_before>// *********************************
// Libraries
// *********************************

var U               = require('util');
var Net             = require('net');
var Events          = require("events");
var Base            = require('./base');
var C               = require('./common');

// ****************************************
// Remote send object
// ****************************************

var _RemoteSend = function() {
    var rs = (function() {
        var obj = Base.BaseObject();

        obj.state_changed   = C._now();
        obj.state_changes   = 0;
        obj.last_sent       = false;
        obj.messages        = 0;
        obj.is_available    = false;

        // needs to be filled in by parent
        //obj.name           = false;
        //obj.send           = false;
        //obj.connection     = false;
        //obj.is_stream      = false;

        obj.mark_available = function () {
            C._trace( "HEALTHY: " + this.name );

            // mark the server as available
            this.is_available    = true;
            this.state_changed   = C._now();
            this.state_changes++;
        };

        obj.mark_unavailable   = function () {
            C._trace( "UNHEALTHY: " + this.name );

            // mark the server as no longer available
            this.is_available    = false;
            this.state_changed   = C._now();
            this.state_changes++;
        };

        obj.incr_stats = function () {
            this.last_sent = C._now();
            this.messages++;
        };

        obj.stats = function () {
            return {
                available:      this.is_available,
                last_sent:      this.last_sent,
                messages:       this.messages,
                state_changes:  this.state_changes,
                state_changed:  (_now() - this.state_changed),
                // If nothing was ever sent, the idle time == uptime
                idle:           (this.last_sent ? (_now() - this.last_sent) : Stats.uptime),
            };
        };

        return obj;
    })();
    return Base.create( rs );
}
// make sure we can emit events
U.inherits( _RemoteSend, Events.EventEmitter );

// TCP & Socket
var RemoteStreamSend = exports.RemoteStreamSend = function(name, host, port, reconnect) {
    var rs = (function() {
        var obj = new _RemoteSend();

        C._trace( obj.state_changed );

        var cfg = obj.config_object().config;

        // set to true, meaning we can use piping
        obj.is_stream       = true;
        obj.name            = name;

        // host might just be a unix socket, it works transparently
        obj.connection = Net.createConnection( port, host );

        // Ideally, we're being piped to. But if not, here's our
        // manual way of sending data
        obj.send = function( data ) { this.connection.write( data ); }.bind(obj);

        // we connected? -- this won't get triggered for UDP, so we
        // set it explicitly in the TCP/socket connection code
        obj.connection.on( 'connect', function( listener ) {
            U.log( U.format( "Connected to %s", obj.name ) );

            // server is now ready for use
            obj.mark_available.bind(obj)();
        });

        // Some error happened?
        obj.connection.on( 'error', function (e) {

            // this can get very chatty, so hide it behind trace
            // always show initial connect though
            if( config.trace || !reconnect) {
                U.error( U.format( "ERROR: %s: %s", obj.name, e ) );
            }
        });

        return obj;
    })();
    return Base.create( rs );
};
<commit_msg>* use C. now that its in common.js<commit_after>// *********************************
// Libraries
// *********************************

var U               = require('util');
var Net             = require('net');
var Events          = require("events");
var Base            = require('./base');
var C               = require('./common');

// ****************************************
// Remote send object
// ****************************************

var _RemoteSend = function() {
    var rs = (function() {
        var obj = Base.BaseObject();

        obj.state_changed   = C._now();
        obj.state_changes   = 0;
        obj.last_sent       = false;
        obj.messages        = 0;
        obj.is_available    = false;

        // needs to be filled in by parent
        //obj.name           = false;
        //obj.send           = false;
        //obj.connection     = false;
        //obj.is_stream      = false;

        obj.mark_available = function () {
            C._trace( "HEALTHY: " + this.name );

            // mark the server as available
            this.is_available    = true;
            this.state_changed   = C._now();
            this.state_changes++;
        };

        obj.mark_unavailable   = function () {
            C._trace( "UNHEALTHY: " + this.name );

            // mark the server as no longer available
            this.is_available    = false;
            this.state_changed   = C._now();
            this.state_changes++;
        };

        obj.incr_stats = function () {
            this.last_sent = C._now();
            this.messages++;
        };

        obj.stats = function () {
            return {
                available:      this.is_available,
                last_sent:      this.last_sent,
                messages:       this.messages,
                state_changes:  this.state_changes,
                state_changed:  (C._now() - this.state_changed),
                // If nothing was ever sent, the idle time == uptime
                idle:           (this.last_sent ? (C._now() - this.last_sent) : Stats.uptime),
            };
        };

        return obj;
    })();
    return Base.create( rs );
}
// make sure we can emit events
U.inherits( _RemoteSend, Events.EventEmitter );

// TCP & Socket
var RemoteStreamSend = exports.RemoteStreamSend = function(name, host, port, reconnect) {
    var rs = (function() {
        var obj = new _RemoteSend();

        var cfg = obj.config_object().config;

        // set to true, meaning we can use piping
        obj.is_stream       = true;
        obj.name            = name;

        // host might just be a unix socket, it works transparently
        obj.connection = Net.createConnection( port, host );

        // Ideally, we're being piped to. But if not, here's our
        // manual way of sending data
        obj.send = function( data ) { this.connection.write( data ); }.bind(obj);

        // we connected? -- this won't get triggered for UDP, so we
        // set it explicitly in the TCP/socket connection code
        obj.connection.on( 'connect', function( listener ) {
            U.log( U.format( "Connected to %s", obj.name ) );

            // server is now ready for use
            obj.mark_available.bind(obj)();
        });

        // Some error happened?
        obj.connection.on( 'error', function (e) {

            // this can get very chatty, so hide it behind trace
            // always show initial connect though
            if( config.trace || !reconnect) {
                U.error( U.format( "ERROR: %s: %s", obj.name, e ) );
            }
        });

        return obj;
    })();
    return Base.create( rs );
};
<|endoftext|>


<commit_before>'use strict'
// needs perf optmization
exports.define = {
  resubscribe (stamp) {
    const emitters = this.emitters
    if (
      this.hasOwnProperty('_emitters') &&
      (
        emitters.hasOwnProperty('subscription') ||
        emitters.hasOwnProperty('_subscription')
      )
    ) {
      const subs = emitters.subscription
      const fn = subs.hasOwnProperty('fn') && subs.fn
      const attach = subs.hasOwnProperty('attach') && subs.attach
      if (fn) {
        fn.each((prop, key) => {
          if (fn.hasOwnProperty(key)) {
            walkTree(prop.tree)
          }
        })
      }
      if (attach) {
        attach.each((prop, key) => {
          if (attach.hasOwnProperty(key)) {
            prop = prop[0]
            walkTree(prop.tree)
          }
        })
      }
      this.emit('subscription', void 0, stamp)
    }
  }
}

function walkTree (tree) {
  for (let key in tree) {
    if (key === '$') {
      delete tree[key]
    } else if (typeof tree[key] === 'object') {
      if (key[0] !== '_') {
        walkTree(tree[key])
      }
    }
  }
}

<commit_msg>ignore base on tree<commit_after>'use strict'
// needs perf optmization
exports.define = {
  resubscribe (stamp) {
    const emitters = this.emitters
    if (
      this.hasOwnProperty('_emitters') &&
      (
        emitters.hasOwnProperty('subscription') ||
        emitters.hasOwnProperty('_subscription')
      )
    ) {
      const subs = emitters.subscription
      const fn = subs.hasOwnProperty('fn') && subs.fn
      const attach = subs.hasOwnProperty('attach') && subs.attach
      if (fn) {
        fn.each((prop, key) => {
          if (fn.hasOwnProperty(key)) {
            walkTree(prop.tree)
          }
        })
      }
      if (attach) {
        attach.each((prop, key) => {
          if (attach.hasOwnProperty(key)) {
            prop = prop[0]
            walkTree(prop.tree)
          }
        })
      }
      this.emit('subscription', void 0, stamp)
    }
  }
}

function walkTree (tree) {
  for (let key in tree) {
    if (key === '$') {
      delete tree[key]
    } else if (typeof tree[key] === 'object') {
      if (key[0] !== '_') {
        if (!tree[key].isBase) {
          walkTree(tree[key])
        }
      }
    }
  }
}

<|endoftext|>


<commit_before>/*jshint unused:false*/
var slug = require('slug');
var uuid = require('uuid');
var moment = require('moment');
var request = require('request');

var async = require('async');

var config = require('../../config.json');
var talks = require('libtlks').talk;

/**
 * Route /search
 * @param req   HTTP Request object
 * @param req   HTTP Response object
 */
exports.search = function(req, res, next) {
    'use strict';

    var q = req.query.q;
    var user = req.session.user;
    var context = {
        title: 'Tech talks by \'' + q + '\'' + ' | tlks.io',
        description: 'Tech talks by \'' + q + '\'' + ' | tlks.io',
        user: user,
        q: q,
        talks: []
    };
    var url = config.elasticsearch + '/tlksio/talk/_search?q=' + q;
    request.get({
        url: url,
        method: 'GET',
        json: true
    }, function(err, response, body) {
        if (err) {
            return next(err);
        }
        var hits = body.hits.hits;
        async.map(hits, function(el, callback) {
            var obj = el._source;
            obj.tags = obj.tags.split(',').map(function(el) {
                return el.trim();
            });
            talks.getBySlug(config.mongodb, obj.slug, function(err, talks) {
                if (err) {
                    return next(err);
                }
                callback(null, talks[0]);
            });
        }, function(err, results) {
            if (err) {
                return next(err);
            }
            context.talks = results;
            res.render('search', context);
        });
    });
};

/**
 * Route /talk/play/:id
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.play = function(req, res) {
    'use strict';

    var slug = req.params.slug;
    talks.play(config.mongodb, slug, function(err, talk) {
        if (err) {
            return next(err);
        }
        var url = 'https://www.youtube.com/watch?v=' + talk.code;
        res.redirect(url);
    });
};

/**
 * Route /talk/upvote/:id
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.upvote = function(req, res, next) {
    'use strict';

    var id = req.params.id;
    var user = req.session.user;
    if (user === undefined) {
        var err = {
            status: 401,
            message: 'Unauthorized'
        };
        return next(err);
    } else {
        var userid = user.id;
        talks.upvote(config.mongodb, id, userid, function(err, updated) {
            if (err) {
                return next(err);
            }
            var result = {
                'result': updated ? true : false
            };
            res.send(result);
        });
    }
};

/**
 * Route /talk/favorite/:id
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.favorite = function(req, res, next) {
    'use strict';

    var id = req.params.id;
    var user = req.session.user;
    if (user === undefined) {
        var err = {
            status: 401,
            message: 'Unauthorized'
        };
        return next(err);
    } else {
        var userid = user.id;
        talks.favorite(config.mongodb, id, userid, function(err, updated) {
            if (err) {
                return next(err);
            }
            var result = {
                'result': updated ? true : false
            };
            res.send(result);
        });
    }
};

/**
 * Route /talk/unfavorite/:id
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.unfavorite = function(req, res, next) {
    'use strict';

    var id = req.params.id;
    var user = req.session.user;
    if (user === undefined) {
        var err = {
            status: 401,
            message: 'Unauthorized'
        };
        return next(err);
    } else {
        var userid = user.id;
        talks.unfavorite(config.mongodb, id, userid, function(err, updated) {
            if (err) {
                return next(err);
            }
            var result = {
                'result': updated ? true : false
            };
            res.send(result);
        });
    }
};

/**
 * Route /talk/:slug
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.talk = function(req, res) {
    'use strict';

    var slug = req.params.slug;
    var user = req.session.user;
    var context = {
        user: user,
        moment: moment
    };
    talks.getBySlug(config.mongodb, slug, function(err, docs) {
        var talk = docs[0];
        if (err) {
            return next(err);
        }
        if (talk) {
            context.talk = talk;
            context.title = talk.title + ' | tlks.io';
            context.description = talk.description.substring(0, 200);
            talks.related(
                config.mongodb,
                talk.id,
                talk.tags,
                5,
                function(err, docs) {
                    if (err) {
                        return next(err);
                    }
                    context.related = docs;
                    res.render('talk', context);
                });
        } else {
            res.status(404).render('404', context);
        }
    });
};

/**
 * Route /add
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.add = function(req, res) {
    'use strict';

    var user = req.session.user;
    if (user === undefined) {
        res.status(401).send('401').end();
    } else {
        var context = {
            title: 'tlks.io : Add a new talk',
            user: user
        };
        res.render('add', context);
    }
};

/**
 * Route /save
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.save = function(req, res, next) {
    'use strict';

    // user
    var user = req.session.user;
    if (user === undefined) {
        var err = {
            status: 401,
            message: 'Unauthorized'
        };
        return next(err);
    } else {

        code = processCode(req.body.code)

        var talk = {
            id: uuid.v1(),
            code: req.body.code,
            title: req.body.title,
            slug: slug(req.body.title).toLowerCase(),
            description: req.body.description,
            author: {
                id: user.id,
                username: user.username,
                avatar: user.avatar
            },
            'viewCount': 0,
            'voteCount': 0,
            'votes': [],
            'favoriteCount': 0,
            'favorites': [],
            'tags': req.body.tags.split(',').map(function(el) {
                return el.trim().toLowerCase();
            }),
            'created': Date.now(),
            'updated': Date.now()
        };
        // create talk
        talks.createTalk(config.mongodb, talk, function(err, talk) {
            if (err) {
                return next(err);
            }
            // render
            res.redirect('/');
        });
    }
};

function processCode(code) {

    if (code.match("youtube.com")) {
        parts = code.split("=");
        code = parts[1];
    }

    return code;
}

// talk
/**
 * Route /popular
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.popular = function(req, res) {
    'use strict';

    var quantity = 25;
    var page = parseInt(req.params.page || 1);
    var pagination = {
        page: page,
        next: page + 1,
        prev: (page - 1 <= 1) ? 1 : page - 1
    };
    var user = req.session.user;
    var context = {
        title: 'tlks.io : Popular talks',
        user: user,
        page: page,
        pagination: pagination
    };
    talks.popular(config.mongodb, quantity, page, function(err, talks) {
        if (err) {
            return next(err);
        }
        if (talks.length === 0) {
            res.status(204).end();
            return;
        }
        context.latest = talks;
        res.render('popular', context);
    });
};

/**
 * Route /latest
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.latest = function(req, res) {
    'use strict';

    var quantity = 25;
    var page = parseInt(req.params.page || 1);
    var pagination = {
        page: page,
        next: page + 1,
        prev: (page - 1 <= 1) ? 1 : page - 1
    };
    var user = req.session.user;
    var context = {
        title: 'tlks.io : Latest talks',
        user: user,
        page: page,
        pagination: pagination
    };
    talks.latest(config.mongodb, quantity, page, function(err, talks) {
        if (err) {
            return next(err);
        }
        if (talks.length === 0) {
            res.status(204).end();
            return;
        }
        context.latest = talks;
        res.render('latest', context);
    });

};
<commit_msg>Getting the code from a url of youtube<commit_after>/*jshint unused:false*/
var slug = require('slug');
var uuid = require('uuid');
var moment = require('moment');
var request = require('request');

var async = require('async');

var config = require('../../config.json');
var talks = require('libtlks').talk;

/**
 * Route /search
 * @param req   HTTP Request object
 * @param req   HTTP Response object
 */
exports.search = function(req, res, next) {
    'use strict';

    var q = req.query.q;
    var user = req.session.user;
    var context = {
        title: 'Tech talks by \'' + q + '\'' + ' | tlks.io',
        description: 'Tech talks by \'' + q + '\'' + ' | tlks.io',
        user: user,
        q: q,
        talks: []
    };
    var url = config.elasticsearch + '/tlksio/talk/_search?q=' + q;
    request.get({
        url: url,
        method: 'GET',
        json: true
    }, function(err, response, body) {
        if (err) {
            return next(err);
        }
        var hits = body.hits.hits;
        async.map(hits, function(el, callback) {
            var obj = el._source;
            obj.tags = obj.tags.split(',').map(function(el) {
                return el.trim();
            });
            talks.getBySlug(config.mongodb, obj.slug, function(err, talks) {
                if (err) {
                    return next(err);
                }
                callback(null, talks[0]);
            });
        }, function(err, results) {
            if (err) {
                return next(err);
            }
            context.talks = results;
            res.render('search', context);
        });
    });
};

/**
 * Route /talk/play/:id
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.play = function(req, res) {
    'use strict';

    var slug = req.params.slug;
    talks.play(config.mongodb, slug, function(err, talk) {
        if (err) {
            return next(err);
        }
        var url = 'https://www.youtube.com/watch?v=' + talk.code;
        res.redirect(url);
    });
};

/**
 * Route /talk/upvote/:id
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.upvote = function(req, res, next) {
    'use strict';

    var id = req.params.id;
    var user = req.session.user;
    if (user === undefined) {
        var err = {
            status: 401,
            message: 'Unauthorized'
        };
        return next(err);
    } else {
        var userid = user.id;
        talks.upvote(config.mongodb, id, userid, function(err, updated) {
            if (err) {
                return next(err);
            }
            var result = {
                'result': updated ? true : false
            };
            res.send(result);
        });
    }
};

/**
 * Route /talk/favorite/:id
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.favorite = function(req, res, next) {
    'use strict';

    var id = req.params.id;
    var user = req.session.user;
    if (user === undefined) {
        var err = {
            status: 401,
            message: 'Unauthorized'
        };
        return next(err);
    } else {
        var userid = user.id;
        talks.favorite(config.mongodb, id, userid, function(err, updated) {
            if (err) {
                return next(err);
            }
            var result = {
                'result': updated ? true : false
            };
            res.send(result);
        });
    }
};

/**
 * Route /talk/unfavorite/:id
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.unfavorite = function(req, res, next) {
    'use strict';

    var id = req.params.id;
    var user = req.session.user;
    if (user === undefined) {
        var err = {
            status: 401,
            message: 'Unauthorized'
        };
        return next(err);
    } else {
        var userid = user.id;
        talks.unfavorite(config.mongodb, id, userid, function(err, updated) {
            if (err) {
                return next(err);
            }
            var result = {
                'result': updated ? true : false
            };
            res.send(result);
        });
    }
};

/**
 * Route /talk/:slug
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.talk = function(req, res) {
    'use strict';

    var slug = req.params.slug;
    var user = req.session.user;
    var context = {
        user: user,
        moment: moment
    };
    talks.getBySlug(config.mongodb, slug, function(err, docs) {
        var talk = docs[0];
        if (err) {
            return next(err);
        }
        if (talk) {
            context.talk = talk;
            context.title = talk.title + ' | tlks.io';
            context.description = talk.description.substring(0, 200);
            talks.related(
                config.mongodb,
                talk.id,
                talk.tags,
                5,
                function(err, docs) {
                    if (err) {
                        return next(err);
                    }
                    context.related = docs;
                    res.render('talk', context);
                });
        } else {
            res.status(404).render('404', context);
        }
    });
};

/**
 * Route /add
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.add = function(req, res) {
    'use strict';

    var user = req.session.user;
    if (user === undefined) {
        res.status(401).send('401').end();
    } else {
        var context = {
            title: 'tlks.io : Add a new talk',
            user: user
        };
        res.render('add', context);
    }
};

/**
 * Route /save
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.save = function(req, res, next) {
    'use strict';

    // user
    var user = req.session.user;
    if (user === undefined) {
        var err = {
            status: 401,
            message: 'Unauthorized'
        };
        return next(err);
    } else {

        var code = processCode(req.body.code)

        var talk = {
            id: uuid.v1(),
            code: code,
            title: req.body.title,
            slug: slug(req.body.title).toLowerCase(),
            description: req.body.description,
            author: {
                id: user.id,
                username: user.username,
                avatar: user.avatar
            },
            'viewCount': 0,
            'voteCount': 0,
            'votes': [],
            'favoriteCount': 0,
            'favorites': [],
            'tags': req.body.tags.split(',').map(function(el) {
                return el.trim().toLowerCase();
            }),
            'created': Date.now(),
            'updated': Date.now()
        };
        // create talk
        talks.createTalk(config.mongodb, talk, function(err, talk) {
            if (err) {
                return next(err);
            }
            // render
            res.redirect('/');
        });
    }
};

function processCode(code) {

    if (code.match("youtube.com")) {
        parts = code.split("=");
        code = parts[1];
    }

    return code;
}

// talk
/**
 * Route /popular
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.popular = function(req, res) {
    'use strict';

    var quantity = 25;
    var page = parseInt(req.params.page || 1);
    var pagination = {
        page: page,
        next: page + 1,
        prev: (page - 1 <= 1) ? 1 : page - 1
    };
    var user = req.session.user;
    var context = {
        title: 'tlks.io : Popular talks',
        user: user,
        page: page,
        pagination: pagination
    };
    talks.popular(config.mongodb, quantity, page, function(err, talks) {
        if (err) {
            return next(err);
        }
        if (talks.length === 0) {
            res.status(204).end();
            return;
        }
        context.latest = talks;
        res.render('popular', context);
    });
};

/**
 * Route /latest
 * @param req   HTTP Request object
 * @param res   HTTP Response object
 */
exports.latest = function(req, res) {
    'use strict';

    var quantity = 25;
    var page = parseInt(req.params.page || 1);
    var pagination = {
        page: page,
        next: page + 1,
        prev: (page - 1 <= 1) ? 1 : page - 1
    };
    var user = req.session.user;
    var context = {
        title: 'tlks.io : Latest talks',
        user: user,
        page: page,
        pagination: pagination
    };
    talks.latest(config.mongodb, quantity, page, function(err, talks) {
        if (err) {
            return next(err);
        }
        if (talks.length === 0) {
            res.status(204).end();
            return;
        }
        context.latest = talks;
        res.render('latest', context);
    });

};
<|endoftext|>


<commit_before>var util = require('../../util');
var rulesUtil = require('./util');
var url = require('url');
var net = require('net');
var dns = require('dns');
var extend = require('util')._extend;

var rules, hosts, heads, req, res, proxy, weinre;
rules = hosts = heads = req = res = proxy = weinre = [];

function parse(text) {
	rules = [];
	hosts = [];
	heads = [];
	req = [];
	res = [];
	weinre = [];
	proxy = [];
	if (!text || !(text = text.trim())) {
		return;
	}

	text.split(/\n|\r\n|\r/g).forEach(pareLine);
}

function pareLine(line) {
	var raw = line;
	line = line.replace(/#.*$/, '').trim();
	if (!line) {
		return;
	}

	line = line.split(/\s+/);
	var pattern = line[0];
	if (net.isIP(pattern) || (util.hasProtocol(pattern) && !/^https?:\/\//.test(pattern))) {
		line.slice(1).forEach(function(matcher) {
			parseRule(matcher, pattern, raw);
		});
	} else if (!util.isRegExp(pattern) && util.isRegExp(line[1])) {
		parseRule(line[1], pattern, raw);
	} else {
		parseRule(pattern, line[1], raw);
	}
}

function parseRule(pattern, matcher, raw) {
	var isRegExp;
	if (!pattern || !matcher ||
			((isRegExp = util.isRegExp(pattern)) && !(pattern = util.toRegExp(pattern)))) {
		return;
	}

	var rule = {
			isRegExp: isRegExp,
			protocol: isRegExp ? null : util.getProtocol(pattern),
			pattern: isRegExp ? pattern : formatUrl(pattern),
			matcher: matcher,
			raw: raw,
			rawPattern: pattern
		};

	if (net.isIP(matcher)) {
		hosts.push(rule);
	} else if (/^head:\/\//.test(matcher)) {
		heads.push(rule);
	} else if (/^req:\/\//.test(matcher)) {
		req.push(rule);
	} else if (/^res:\/\//.test(matcher)) {
		res.push(rule);
	} else if (/^proxy:\/\//.test(matcher)) {
		proxy.push(rule);
	} else if (/^weinre:\/\//.test(matcher)) {
		weinre.push(rule);
	} else {
		rules.push(rule);
	}
}

exports.parse = parse;

function resolveHost(_url, callback) {
	_url = formatUrl(util.setProtocol(_url));
	var options = url.parse(_url);
	if (!util.isWebProtocol(options.protocol)) {

		return callback(null, null);
	}

	var host = getRule(_url, hosts);
	//兼容传统host配置
	if (!host && (host = getRule(_url.replace(/^(https?:\/\/[^\/]+):\d+(\/.*)/i, '$1$2'), hosts))
			&& /[\/]/.test(host.rawPattern)) {
		host = null;
	}

	if (host) {
		return callback(null, host.matcher);
	}

	try {
		dns.lookup(options.hostname, function(err, ip, addressType) {
		      callback(err, err ? null : (ip || (!addressType || addressType === 4 ? '127.0.0.1' : '0:0:0:0:0:0:0:1')));
		  });
	} catch(err) {//如果断网，可能直接抛异常，https代理没有用到error-handler
		callback(err);
	}
}

function formatUrl(pattern) {

	return pattern.indexOf('/', util.getProtocol(pattern) == null ? 0 : pattern.indexOf('://') + 3) == -1 ?
			pattern + '/' : pattern;
}

exports.resolveHost = resolveHost;

function getRule(url, rules) {
	rules = _getRule(url, rules);

	if (rules) {
		url = rules.url;
		var index = url.indexOf('://') + 3;
		var protocol = url.substring(0, index);
		url = url.substring(index);
		var key = getKey(url);
		if (key) {
			rules.key = key;
		}
		var value = key && rulesUtil.getValue(key);
		if (value == null) {
			value = false;
		}
		if (value !== false || (value = getValue(url)) !== false) {
			rules.value = protocol + value;
		} else if ((value = getPath(url)) !== false) {
			rules.path = protocol + value;
		}
	}

	return rules;
}

function getKey(url) {
	if (url.indexOf('{') == 0) {
		var index = url.lastIndexOf('}');
		return index > 1 && url.substring(1, index);
	}

	return false;
}

function getValue(url) {
	if (url.indexOf('(') == 0) {
		var index = url.lastIndexOf(')');
		return index != -1 && url.substring(1, index) || '';
	}

	return false;
}

function getPath(url) {
	if (url.indexOf('<') == 0) {
		var index = url.lastIndexOf('>');
		return index != -1 && url.substring(1, index) || '';
	}

	return false;
}

function _getRule(url, _rules) {
	_rules = _rules || rules;
	if (util.removeProtocol(url, true).indexOf('/') == -1) {
		url += '/';
	}
	var _url = url.replace(/(?:\?|#).*$/, '');
	for (var i = 0, rule; rule = _rules[i]; i++) {
		var pattern = rule.pattern;
		if (rule.isRegExp) {
			if (pattern.test(url)) {
				var regExp = {};
				for (var i = 0; i < 10; i++) {
					regExp['$' + i] = RegExp['$' + i] || '';
				}

				return extend({
					url: setProtocol(rule.matcher.replace(/(^|.)?(\$[1-9])/g,
							function(matched, $1, $2) {
						return $1 == '\\' ? $2 : ($1 || '') + regExp[$2];
					}), url)
				}, rule);;
			}
		} else {
			pattern = setProtocol(pattern, url);
			if (_url.indexOf(pattern) === 0) {
				var len = pattern.length;
				if (pattern == _url || isPathSeparator(_url[len]) || isPathSeparator(pattern[len - 1])) {
					return extend({
						url: join(setProtocol(rule.matcher, url), url.substring(len))
					}, rule);
				}
			}
		}
	}
}

function setProtocol(target, source) {
	if (util.hasProtocol(target)) {
		return target;
	}

	var protocol = util.getProtocol(source);
	if (protocol == null) {
		return target;
	}

	return protocol + '//' + target;
}

function resolveRule(url) {
	return getRule(url);
}

function resolveHead(url) {
	return getRule(url, heads);
}

function resolveReq(url) {
	return getRule(url, req);
}

function resolveRes(url) {
	return getRule(url, res);
}

function resolveProxy(url) {
	return getRule(url, proxy);
}

function resolveWeinre(url) {
	return getRule(url, weinre);
}

function isPathSeparator(ch) {
	return ch == '/' || ch == '\\';
}

function join(first, last) {
	if (!first || !last) {
		return first + last;
	}

	var len = first.length - 1;
	if (isPathSeparator(first[len])) {
		return isPathSeparator(last[0]) ? first.substring(0, len) + last : first + last;
	}

	return isPathSeparator(last[0]) ? first + last : first + '/' + last;
}

exports.resolveRules = function resolveRules(url) {
	var rules = {};
	var rule = resolveRule(url);
	if (rule) {
		rules.rule = rule;
	}
	if (rule = resolveHead(url)) {
		rules.head = rule;
	}
	if (rule = resolveReq(url)) {
		rules.req = rule;
	}
	if (rule = resolveRes(url)) {
		rules.res = rule;
	}
	if (rule = resolveProxy(url)) {
		rules.proxy = rule;
	}
	if (rule = resolveWeinre(url)) {
		rules.weinre = rule;
	}

	return rules;
};
<commit_msg>change hosts rule<commit_after>var util = require('../../util');
var rulesUtil = require('./util');
var url = require('url');
var net = require('net');
var dns = require('dns');
var extend = require('util')._extend;

var rules, hosts, heads, req, res, proxy, weinre;
rules = hosts = heads = req = res = proxy = weinre = [];

function parse(text) {
	rules = [];
	hosts = [];
	heads = [];
	req = [];
	res = [];
	weinre = [];
	proxy = [];
	if (!text || !(text = text.trim())) {
		return;
	}

	text.split(/\n|\r\n|\r/g).forEach(pareLine);
}

function pareLine(line) {
	var raw = line;
	line = line.replace(/#.*$/, '').trim();
	if (!line) {
		return;
	}

	line = line.split(/\s+/);
	var pattern = line[0];
	if (net.isIP(pattern) || (util.hasProtocol(pattern) && !/^https?:\/\//.test(pattern))) {
		line.slice(1).forEach(function(matcher) {
			parseRule(matcher, pattern, raw);
		});
	} else if (!util.isRegExp(pattern) && util.isRegExp(line[1])) {
		parseRule(line[1], pattern, raw);
	} else {
		parseRule(pattern, line[1], raw);
	}
}

function parseRule(pattern, matcher, raw) {
	var isRegExp;
	if (!pattern || !matcher ||
			((isRegExp = util.isRegExp(pattern)) && !(pattern = util.toRegExp(pattern)))) {
		return;
	}

	var rule = {
			isRegExp: isRegExp,
			protocol: isRegExp ? null : util.getProtocol(pattern),
			pattern: isRegExp ? pattern : formatUrl(pattern),
			matcher: matcher,
			raw: raw,
			rawPattern: pattern
		};

	if (net.isIP(matcher)) {
		hosts.push(rule);
	} else if (/^head:\/\//.test(matcher)) {
		heads.push(rule);
	} else if (/^req:\/\//.test(matcher)) {
		req.push(rule);
	} else if (/^res:\/\//.test(matcher)) {
		res.push(rule);
	} else if (/^proxy:\/\//.test(matcher)) {
		proxy.push(rule);
	} else if (/^weinre:\/\//.test(matcher)) {
		weinre.push(rule);
	} else {
		rules.push(rule);
	}
}

exports.parse = parse;

function resolveHost(_url, callback) {
	_url = formatUrl(util.setProtocol(_url));
	var options = url.parse(_url);
	if (!util.isWebProtocol(options.protocol)) {

		return callback(null, null);
	}

	var host = getRule(_url, hosts);
	if (host) {
		return callback(null, host.matcher);
	}

	try {
		dns.lookup(options.hostname, function(err, ip, addressType) {
		      callback(err, err ? null : (ip || (!addressType || addressType === 4 ? '127.0.0.1' : '0:0:0:0:0:0:0:1')));
		  });
	} catch(err) {//如果断网，可能直接抛异常，https代理没有用到error-handler
		callback(err);
	}
}

function formatUrl(pattern) {

	return pattern.indexOf('/', util.getProtocol(pattern) == null ? 0 : pattern.indexOf('://') + 3) == -1 ?
			pattern + '/' : pattern;
}

exports.resolveHost = resolveHost;

function getRule(url, _rules) {
	var rules = _getRule(url, _rules);
	//支持域名匹配
	if (!rules && (rules = _getRule(url.replace(/^(https?:\/\/[^\/]+):\d+(\/.*)/i, '$1$2'), _rules))
			&& util.removeProtocol(rules.rawPattern, true).indexOf('/') != -1) {
		rules = null;
	}
	if (rules) {
		url = rules.url;
		var index = url.indexOf('://') + 3;
		var protocol = url.substring(0, index);
		url = url.substring(index);
		var key = getKey(url);
		if (key) {
			rules.key = key;
		}
		var value = key && rulesUtil.getValue(key);
		if (value == null) {
			value = false;
		}
		if (value !== false || (value = getValue(url)) !== false) {
			rules.value = protocol + value;
		} else if ((value = getPath(url)) !== false) {
			rules.path = protocol + value;
		}
	}

	return rules;
}

function getKey(url) {
	if (url.indexOf('{') == 0) {
		var index = url.lastIndexOf('}');
		return index > 1 && url.substring(1, index);
	}

	return false;
}

function getValue(url) {
	if (url.indexOf('(') == 0) {
		var index = url.lastIndexOf(')');
		return index != -1 && url.substring(1, index) || '';
	}

	return false;
}

function getPath(url) {
	if (url.indexOf('<') == 0) {
		var index = url.lastIndexOf('>');
		return index != -1 && url.substring(1, index) || '';
	}

	return false;
}

function _getRule(url, _rules) {
	_rules = _rules || rules;
	if (util.removeProtocol(url, true).indexOf('/') == -1) {
		url += '/';
	}
	var _url = url.replace(/(?:\?|#).*$/, '');
	for (var i = 0, rule; rule = _rules[i]; i++) {
		var pattern = rule.pattern;
		if (rule.isRegExp) {
			if (pattern.test(url)) {
				var regExp = {};
				for (var i = 0; i < 10; i++) {
					regExp['$' + i] = RegExp['$' + i] || '';
				}

				return extend({
					url: setProtocol(rule.matcher.replace(/(^|.)?(\$[1-9])/g,
							function(matched, $1, $2) {
						return $1 == '\\' ? $2 : ($1 || '') + regExp[$2];
					}), url)
				}, rule);;
			}
		} else {
			pattern = setProtocol(pattern, url);
			if (_url.indexOf(pattern) === 0) {
				var len = pattern.length;
				if (pattern == _url || isPathSeparator(_url[len]) || isPathSeparator(pattern[len - 1])) {
					return extend({
						url: join(setProtocol(rule.matcher, url), url.substring(len))
					}, rule);
				}
			}
		}
	}
}

function setProtocol(target, source) {
	if (util.hasProtocol(target)) {
		return target;
	}

	var protocol = util.getProtocol(source);
	if (protocol == null) {
		return target;
	}

	return protocol + '//' + target;
}

function resolveRule(url) {
	return getRule(url);
}

function resolveHead(url) {
	return getRule(url, heads);
}

function resolveReq(url) {
	return getRule(url, req);
}

function resolveRes(url) {
	return getRule(url, res);
}

function resolveProxy(url) {
	return getRule(url, proxy);
}

function resolveWeinre(url) {
	return getRule(url, weinre);
}

function isPathSeparator(ch) {
	return ch == '/' || ch == '\\';
}

function join(first, last) {
	if (!first || !last) {
		return first + last;
	}

	var len = first.length - 1;
	if (isPathSeparator(first[len])) {
		return isPathSeparator(last[0]) ? first.substring(0, len) + last : first + last;
	}

	return isPathSeparator(last[0]) ? first + last : first + '/' + last;
}

exports.resolveRules = function resolveRules(url) {
	var rules = {};
	var rule = resolveRule(url);
	if (rule) {
		rules.rule = rule;
	}
	if (rule = resolveHead(url)) {
		rules.head = rule;
	}
	if (rule = resolveReq(url)) {
		rules.req = rule;
	}
	if (rule = resolveRes(url)) {
		rules.res = rule;
	}
	if (rule = resolveProxy(url)) {
		rules.proxy = rule;
	}
	if (rule = resolveWeinre(url)) {
		rules.weinre = rule;
	}

	return rules;
};
<|endoftext|>


<commit_before>function ScoreBoard(list){
  this.list = list;
  this.scores = [];
}

ScoreBoard.prototype.loadStoredScores = function(){
  this.scores = localStorage.getItem('scores').split(",");
  var list = this.list;
  this.scores.forEach( function(score){
    var scoreItem = document.createElement('li');
    scoreItem.innerText = score;
    list.appendChild(scoreItem);
  });
};

ScoreBoard.prototype.addHighScoreToPage = function(score){
  var scoreItem = document.createElement('li');
  scoreItem.innerText = score;
  this.appendChild(scoreItem);
  this.scores.push(score);
  localStorage.setItem("scores", this.scores);
};

module.exports = ScoreBoard;
<commit_msg>append scores in dscending order<commit_after>function ScoreBoard(list){
  this.list = list;
  this.scores = [];
}

ScoreBoard.prototype.loadStoredScores = function(){
  this.scores = localStorage.getItem('scores').split(",");
  var list = this.list;
  var descendingScores = this.scores.reverse();
  descendingScores.forEach( function(score){
    var scoreItem = document.createElement('li');
    scoreItem.innerText = score;
    list.appendChild(scoreItem);
  });
};

ScoreBoard.prototype.addHighScoreToPage = function(score){
  var scoreItem = document.createElement('li');
  scoreItem.innerText = score;
  this.appendChild(scoreItem);
  this.scores.push(score);
  localStorage.setItem("scores", this.scores);
};

module.exports = ScoreBoard;
<|endoftext|>


<commit_before>var MochaTestRunner = require('./mocha-test-runner'),
	FileRepository = require('./FileRepository'),
	path = require('path'),
	SourceFile = require('./source-file');

var Sentinaught = function(sentinaughtDisplay){
	var moreThanOneTestFileSpecification = new MoreThanOneTestFileSpecification(),
		noSourceFilesSpecification = new NoSourceFilesSpecification(),
		testRunnerMonitor = new TestRunnerMonitor(sentinaughtDisplay);

	this.run = function(options){
		if(!options.tests){
			throw new Error("No Tests Specified");
		}
		var getFileOptions = {recursive: options.recursive, name: "*.js"},
			fileRepository = new FileRepository(getFileOptions),
			files = {
				tests : fileRepository.get(options.tests),
				src : fileRepository.get(options.src)
			};

		if (moreThanOneTestFileSpecification.isSatisifiedBy(files.tests)){
			runMutation(files);
		}
		else{
			if (noSourceFilesSpecification.isSatisifiedBy(files)){
				sentinaughtDisplay.passed();
			}
			else {
				sentinaughtDisplay.failed();
			}
		}
	};

	function runMutation(files){
		var fileToMutate = files.src[0],
			fileToMutatePath = path.resolve(fileToMutate);
		require(fileToMutatePath);
		require.cache[fileToMutatePath].exports = function(){};
		new MochaTestRunner(files, testRunnerMonitor).start();
	}
};

var TestRunnerMonitor = function(display){
	this.passed = function(){
		display.failed();
	};
	this.failed = function(){
		display.passed();
	};
};

var MoreThanOneTestFileSpecification = function(){
	this.isSatisifiedBy = function(tests){
		return tests.length > 0;
	};
};

var NoSourceFilesSpecification = function(){
	this.isSatisifiedBy = function(files){
		return files.src.length === 0;
	};
};

module.exports = Sentinaught;<commit_msg>removing redundant code<commit_after>var MochaTestRunner = require('./mocha-test-runner'),
	FileRepository = require('./FileRepository'),
	path = require('path'),
	SourceFile = require('./source-file');

var Sentinaught = function(sentinaughtDisplay){
	var moreThanOneTestFileSpecification = new MoreThanOneTestFileSpecification(),
		noSourceFilesSpecification = new NoSourceFilesSpecification(),
		testRunnerMonitor = new TestRunnerMonitor(sentinaughtDisplay);

	this.run = function(options){
		var getFileOptions = {recursive: options.recursive, name: "*.js"},
			fileRepository = new FileRepository(getFileOptions),
			files = {
				tests : fileRepository.get(options.tests),
				src : fileRepository.get(options.src)
			};

		if (moreThanOneTestFileSpecification.isSatisifiedBy(files.tests)){
			runMutation(files);
		}
		else{
			if (noSourceFilesSpecification.isSatisifiedBy(files)){
				sentinaughtDisplay.passed();
			}
			else {
				sentinaughtDisplay.failed();
			}
		}
	};

	function runMutation(files){
		var fileToMutate = files.src[0],
			fileToMutatePath = path.resolve(fileToMutate);
		require(fileToMutatePath);
		require.cache[fileToMutatePath].exports = function(){};
		new MochaTestRunner(files, testRunnerMonitor).start();
	}
};

var TestRunnerMonitor = function(display){
	this.passed = function(){
		display.failed();
	};
	this.failed = function(){
		display.passed();
	};
};

var MoreThanOneTestFileSpecification = function(){
	this.isSatisifiedBy = function(tests){
		return tests.length > 0;
	};
};

var NoSourceFilesSpecification = function(){
	this.isSatisifiedBy = function(files){
		return files.src.length === 0;
	};
};

module.exports = Sentinaught;<|endoftext|>


<commit_before>'use strict'

var log = require('npmlog')
var path = require('path')
var Promise = require('promise')
var express = require('express')
var expressValidator = require('express-validator')
var marked = require('marked')
var hash = require('vigour-js/lib/util/hash.js')
var fs = require('vigour-fs-promised')
var validate = require('../validation')
var imgManip = require('../imgManip')
var util = require('../util')

var setHeaders = require('../setHeaders')

module.exports = exports = function () {
  var self = this
  var handle
  validate.init(this.config)
  imgManip.init(this.config)
  var app = express()

  if (this.config.verbose.val) {
    app.use(logRequests)
  }

  // app.use(bodyParser.urlencoded({
  //   extended: true
  // }))

  app.use(expressValidator())

  // use README.md file as a homepage
  app.get('/', serveReadme)

  app.get('/invalidate/*', function (req, res, next) {
    var paths = {}
    var stripped = req.originalUrl.slice(1)
    var target = stripped.slice(stripped.indexOf('/'))

    paths.out = path.join(self.config.outDir.val, encodeURIComponent(target))
    if (req.query.url) {
      paths.original = req.query.url.slice(req.query.url.lastIndexOf('/') + 1)
    } else {
      if (target.indexOf('/image/') === 0) {
        target = target.slice(7)
        target = target.slice(0, target.indexOf('/'))
      }
      paths.original = target
    }
    paths.original = path.join(self.config.originalsPath.val, paths.original)
    Promise.all(fs.unlinkAsync(paths.out + '.jpg'), fs.unlinkAsync(paths.out + '.png'), fs.unlinkAsync(paths.original))
      .then(function (results) {
        // log.info('Erased', paths.out)
        // log.info('Erased', paths.original)
        res.end(JSON.stringify(paths, null, 2))
      })
      .catch(function (reason) {
        log.error('Failed to remove cache', reason)
        res.status(500).end('Failed')
      })
  })

  app.post('/image/:width/:height'
    , validate.dimensions()
    , validate.effects
    , makeOutPost.bind(self)
    , prepare.call(self)
    , morePrepPost(self.config)
    , imageTransform
    , serveTransformed
  )

  app.post('/image'
    , validate.dimensions(true)
    , validate.effects
    , makeOutPost.bind(self)
    , prepare.call(self, true)
    , morePrepPost(self.config)
    , imageTransform
    , serveTransformed
  )

  app.get('/image/:width/:height'
    , validate.dimensions()
    , validate.imgURL
    , validate.effects
    , cacheForever(true)
    , makeOut.bind(self)
    , serveCached
    , prepare.call(self)
    , morePrep(self.config)
    , imageDownload.bind(self)
    , imageTransform
    , serveTransformed
  )

  app.get('/image'
    , validate.dimensions(true)
    , validate.imgURL
    , validate.effects
    , cacheForever(true)
    , makeOut.bind(self)
    , serveCached
    , prepare.call(self, true)
    , morePrep(self.config)
    , imageDownload.bind(self)
    , imageTransform
    , serveTransformed
  )

  app.post('/batch',
    morePrepPost(self.config),
    function (req, res, next) {
      try {
        var items = JSON.parse(req.query.items)
      } catch (e) {
        var error = new Error('Invalid JSON')
        error.info = {
          msg: 'items should be a valid JSON array'
        }
        res.status(400).send(JSON.stringify(error, null, 2))
        res.end()
      }
      res.status(200)

      var prom = Promise.resolve()
      var transformed = items.map(function (item) {
        var disc = Math.random()
        return imgManip.effect(
          item,
          req.pathToOriginal,
          {
            width: item.width,
            height: item.height
          },
          path.join(self.config.outDir.val, 'POSTEDIMAGE' + disc)
        ).then(function (newPath) {
          prom = prom.then(function () {
            return new Promise(function (resolve, reject) {
              var rs = fs.createReadStream(newPath)
              res.write(self.separatorPrefix + item.dst)
              rs.on('error', reject)

              rs.on('data', function (chunk) {
                res.write(chunk)
              })

              rs.on('end', function () {
                var timeOut = setTimeout(function () {
                  onDrain()
                  res.removeListener('drain', onDrain)
                }, 100)

                function onDrain () {
                  clearTimeout(timeOut)
                  res.removeListener('drain', onDrain)
                  resolve(item)
                }

                res.once('drain', onDrain)
              })
            })
          })
          return prom
        }, function (reason) {
          prom = prom.then(function () {
            return new Promise(function (resolve, reject) {
              res.write(self.separatorPrefix + item.dst + self.separatorErrorSuffix)
              res.write(reason.toString())
              var timeOut = setTimeout(function () {
                onDrain()
                res.removeListener('drain', onDrain)
              }, 100)

              function onDrain () {
                clearTimeout(timeOut)
                res.removeListener('drain', onDrain)
                resolve(item)
              }
              res.once('drain', onDrain)
            })
          })
          return prom
        })
      })
      Promise.all(transformed)
        .then(function (arr) {
          res.end()
          util.cleanup(req.pathToOriginal)
        })
    }
  )

  // Deprecated
  app.get('/image/:id/:width/:height'
    , validate.dimensions()
    , validate.imgId
    , validate.effects
    , cacheForever(true)
    , makeOut.bind(self)
    , serveCached
    , prepare.call(self)
    , function (req, res, next) {
      var url = util.urlFromId(req.params.id)
      req.url = url
      req.pathToOriginal = path.join(self.config.originalsPath.val, hash(url))

      next()
    }
    , imageDownload.bind(self)
    , imageTransform
    , serveTransformed
  )

  // app.get('/sprite/:country/:lang/shows/:width/:height'
  //  , validateDimensions()
  //  , cacheForever(false)
  //  , makeOut.bind(self)
  //  , serveCached
  //  , prepare.call(self)
  //  , function (req, res, next) {
  //    var p = req.params
  //    req.pathToSpriteData = [p.country
  //      , p.lang
  //      , 'shows'
  //    ]
  //    next()
  //  }
  //  , requestSprite)

  // app.get('/sprite/:country/:lang/episodes/:showId/:seasonId/:width/:height'
  //  , validateDimensions()
  //  , cacheForever(false)
  //  , makeOut.bind(self)
  //  , serveCached
  //  , prepare.call(self)
  //  , function (req, res, next) {
  //    var p = req.params
  //    req.pathToSpriteData = [p.country
  //      , p.lang
  //      , 'shows'
  //      , p.showId
  //      , 'seasons'
  //      , p.seasonId
  //      , 'episodes'
  //    ]
  //    next()
  //  }
  //  , requestSprite)

  app.get('*'
    , function (req, res, next) {
      invalidRequest.call(self, res)
    })
  return new Promise(function (resolve, reject) {
    handle = app.listen(self.config.port.val, function () {
      log.info('Listening on port ', self.config.port.val)
      resolve(handle)
    })
  })
}

function logRequests (req, res, next) {
  log.info(req.method, req.originalUrl)
  next()
}

// TODO Cache this page
function serveReadme (req, res, next) {
  res.set('content-type', 'text/html')
  Promise.all([
    path.join(__dirname, '..', '..', 'node_modules', 'github-markdown-css', 'github-markdown.css'),
    path.join(__dirname, '..', '..', 'README.md')
  ].map(function (item) {
    return fs.readFileAsync(item, 'utf8')
  }))
    .then(function (contents) {
      res.send(
        '<!doctype html>' +
        '' +
        '' +
        '<meta charset="utf-8">' +
        '<title>Shutter - README.md<title>' +
        '' +
        '' +
        '' +
        '
' +
        marked(contents[1]) +
        '
' +
        '' +
        ''
      )
      res.end()
    })
}

function makeOutPost (req, res, next) {
  var disc = Math.random()
  req.out = path.join(this.config.outDir.val, 'POSTEDIMAGE' + disc)
  next()
}

function makeOut (req, res, next) {
  // log.info('making out')
  try {
    req.out = path.join(this.config.outDir.val, hash(req.originalUrl))
    next()
  } catch (e) {
    invalidRequest.call(this, res)
  }
}

function invalidRequest (res) {
  // log.info('Serving 400')
  res.status(400).end(this.config.invalidRequestMessage.val)
}

function prepare (fromQuery) {
  var self = this
  return function (req, res, next) {
    req.tmpDir = path.join(self.config.tmpDir.val, Math.random().toString().slice(1))
    fs.mkdir(req.tmpDir, function (err) {
      if (err) {
        err.detail = 'fs.mkdir error'
        err.path = req.tmpDir
        res.status(500).end(JSON.stringify(err, null, ' '))
      } else {
        if (fromQuery) {
          req.dimensions = {
            width: req.query.width,
            height: req.query.height
          }
        } else {
          req.dimensions = {
            width: req.params.width,
            height: req.params.height
          }
        }
        next()
      }
    })
  }
}

function morePrep (options) {
  return function (req, res, next) {
    req.url = req.query.url
    req.pathToOriginal = path.join(options.originalsPath.val, hash(req.url))
    next()
  }
}

function morePrepPost (options) {
  return function (req, res, next) {
    var disc = Math.random()
    req.pathToOriginal = path.join(options.originalsPath.val, 'POSTEDIMAGE' + disc)
    var ws = fs.createWriteStream(req.pathToOriginal)
    req.pipe(ws)
    req.on('error', function (err) {
      console.error('Error streaming POSTed file to disk', err)
      res.status(500).end()
    })
    req.on('end', function () {
      next()
    })
  }
}

// download original image
// to `originals/` directory
function imageDownload (req, res, next) {
  var self = this
  // log.info('req.pathToOriginal'.red, req.pathToOriginal)
  // log.info('url'.red, req.url)

  fs.exists(req.pathToOriginal, function (exists) {
    if (exists) {
      next()
    } else {
      // log.info("Downloading original image".cyan)

      fs.writeFile(req.pathToOriginal, req.url, {
        maxTries: self.config.maxTries.val,
        retryOn404: true // MTV's image server sometimes returns 404 even if image does exists, i.e. retrying may work
      }, function (err) {
        var status
        if (err) {
          err.details = 'vigour-fs.write (download) error'
          err.path = req.pathToOriginal
          err.data = req.url
          status = err.statusCode || 500
          res.status(status).end(JSON.stringify(err, null, ' '))
          util.cleanup(req.tmpDir)
        } else {
          next()
        }
      })
    }
  })
}

function imageTransform (req, res, next) {
  imgManip.effect(
    req.query,
    req.pathToOriginal,
    req.dimensions,
    req.out
  ).then(effectThen(req, next), effectCatch(req, res))
}

function effectThen (req, next, item) {
  return function (newPath) {
    req.newPath = newPath
    next()
    return item
  }
}

function effectCatch (req, res) {
  return function (reason) {
    reason.details = 'imgManip.effect error'
    reason.query = req.query
    reason.path = req.pathToOriginal
    reason.dimensions = req.dimensions
    reason.out = req.out
    log.error('EFFECT CATCH', reason)
    res.status(500).end(
      JSON.stringify(reason, null, ' ')
    )
    util.cleanup(req.tmpDir)
  }
}

function serveTransformed (req, res, next) {
  serve(res, req.newPath, req.cacheForever, function (err) {
    if (err) {
      log.error('Error serving file', req.newPath, err)
    } else {
      if (req.query.cache === 'false') {
        fs.removeAsync(req.newPath)
        fs.removeAsync(req.pathToOriginal)
      }
      util.cleanup(req.tmpDir)
    }
  })
}

function serveCached (req, res, next) {
  var filePath = req.out + '.jpg'
  serveIfExists(filePath
    , req.cacheForever
    , res
    , function (err) {
      if (err) {
        filePath = req.out + '.png'
        serveIfExists(filePath
          , req.cacheForever
          , res
          , function (err) {
            if (err) {
              next()
            }
          })
      }
    })
}

function serveIfExists (path, cacheForever, res, cb) {
  fs.exists(path, function (exists) {
    if (exists) {
      serve(res, path, cacheForever)
      cb(null)
    } else {
      cb(true)
    }
  })
}

function cacheForever (bool) {
  return function (req, res, next) {
    if (bool) {
      if (req.query.cache !== undefined) {
        req.cacheForever = !(req.query.cache === 'false')
      } else {
        req.cacheForever = true
      }
    }
    next()
  }
}

function serve (res, path, cacheForever, cb) {
  setHeaders(res, cacheForever)
  res.sendFile(path
    , function (err) {
      if (err) {
        err.message += ': sendFile error'
        if (err.code === 'ECONNABORT' && res.statusCode === 304) {
          // log.info('sent 304 for', path)
        } else {
          log.error('Error sending file', err)
          // TODO Warn dev
        }
      } else {
        // log.info("sendFile succeeds", path)
      }
      if (cb) {
        cb(err)
      }
    })
}
<commit_msg>Added missing `.val` and missing `.config`<commit_after>'use strict'

var log = require('npmlog')
var path = require('path')
var Promise = require('promise')
var express = require('express')
var expressValidator = require('express-validator')
var marked = require('marked')
var hash = require('vigour-js/lib/util/hash.js')
var fs = require('vigour-fs-promised')
var validate = require('../validation')
var imgManip = require('../imgManip')
var util = require('../util')

var setHeaders = require('../setHeaders')

module.exports = exports = function () {
  var self = this
  var handle
  validate.init(this.config)
  imgManip.init(this.config)
  var app = express()

  if (this.config.verbose.val) {
    app.use(logRequests)
  }

  // app.use(bodyParser.urlencoded({
  //   extended: true
  // }))

  app.use(expressValidator())

  // use README.md file as a homepage
  app.get('/', serveReadme)

  app.get('/invalidate/*', function (req, res, next) {
    var paths = {}
    var stripped = req.originalUrl.slice(1)
    var target = stripped.slice(stripped.indexOf('/'))

    paths.out = path.join(self.config.outDir.val, encodeURIComponent(target))
    if (req.query.url) {
      paths.original = req.query.url.slice(req.query.url.lastIndexOf('/') + 1)
    } else {
      if (target.indexOf('/image/') === 0) {
        target = target.slice(7)
        target = target.slice(0, target.indexOf('/'))
      }
      paths.original = target
    }
    paths.original = path.join(self.config.originalsPath.val, paths.original)
    Promise.all(fs.unlinkAsync(paths.out + '.jpg'), fs.unlinkAsync(paths.out + '.png'), fs.unlinkAsync(paths.original))
      .then(function (results) {
        // log.info('Erased', paths.out)
        // log.info('Erased', paths.original)
        res.end(JSON.stringify(paths, null, 2))
      })
      .catch(function (reason) {
        log.error('Failed to remove cache', reason)
        res.status(500).end('Failed')
      })
  })

  app.post('/image/:width/:height'
    , validate.dimensions()
    , validate.effects
    , makeOutPost.bind(self)
    , prepare.call(self)
    , morePrepPost(self.config)
    , imageTransform
    , serveTransformed
  )

  app.post('/image'
    , validate.dimensions(true)
    , validate.effects
    , makeOutPost.bind(self)
    , prepare.call(self, true)
    , morePrepPost(self.config)
    , imageTransform
    , serveTransformed
  )

  app.get('/image/:width/:height'
    , validate.dimensions()
    , validate.imgURL
    , validate.effects
    , cacheForever(true)
    , makeOut.bind(self)
    , serveCached
    , prepare.call(self)
    , morePrep(self.config)
    , imageDownload.bind(self)
    , imageTransform
    , serveTransformed
  )

  app.get('/image'
    , validate.dimensions(true)
    , validate.imgURL
    , validate.effects
    , cacheForever(true)
    , makeOut.bind(self)
    , serveCached
    , prepare.call(self, true)
    , morePrep(self.config)
    , imageDownload.bind(self)
    , imageTransform
    , serveTransformed
  )

  app.post('/batch',
    morePrepPost(self.config),
    function (req, res, next) {
      try {
        var items = JSON.parse(req.query.items)
      } catch (e) {
        var error = new Error('Invalid JSON')
        error.info = {
          msg: 'items should be a valid JSON array'
        }
        res.status(400).send(JSON.stringify(error, null, 2))
        res.end()
      }
      res.status(200)

      var prom = Promise.resolve()
      var transformed = items.map(function (item) {
        var disc = Math.random()
        return imgManip.effect(
          item,
          req.pathToOriginal,
          {
            width: item.width,
            height: item.height
          },
          path.join(self.config.outDir.val, 'POSTEDIMAGE' + disc)
        ).then(function (newPath) {
          prom = prom.then(function () {
            return new Promise(function (resolve, reject) {
              var rs = fs.createReadStream(newPath)
              res.write(self.config.separatorPrefix.val + item.dst)
              rs.on('error', reject)

              rs.on('data', function (chunk) {
                res.write(chunk)
              })

              rs.on('end', function () {
                var timeOut = setTimeout(function () {
                  onDrain()
                  res.removeListener('drain', onDrain)
                }, 100)

                function onDrain () {
                  clearTimeout(timeOut)
                  res.removeListener('drain', onDrain)
                  resolve(item)
                }

                res.once('drain', onDrain)
              })
            })
          })
          return prom
        }, function (reason) {
          prom = prom.then(function () {
            return new Promise(function (resolve, reject) {
              res.write(self.separatorPrefix + item.dst + self.separatorErrorSuffix)
              res.write(reason.toString())
              var timeOut = setTimeout(function () {
                onDrain()
                res.removeListener('drain', onDrain)
              }, 100)

              function onDrain () {
                clearTimeout(timeOut)
                res.removeListener('drain', onDrain)
                resolve(item)
              }
              res.once('drain', onDrain)
            })
          })
          return prom
        })
      })
      Promise.all(transformed)
        .then(function (arr) {
          res.end()
          util.cleanup(req.pathToOriginal)
        })
    }
  )

  // Deprecated
  app.get('/image/:id/:width/:height'
    , validate.dimensions()
    , validate.imgId
    , validate.effects
    , cacheForever(true)
    , makeOut.bind(self)
    , serveCached
    , prepare.call(self)
    , function (req, res, next) {
      var url = util.urlFromId(req.params.id)
      req.url = url
      req.pathToOriginal = path.join(self.config.originalsPath.val, hash(url))

      next()
    }
    , imageDownload.bind(self)
    , imageTransform
    , serveTransformed
  )

  // app.get('/sprite/:country/:lang/shows/:width/:height'
  //  , validateDimensions()
  //  , cacheForever(false)
  //  , makeOut.bind(self)
  //  , serveCached
  //  , prepare.call(self)
  //  , function (req, res, next) {
  //    var p = req.params
  //    req.pathToSpriteData = [p.country
  //      , p.lang
  //      , 'shows'
  //    ]
  //    next()
  //  }
  //  , requestSprite)

  // app.get('/sprite/:country/:lang/episodes/:showId/:seasonId/:width/:height'
  //  , validateDimensions()
  //  , cacheForever(false)
  //  , makeOut.bind(self)
  //  , serveCached
  //  , prepare.call(self)
  //  , function (req, res, next) {
  //    var p = req.params
  //    req.pathToSpriteData = [p.country
  //      , p.lang
  //      , 'shows'
  //      , p.showId
  //      , 'seasons'
  //      , p.seasonId
  //      , 'episodes'
  //    ]
  //    next()
  //  }
  //  , requestSprite)

  app.get('*'
    , function (req, res, next) {
      invalidRequest.call(self, res)
    })
  return new Promise(function (resolve, reject) {
    handle = app.listen(self.config.port.val, function () {
      log.info('Listening on port ', self.config.port.val)
      resolve(handle)
    })
  })
}

function logRequests (req, res, next) {
  log.info(req.method, req.originalUrl)
  next()
}

// TODO Cache this page
function serveReadme (req, res, next) {
  res.set('content-type', 'text/html')
  Promise.all([
    path.join(__dirname, '..', '..', 'node_modules', 'github-markdown-css', 'github-markdown.css'),
    path.join(__dirname, '..', '..', 'README.md')
  ].map(function (item) {
    return fs.readFileAsync(item, 'utf8')
  }))
    .then(function (contents) {
      res.send(
        '<!doctype html>' +
        '' +
        '' +
        '<meta charset="utf-8">' +
        '<title>Shutter - README.md<title>' +
        '' +
        '' +
        '' +
        '
' +
        marked(contents[1]) +
        '
' +
        '' +
        ''
      )
      res.end()
    })
}

function makeOutPost (req, res, next) {
  var disc = Math.random()
  req.out = path.join(this.config.outDir.val, 'POSTEDIMAGE' + disc)
  next()
}

function makeOut (req, res, next) {
  // log.info('making out')
  try {
    req.out = path.join(this.config.outDir.val, hash(req.originalUrl))
    next()
  } catch (e) {
    invalidRequest.call(this, res)
  }
}

function invalidRequest (res) {
  // log.info('Serving 400')
  res.status(400).end(this.config.invalidRequestMessage.val)
}

function prepare (fromQuery) {
  var self = this
  return function (req, res, next) {
    req.tmpDir = path.join(self.config.tmpDir.val, Math.random().toString().slice(1))
    fs.mkdir(req.tmpDir, function (err) {
      if (err) {
        err.detail = 'fs.mkdir error'
        err.path = req.tmpDir
        res.status(500).end(JSON.stringify(err, null, ' '))
      } else {
        if (fromQuery) {
          req.dimensions = {
            width: req.query.width,
            height: req.query.height
          }
        } else {
          req.dimensions = {
            width: req.params.width,
            height: req.params.height
          }
        }
        next()
      }
    })
  }
}

function morePrep (options) {
  return function (req, res, next) {
    req.url = req.query.url
    req.pathToOriginal = path.join(options.originalsPath.val, hash(req.url))
    next()
  }
}

function morePrepPost (options) {
  return function (req, res, next) {
    var disc = Math.random()
    req.pathToOriginal = path.join(options.originalsPath.val, 'POSTEDIMAGE' + disc)
    var ws = fs.createWriteStream(req.pathToOriginal)
    req.pipe(ws)
    req.on('error', function (err) {
      console.error('Error streaming POSTed file to disk', err)
      res.status(500).end()
    })
    req.on('end', function () {
      next()
    })
  }
}

// download original image
// to `originals/` directory
function imageDownload (req, res, next) {
  var self = this
  // log.info('req.pathToOriginal'.red, req.pathToOriginal)
  // log.info('url'.red, req.url)

  fs.exists(req.pathToOriginal, function (exists) {
    if (exists) {
      next()
    } else {
      // log.info("Downloading original image".cyan)

      fs.writeFile(req.pathToOriginal, req.url, {
        maxTries: self.config.maxTries.val,
        retryOn404: true // MTV's image server sometimes returns 404 even if image does exists, i.e. retrying may work
      }, function (err) {
        var status
        if (err) {
          err.details = 'vigour-fs.write (download) error'
          err.path = req.pathToOriginal
          err.data = req.url
          status = err.statusCode || 500
          res.status(status).end(JSON.stringify(err, null, ' '))
          util.cleanup(req.tmpDir)
        } else {
          next()
        }
      })
    }
  })
}

function imageTransform (req, res, next) {
  imgManip.effect(
    req.query,
    req.pathToOriginal,
    req.dimensions,
    req.out
  ).then(effectThen(req, next), effectCatch(req, res))
}

function effectThen (req, next, item) {
  return function (newPath) {
    req.newPath = newPath
    next()
    return item
  }
}

function effectCatch (req, res) {
  return function (reason) {
    reason.details = 'imgManip.effect error'
    reason.query = req.query
    reason.path = req.pathToOriginal
    reason.dimensions = req.dimensions
    reason.out = req.out
    log.error('EFFECT CATCH', reason)
    res.status(500).end(
      JSON.stringify(reason, null, ' ')
    )
    util.cleanup(req.tmpDir)
  }
}

function serveTransformed (req, res, next) {
  serve(res, req.newPath, req.cacheForever, function (err) {
    if (err) {
      log.error('Error serving file', req.newPath, err)
    } else {
      if (req.query.cache === 'false') {
        fs.removeAsync(req.newPath)
        fs.removeAsync(req.pathToOriginal)
      }
      util.cleanup(req.tmpDir)
    }
  })
}

function serveCached (req, res, next) {
  var filePath = req.out + '.jpg'
  serveIfExists(filePath
    , req.cacheForever
    , res
    , function (err) {
      if (err) {
        filePath = req.out + '.png'
        serveIfExists(filePath
          , req.cacheForever
          , res
          , function (err) {
            if (err) {
              next()
            }
          })
      }
    })
}

function serveIfExists (path, cacheForever, res, cb) {
  fs.exists(path, function (exists) {
    if (exists) {
      serve(res, path, cacheForever)
      cb(null)
    } else {
      cb(true)
    }
  })
}

function cacheForever (bool) {
  return function (req, res, next) {
    if (bool) {
      if (req.query.cache !== undefined) {
        req.cacheForever = !(req.query.cache === 'false')
      } else {
        req.cacheForever = true
      }
    }
    next()
  }
}

function serve (res, path, cacheForever, cb) {
  setHeaders(res, cacheForever)
  res.sendFile(path
    , function (err) {
      if (err) {
        err.message += ': sendFile error'
        if (err.code === 'ECONNABORT' && res.statusCode === 304) {
          // log.info('sent 304 for', path)
        } else {
          log.error('Error sending file', err)
          // TODO Warn dev
        }
      } else {
        // log.info("sendFile succeeds", path)
      }
      if (cb) {
        cb(err)
      }
    })
}
<|endoftext|>


<commit_before>"use strict";
var parser = require('./parser.js')()
  , logFactory = require('./logger.js')
  , logger = null
  , args = null;

if (require.main === module) {
  args = parser.parseArgs();
  logFactory.init(args);
}

logger = logFactory.get('appium');

var http = require('http')
  , express = require('express')
  , path = require('path')
  , fs = require('fs')
  , appium = require('../appium.js')
  , parserWrap = require('./middleware').parserWrap
  , appiumVer = require('../../package.json').version
  , appiumRev = null
  , async = require('async')
  , helpers = require('./helpers.js')
  , getConfig = require('../helpers.js').getAppiumConfig
  , allowCrossDomain = helpers.allowCrossDomain
  , catchAllHandler = helpers.catchAllHandler
  , checkArgs = helpers.checkArgs
  , winstonStream = helpers.winstonStream
  , configureServer = helpers.configureServer
  , startListening = helpers.startListening
  , conditionallyPreLaunch = helpers.conditionallyPreLaunch
  , noColorLogger = helpers.noColorLogger;

var main = function (args, readyCb, doneCb) {

  if (args.showConfig) {
    try {
      console.log(JSON.stringify(getConfig()));
    } catch (e) {
      process.exit(1);
    }
    process.exit(0);
  }

  checkArgs(args);
  if (typeof doneCb === "undefined") {
    doneCb = function () {};
  }
  var rest = express()
    , server = http.createServer(rest);

  rest.configure(function () {
    rest.use(express.favicon());
    rest.use(express.static(path.join(__dirname, 'static')));
    rest.use(allowCrossDomain);
    if (!args.quiet) {
      if (args.logNoColors) {
        rest.use(express.logger(noColorLogger));
      } else {
        rest.use(express.logger('dev'));
      }
    }
    if (args.log || args.webhook) {
      rest.use(express.logger({stream: winstonStream}));
    }
    rest.use(parserWrap);
    rest.use(express.urlencoded());
    rest.use(express.json());
    rest.use(express.methodOverride());
    rest.use(rest.router);
    rest.use(catchAllHandler);
  });

  // Instantiate the appium instance
  var appiumServer = appium(args);

  // Hook up REST http interface
  appiumServer.attachTo(rest);

  async.series([
    function (cb) {
      configureServer(getConfig(), appiumVer, appiumServer, function (err, rev) {
        if (err) return cb(err);
        appiumRev = rev;
        cb();
      });
    },
    function (cb) {
      conditionallyPreLaunch(args, appiumServer, cb);
    },
    function (cb) {
      startListening(server, args, parser, appiumVer, appiumRev, appiumServer, cb);
    }
  ], function (err) {
    if (err) {
      process.exit(1);
    } else if (typeof readyCb === "function") {
      readyCb(appiumServer);
    }
  });

  server.on('close', doneCb);
  return server;
};

if (require.main === module) {
  main(args);
}

module.exports.run = main;
<commit_msg>Making sure cwd is appium install dir<commit_after>"use strict";
var parser = require('./parser.js')()
  , logFactory = require('./logger.js')
  , logger = null
  , args = null
  , path = require('path');

process.chdir(path.resolve(__dirname, '../..'));

if (require.main === module) {
  args = parser.parseArgs();
  logFactory.init(args);
}

logger = logFactory.get('appium');

var http = require('http')
  , express = require('express')
  , path = require('path')
  , fs = require('fs')
  , appium = require('../appium.js')
  , parserWrap = require('./middleware').parserWrap
  , appiumVer = require('../../package.json').version
  , appiumRev = null
  , async = require('async')
  , helpers = require('./helpers.js')
  , getConfig = require('../helpers.js').getAppiumConfig
  , allowCrossDomain = helpers.allowCrossDomain
  , catchAllHandler = helpers.catchAllHandler
  , checkArgs = helpers.checkArgs
  , winstonStream = helpers.winstonStream
  , configureServer = helpers.configureServer
  , startListening = helpers.startListening
  , conditionallyPreLaunch = helpers.conditionallyPreLaunch
  , noColorLogger = helpers.noColorLogger;

var main = function (args, readyCb, doneCb) {

  if (args.showConfig) {
    try {
      console.log(JSON.stringify(getConfig()));
    } catch (e) {
      process.exit(1);
    }
    process.exit(0);
  }

  checkArgs(args);
  if (typeof doneCb === "undefined") {
    doneCb = function () {};
  }
  var rest = express()
    , server = http.createServer(rest);

  rest.configure(function () {
    rest.use(express.favicon());
    rest.use(express.static(path.join(__dirname, 'static')));
    rest.use(allowCrossDomain);
    if (!args.quiet) {
      if (args.logNoColors) {
        rest.use(express.logger(noColorLogger));
      } else {
        rest.use(express.logger('dev'));
      }
    }
    if (args.log || args.webhook) {
      rest.use(express.logger({stream: winstonStream}));
    }
    rest.use(parserWrap);
    rest.use(express.urlencoded());
    rest.use(express.json());
    rest.use(express.methodOverride());
    rest.use(rest.router);
    rest.use(catchAllHandler);
  });

  // Instantiate the appium instance
  var appiumServer = appium(args);

  // Hook up REST http interface
  appiumServer.attachTo(rest);

  async.series([
    function (cb) {
      configureServer(getConfig(), appiumVer, appiumServer, function (err, rev) {
        if (err) return cb(err);
        appiumRev = rev;
        cb();
      });
    },
    function (cb) {
      conditionallyPreLaunch(args, appiumServer, cb);
    },
    function (cb) {
      startListening(server, args, parser, appiumVer, appiumRev, appiumServer, cb);
    }
  ], function (err) {
    if (err) {
      process.exit(1);
    } else if (typeof readyCb === "function") {
      readyCb(appiumServer);
    }
  });

  server.on('close', doneCb);
  return server;
};

if (require.main === module) {
  main(args);
}

module.exports.run = main;
<|endoftext|>


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

    /* Global var accessible from any loaded module */
    global.cloudcmd     = {};

    var DIR, LIBDIR, SRVDIR, JSONDIR, HTMLDIR,
        Util,
        UTIL = 'util',

        SLASH,
        ISWIN32,
        ext,
        path, fs, zlib, url, pipe, CloudFunc, diffPatch, querystring,

        Config = {
            server  : true,
            socket  : true,
            port    : 80
        };

    /* Native Modules*/
    exports.crypto                          = require('crypto'),
    exports.child_process                   = require('child_process'),
    exports.fs          = fs                = require('fs'),
    exports.http                            = require('http'),
    exports.https                           = require('https'),
    exports.path        = path              = require('path'),
    exports.url         = url               = require('url'),
    exports.querystring = querystring       = require('querystring'),

    /* Constants */
    /* current dir + 2 levels up */
    exports.WIN32       = ISWIN32           = isWin32();
    exports.SLASH       = SLASH             = '/',

    exports.SRVDIR      = SRVDIR            = __dirname + SLASH,
    exports.LIBDIR      = LIBDIR            = path.normalize(SRVDIR + '../'),
    exports.DIR         = DIR               = path.normalize(LIBDIR + '../'),
    exports.HTMLDIR     = HTMLDIR           = DIR + 'html' + SLASH,
    exports.JSONDIR     = JSONDIR           = DIR + 'json' + SLASH,

    /* Functions */
    exports.require                         = mrequire,
    exports.librequire                      = librequire,
    exports.srvrequire                      = srvrequire,
    exports.rootrequire                     = rootrequire,
    exports.quietrequire                    = quietrequire,

    /* compitability with old versions of node */
    exports.fs.exists                       = exports.fs.exists || exports.path.exists,

    /* Needed Modules */

    /* we can not use librequare here */
    exports.util        = Util              = require(LIBDIR + UTIL),

    exports.zlib        = zlib              = mrequire('zlib'),

    /* Main Information */
    exports.modules                         = jsonrequire('modules');
    exports.ext         = ext               = jsonrequire('ext');
    exports.mainpackage                     = rootrequire('package');
    /* base configuration */
    exports.config                          = Config,

    /*
     * Any of loaded below modules could work with global var so
     * it should be initialized first. Becouse of almost any of
     * moudles do not depends on each other all needed information
     * for all modules is initialized hear.
     */
    global.cloudcmd.main                    = exports;

    /* Additional Modules */
    exports.cloudfunc   = CloudFunc         = librequire('cloudfunc'),
    exports.pipe        = pipe              = srvrequire('pipe'),
    exports.socket                          = srvrequire('socket'),
    exports.auth                            = srvrequire('auth').auth,
    exports.appcache                        = srvrequire('appcache'),
    diffPatch                               = librequire('diff/diff-match-patch').diff_match_patch,
    exports.diff                            = new (librequire('diff').DiffProto)(diffPatch),
    exports.rest                            = srvrequire('rest').api,
    exports.update                          = srvrequire('update'),
    exports.ischanged                       = srvrequire('ischanged');
    exports.files                           = srvrequire('files');

    exports.minify                          = srvrequire('minify');

    /* second initializing after all modules load, so global var is   *
     * totally filled of all information that should know all modules */
    global.cloudcmd.main            = exports;

    /**
     * function do safe require of needed module
     * @param {Strin} src
     */
    function mrequire(src) {
        var module, msg,
            error = Util.exec.try(function() {
                module = require(src);
            });

        if (error)
            if (error.code === 'MODULE_NOT_FOUND')
                msg = CloudFunc.formatMsg('require', src, 'no');
            else
                Util.log(error);

        Util.log(msg);

        return module;
    }

    function quietrequire(src) {
        var module;

        Util.exec.try(function() {
            module = require(src);
        });

        return module;
    }

    function rootrequire(src) { return mrequire(DIR + src); }

    function librequire(src) { return mrequire(LIBDIR + src); }

    function srvrequire(src) { return mrequire(SRVDIR + src); }

    function jsonrequire(src) { return mrequire(JSONDIR + src);}

    /**
     * function check is current platform is win32
     */
    function isWin32() { return process.platform === 'win32'; }

})();
<commit_msg>feature(main) rm ischanged<commit_after>(function() {
    'use strict';

    /* Global var accessible from any loaded module */
    global.cloudcmd     = {};

    var DIR, LIBDIR, SRVDIR, JSONDIR, HTMLDIR,
        Util,
        UTIL = 'util',

        SLASH,
        ISWIN32,
        ext,
        path, fs, zlib, url, pipe, CloudFunc, diffPatch, querystring,

        Config = {
            server  : true,
            socket  : true,
            port    : 80
        };

    /* Native Modules*/
    exports.crypto                          = require('crypto'),
    exports.child_process                   = require('child_process'),
    exports.fs          = fs                = require('fs'),
    exports.http                            = require('http'),
    exports.https                           = require('https'),
    exports.path        = path              = require('path'),
    exports.url         = url               = require('url'),
    exports.querystring = querystring       = require('querystring'),

    /* Constants */
    /* current dir + 2 levels up */
    exports.WIN32       = ISWIN32           = isWin32();
    exports.SLASH       = SLASH             = '/',

    exports.SRVDIR      = SRVDIR            = __dirname + SLASH,
    exports.LIBDIR      = LIBDIR            = path.normalize(SRVDIR + '../'),
    exports.DIR         = DIR               = path.normalize(LIBDIR + '../'),
    exports.HTMLDIR     = HTMLDIR           = DIR + 'html' + SLASH,
    exports.JSONDIR     = JSONDIR           = DIR + 'json' + SLASH,

    /* Functions */
    exports.require                         = mrequire,
    exports.librequire                      = librequire,
    exports.srvrequire                      = srvrequire,
    exports.rootrequire                     = rootrequire,
    exports.quietrequire                    = quietrequire,

    /* compitability with old versions of node */
    exports.fs.exists                       = exports.fs.exists || exports.path.exists,

    /* Needed Modules */

    /* we can not use librequare here */
    exports.util        = Util              = require(LIBDIR + UTIL),

    exports.zlib        = zlib              = mrequire('zlib'),

    /* Main Information */
    exports.modules                         = jsonrequire('modules');
    exports.ext         = ext               = jsonrequire('ext');
    exports.mainpackage                     = rootrequire('package');
    /* base configuration */
    exports.config                          = Config,

    /*
     * Any of loaded below modules could work with global var so
     * it should be initialized first. Becouse of almost any of
     * moudles do not depends on each other all needed information
     * for all modules is initialized hear.
     */
    global.cloudcmd.main                    = exports;

    /* Additional Modules */
    exports.cloudfunc   = CloudFunc         = librequire('cloudfunc'),
    exports.pipe        = pipe              = srvrequire('pipe'),
    exports.socket                          = srvrequire('socket'),
    exports.auth                            = srvrequire('auth').auth,
    exports.appcache                        = srvrequire('appcache'),
    diffPatch                               = librequire('diff/diff-match-patch').diff_match_patch,
    exports.diff                            = new (librequire('diff').DiffProto)(diffPatch),
    exports.rest                            = srvrequire('rest').api,
    exports.update                          = srvrequire('update'),
    exports.files                           = srvrequire('files');

    exports.minify                          = srvrequire('minify');

    /* second initializing after all modules load, so global var is   *
     * totally filled of all information that should know all modules */
    global.cloudcmd.main            = exports;

    /**
     * function do safe require of needed module
     * @param {Strin} src
     */
    function mrequire(src) {
        var module, msg,
            error = Util.exec.try(function() {
                module = require(src);
            });

        if (error)
            if (error.code === 'MODULE_NOT_FOUND')
                msg = CloudFunc.formatMsg('require', src, 'no');
            else
                Util.log(error);

        Util.log(msg);

        return module;
    }

    function quietrequire(src) {
        var module;

        Util.exec.try(function() {
            module = require(src);
        });

        return module;
    }

    function rootrequire(src) { return mrequire(DIR + src); }

    function librequire(src) { return mrequire(LIBDIR + src); }

    function srvrequire(src) { return mrequire(SRVDIR + src); }

    function jsonrequire(src) { return mrequire(JSONDIR + src);}

    /**
     * function check is current platform is win32
     */
    function isWin32() { return process.platform === 'win32'; }

})();
<|endoftext|>