<commit_before>//    (The MIT License)
//
//    Copyright (c) 2012 Richard S Allinson <rsa@mountainmansoftware.com>
//
//    Permission is hereby granted, free of charge, to any person obtaining
//    a copy of this software and associated documentation files (the
//    'Software'), to deal in the Software without restriction, including
//    without limitation the rights to use, copy, modify, merge, publish,
//    distribute, sublicense, and/or sell copies of the Software, and to
//    permit persons to whom the Software is furnished to do so, subject to
//    the following conditions:
//
//    The above copyright notice and this permission notice shall be
//    included in all copies or substantial portions of the Software.
//
//    THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
//    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
//    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
//    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
//    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*global window: true*/

'use strict';

/*!
 * Connect - HTTPServer
 * Copyright(c) 2010 Sencha Inc.
 * Copyright(c) 2011 TJ Holowaychuk
 * MIT Licensed
 */

/*
 * Module dependencies
 */

var parse = require('url').parse;

// prototype

var app = module.exports = {};

// environment

//var env = process.env.NODE_ENV || 'development';

// runtime

var runtime = typeof window === 'undefined' ? 'server' : 'client';

/**
 * Utilize the given middleware `handle` to the given `route`,
 * defaulting to _/_. This "route" is the mount-point for the
 * middleware, when given a value other than _/_ the middleware
 * is only effective when that segment is present in the request's
 * pathname.
 *
 * For example if we were to mount a function at _/admin_, it would
 * be invoked on _/admin_, and _/admin/settings_, however it would
 * not be invoked for _/_, or _/posts_.
 *
 * Examples:
 *
 *      var app = connect();
 *      app.use(connect.favicon());
 *      app.use(connect.logger());
 *      app.use(connect.static(__dirname + '/public'));
 *
 * If we wanted to prefix static files with _/public_, we could
 * "mount" the `static()` middleware:
 *
 *      app.use('/public', connect.static(__dirname + '/public'));
 *
 * This api is chainable, so the following is valid:
 *
 *      connect
 *        .use(connect.favicon())
 *        .use(connect.logger())
 *        .use(connect.static(__dirname + '/public'))
 *        .listen(3000);
 *
 * @param {String|Function} route path or callback
 * @param {Function} fn callback
 * @return {Server} for chaining
 * @api public
 */

app.use = function (route, fn) {
    // default route to '/'
    if ('string' !== typeof route) {
        fn = route;
        route = '/';
    }

    // wrap sub-apps
    if ('function' === typeof fn.handle) {
        var server = fn;
        fn.route = route;
        fn = function (req, res, next) {
            server.handle(req, res, next);
        };
    }

    // catch all other fn types
    if ('function' !== typeof fn) {
        throw new Error();
    }

    // strip trailing slash
    if ('/' === route[route.length - 1]) {
        route = route.slice(0, -1);
    }

    // add the middleware
    this.stack.push({
        route: route,
        handle: fn
    });

    return this;
};

/**
 * Handle server requests, punting them down
 * the middleware stack.
 *
 * @api private
 */

app.handle = function (req, res, out) {
    var stack = this.stack,
        removed = '',
        index = 0;

    function next(err) {
        var layer,
            path,
            c,
            msg,
            arity;

        req.url = removed + req.url;
        req.originalUrl = req.originalUrl || req.url;
        removed = '';

        // next callback
        layer = stack[index];
        // bump the index for next time
        index = index + 1;

        // all done
        if (!layer || res.headerSent) {
            // delegate to parent
            if (out) {
                out(err);
                return;
            }

            // unhandled error
            if (err) {
                // default to 500
                if (res.statusCode < 400) {
                    res.statusCode = 500;
                }

                // respect err.status
                if (err.status) {
                    res.statusCode = err.status;
                }

                msg = err.stack || err.toString();
                // production gets a basic error message
                //        var msg = 'production' == env
                //          ? http.STATUS_CODES[res.statusCode]
                //          : err.stack || err.toString();

                // log to stderr in a non-test env
//                if ('test' != env) console.error(err.stack || err.toString());
//                if (res.headerSent) {
//                    req.socket.destroy();
//                    return;
//                }
//                res.setHeader('Content-Type', 'text/plain');
//                res.setHeader('Content-Length', Buffer.byteLength(msg));
//                if ('HEAD' === req.method) {
//                    res.done();
//                    return;
//                }

                res.done(msg);
            } else {
                res.statusCode = 404;
//                res.setHeader('Content-Type', 'text/plain');
//                if ('HEAD' == req.method) return res.done();
                res.done('Cannot ' + req.method + ' ' + req.url);
            }
            return;
        }

        try {
            path = parse(req.url).pathname;

            if (path === undefined) {
                path = '/';
            }

            // skip this layer if the route doesn't match.
            if (0 !== path.indexOf(layer.route)) {
                next(err);
                return;
            }

            c = path[layer.route.length];
            if (c && '/' !== c && '.' !== c) {
                next(err);
                return;
            }

            // Call the layer handler
            // Trim off the part of the url that matches the route
            removed = layer.route;
            req.url = req.url.substr(removed.length);

            // Ensure leading slash
            if ('/' !== req.url[0]) {
                req.url = '/' + req.url;
            }

            arity = layer.handle.length;

            if (err) {
                if (arity === 4) {
                    layer.handle(err, req, res, next);
                } else {
                    next(err);
                }
            } else if (arity < 4) {
                layer.handle(req, res, next);
            } else {
                next();
            }
        } catch (e) {
            next(e);
        }
    }
    next();
};

/*
 * Starts the server
 */

app.listen = function (port) {
    var self = this,
        server,
        ashReq,
        ashRes;

    /*
     * Are we on the server or the client?
     */
    if (runtime === 'server') {
        server = require('connect').createServer();
        server.use(require('knot').node(process.cwd()));
        server.use(function (req, res) {
            ashReq = require('./http/Request').create(req, 'server');
            ashRes = require('./http/Response').create(res);
            self.handle(ashReq, ashRes);
        });
        server.listen(port);
    } else {
        server = require('./http/index').createServer(function (req, res) {
            ashReq = require('./http/Request').create(req, 'client');
            ashRes = require('./http/Response').create(res);
            self.handle(ashReq, ashRes);
        });
        server.listen('body');
    }
};
<commit_msg>Fixing bad test<commit_after>//    (The MIT License)
//
//    Copyright (c) 2012 Richard S Allinson <rsa@mountainmansoftware.com>
//
//    Permission is hereby granted, free of charge, to any person obtaining
//    a copy of this software and associated documentation files (the
//    'Software'), to deal in the Software without restriction, including
//    without limitation the rights to use, copy, modify, merge, publish,
//    distribute, sublicense, and/or sell copies of the Software, and to
//    permit persons to whom the Software is furnished to do so, subject to
//    the following conditions:
//
//    The above copyright notice and this permission notice shall be
//    included in all copies or substantial portions of the Software.
//
//    THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
//    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
//    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
//    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
//    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*global window: true*/

'use strict';

/*!
 * Connect - HTTPServer
 * Copyright(c) 2010 Sencha Inc.
 * Copyright(c) 2011 TJ Holowaychuk
 * MIT Licensed
 */

/*
 * Module dependencies
 */

var parse = require('url').parse;

// prototype

var app = module.exports = {};

// environment

//var env = process.env.NODE_ENV || 'development';

// runtime

var runtime = typeof window === 'undefined' ? 'server' : 'client';

/**
 * Utilize the given middleware `handle` to the given `route`,
 * defaulting to _/_. This "route" is the mount-point for the
 * middleware, when given a value other than _/_ the middleware
 * is only effective when that segment is present in the request's
 * pathname.
 *
 * For example if we were to mount a function at _/admin_, it would
 * be invoked on _/admin_, and _/admin/settings_, however it would
 * not be invoked for _/_, or _/posts_.
 *
 * Examples:
 *
 *      var app = connect();
 *      app.use(connect.favicon());
 *      app.use(connect.logger());
 *      app.use(connect.static(__dirname + '/public'));
 *
 * If we wanted to prefix static files with _/public_, we could
 * "mount" the `static()` middleware:
 *
 *      app.use('/public', connect.static(__dirname + '/public'));
 *
 * This api is chainable, so the following is valid:
 *
 *      connect
 *        .use(connect.favicon())
 *        .use(connect.logger())
 *        .use(connect.static(__dirname + '/public'))
 *        .listen(3000);
 *
 * @param {String|Function} route path or callback
 * @param {Function} fn callback
 * @return {Server} for chaining
 * @api public
 */

app.use = function (route, fn) {
    // default route to '/'
    if ('string' !== typeof route) {
        fn = route;
        route = '/';
    }

    // wrap sub-apps
    if (fn && 'function' === typeof fn.handle) {
        var server = fn;
        fn.route = route;
        fn = function (req, res, next) {
            server.handle(req, res, next);
        };
    }

    // catch all other fn types
    if ('function' !== typeof fn) {
        throw new Error();
    }

    // strip trailing slash
    if ('/' === route[route.length - 1]) {
        route = route.slice(0, -1);
    }

    // add the middleware
    this.stack.push({
        route: route,
        handle: fn
    });

    return this;
};

/**
 * Handle server requests, punting them down
 * the middleware stack.
 *
 * @api private
 */

app.handle = function (req, res, out) {
    var stack = this.stack,
        removed = '',
        index = 0;

    function next(err) {
        var layer,
            path,
            c,
            msg,
            arity;

        req.url = removed + req.url;
        req.originalUrl = req.originalUrl || req.url;
        removed = '';

        // next callback
        layer = stack[index];
        // bump the index for next time
        index = index + 1;

        // all done
        if (!layer || res.headerSent) {
            // delegate to parent
            if (out) {
                out(err);
                return;
            }

            // unhandled error
            if (err) {
                // default to 500
                if (res.statusCode < 400) {
                    res.statusCode = 500;
                }

                // respect err.status
                if (err.status) {
                    res.statusCode = err.status;
                }

                msg = err.stack || err.toString();
                // production gets a basic error message
                //        var msg = 'production' == env
                //          ? http.STATUS_CODES[res.statusCode]
                //          : err.stack || err.toString();

                // log to stderr in a non-test env
//                if ('test' != env) console.error(err.stack || err.toString());
//                if (res.headerSent) {
//                    req.socket.destroy();
//                    return;
//                }
//                res.setHeader('Content-Type', 'text/plain');
//                res.setHeader('Content-Length', Buffer.byteLength(msg));
//                if ('HEAD' === req.method) {
//                    res.done();
//                    return;
//                }

                res.done(msg);
            } else {
                res.statusCode = 404;
//                res.setHeader('Content-Type', 'text/plain');
//                if ('HEAD' == req.method) return res.done();
                res.done('Cannot ' + req.method + ' ' + req.url);
            }
            return;
        }

        try {
            path = parse(req.url).pathname;

            if (path === undefined) {
                path = '/';
            }

            // skip this layer if the route doesn't match.
            if (0 !== path.indexOf(layer.route)) {
                next(err);
                return;
            }

            c = path[layer.route.length];
            if (c && '/' !== c && '.' !== c) {
                next(err);
                return;
            }

            // Call the layer handler
            // Trim off the part of the url that matches the route
            removed = layer.route;
            req.url = req.url.substr(removed.length);

            // Ensure leading slash
            if ('/' !== req.url[0]) {
                req.url = '/' + req.url;
            }

            arity = layer.handle.length;

            if (err) {
                if (arity === 4) {
                    layer.handle(err, req, res, next);
                } else {
                    next(err);
                }
            } else if (arity < 4) {
                layer.handle(req, res, next);
            } else {
                next();
            }
        } catch (e) {
            next(e);
        }
    }
    next();
};

/*
 * Starts the server
 */

app.listen = function (port) {
    var self = this,
        server,
        ashReq,
        ashRes;

    /*
     * Are we on the server or the client?
     */
    if (runtime === 'server') {
        server = require('connect').createServer();
        server.use(require('knot').node(process.cwd()));
        server.use(function (req, res) {
            ashReq = require('./http/Request').create(req, 'server');
            ashRes = require('./http/Response').create(res);
            self.handle(ashReq, ashRes);
        });
        server.listen(port);
    } else {
        server = require('./http/index').createServer(function (req, res) {
            ashReq = require('./http/Request').create(req, 'client');
            ashRes = require('./http/Response').create(res);
            self.handle(ashReq, ashRes);
        });
        server.listen('body');
    }
};
<|endoftext|>


<commit_before>'use strict';

const request = require('request');
const _       = require('lodash');
const URL     = require('url');
const async   = require('async');
const colors  = require('colors');
const helpers = require('./helpers');

////////////////////////////////////////////////////////////
//
// Middleware setup
//
////////////////////////////////////////////////////////////

module.exports = function (host, options, secure) {
  if (typeof host !== 'string') {
    throw new Error('proxy-express expects `host` to be a string');
  }

  options = helpers.buildOptions(options);

  let stream = buildStream(host, options, secure);

  return buildResultingMiddleware(host, options, stream);
};

////////////////////////////////////////////////////////////
//
// Stream setup
//
////////////////////////////////////////////////////////////

// construct the async waterfall stream
//
// accept
// buildStream(host)
//      OR
// buildStream(host, secureBool)
//      OR
// buildStream(host, secureBool)
//      OR
// buildStream(host, prefix, secureBool)
//      OR
// buildStream(host, optionsObj)
//
function buildStream (host, options, secure) {
  var stream = [];

  // accept options as a secure boolean
  if (options === true) {
    secure = true;
  }

  options = _.defaults(_.isObject(options) ? options : {}, {
    request  : {},
    response : {}
  });

  function applyStreamFunctions (funcSet) {
    _.each(funcSet || [], function (middleware) {
      if (_.isFunction(middleware)) {
        // wrapper allows us to call the callback without passing proxyObj
        stream.push(function asyncWrapper (proxyObj, callback) {
          return middleware(proxyObj, (error, _proxyObj) => callback(error, _proxyObj || proxyObj));
        });
      }
    });
  }

  // if there is `pre` middleware
  let preSet = options.pre;
  if (preSet) {
    // accept raw functions, but wrap it in an array
    preSet = _.isFunction(preSet) ? [preSet] : preSet;
    applyStreamFunctions(preSet);
  }

  // push the core request
  stream.push(proxyReq);

  // if there is `post` middleware
  let postSet = options.post;
  if (postSet) {
    // accept raw functions, but wrap it in an array
    postSet = _.isFunction(postSet) ? [postSet] : postSet;
    applyStreamFunctions(postSet);
  }

  if (secure) {
    options.request.forceHttps = true;
  }

  return stream;
}

////////////////////////////////////////////////////////////
//
// Resulting middleware
//
////////////////////////////////////////////////////////////

function buildResultingMiddleware (host, options, sharedStream) {
  return function proxyMiddleware (req, res, next) {
    let stream = _.clone(sharedStream, true);
    let reqUrl = URL.parse(req.url, true);
    let proxyUrl = {
      pathname : reqUrl.pathname,
      protocol : options.request.forceHttps ? 'https' : req.protocol,
      host     : host
    };

    //
    // Check user defined proxy conditions
    //

    var shouldProxy = true;

    // If there is a prefix, it must match the route to continue
    if (typeof options.prefix === 'string') {
      let prefix = options.prefix[0] === '/' ? options.prefix : '/' + options.prefix;

      // if thre prefix failed to match, set shouldProxy to false
      if ((reqUrl.pathname || '').indexOf(prefix) !== 0) {
        shouldProxy = false;

        // otherwise, remove the prefix and continue
      } else {
        proxyUrl.pathname = proxyUrl.pathname.replace(prefix, '');
      }
    }

    if (typeof options.request.prepend === 'string') {
      proxyUrl.pathname = (/^\//.test(options.request.prepend) ? options.request.prepend : '/' + options.request.prepend) + (/^\//.test(proxyUrl.pathname) ? proxyUrl.pathname : '/' + proxyUrl.pathname);
    }

    // if there are restricts applied, and we havent failed out yet
    if (options.restrict && shouldProxy) {
      shouldProxy = helpers.matchesRestriction(req, options.restrict);
    }

    // if the current route isn't greenlit for the passthrough, bail out
    if (!shouldProxy) { return next(); }

    let encoding;
    // Handle Image Files
    if (/jpe?g|gif|png|ico|bmp|tiff/i.test(req.url)) {
      encoding = null;
    }

    //
    // compile the request object used for the `request` module call
    //

    req.headers.host = host;

    let reqOpts = {
      url     : URL.format(proxyUrl),
      method  : req.method,
      form    : _.defaults(options.request.form, req.body),
      qs      : _.defaults({}, options.request.query, req.query),
      headers : helpers.defaultHeaders(options.request.headers, req.headers),
      encoding: encoding,
      followAllRedirects : options.request.followRedirects !== false,
      strictSSL: options.request.strictSSL !== undefined ? options.request.strictSSL : true
    };

    // if the route is greenlit, add the proxy option builder to the stream
    stream.unshift(function (callback) {
      return callback(null, {
        req     : req,
        res     : res,
        reqOpts : reqOpts,
        options : options
      });
    });

    // header cleanup before request
    res.removeHeader('x-powered-by');

    return async.waterfall(stream, respond(next));
  };
}

////////////////////////////////////////////////////////////
//
// Stream functions
//
////////////////////////////////////////////////////////////

//
// async function to make the proxied request (fires between brefore `pre` and `post` functions)
//
function proxyReq (proxyObj, callback) {
  let proxyError = proxyObjErrors(proxyObj);
  if (proxyError) { return callback(new Error(proxyError)); }

  if (proxyObj.options.log) { logReqOpts(proxyObj.reqOpts); }

  // TESTING HELPER ONLY
  if (proxyObj.options.shortCircuit) { return callback(null, proxyObj); }

  // unless explicitly set, ignore encoding
  // THIS IS A HACK THAT MAY CAUSE ISSUES. I DON'T
  // KNOW OF AN IMMEDIATE WORKAROUND TO FIX IT.
  if (!proxyObj.options['accept-encoding']) {
    delete proxyObj.reqOpts.headers['accept-encoding'];
  }

  // Check for Form Post Parameters
  if (proxyObj.req.body && (proxyObj.reqOpts.method === 'POST' || proxyObj.reqOpts.method === 'PUT')) {
    proxyObj.reqOpts.form = proxyObj.req.body;
  }

  // make request
  request(proxyObj.reqOpts, function (error, response, body) {
    if (proxyObj.options.log) { logResponse(response, body); }

    // transfer result to resulting o
    proxyObj.res.set(helpers.defaultHeaders(proxyObj.options.response.headers, response ? response.headers : {}));

    proxyObj.result = {
      response : response,
      body     : body
    };

    return callback(error, proxyObj);
  });
}

//
// respond with proxied result (fires at the end of all middleware execution)
//
function respond (next) {
  return function sendResult (error, proxyObj) {
    if (error) { return next(error); }

    // TESTING HELPER ONLY
    if (proxyObj.options.shortCircuit) {
      return proxyObj.res.send({
        result: 'proxy-express set to short circuit. If this is not expected, please check your config'
      });
    }

    let proxyError = proxyObjErrors(proxyObj);
    if (proxyError) {
      return next(new Error(proxyError));
    } else if (!(proxyObj.result && proxyObj.result.response)) {
      return next(new Error('Proxy to ' + proxyObj.reqOpts.url + ' failed for an unkown reason'));
    } else {
      proxyObj.res.status(proxyObj.result.response.statusCode || 400).send(proxyObj.result.body);
    }
  };
}

////////////////////////////////////////////////////////////
//
// Helpers
//
////////////////////////////////////////////////////////////

function proxyObjErrors (proxyObj) {
  if (!proxyObj) { return '`proxyObj` not defined'; }

  let errors   = '';
  let expected = ['req', 'req', 'reqOpts', 'options'];

  _.each(expected, function (expect, index) {
    if (!proxyObj[expect]) {
      errors += (index ? ', ' : '') + 'Missing property: `' + expect + '`';
    }
  });

  return errors ? 'Errors found in `proxyObj`: [' + errors + ']' : false;
}

function logReqOpts (reqOpts) {
  reqOpts = reqOpts || {};

  console.log('\n>>>>>>>> Request >>>>>>>\n'.cyan);

  console.log('=====     URL     =====\n'.yellow);
  console.log('  ' + (reqOpts.method || '').green + ' ' + (reqOpts.url || ''));

  console.log('\n=====   Headers   =====\n'.yellow);
  console.log(JSON.stringify(reqOpts.headers || {}, null, '  '));

  console.log('\n=====    Form     =====\n'.yellow);
  console.log(JSON.stringify(reqOpts.form || {}, null, '  ') + '\n');
}

function logResponse (response, body) {
  response = response || {};
  console.log('\n<<<<<<<< Response <<<<<<<\n'.cyan);

  console.log('=====    Status   =====\n'.yellow);
  console.log(response.statusCode + '\n');

  console.log('=====   Headers   =====\n'.yellow);
  console.log(JSON.stringify((response).headers || {}, null, '  '));

  console.log('\n=====     Body     =====\n'.yellow);
  console.log('  type: [' + (typeof body) + ']\n');
}
<commit_msg>Update proxy.js<commit_after>'use strict';

const request = require('request');
const _       = require('lodash');
const URL     = require('url');
const async   = require('async');
const colors  = require('colors');
const helpers = require('./helpers');

////////////////////////////////////////////////////////////
//
// Middleware setup
//
////////////////////////////////////////////////////////////

module.exports = function (host, options, secure) {
  if (typeof host !== 'string') {
    throw new Error('proxy-express expects `host` to be a string');
  }

  options = helpers.buildOptions(options);

  let stream = buildStream(host, options, secure);

  return buildResultingMiddleware(host, options, stream);
};

////////////////////////////////////////////////////////////
//
// Stream setup
//
////////////////////////////////////////////////////////////

// construct the async waterfall stream
//
// accept
// buildStream(host)
//      OR
// buildStream(host, secureBool)
//      OR
// buildStream(host, secureBool)
//      OR
// buildStream(host, prefix, secureBool)
//      OR
// buildStream(host, optionsObj)
//
function buildStream (host, options, secure) {
  var stream = [];

  // accept options as a secure boolean
  if (options === true) {
    secure = true;
  }

  options = _.defaults(_.isObject(options) ? options : {}, {
    request  : {},
    response : {}
  });

  function applyStreamFunctions (funcSet) {
    _.each(funcSet || [], function (middleware) {
      if (_.isFunction(middleware)) {
        // wrapper allows us to call the callback without passing proxyObj
        stream.push(function asyncWrapper (proxyObj, callback) {
          return middleware(proxyObj, (error, _proxyObj) => callback(error, _proxyObj || proxyObj));
        });
      }
    });
  }

  // if there is `pre` middleware
  let preSet = options.pre;
  if (preSet) {
    // accept raw functions, but wrap it in an array
    preSet = _.isFunction(preSet) ? [preSet] : preSet;
    applyStreamFunctions(preSet);
  }

  // push the core request
  stream.push(proxyReq);

  // if there is `post` middleware
  let postSet = options.post;
  if (postSet) {
    // accept raw functions, but wrap it in an array
    postSet = _.isFunction(postSet) ? [postSet] : postSet;
    applyStreamFunctions(postSet);
  }

  if (secure) {
    options.request.forceHttps = true;
  }

  return stream;
}

////////////////////////////////////////////////////////////
//
// Resulting middleware
//
////////////////////////////////////////////////////////////

function buildResultingMiddleware (host, options, sharedStream) {
  return function proxyMiddleware (req, res, next) {
    let stream = _.clone(sharedStream, true);
    let reqUrl = URL.parse(req.url, true);
    let proxyUrl = {
      pathname : reqUrl.pathname,
      protocol : options.request.forceHttps ? 'https' : req.protocol,
      host     : host
    };

    //
    // Check user defined proxy conditions
    //

    var shouldProxy = true;

    // If there is a prefix, it must match the route to continue
    if (typeof options.prefix === 'string') {
      let prefix = options.prefix[0] === '/' ? options.prefix : '/' + options.prefix;

      // if thre prefix failed to match, set shouldProxy to false
      if ((reqUrl.pathname || '').indexOf(prefix) !== 0) {
        shouldProxy = false;

        // otherwise, remove the prefix and continue
      } else {
        proxyUrl.pathname = proxyUrl.pathname.replace(prefix, '');
      }
    }

    if (typeof options.request.prepend === 'string') {
      proxyUrl.pathname = (/^\//.test(options.request.prepend) ? options.request.prepend : '/' + options.request.prepend) + (/^\//.test(proxyUrl.pathname) ? proxyUrl.pathname : '/' + proxyUrl.pathname);
    }

    // if there are restricts applied, and we havent failed out yet
    if (options.restrict && shouldProxy) {
      shouldProxy = helpers.matchesRestriction(req, options.restrict);
    }

    // if the current route isn't greenlit for the passthrough, bail out
    if (!shouldProxy) { return next(); }

    let encoding;
    // Handle Image Files
    if (/jpe?g|gif|png|ico|bmp|tiff/i.test(req.url)) {
      encoding = null;
    }

    //
    // compile the request object used for the `request` module call
    //

    req.headers.host = host;

    let reqOpts = {
      url     : URL.format(proxyUrl),
      method  : req.method,
      form    : _.defaults(options.request.form, req.body),
      qs      : _.defaults({}, options.request.query, req.query),
      headers : helpers.defaultHeaders(options.request.headers, req.headers),
      encoding: encoding,
      followRedirect: options.request.followRedirects !== false,
      followAllRedirects : options.request.followRedirects !== false,
      strictSSL: options.request.strictSSL !== undefined ? options.request.strictSSL : true
    };

    // if the route is greenlit, add the proxy option builder to the stream
    stream.unshift(function (callback) {
      return callback(null, {
        req     : req,
        res     : res,
        reqOpts : reqOpts,
        options : options
      });
    });

    // header cleanup before request
    res.removeHeader('x-powered-by');

    return async.waterfall(stream, respond(next));
  };
}

////////////////////////////////////////////////////////////
//
// Stream functions
//
////////////////////////////////////////////////////////////

//
// async function to make the proxied request (fires between brefore `pre` and `post` functions)
//
function proxyReq (proxyObj, callback) {
  let proxyError = proxyObjErrors(proxyObj);
  if (proxyError) { return callback(new Error(proxyError)); }

  if (proxyObj.options.log) { logReqOpts(proxyObj.reqOpts); }

  // TESTING HELPER ONLY
  if (proxyObj.options.shortCircuit) { return callback(null, proxyObj); }

  // unless explicitly set, ignore encoding
  // THIS IS A HACK THAT MAY CAUSE ISSUES. I DON'T
  // KNOW OF AN IMMEDIATE WORKAROUND TO FIX IT.
  if (!proxyObj.options['accept-encoding']) {
    delete proxyObj.reqOpts.headers['accept-encoding'];
  }

  // Check for Form Post Parameters
  if (proxyObj.req.body && (proxyObj.reqOpts.method === 'POST' || proxyObj.reqOpts.method === 'PUT')) {
    proxyObj.reqOpts.form = proxyObj.req.body;
  }

  // make request
  request(proxyObj.reqOpts, function (error, response, body) {
    if (proxyObj.options.log) { logResponse(response, body); }

    // transfer result to resulting o
    proxyObj.res.set(helpers.defaultHeaders(proxyObj.options.response.headers, response ? response.headers : {}));

    proxyObj.result = {
      response : response,
      body     : body
    };

    return callback(error, proxyObj);
  });
}

//
// respond with proxied result (fires at the end of all middleware execution)
//
function respond (next) {
  return function sendResult (error, proxyObj) {
    if (error) { return next(error); }

    // TESTING HELPER ONLY
    if (proxyObj.options.shortCircuit) {
      return proxyObj.res.send({
        result: 'proxy-express set to short circuit. If this is not expected, please check your config'
      });
    }

    let proxyError = proxyObjErrors(proxyObj);
    if (proxyError) {
      return next(new Error(proxyError));
    } else if (!(proxyObj.result && proxyObj.result.response)) {
      return next(new Error('Proxy to ' + proxyObj.reqOpts.url + ' failed for an unkown reason'));
    } else {
      proxyObj.res.status(proxyObj.result.response.statusCode || 400).send(proxyObj.result.body);
    }
  };
}

////////////////////////////////////////////////////////////
//
// Helpers
//
////////////////////////////////////////////////////////////

function proxyObjErrors (proxyObj) {
  if (!proxyObj) { return '`proxyObj` not defined'; }

  let errors   = '';
  let expected = ['req', 'req', 'reqOpts', 'options'];

  _.each(expected, function (expect, index) {
    if (!proxyObj[expect]) {
      errors += (index ? ', ' : '') + 'Missing property: `' + expect + '`';
    }
  });

  return errors ? 'Errors found in `proxyObj`: [' + errors + ']' : false;
}

function logReqOpts (reqOpts) {
  reqOpts = reqOpts || {};

  console.log('\n>>>>>>>> Request >>>>>>>\n'.cyan);

  console.log('=====     URL     =====\n'.yellow);
  console.log('  ' + (reqOpts.method || '').green + ' ' + (reqOpts.url || ''));

  console.log('\n=====   Headers   =====\n'.yellow);
  console.log(JSON.stringify(reqOpts.headers || {}, null, '  '));

  console.log('\n=====    Form     =====\n'.yellow);
  console.log(JSON.stringify(reqOpts.form || {}, null, '  ') + '\n');
}

function logResponse (response, body) {
  response = response || {};
  console.log('\n<<<<<<<< Response <<<<<<<\n'.cyan);

  console.log('=====    Status   =====\n'.yellow);
  console.log(response.statusCode + '\n');

  console.log('=====   Headers   =====\n'.yellow);
  console.log(JSON.stringify((response).headers || {}, null, '  '));

  console.log('\n=====     Body     =====\n'.yellow);
  console.log('  type: [' + (typeof body) + ']\n');
}
<|endoftext|>


<commit_before>var Query = module.exports = function Query(db, opts, cb) {

  var self = this
  if (!(self instanceof Query)) {
    return new Query(db, opts, cb)
  }

  self.opts = opts
  self.db = db

  // list of host connection settings that are writable/readOnly
  self.writable = []
  self.readOnly = []

  if (typeof cb !== 'function') cb = function() {}

  self.detectTopology(cb)
}

Query.prototype.getConn = function(options) {
  var self = this
  if (options.write) {
    return self.writable[randomInt(0, self.writable.length - 1)]
  }
  return self.readOnly[randomInt(0, self.readOnly.length - 1)]
}

Query.prototype.execute = function(sql, values, options, cb) {
  var self = this
  var conn
  var start

  if (typeof options === 'function') {
    cb = options
    options = undefined
  }

  if (typeof sql !== 'string' && !isArray(sql)) {
    return cb(new Error('sql must be string or array multiline string'))
  }

  if (typeof values === 'function') {
    cb = values
    values = undefined
  }

  if (isArray(sql)) {
    sql = sql.join('\n')
  }

  if (values) {
    sql = self.queryValues(sql, values)
  }

  options = options || {}
  conn = self.getConn(options)
  start = Date.now()

  self.db._platform.getClient(conn, function(err, client, release) {
    if (err) return cb(err)
    self.db._platform.execute(client, sql, function(err, rows) {
      if (err) {
        if (!self.opts.silent) {
          console.error('\n' + sql + '\nSQL ERROR:', err)
        }
        return cb(err)
      }

      // release the client back to the pool
      release()

      if (self.opts.debug) {
        console.log('\n' + sql + '\n' + (Date.now() - start) + 'ms')
      }
      cb(null, rows)
    })
  })
}

Query.prototype.detectTopology = function(cb) {
  var self = this
  self.db._platform.determineHosts(function(hosts) {
    if (hosts.readOnly.length === 0 && hosts.writable.length === 0) {
      return cb(new Error('Unable to connect to database.'))
    }
    if (hosts.readOnly.length === 0) {
      hosts.readOnly = hosts.writable
    }
    self.readOnly = hosts.readOnly
    self.writable = hosts.writable
    cb(null)
  })
}

// based on https://github.com/felixge/node-mysql#custom-format
// TODO: make sure you can't sqli with ';'
Query.prototype.queryValues = function(query, values) {
  if (!values) return query;
  return query.replace(/\:(\w+)/g, function (txt, key) {
    if (values.hasOwnProperty(key)) {
      if (typeof values[key] !== 'string') {
        return values[key];
      }
      return "'" + values[key].replace(/'/g, "''") + "'";
    }
    return txt;
  });
};

function isArray(value) {
  return (Object.prototype.toString.call(value) === '[object Array]')
}

function randomInt(min, max) {
    return Math.floor(Math.random()*(max-min+1)+min);
}

<commit_msg>save objects as stringified json<commit_after>var Query = module.exports = function Query(db, opts, cb) {

  var self = this
  if (!(self instanceof Query)) {
    return new Query(db, opts, cb)
  }

  self.opts = opts
  self.db = db

  // list of host connection settings that are writable/readOnly
  self.writable = []
  self.readOnly = []

  if (typeof cb !== 'function') cb = function() {}

  self.detectTopology(cb)
}

Query.prototype.getConn = function(options) {
  var self = this
  if (options.write) {
    return self.writable[randomInt(0, self.writable.length - 1)]
  }
  return self.readOnly[randomInt(0, self.readOnly.length - 1)]
}

Query.prototype.execute = function(sql, values, options, cb) {
  var self = this
  var conn
  var start

  if (typeof options === 'function') {
    cb = options
    options = undefined
  }

  if (typeof sql !== 'string' && !isArray(sql)) {
    return cb(new Error('sql must be string or array multiline string'))
  }

  if (typeof values === 'function') {
    cb = values
    values = undefined
  }

  if (isArray(sql)) {
    sql = sql.join('\n')
  }

  if (values) {
    sql = self.queryValues(sql, values)
  }

  options = options || {}
  conn = self.getConn(options)
  start = Date.now()

  self.db._platform.getClient(conn, function(err, client, release) {
    if (err) return cb(err)
    self.db._platform.execute(client, sql, function(err, rows) {
      if (err) {
        if (!self.opts.silent) {
          console.error('\n' + sql + '\nSQL ERROR:', err)
        }
        return cb(err)
      }

      // release the client back to the pool
      release()

      if (self.opts.debug) {
        console.log('\n' + sql + '\n' + (Date.now() - start) + 'ms')
      }
      cb(null, rows)
    })
  })
}

Query.prototype.detectTopology = function(cb) {
  var self = this
  self.db._platform.determineHosts(function(hosts) {
    if (hosts.readOnly.length === 0 && hosts.writable.length === 0) {
      return cb(new Error('Unable to connect to database.'))
    }
    if (hosts.readOnly.length === 0) {
      hosts.readOnly = hosts.writable
    }
    self.readOnly = hosts.readOnly
    self.writable = hosts.writable
    cb(null)
  })
}

// based on https://github.com/felixge/node-mysql#custom-format
// TODO: make sure you can't sqli with ';'
Query.prototype.queryValues = function(query, values) {
  if (!values) return query;
  return query.replace(/\:(\w+)/g, function (txt, key) {
    if (values.hasOwnProperty(key)) {
      if (typeof values[key] === 'object') {
        values[key] = JSON.stringify(values[key])
      }
      if (typeof values[key] !== 'string') {
        return values[key];
      }
      return "'" + values[key].replace(/'/g, "''") + "'";
    }
    return txt;
  });
};

function isArray(value) {
  return (Object.prototype.toString.call(value) === '[object Array]')
}

function randomInt(min, max) {
    return Math.floor(Math.random()*(max-min+1)+min);
}

<|endoftext|>


<commit_before>'use strict'

var semver = require('semver')
var DepDb = require('dependency-db')

module.exports = function (db, name, range) {
  range = range || '*'

  var depDb = new DepDb(db)

  if (!name) throw new Error('missing required name')

  console.log('Looking up %s %s dependants...', name, range)

  var pkgCount = 0
  var uniqueCount = 0
  var prevPkg
  var results = depDb.query(name, range)

  results.on('error', function (err) {
    throw err
  })

  results.on('data', function (pkg) {
    pkgCount++

    if (prevPkg && prevPkg.name !== pkg.name) {
      flush()
    } else if (prevPkg && semver.lt(pkg.version, prevPkg.version)) {
      return
    }

    prevPkg = pkg
  })

  results.on('end', function () {
    flush()
    console.log('Found %d dependant package releases', pkgCount)
    console.log('Filtered down to %d unique packages:', uniqueCount)
  })

  function flush () {
    uniqueCount++
    console.log('- %s@%s (latest dependency: %s)', prevPkg.name, prevPkg.version, prevPkg.dependencies[name])
  }
}
<commit_msg>Allow range query to be a simple digit<commit_after>'use strict'

var semver = require('semver')
var DepDb = require('dependency-db')

module.exports = function (db, name, range) {
  range = String(range || '*')

  var depDb = new DepDb(db)

  if (!name) throw new Error('missing required name')

  console.log('Looking up %s %s dependants...', name, range)

  var pkgCount = 0
  var uniqueCount = 0
  var prevPkg
  var results = depDb.query(name, range)

  results.on('error', function (err) {
    throw err
  })

  results.on('data', function (pkg) {
    pkgCount++

    if (prevPkg && prevPkg.name !== pkg.name) {
      flush()
    } else if (prevPkg && semver.lt(pkg.version, prevPkg.version)) {
      return
    }

    prevPkg = pkg
  })

  results.on('end', function () {
    flush()
    console.log('Found %d dependant package releases', pkgCount)
    console.log('Filtered down to %d unique packages:', uniqueCount)
  })

  function flush () {
    uniqueCount++
    console.log('- %s@%s (latest dependency: %s)', prevPkg.name, prevPkg.version, prevPkg.dependencies[name])
  }
}
<|endoftext|>


<commit_before>'use strict';

var EventEmitter = require('events').EventEmitter;
var util = require('util');

var Query = function Query(pool) {
  EventEmitter.call(this);
  this.pool = pool;         // Database connection pool

  this._select = [];        // Array of fields or string
  this._highlight = [];     // Array of fields to highlight matching keywords when searching
  this._from = [];          // Target table(s)
  this._join = [];          // Array or string of SQL JOIN statements
  this._where = [];         // Array or string of SQL WHERE clause
  this._group = [];         // Array or string of fields
  this._having = [];        // Array or string of conditions
  this._order = [];         // Array or string of statements
  this._limit = 20;
  this._offset = 0;
  this._as = '';            // Alias (ie this is a subquery)
  this._sql = '';           // Holds the SQL to be output
  this._sql_count = '';     // Holds the SQL to be output
  this._params = [];        // Using parameterized queries
  this._ids = undefined;    // Set when we're querying by id's
};

util.inherits(Query, EventEmitter);

var p = Query.prototype;

// Apply the request query parameters
p.parameterize = function(params) {
  if(params.limit) { this.limit(params.limit); }
  if(params.offset) { this.offset(params.offset); return; }
  if(params.page) {
    this.offset((params.page - 1) * parseInt(params.limit, 10));
  }
};

p.count = function() {
  if(!this._sql_count.length) {
    this._sql_count = 'SELECT count(*)';
    this._sql_count += ' FROM ' + this._from.join(', ');
    if(this._join.length) { this._sql_count += ' ' + this._join.join(' '); }
    if(this._where.length) { this._sql_count += ' WHERE ' + this._where.join(' AND '); }
    if(this._having.length) { this._sql_count += ' HAVING ' + this._having.join(' AND '); }
  }
  return this._sql_count;
};

// Return this query as a SQL statement
p.sql = function() {
  if(!this._sql.length) {
    this._sql = 'SELECT ' + this._select.join(', ');
    this._sql += ' FROM ' + this._from.join(', ');
    if(this._join.length) { this._sql += ' ' + this._join.join(' '); }
    if(this._where.length) { this._sql += ' WHERE ' + this._where.join(' AND '); }
    if(this._group.length) { this._sql += ' GROUP BY ' + this._group.join(', '); }
    if(this._having.length) { this._sql += ' HAVING ' + this._having.join(' AND '); }
    if(this._order.length) { this._sql += ' ORDER BY ' + this._order.join(', '); }
    if(this._limit) { this._sql += ' LIMIT ' + this._limit; }
    if(this._offset) { this._sql += ' OFFSET ' + this._offset; }
  }
  return this._sql;
};

p.select = function(fields) {
  this._select.push(fields instanceof Array ? fields.join(', ') : fields);
  return this;
};

p.highlight = function(fields, options) {
  options = options || {};
  var opt = 'MaxWords=35, MinWords=10, ShortWord=3, HighlightAll=FALSE, MaxFragments=10, FragmentDelimiter=" ... "';
  this._select.push(fields.map(function(field) {
    return  "ts_headline('" + (options.config || 'english') + "', " + field + ", query, '" + opt + "') AS " + field;
  }).join(', '));
  return this;
};

p.from = function(tables) {
  this._from.push(tables instanceof Array ? tables.join(', ') : tables);
  return this;
};

p.join = function(tables) {
  this._join.push(tables instanceof Array ? tables.join(' ') : tables);
  return this;
};

p.where = function(conditions) {
  this._where.push('(' + (conditions instanceof Array ? conditions.join(' AND ') : conditions) + ')');
  return this;
};

p.group = function(fields) {
  this._group.push(fields instanceof Array ? fields.join(', ') : fields);
  return this;
};

p.having = function(fields) {
  this._having.push(fields instanceof Array ? fields.join(', ') : fields);
  return this;
};

p.order = function(fields) {
  this._order.push(fields instanceof Array ? fields.join(', ') : fields);
  return this;
};

p.limit = function(max) {
  this._limit = max;
  return this;
};

p.offset = function(offset) {
  this._offset = offset;
  return this;
};

p.as = function(alias) {
  this._as = alias;
  return this;
};

p.param = function(data) {
  this._params.push(data);
  return this;
};

p.params = function() {
  return this._params;
};

p.paramNo = function() {
  return '$' + (this._params.length);
};

// Used in Postgres queries to be able to say : WHERE id = ANY($1::int[])
p.ids = function(ids) {
  if(ids === undefined) { throw 'SQL.ids called with ' + ids; }
  if(ids instanceof Array) { ids = ids.join(','); }
  this._params.push('{' + ids + '}');
  return this;
};

// Return this as a format suitable for node postgres
p.query = function() {
  var q = {
    text: this.sql(),
    values: this._params
  };
  console.log(q);
  return q;
};

// Run a sledgehammer style count query (same SQL, but with only count related parameters instead)
p.count_query = function() {
  return {
    text: this.count(),
    values: this.params()
  };
};

// Run this SQL. Options are : { rows: true|false, count:true|false|query }
p.execute = function(options, cb) {
  this.rows = [];
  this.cb = cb;
  this.pool.query(this.query())
    .on('error', this.error.bind(this))
    .on('row', this.row.bind(this))
    .on('end', this.end.bind(this));
};

p.error = function(err) {
  this.emit('error', err);
};

// Store result rows as they come in
p.row = function(row) {
  this.rows.push(row);
  this.emit('row', row);
};

// This is called when a query has been executed
p.end = function() {
  this.emit('end', this.rows);
  if(this.cb) { this.cb(this.rows); }
};

module.exports = Query;
<commit_msg>Added default to global.dbPool if no pool passed to constructor<commit_after>'use strict';

var EventEmitter = require('events').EventEmitter;
var util = require('util');

var Query = function Query(pool) {
  EventEmitter.call(this);

  // Database connection pool. If none provided will try to use global 'dbPool'
  this.pool = pool || global.dbPool;

  this._select = [];            // Array of fields or string
  this._highlight = [];         // Array of fields to highlight matching keywords when searching
  this._from = [];              // Target table(s)
  this._join = [];              // Array or string of SQL JOIN statements
  this._where = [];             // Array or string of SQL WHERE clause
  this._group = [];             // Array or string of fields
  this._having = [];            // Array or string of conditions
  this._order = [];             // Array or string of statements
  this._limit = 20;
  this._offset = 0;
  this._as = '';                // Alias (ie this is a subquery)
  this._sql = '';               // Holds the SQL to be output
  this._sql_count = '';         // Holds the SQL to be output
  this._params = [];            // Using parameterized queries
  this._ids = undefined;        // Set when we're querying by id's
};

util.inherits(Query, EventEmitter);

var p = Query.prototype;

// Apply the request query parameters
p.parameterize = function(params) {
  if(params.limit) { this.limit(params.limit); }
  if(params.offset) { this.offset(params.offset); return; }
  if(params.page) {
    this.offset((params.page - 1) * parseInt(params.limit, 10));
  }
};

p.count = function() {
  if(!this._sql_count.length) {
    this._sql_count = 'SELECT count(*)';
    this._sql_count += ' FROM ' + this._from.join(', ');
    if(this._join.length) { this._sql_count += ' ' + this._join.join(' '); }
    if(this._where.length) { this._sql_count += ' WHERE ' + this._where.join(' AND '); }
    if(this._having.length) { this._sql_count += ' HAVING ' + this._having.join(' AND '); }
  }
  return this._sql_count;
};

// Return this query as a SQL statement
p.sql = function() {
  if(!this._sql.length) {
    this._sql = 'SELECT ' + this._select.join(', ');
    this._sql += ' FROM ' + this._from.join(', ');
    if(this._join.length) { this._sql += ' ' + this._join.join(' '); }
    if(this._where.length) { this._sql += ' WHERE ' + this._where.join(' AND '); }
    if(this._group.length) { this._sql += ' GROUP BY ' + this._group.join(', '); }
    if(this._having.length) { this._sql += ' HAVING ' + this._having.join(' AND '); }
    if(this._order.length) { this._sql += ' ORDER BY ' + this._order.join(', '); }
    if(this._limit) { this._sql += ' LIMIT ' + this._limit; }
    if(this._offset) { this._sql += ' OFFSET ' + this._offset; }
  }
  return this._sql;
};

p.select = function(fields) {
  this._select.push(fields instanceof Array ? fields.join(', ') : fields);
  return this;
};

p.highlight = function(fields, options) {
  options = options || {};
  var opt = 'MaxWords=35, MinWords=10, ShortWord=3, HighlightAll=FALSE, MaxFragments=10, FragmentDelimiter=" ... "';
  this._select.push(fields.map(function(field) {
    return  "ts_headline('" + (options.config || 'english') + "', " + field + ", query, '" + opt + "') AS " + field;
  }).join(', '));
  return this;
};

p.from = function(tables) {
  this._from.push(tables instanceof Array ? tables.join(', ') : tables);
  return this;
};

p.join = function(tables) {
  this._join.push(tables instanceof Array ? tables.join(' ') : tables);
  return this;
};

p.where = function(conditions) {
  this._where.push('(' + (conditions instanceof Array ? conditions.join(' AND ') : conditions) + ')');
  return this;
};

p.group = function(fields) {
  this._group.push(fields instanceof Array ? fields.join(', ') : fields);
  return this;
};

p.having = function(fields) {
  this._having.push(fields instanceof Array ? fields.join(', ') : fields);
  return this;
};

p.order = function(fields) {
  this._order.push(fields instanceof Array ? fields.join(', ') : fields);
  return this;
};

p.limit = function(max) {
  this._limit = max;
  return this;
};

p.offset = function(offset) {
  this._offset = offset;
  return this;
};

p.as = function(alias) {
  this._as = alias;
  return this;
};

p.param = function(data) {
  this._params.push(data);
  return this;
};

p.params = function() {
  return this._params;
};

p.paramNo = function() {
  return '$' + (this._params.length);
};

// Used in Postgres queries to be able to say : WHERE id = ANY($1::int[])
p.ids = function(ids) {
  if(ids === undefined) { throw 'SQL.ids called with ' + ids; }
  if(ids instanceof Array) { ids = ids.join(','); }
  this._params.push('{' + ids + '}');
  return this;
};

// Return this as a format suitable for node postgres
p.query = function() {
  var q = {
    text: this.sql(),
    values: this._params
  };
  console.log(q);
  return q;
};

// Run a sledgehammer style count query (same SQL, but with only count related parameters instead)
p.count_query = function() {
  return {
    text: this.count(),
    values: this.params()
  };
};

// Run this SQL. Options are : { rows: true|false, count:true|false|query }
p.execute = function(options, cb) {
  this.rows = [];
  this.cb = cb;
  this.pool.query(this.query())
    .on('error', this.error.bind(this))
    .on('row', this.row.bind(this))
    .on('end', this.end.bind(this));
};

p.error = function(err) {
  this.emit('error', err);
};

// Store result rows as they come in
p.row = function(row) {
  this.rows.push(row);
  this.emit('row', row);
};

// This is called when a query has been executed
p.end = function() {
  this.emit('end', this.rows);
  if(this.cb) { this.cb(this.rows); }
};

module.exports = Query;
<|endoftext|>


<commit_before>'use strict';

var traverse = require('traverse');
var ObjectID = require('mongodb').ObjectID;

var TWO_DAYS = 172800000;

function default_options (opts) {
  if (!opts) {
    opts = { };
  }
  if (opts) {
    // if (!'laxDate' in opts) { opts.laxDate = false; }
    if (!'deltaAgo' in opts) {
      opts.deltaAgo = ( TWO_DAYS * 2 );
    }
    if (!'walker' in opts) {
      opts.walker = { date: parseInt, sgv: parseInt };
    }
  }
  return opts;
}

function create (params, opts) {
  opts = default_options(opts);
  var finder = walker(opts.walker)(params);
  var query = finder && finder.find ? finder.find : { };
  if (!query.date && !query.dateString) {
    // if (!laxDate) { }
    query.date = { $gte: Date.now( ) - opts.deltaAgo };
  }
  if (query._id && query._id.length) {
    query._id = ObjectID(query._id);
  }
  return query;
}

function walker (spec) {
  var fns = [ ];
  for (var prop in spec) {
    var typer = spec[prop];
    fns.push(walk_prop(prop, typer));
  }

  function exec (obj) {
    var fn;
    while (fn = fns.shift( )) {
      obj = fn(obj);
    }
    return obj;
  }
  return exec
}

function walk_prop (prop, typer) {
  function iter (opts) {
    if (opts && opts.find && opts.find[prop]) {
      traverse(opts.find[prop]).forEach(function (x) {
        if (this.isLeaf) {
          this.update(typer(x));
        }
      });
    }
    return opts;
  }
  return iter;
}

walker.walk_prop = walk_prop;
create.walker = walker;
create.default_options = default_options;

exports = module.exports = create;

<commit_msg>fix options passed to walker/query module<commit_after>'use strict';

var traverse = require('traverse');
var ObjectID = require('mongodb').ObjectID;

var TWO_DAYS = 172800000;

function default_options (opts) {
  opts = opts || { };
  if (opts) {
    var keys = [null].concat(Object.keys(opts));
    // if (keys.indexOf('laxDate') < 1) { opts.laxDate = false; }
    if (keys.indexOf('deltaAgo') < 1) {
      opts.deltaAgo = ( TWO_DAYS * 2 );
    }
    if (keys.indexOf('walker') < 1) {
      opts.walker = { date: parseInt, sgv: parseInt };
    }
  }
  return opts;
}

function create (params, opts) {
  opts = default_options(opts);
  var finder = walker(opts.walker)(params);
  var query = finder && finder.find ? finder.find : { };
  if (!query.date && !query.dateString) {
    // if (!laxDate) { }
    query.date = { $gte: Date.now( ) - opts.deltaAgo };
  }
  if (query._id && query._id.length) {
    query._id = ObjectID(query._id);
  }
  return query;
}

function walker (spec) {
  var fns = [ ];
  var keys = Object.keys(spec);
  keys.forEach(function config (prop) {
    var typer = spec[prop];
    fns.push(walk_prop(prop, typer));
  });

  function exec (obj) {
    var fn;
    while (fn = fns.shift( )) {
      obj = fn(obj);
    }
    return obj;
  }
  return exec
}

function walk_prop (prop, typer) {
  function iter (opts) {
    if (opts && opts.find && opts.find[prop]) {
      traverse(opts.find[prop]).forEach(function (x) {
        if (this.isLeaf) {
          this.update(typer(x));
        }
      });
    }
    return opts;
  }
  return iter;
}

walker.walk_prop = walk_prop;
create.walker = walker;
create.default_options = default_options;

exports = module.exports = create;

<|endoftext|>


<commit_before>'use strict';

var sqs = require('sqs');
var decrypt = require('./utils').decrypt;

function Queue(config) {
  this.polling = Number(config.get('queue:poll'));
  this.name = config.get('queue:name');
  this.q = sqs({
    access: decrypt(config.get('queue:accessKey')),
    secret: decrypt(config.get('queue:secretKey')),
    region: config.get('queue:region')
  });
}

Queue.prototype.poll = function () {
  var self = this;
  setInterval(function () {
    self.q.pull(self.name, function (msg, cb) {

    });
  }, self.polling);
  return this;
};

module.exports = Queue;<commit_msg>Parsing SQS messages and displaying on the buffer appropriately<commit_after>'use strict';

var sqs = require('sqs');
var S = require('string');
var conf = require('./config');
var ledstrip = require('./ledstrip');
var decrypt = require('./utils').decrypt;
var h2r = require('./utils').hexToRgb;

function Queue() {
  this.polling = Number(conf.get('queue:poll'));
  this.name = conf.get('queue:name');
  this.q = sqs({
    access: decrypt(conf.get('queue:accessKey')),
    secret: decrypt(conf.get('queue:secretKey')),
    region: conf.get('queue:region')
  });
}

function findStageConfig(pipelines, pipeline, stage) {
  var stageConfig = pipelines
    .filter(function (el) {
      return el.name === pipeline;
    })[0].stages
    .filter(function (el) {
      return el.name === stage;
    });

  return stageConfig[0];
}

Queue.prototype.poll = function () {
  var self = this,
    currentInterval,
    pipelines = conf.get('pipelines'),
    building = conf.get('leds:building');

  setInterval(function () {
    self.q.pull(self.name, function (msg, cb) {

      var splitMsg = msg.Subject.split(' ');
      var status = S(splitMsg[1]).toLowerCase();
      var stageConfig = findStageConfig(pipelines, splitMsg[2], splitMsg[4]);

      if (currentInterval) {
        var colour = h2r.hexToRgb(conf.get('leds:colours:' + status));
        clearInterval(currentInterval);

        var buff = ledstrip.fill(colour.r, colour.g, colour.b);
        ledstrip.sendRgbBuf(buff);
      }

      ledstrip.connect(stageConfig.offset, stageConfig.length);

      if (status.startsWith('started')) {
        currentInterval = ledstrip.animate(building);
      }

    });
  }, self.polling);
};

module.exports = Queue;<|endoftext|>


<commit_before>module.exports = class Radar {
  constructor(github, config) {
    this.github = github;
    this.config = Object.assign({}, require('./defaults'), config || {});
    this.logger = config.logger || console;
  }

  //return most recent issues with select labels
  async getIssuesWithLabel(){
    const {owner, repo, labels} = this.config;
    this.logger.debug(owner, repo, labels);
    var all_issues = {};
    await Promise.all(labels.map( async (label) => {
      var query = `repo:${owner}/${repo} is:issue is:open label:${label} `;
      const params = {
        q: query,
        sort: 'updated',
        order: 'desc',
        per_page: 100
      };

      this.logger.debug(params, 'searching %s/%s for issues', owner, repo);
      var issues = await this.github.search.issues(params);
      if(!all_issues[label]){
        all_issues[label] = issues;
      }else{
        all_issues[label] = all_issues.concat(issues);
      }
    }));

    this.logger.debug("all_issues:", all_issues);
    return all_issues;
  }

  async getIssueTitleLink(label, issues){
    issues.items.forEach(issue =>{
      this.logger.info("label", label);
      this.logger.info("issue_title", issue.title);
      this.logger.info("issue_title", issue.html_url);
    });
  }

  // Create radar issue with issue titles links
  async createRadarIssue(){
    // Check if we need to create an issue
    //TODO  isRadarIssueOpen
    const {owner, radar} = this.config;
    const data = await this.getIssuesWithLabel();
    Object.keys(data).forEach((label) =>{
      this.getIssueTitleLink(label, data[label]);
    });
  }

  // Close a radar issue if it's open for more than x days
  async closeRadarIssue(){

  }

  //check if there is an open radar issue in the radar repo
  async isRadarIssueOpen(){
    const {owner, radar} = this.config;

    // Get all radar labels
    var radar_labels = radar.labels.join(" label:")
    this.logger.debug("radar_labels: ", radar_labels)

    // Check if the radar issue has an open radar label issue
    var query = `repo:${owner}/${radar.repo} is:issue is:open label:${radar_labels} `
    const params = {
      q: query,
      sort: 'updated',
      order: 'desc',
      per_page: 1
    };

    var radar_issues = await this.github.search.issues(params);

    if(radar_issues.count === 1){
      this.logger.info("Found atleast 1 open radar open issue", radar_issues);
      return true;
    }
    return false;
  }
};
<commit_msg>implement radar issue creation<commit_after>module.exports = class Radar {
  constructor(github, config) {
    this.github = github;
    this.config = Object.assign({}, require('./defaults'), config || {});
    this.logger = config.logger || console;
    this.issue_body = '## Here is the radar for the week\n'
  }

  //return most recent issues with select labels
  async getIssuesWithLabel(){
    const {owner, repo, labels} = this.config;
    this.logger.debug(owner, repo, labels);
    var all_issues = {};

    await Promise.all(labels.map( async (label) => {
      var query = `repo:${owner}/${repo} is:issue is:open label:${label} `;
      const params = {
        q: query,
        sort: 'updated',
        order: 'desc',
        per_page: 100
      };

      this.logger.debug(params, 'searching %s/%s for issues', owner, repo);
      var issues = await this.github.search.issues(params);
      if(!all_issues[label]){
        all_issues[label] = issues;
      }else{
        all_issues[label] = all_issues.concat(issues);
      }
    }));

    this.logger.debug('all_issues:', all_issues);
    return all_issues;
  }

  async getIssueTitleLink(issues){
    issues.items.forEach(issue =>{
      this.logger.debug('issue_title', issue.title);
      this.logger.debug('issue_title', issue.html_url);
      this.issue_body += `[${issue.title}](${issue.html_url})\n`
    });
  }

  // Create radar issue with issue titles links
  async createRadarIssue(){
    // Check if we need to create an issue
    //TODO  isRadarIssueOpen
    const {owner, radar} = this.config;
    const data = await this.getIssuesWithLabel();
    var
    Object.keys(data).forEach(async (label) =>{
      this.issue_body += `### ${label}`
      await this.getIssueTitleLink(data[label]);
    });

    var params = {
      title: 'Radar for the week',
      labels: radar.labels,
      body: this.issue_body
    }
    this.github.issues.create({owner, radar.repo, params})
  }

  // Close a radar issue if it's open for more than x days
  async closeRadarIssue(){

  }

  //check if there is an open radar issue in the radar repo
  async isRadarIssueOpen(){
    const {owner, radar} = this.config;

    // Get all radar labels
    var radar_labels = radar.labels.join(' label:')
    this.logger.debug('radar_labels: ', radar_labels)

    // Check if the radar issue has an open radar label issue
    var query = `repo:${owner}/${radar.repo} is:issue is:open label:${radar_labels} `
    const params = {
      q: query,
      sort: 'updated',
      order: 'desc',
      per_page: 1
    };

    var radar_issues = await this.github.search.issues(params);

    if(radar_issues.count === 1){
      this.logger.info('Found atleast 1 open radar open issue', radar_issues);
      return true;
    }
    return false;
  }
};
<|endoftext|>


<commit_before>/**
 * Rails Behaviors v0.1.2
 * https://github.com/josh/rails-behaviors
 *
 * Copyright 2011, Joshua Peek
 * Released under the MIT License
 */

//= require_self
//= require rails/beforesend
//= require rails/accept
//= require rails/confirm
//= require rails/csrf
//= require rails/disable
//= require rails/method
//= require rails/remote
//= require rails/remote_submit
<commit_msg>Rails Behaviors 0.1.3<commit_after>/**
 * Rails Behaviors v0.1.3
 * https://github.com/josh/rails-behaviors
 *
 * Copyright 2011, Joshua Peek
 * Released under the MIT License
 */

//= require_self
//= require rails/beforesend
//= require rails/accept
//= require rails/confirm
//= require rails/csrf
//= require rails/disable
//= require rails/method
//= require rails/remote
//= require rails/remote_submit
<|endoftext|>


<commit_before>var $ = require('jquery');
var Element = require('./element');
var getEventProperty = require('./eventprop');
var vertical = require('./vertical');
require('es5-shim');

var Range = Element.extend(vertical).extend({
  initialize: function initialize(options) {
    var self = this;
    initialize.super$.call(this,
      '
'
    );
    this.options = options;
    this.parent = options.parent;

    if(this.options.rangeClass) this.$el.addClass(this.options.rangeClass);

    if(!this.options.readonly) {
      this.$el.prepend('
').append('
');
      this.on('mouseenter.elessar touchstart.elessar', $.proxy(this.removePhantom, this));
      this.on('mousedown.elessar touchstart.elessar', $.proxy(this.mousedown, this));
      this.on('click', $.proxy(this.click, this));
    } else {
      this.$el.addClass('elessar-readonly');
    }
    if(typeof this.options.label === 'function') {
      this.on('changing', function(ev, range) {
        self.$el.find('.elessar-barlabel').text(
          self.options.label.call(self, range.map($.proxy(self.parent.normalise, self.parent)))
        );
      });
    } else {
      this.$el.find('.elessar-barlabel').text(this.options.label);
    }

    this.range = [];
    this.hasChanged = false;

    if(this.options.value) this.val(this.options.value);

  },

  isVertical: function() {
    return this.parent.options.vertical;
  },

  removePhantom: function() {
    this.parent.removePhantom();
  },

  val: function(range, valOpts) {

    if(typeof range === 'undefined') {
      return this.range;
    }

    valOpts  = $.extend({},{
      dontApplyDelta: false,
      trigger: true
    }, valOpts || {});

    var next = this.parent.nextRange(this.$el),
    prev = this.parent.prevRange(this.$el),
    delta = range[1] - range[0],
    self = this;

    if(this.options.snap) {
      range = range.map(snap);
      delta = snap(delta);
    }
    if (next && next.val()[0] <= range[1] && prev && prev.val()[1] >= range[0]) {
      range[1] = next.val()[0];
      range[0] = prev.val()[1];
    }
    if (next && next.val()[0] < range[1]) {
      range[1] = next.val()[0];
      if(!valOpts.dontApplyDelta) range[0] = range[1] - delta;
    }
    if (prev && prev.val()[1] > range[0]) {
      range[0] = prev.val()[1];
      if(!valOpts.dontApplyDelta) range[1] = range[0] + delta;
    }
    if (range[1] >= 1) {
      range[1] = 1;
      if(!valOpts.dontApplyDelta) range[0] = 1 - delta;
    }
    if (range[0] <= 0) {
      range[0] = 0;
      if(!valOpts.dontApplyDelta) range[1] = delta;
    }

    if(this.options.minSize && range[1] - range[0] < this.options.minSize) {
      range[1] = range[0] + this.options.minSize;
    }

    if(this.range[0] === range[0] && this.range[1] === range[1]) return this.$el;

    this.range = range;
    if(valOpts.trigger) {
      this.$el.triggerHandler('changing', [range, this.$el]);
      this.hasChanged = true;
    }

    var start = 100*range[0] + '%',
        size = 100*(range[1] - range[0]) + '%';

    this.draw(
      this.parent.options.vertical ?
      {top: start, minHeight: size} :
      {left: start, minWidth: size}
    );

    return this;

    function snap(val) { return Math.round(val / self.options.snap) * self.options.snap; }
    function sign(x)   { return x ? x < 0 ? -1 : 1 : 0; }
  },

  click: function(ev) {
    ev.stopPropagation();
    ev.preventDefault();

    var self = this;

    if(ev.which !== 2 || !this.parent.options.allowDelete) return;

    if(this.deleteConfirm) {
      this.parent.removeRange(this);
      clearTimeout(this.deleteTimeout);
    } else {
      this.$el.addClass('elessar-delete-confirm');
      this.deleteConfirm = true;

      this.deleteTimeout = setTimeout(function() {
        self.$el.removeClass('elessar-delete-confirm');
        self.deleteConfirm = false;
      }, this.parent.options.deleteTimeout);
    }
  },

  mousedown: function(ev) {
    ev.stopPropagation();
    ev.preventDefault();
    this.hasChanged = false;
    if(ev.which > 1) return;

    if ($(ev.target).is('.elessar-handle:first-child')) {
      $('body').addClass('elessar-resizing');
      $(document).on('mousemove.elessar touchmove.elessar', this.resizeStart(ev));
    } else if ($(ev.target).is('.elessar-handle:last-child')) {
      $('body').addClass('elessar-resizing');
      $(document).on('mousemove.elessar touchmove.elessar', this.resizeStart(ev));
    } else {
      $('body').addClass('elessar-dragging');
      $(document).on('mousemove.elessar touchmove.elessar', this.drag(ev));
    }

    var self = this;

    $(document).on('mouseup touchend', function(ev) {
      ev.stopPropagation();
      ev.preventDefault();

      if(self.hasChanged) self.trigger('change', [self.range, self.$el]);
      $(document).off('mouseup.elessar mousemove.elessar touchend.elessar touchmove.elessar');
      $('body').removeClass('elessar-resizing elessar-dragging');
    });
  },

  drag: function(origEv) {
    var self = this,
    beginStart = this.startProp('offset'),
    beginPosStart = this.startProp('position'),
    mousePos = getEventProperty(this.ifVertical('clientY','clientX'), origEv);
    mouseOffset = mousePos ? mousePos - beginStart : 0,
    beginSize = this.totalSize(),
    parent = this.options.parent,
    parentStart = parent.startProp('offset'),
    parentSize = parent.totalSize();

    return function(ev) {
      ev.stopPropagation();
      ev.preventDefault();
      var mousePos = getEventProperty(self.ifVertical('clientY','clientX'), ev);
      if(mousePos) {
        var start = mousePos - parentStart - mouseOffset;

        if (start >= 0 && start <= parentSize - beginSize) {
          var rangeOffset = start / parentSize - self.range[0];
          self.val([start / parentSize, self.range[1] + rangeOffset]);
        } else {
          mouseOffset = mousePos - self.startProp('offset');
        }
      }
    };
  },
  resizeEnd: function(origEv) {
    var self = this,
    beginStart = this.startProp('offset'),
    beginPosStart = this.startProp('position'),
    mousePos = getEventProperty(this.ifVertical('clientY','clientX'), origEv),
    mouseOffset = mousePos ? mousePos - beginStart : 0,
    beginSize = this.totalSize(),
    parent = this.options.parent,
    parentStart = parent.startProp('offset'),
    parentSize = parent.totalSize(),
    minSize = this.options.minSize * parentWidth;

    return function(ev) {
      var opposite = ev.type === 'touchmove' ? 'touchend' : 'mouseup',
      subsequent = ev.type === 'touchmove' ? 'touchstart' : 'mousedown';
      ev.stopPropagation();
      ev.preventDefault();
      var mousePos = getEventProperty(self.ifVertical('clientY','clientX'), ev);
      var size = mousePos - beginStart;

      if(mousePos) {
        if (size > parentSize - beginPosStart) size = parentSize - beginPosStart;
        if (size >= minSize) {
          self.val([self.range[0], self.range[0] + size / parentSize], {dontApplyDelta: true});
        } else if(size <= 10) {
          $(document).trigger(opposite + '.elessar');
          self.$el.find('.elessar-handle:first-child').trigger(subsequent + '.elessar');
        }
      }
    };
  },

  resizeStart: function(origEv) {
    var self = this,
    beginStart = this.startProp('offset'),
    beginPosStart = this.startProp('position'),
    mousePos = getEventProperty(this.ifVertical('clientY','clientX'), origEv),
    mouseOffset = mousePos ? mousePos - beginStart : 0,
    beginSize = this.totalSize(),
    parent = this.options.parent,
    parentStart = parent.startProp('offset'),
    parentSize = parent.totalSize(),
    minSize = this.options.minSize * parentSize;

    return function(ev) {
      var opposite = ev.type === 'touchmove' ? 'touchend' : 'mouseup',
      subsequent = ev.type === 'touchmove' ? 'touchstart' : 'mousedown';

      ev.stopPropagation();
      ev.preventDefault();
      var mousePos = getEventProperty(self.ifVertical('clientY','clientX'), ev);
      var start = mousePos - parentStart - mouseOffset;
      var size = beginPosStart + beginSize - start;

      if(mousePos) {
        if (start < 0) {
          start = 0;
          size = beginPosStart + beginSize;
        }
        if (size >= minSize) {
          self.val([start / parentSize, self.range[1]], {dontApplyDelta: true});
        } else if(size <= 10) {
          $(document).trigger(opposite);
          self.$el.find('.elessar-handle:last-child').trigger(subsequent);
        }
      }
    };
  }
});

module.exports = Range;
<commit_msg>fix end resizing<commit_after>var $ = require('jquery');
var Element = require('./element');
var getEventProperty = require('./eventprop');
var vertical = require('./vertical');
require('es5-shim');

var Range = Element.extend(vertical).extend({
  initialize: function initialize(options) {
    var self = this;
    initialize.super$.call(this,
      '
'
    );
    this.options = options;
    this.parent = options.parent;

    if(this.options.rangeClass) this.$el.addClass(this.options.rangeClass);

    if(!this.options.readonly) {
      this.$el.prepend('
').append('
');
      this.on('mouseenter.elessar touchstart.elessar', $.proxy(this.removePhantom, this));
      this.on('mousedown.elessar touchstart.elessar', $.proxy(this.mousedown, this));
      this.on('click', $.proxy(this.click, this));
    } else {
      this.$el.addClass('elessar-readonly');
    }
    if(typeof this.options.label === 'function') {
      this.on('changing', function(ev, range) {
        self.$el.find('.elessar-barlabel').text(
          self.options.label.call(self, range.map($.proxy(self.parent.normalise, self.parent)))
        );
      });
    } else {
      this.$el.find('.elessar-barlabel').text(this.options.label);
    }

    this.range = [];
    this.hasChanged = false;

    if(this.options.value) this.val(this.options.value);

  },

  isVertical: function() {
    return this.parent.options.vertical;
  },

  removePhantom: function() {
    this.parent.removePhantom();
  },

  val: function(range, valOpts) {

    if(typeof range === 'undefined') {
      return this.range;
    }

    valOpts  = $.extend({},{
      dontApplyDelta: false,
      trigger: true
    }, valOpts || {});

    var next = this.parent.nextRange(this.$el),
    prev = this.parent.prevRange(this.$el),
    delta = range[1] - range[0],
    self = this;

    if(this.options.snap) {
      range = range.map(snap);
      delta = snap(delta);
    }
    if (next && next.val()[0] <= range[1] && prev && prev.val()[1] >= range[0]) {
      range[1] = next.val()[0];
      range[0] = prev.val()[1];
    }
    if (next && next.val()[0] < range[1]) {
      range[1] = next.val()[0];
      if(!valOpts.dontApplyDelta) range[0] = range[1] - delta;
    }
    if (prev && prev.val()[1] > range[0]) {
      range[0] = prev.val()[1];
      if(!valOpts.dontApplyDelta) range[1] = range[0] + delta;
    }
    if (range[1] >= 1) {
      range[1] = 1;
      if(!valOpts.dontApplyDelta) range[0] = 1 - delta;
    }
    if (range[0] <= 0) {
      range[0] = 0;
      if(!valOpts.dontApplyDelta) range[1] = delta;
    }

    if(this.options.minSize && range[1] - range[0] < this.options.minSize) {
      range[1] = range[0] + this.options.minSize;
    }

    if(this.range[0] === range[0] && this.range[1] === range[1]) return this.$el;

    this.range = range;
    if(valOpts.trigger) {
      this.$el.triggerHandler('changing', [range, this.$el]);
      this.hasChanged = true;
    }

    var start = 100*range[0] + '%',
        size = 100*(range[1] - range[0]) + '%';

    this.draw(
      this.parent.options.vertical ?
      {top: start, minHeight: size} :
      {left: start, minWidth: size}
    );

    return this;

    function snap(val) { return Math.round(val / self.options.snap) * self.options.snap; }
    function sign(x)   { return x ? x < 0 ? -1 : 1 : 0; }
  },

  click: function(ev) {
    ev.stopPropagation();
    ev.preventDefault();

    var self = this;

    if(ev.which !== 2 || !this.parent.options.allowDelete) return;

    if(this.deleteConfirm) {
      this.parent.removeRange(this);
      clearTimeout(this.deleteTimeout);
    } else {
      this.$el.addClass('elessar-delete-confirm');
      this.deleteConfirm = true;

      this.deleteTimeout = setTimeout(function() {
        self.$el.removeClass('elessar-delete-confirm');
        self.deleteConfirm = false;
      }, this.parent.options.deleteTimeout);
    }
  },

  mousedown: function(ev) {
    ev.stopPropagation();
    ev.preventDefault();
    this.hasChanged = false;
    if(ev.which > 1) return;

    if ($(ev.target).is('.elessar-handle:first-child')) {
      $('body').addClass('elessar-resizing');
      $(document).on('mousemove.elessar touchmove.elessar', this.resizeStart(ev));
    } else if ($(ev.target).is('.elessar-handle:last-child')) {
      $('body').addClass('elessar-resizing');
      $(document).on('mousemove.elessar touchmove.elessar', this.resizeEnd(ev));
    } else {
      $('body').addClass('elessar-dragging');
      $(document).on('mousemove.elessar touchmove.elessar', this.drag(ev));
    }

    var self = this;

    $(document).on('mouseup touchend', function(ev) {
      ev.stopPropagation();
      ev.preventDefault();

      if(self.hasChanged) self.trigger('change', [self.range, self.$el]);
      $(document).off('mouseup.elessar mousemove.elessar touchend.elessar touchmove.elessar');
      $('body').removeClass('elessar-resizing elessar-dragging');
    });
  },

  drag: function(origEv) {
    var self = this,
    beginStart = this.startProp('offset'),
    beginPosStart = this.startProp('position'),
    mousePos = getEventProperty(this.ifVertical('clientY','clientX'), origEv);
    mouseOffset = mousePos ? mousePos - beginStart : 0,
    beginSize = this.totalSize(),
    parent = this.options.parent,
    parentStart = parent.startProp('offset'),
    parentSize = parent.totalSize();

    return function(ev) {
      ev.stopPropagation();
      ev.preventDefault();
      var mousePos = getEventProperty(self.ifVertical('clientY','clientX'), ev);
      if(mousePos) {
        var start = mousePos - parentStart - mouseOffset;

        if (start >= 0 && start <= parentSize - beginSize) {
          var rangeOffset = start / parentSize - self.range[0];
          self.val([start / parentSize, self.range[1] + rangeOffset]);
        } else {
          mouseOffset = mousePos - self.startProp('offset');
        }
      }
    };
  },
  resizeEnd: function(origEv) {
    var self = this,
    beginStart = this.startProp('offset'),
    beginPosStart = this.startProp('position'),
    mousePos = getEventProperty(this.ifVertical('clientY','clientX'), origEv),
    mouseOffset = mousePos ? mousePos - beginStart : 0,
    beginSize = this.totalSize(),
    parent = this.options.parent,
    parentStart = parent.startProp('offset'),
    parentSize = parent.totalSize(),
    minSize = this.options.minSize * parentSize;

    return function(ev) {
      var opposite = ev.type === 'touchmove' ? 'touchend' : 'mouseup',
      subsequent = ev.type === 'touchmove' ? 'touchstart' : 'mousedown';
      ev.stopPropagation();
      ev.preventDefault();
      var mousePos = getEventProperty(self.ifVertical('clientY','clientX'), ev);
      var size = mousePos - beginStart;

      if(mousePos) {
        if (size > parentSize - beginPosStart) size = parentSize - beginPosStart;
        if (size >= minSize) {
          self.val([self.range[0], self.range[0] + size / parentSize], {dontApplyDelta: true});
        } else if(size <= 10) {
          $(document).trigger(opposite + '.elessar');
          self.$el.find('.elessar-handle:first-child').trigger(subsequent + '.elessar');
        }
      }
    };
  },

  resizeStart: function(origEv) {
    var self = this,
    beginStart = this.startProp('offset'),
    beginPosStart = this.startProp('position'),
    mousePos = getEventProperty(this.ifVertical('clientY','clientX'), origEv),
    mouseOffset = mousePos ? mousePos - beginStart : 0,
    beginSize = this.totalSize(),
    parent = this.options.parent,
    parentStart = parent.startProp('offset'),
    parentSize = parent.totalSize(),
    minSize = this.options.minSize * parentSize;

    return function(ev) {
      var opposite = ev.type === 'touchmove' ? 'touchend' : 'mouseup',
      subsequent = ev.type === 'touchmove' ? 'touchstart' : 'mousedown';

      ev.stopPropagation();
      ev.preventDefault();
      var mousePos = getEventProperty(self.ifVertical('clientY','clientX'), ev);
      var start = mousePos - parentStart - mouseOffset;
      var size = beginPosStart + beginSize - start;

      if(mousePos) {
        if (start < 0) {
          start = 0;
          size = beginPosStart + beginSize;
        }
        if (size >= minSize) {
          self.val([start / parentSize, self.range[1]], {dontApplyDelta: true});
        } else if(size <= 10) {
          $(document).trigger(opposite);
          self.$el.find('.elessar-handle:last-child').trigger(subsequent);
        }
      }
    };
  }
});

module.exports = Range;
<|endoftext|>


<commit_before>// relyq
// A reliable task queue

// vendor
var async = require('async'),
  _ = require('underscore'),
  redisPkg = require('redis'),
  simpleq = require('simpleq');

// local
var DeferredTaskList = require('./deferred');

// -- Master Type: Q --
// The master type, a task queue
function Q(redis, preopts) {
  // handle forgetting a 'new'
  if (!(this instanceof Q)) {
    return new Q(redis, preopts);
  }

  var Constructor = this.constructor;
  this.clone = this.clone || function () {
    return new Constructor(redisPkg.createClient(redis.port, redis.host, redis.options), preopts);
  };

  this._delimeter = preopts.delimeter || ':';

  var idfield = this._idfield = preopts.idfield || 'id';
  this._getid = preopts.getid || function (task) {
    return task[idfield];
  };

  this._prefix = preopts.prefix || preopts;
  this._clean_finish = preopts.clean_finish === undefined || preopts.clean_finish;
  this._keep_storage = preopts.clean_finish === 'keep_storage';

  this.todo = new simpleq.Q(redis, this._prefix + this._delimeter + 'todo');
  this.doing = new simpleq.Q(redis, this._prefix + this._delimeter + 'doing');
  this.failed = new simpleq.Q(redis, this._prefix + this._delimeter + 'failed');
  if (!this._clean_finish) {
    this.done = new simpleq.Q(redis, this._prefix + this._delimeter + 'done');
  }

  if (preopts.allow_defer) {
    this.deferred = new DeferredTaskList(this, {
      interval: preopts.defer_interval,
      key: this._prefix + this._delimeter + 'deferred',
      redis: redis,
    });
  }
}

// @overridable
// Get a task object from its reference id
Q.prototype.get = function get(taskref, callback) {
  callback(null, taskref);
};

// @overridable
// Set a task object and return its reference ID
Q.prototype.set = function set(taskobj, taskref, callback) {
  callback();
};

// @overridable
// Delete the task obj and return its reference ID
Q.prototype.del = function del(taskobj, taskref, callback) {
  callback();
};

// Override these to add a new serialization
// refs get put into the queue
// @overridable
Q.prototype.ref = function (obj) {
  return obj;
};

// End the listeners that might be listening
Q.prototype.end = function (callback) {
  if (this.deferred) {
    this.deferred.end();
  }
  if (this._sql) {
    this._sql.on('end', callback).end();
  } else {
    callback();
  }
}

// -- Superclass methods ---

Q.prototype.push = function push(task, callback) {
  var ref = this.ref(task);
  async.parallel([
    _.bind(this.set, this, task, ref),
    _.bind(this.todo.push, this.todo, ref)
  ], function (err, results) {
    callback(err, results && results.length === 2 && results[1]);
  });
};

Q.prototype.defer = function defer(task, when, callback) {
  if (!this.deferred) {
    throw new Error('Must use option allow_defer to allow defer calls.');
  }

  var ref = this.ref(task);
  async.parallel([
    _.bind(this.set, this, task, ref),
    _.bind(this.deferred.defer, this.deferred, ref, when),
  ], function (err, results) {
    callback(err, results && results.length === 2 && results[1]);
  });
};

Q.prototype.process = function process(callback) {
  async.waterfall([
    _.bind(this.todo.poppipe, this.todo, this.doing),
    _.bind(this.get, this)
  ], callback);
};

Q.prototype.bprocess = function bprocess(timeout, callback) {
  if (callback === undefined) {
    callback = timeout;
    timeout = 0;
  }

  async.waterfall([
    _.bind(this.todo.bpoppipe, this.todo, this.doing, timeout),
    _.bind(this.get, this)
  ], callback);
};

Q.prototype.finish = function finish() {
  if (this._clean_finish) {
    this._finish_clean.apply(this, arguments);
  } else {
    this._finish_dirty.apply(this, arguments);
  }
};

Q.prototype.fail = function fail(task, optional_error, callback) {
  if (callback === undefined) callback = optional_error, optional_error = undefined;
  if (optional_error) task.error = optional_error.toString();

  var ref = this.ref(task);
  async.parallel([
    _.bind(this.set, this, task, ref),
    _.bind(this.doing.spullpipe, this.doing, this.failed, ref)
  ], function (err, results) {
    if (err) {
      return callback(err);
    }
    if (results && results[1] === 0) {
      return callback(new Error('Element ' + (_.isObject(task) ? JSON.stringify(task) : task.toString()) + ' is not currently processing.'));
    }
    callback(null, results[1]);
  });
};

Q.prototype.remove = function remove(from, task, dontdel, callback) {
  if (callback === undefined) {
    callback = dontdel;
    dontdel = false;
  }
  var ref = this.ref(task);

  if (dontdel) {
    return this[from].pull(ref, callback);
  }

  async.parallel([
    _.bind(this.del, this, task, ref),
    _.bind(this[from].pull, this[from], ref)
  ], function (err, results) {
    callback(err, results && results.length === 2 && results[1]);
  });
};

// Start a process listener
/*
Example Usage

    var listener = rq.listen({
      timeout: 2, // seconds
      max_out: 10, // maximum tasks to emit at one time
    })
      .on('error', function (err, optional_taskref) {
        if (taskref) {...}
        else {...}
      })
      .on('task', function (task, done) {
        // do task
        done(error_or_not); // This will call rq.fail or rq.finish!
      });

    // some time later
    listener.end();
*/
Q.prototype.listen = function rqlistener(opts) {
  var rq = this,
    sql = this._sql = rq.todo.poppipelisten(rq.doing, opts);

  sql.on('message', function (taskref, done) {
    async.waterfall([
      _.bind(rq.get, rq, taskref),
      function (taskobj, cb) {
        function ondone (err) {
          if (err) {
            sql.emit('error', err, taskref);
          }
          done();
        }

        var called = false;
        function newdone (err) {
          if (called) {
            return;
          }
          called = true;

          if (err) {
            rq.fail(taskobj, err, ondone);
          } else {
            rq.finish(taskobj, ondone);
          }
        }

        sql.emit('task', taskobj, newdone);
        cb();
      }
    ], function (err) {
      if (err) {
        sql.emit('error', err, taskref);
      }
    });
  });

  return sql;
};

module.exports = Q;

// -- Finish Helpers --

Q.prototype._finish_clean = function finish_clean(task, dontCheckFailed, callback) {
  if (callback === undefined) callback = dontCheckFailed, dontCheckFailed = false;

  var ref = this.ref(task),
    self = this;

  async.auto({
    setTask: _.bind(this._keep_storage ? this.set : this.del, this, task, ref),
    sPullPipe: _.bind(this.doing.pull, this.doing, ref),
    checkFailed: ['sPullPipe', function (cb, results) {
      if (results.sPullPipe === 0) {
        if (dontCheckFailed) {
          return cb(null, 0);
        }

        return self.failed.pull(ref, cb);
      }
      cb(null, results.sPullPipe);
    }],
    last: ['checkFailed', function (cb, results) {
      if (results.checkFailed === 0) {
        return callback(new Error('Element ' + (_.isObject(task) ? JSON.stringify(task) : task.toString()) + ' is not currently processing or failed.'));
      }
      callback(null);
    }]
  }, function (err, results) {
    callback(err, results.checkFailed);
  });
};

Q.prototype._finish_dirty = function finish_dirty(task, dontCheckFailed, callback) {
  if (callback === undefined) callback = dontCheckFailed, dontCheckFailed = false;

  var ref = this.ref(task),
    self = this;

  async.auto({
    setTask: _.bind(this.set, this, task, ref),
    sPullPipe: _.bind(this.doing.spullpipe, this.doing, this.done, ref),
    checkFailed: ['sPullPipe', function (cb, results) {
      if (results.sPullPipe === 0) {
        if (dontCheckFailed) {
          return cb(null, 0);
        }

        return self.failed.spullpipe(self.done, ref, cb);
      }
      cb(null, results.sPullPipe);
    }],
    last: ['checkFailed', function (cb, results) {
      if (results.checkFailed === 0) {
        return callback(new Error('Element ' + (_.isObject(task) ? JSON.stringify(task) : task.toString()) + ' is not currently processing or failed.'));
      }
      callback(null);
    }]
  }, function (err, results) {
    callback(err, results.checkFailed);
  });
};<commit_msg>Only call end callback once<commit_after>// relyq
// A reliable task queue

// vendor
var async = require('async'),
  _ = require('underscore'),
  redisPkg = require('redis'),
  simpleq = require('simpleq');

// local
var DeferredTaskList = require('./deferred');

// -- Master Type: Q --
// The master type, a task queue
function Q(redis, preopts) {
  // handle forgetting a 'new'
  if (!(this instanceof Q)) {
    return new Q(redis, preopts);
  }

  var Constructor = this.constructor;
  this.clone = this.clone || function () {
    return new Constructor(redisPkg.createClient(redis.port, redis.host, redis.options), preopts);
  };

  this._delimeter = preopts.delimeter || ':';

  var idfield = this._idfield = preopts.idfield || 'id';
  this._getid = preopts.getid || function (task) {
    return task[idfield];
  };

  this._prefix = preopts.prefix || preopts;
  this._clean_finish = preopts.clean_finish === undefined || preopts.clean_finish;
  this._keep_storage = preopts.clean_finish === 'keep_storage';

  this.todo = new simpleq.Q(redis, this._prefix + this._delimeter + 'todo');
  this.doing = new simpleq.Q(redis, this._prefix + this._delimeter + 'doing');
  this.failed = new simpleq.Q(redis, this._prefix + this._delimeter + 'failed');
  if (!this._clean_finish) {
    this.done = new simpleq.Q(redis, this._prefix + this._delimeter + 'done');
  }

  if (preopts.allow_defer) {
    this.deferred = new DeferredTaskList(this, {
      interval: preopts.defer_interval,
      key: this._prefix + this._delimeter + 'deferred',
      redis: redis,
    });
  }
}

// @overridable
// Get a task object from its reference id
Q.prototype.get = function get(taskref, callback) {
  callback(null, taskref);
};

// @overridable
// Set a task object and return its reference ID
Q.prototype.set = function set(taskobj, taskref, callback) {
  callback();
};

// @overridable
// Delete the task obj and return its reference ID
Q.prototype.del = function del(taskobj, taskref, callback) {
  callback();
};

// Override these to add a new serialization
// refs get put into the queue
// @overridable
Q.prototype.ref = function (obj) {
  return obj;
};

// End the listeners that might be listening
Q.prototype.end = function (callback) {
  if (this.deferred) {
    this.deferred.end();
  }
  if (this._sql) {
    this._sql.once('end', callback).end();
  } else {
    callback();
  }
}

// -- Superclass methods ---

Q.prototype.push = function push(task, callback) {
  var ref = this.ref(task);
  async.parallel([
    _.bind(this.set, this, task, ref),
    _.bind(this.todo.push, this.todo, ref)
  ], function (err, results) {
    callback(err, results && results.length === 2 && results[1]);
  });
};

Q.prototype.defer = function defer(task, when, callback) {
  if (!this.deferred) {
    throw new Error('Must use option allow_defer to allow defer calls.');
  }

  var ref = this.ref(task);
  async.parallel([
    _.bind(this.set, this, task, ref),
    _.bind(this.deferred.defer, this.deferred, ref, when),
  ], function (err, results) {
    callback(err, results && results.length === 2 && results[1]);
  });
};

Q.prototype.process = function process(callback) {
  async.waterfall([
    _.bind(this.todo.poppipe, this.todo, this.doing),
    _.bind(this.get, this)
  ], callback);
};

Q.prototype.bprocess = function bprocess(timeout, callback) {
  if (callback === undefined) {
    callback = timeout;
    timeout = 0;
  }

  async.waterfall([
    _.bind(this.todo.bpoppipe, this.todo, this.doing, timeout),
    _.bind(this.get, this)
  ], callback);
};

Q.prototype.finish = function finish() {
  if (this._clean_finish) {
    this._finish_clean.apply(this, arguments);
  } else {
    this._finish_dirty.apply(this, arguments);
  }
};

Q.prototype.fail = function fail(task, optional_error, callback) {
  if (callback === undefined) callback = optional_error, optional_error = undefined;
  if (optional_error) task.error = optional_error.toString();

  var ref = this.ref(task);
  async.parallel([
    _.bind(this.set, this, task, ref),
    _.bind(this.doing.spullpipe, this.doing, this.failed, ref)
  ], function (err, results) {
    if (err) {
      return callback(err);
    }
    if (results && results[1] === 0) {
      return callback(new Error('Element ' + (_.isObject(task) ? JSON.stringify(task) : task.toString()) + ' is not currently processing.'));
    }
    callback(null, results[1]);
  });
};

Q.prototype.remove = function remove(from, task, dontdel, callback) {
  if (callback === undefined) {
    callback = dontdel;
    dontdel = false;
  }
  var ref = this.ref(task);

  if (dontdel) {
    return this[from].pull(ref, callback);
  }

  async.parallel([
    _.bind(this.del, this, task, ref),
    _.bind(this[from].pull, this[from], ref)
  ], function (err, results) {
    callback(err, results && results.length === 2 && results[1]);
  });
};

// Start a process listener
/*
Example Usage

    var listener = rq.listen({
      timeout: 2, // seconds
      max_out: 10, // maximum tasks to emit at one time
    })
      .on('error', function (err, optional_taskref) {
        if (taskref) {...}
        else {...}
      })
      .on('task', function (task, done) {
        // do task
        done(error_or_not); // This will call rq.fail or rq.finish!
      });

    // some time later
    listener.end();
*/
Q.prototype.listen = function rqlistener(opts) {
  var rq = this,
    sql = this._sql = rq.todo.poppipelisten(rq.doing, opts);

  sql.on('message', function (taskref, done) {
    async.waterfall([
      _.bind(rq.get, rq, taskref),
      function (taskobj, cb) {
        function ondone (err) {
          if (err) {
            sql.emit('error', err, taskref);
          }
          done();
        }

        var called = false;
        function newdone (err) {
          if (called) {
            return;
          }
          called = true;

          if (err) {
            rq.fail(taskobj, err, ondone);
          } else {
            rq.finish(taskobj, ondone);
          }
        }

        sql.emit('task', taskobj, newdone);
        cb();
      }
    ], function (err) {
      if (err) {
        sql.emit('error', err, taskref);
      }
    });
  });

  return sql;
};

module.exports = Q;

// -- Finish Helpers --

Q.prototype._finish_clean = function finish_clean(task, dontCheckFailed, callback) {
  if (callback === undefined) callback = dontCheckFailed, dontCheckFailed = false;

  var ref = this.ref(task),
    self = this;

  async.auto({
    setTask: _.bind(this._keep_storage ? this.set : this.del, this, task, ref),
    sPullPipe: _.bind(this.doing.pull, this.doing, ref),
    checkFailed: ['sPullPipe', function (cb, results) {
      if (results.sPullPipe === 0) {
        if (dontCheckFailed) {
          return cb(null, 0);
        }

        return self.failed.pull(ref, cb);
      }
      cb(null, results.sPullPipe);
    }],
    last: ['checkFailed', function (cb, results) {
      if (results.checkFailed === 0) {
        return callback(new Error('Element ' + (_.isObject(task) ? JSON.stringify(task) : task.toString()) + ' is not currently processing or failed.'));
      }
      callback(null);
    }]
  }, function (err, results) {
    callback(err, results.checkFailed);
  });
};

Q.prototype._finish_dirty = function finish_dirty(task, dontCheckFailed, callback) {
  if (callback === undefined) callback = dontCheckFailed, dontCheckFailed = false;

  var ref = this.ref(task),
    self = this;

  async.auto({
    setTask: _.bind(this.set, this, task, ref),
    sPullPipe: _.bind(this.doing.spullpipe, this.doing, this.done, ref),
    checkFailed: ['sPullPipe', function (cb, results) {
      if (results.sPullPipe === 0) {
        if (dontCheckFailed) {
          return cb(null, 0);
        }

        return self.failed.spullpipe(self.done, ref, cb);
      }
      cb(null, results.sPullPipe);
    }],
    last: ['checkFailed', function (cb, results) {
      if (results.checkFailed === 0) {
        return callback(new Error('Element ' + (_.isObject(task) ? JSON.stringify(task) : task.toString()) + ' is not currently processing or failed.'));
      }
      callback(null);
    }]
  }, function (err, results) {
    callback(err, results.checkFailed);
  });
};<|endoftext|>