<commit_before>'use strict';

var express = require('express'),
    http = require('http'),
    path = require('path'),
    _ = require('underscore'),
    fs = require('fs');

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

    _.defaults(options, {
        port: 8080,
        host: 'localhost',
        testGroup: null,
        dir: 'webtest'
    });

    console.log(options);
    var webTestRoot = path.resolve(options.dir),
        root = __dirname;

    var app = express();

    // do not cache
    app.use(function (req, res, next) {
        res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
        res.header('Expires', '-1');
        res.header('Pragma', 'no-cache');

        next();
    });

    // serve all public directories

    var staticFiles = {
        "/": "public/index.html",
        "/container.html": "public/container.html",
        "/test/TestApplication.js": "public/test/TestApplication.js",

        "/lib/mocha.js": "node_modules/mocha/mocha.js",
        "/lib/mocha.css": "node_modules/mocha/mocha.css",
        "/lib/chai.js": "node_modules/chai/chai.js",
        "/lib/jquery.expect.js": "node_modules/jquery.expect/jquery.expect.js",
        "/lib/jquery.js": "public/lib/jquery-1.11.1.min.js"
    };

    console.log("\nregistering routes for component-tests");
    for (var route in staticFiles) {
        if (staticFiles.hasOwnProperty(route)) {
            (function(route) {
                console.log(route + " -> " + staticFiles[route]);

                app.get(route, function (req, res) {
                    res.sendfile(path.join(root, staticFiles[route]));
                });
            })(route);
        }
    }

    var publicPath = path.resolve('public');
    console.log("\nmaking the public directory available");
    console.log("public -> " + publicPath);
    app.use(express.static(publicPath));

    console.log("\nusing the following web test root");
    console.log(webTestRoot);
    app.use(express.static(webTestRoot, {
        maxAge: 0
    }));

    return http.createServer(app).listen(options.port);

};<commit_msg>option to define logger<commit_after>'use strict';

var express = require('express'),
    http = require('http'),
    path = require('path'),
    _ = require('underscore'),
    fs = require('fs');

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

    _.defaults(options, {
        port: 8080,
        host: 'localhost',
        testGroup: null,
        dir: 'webtest'
    });

    log(options);
    var webTestRoot = path.resolve(options.dir),
        root = __dirname;

    var app = express();

    // do not cache
    app.use(function (req, res, next) {
        res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
        res.header('Expires', '-1');
        res.header('Pragma', 'no-cache');

        next();
    });

    // serve all public directories

    var staticFiles = {
        "/": "public/index.html",
        "/container.html": "public/container.html",
        "/test/TestApplication.js": "public/test/TestApplication.js",

        "/lib/mocha.js": "node_modules/mocha/mocha.js",
        "/lib/mocha.css": "node_modules/mocha/mocha.css",
        "/lib/chai.js": "node_modules/chai/chai.js",
        "/lib/jquery.expect.js": "node_modules/jquery.expect/jquery.expect.js",
        "/lib/jquery.js": "public/lib/jquery-1.11.1.min.js"
    };

    log("\nregistering routes for component-tests");
    for (var route in staticFiles) {
        if (staticFiles.hasOwnProperty(route)) {
            (function(route) {
                log(route + " -> " + staticFiles[route]);

                app.get(route, function (req, res) {
                    res.sendfile(path.join(root, staticFiles[route]));
                });
            })(route);
        }
    }

    var publicPath = path.resolve('public');
    log("\nmaking the public directory available");
    log("public -> " + publicPath);
    app.use(express.static(publicPath));

    log("\nusing the following web test root");
    log(webTestRoot);
    app.use(express.static(webTestRoot, {
        maxAge: 0
    }));

    return http.createServer(app).listen(options.port);

};<|endoftext|>


<commit_before>/**
 * @copyright Copyright 2017 Kevin Locke <kevin@kevinlocke.name>
 * @license MIT
 */

'use strict';

var assign = require('object-assign');
var fs = require('fs');
var http = require('http');
var https = require('https');
var packageJson = require('./package.json');
var path = require('path');
var pify = require('pify');
var tls = require('tls');
var url = require('url');

var readFileP = pify(fs.readFile);
var readdirP = pify(fs.readdir);

/** Default URL to which validation requests are sent.
 * @const
 */
var DEFAULT_URL = 'https://online.swagger.io/validator/debug';

/** Default headers sent with API requests.
 * @const
 */
var DEFAULT_HEADERS = Object.freeze({
  Accept: 'application/json',
  'User-Agent': packageJson.name + '/' + packageJson.version +
    ' Node.js/' + process.version.slice(1)
});

/** HTTPS Agent for online.swagger.io which can valididate the HTTPS
 * certificate lacking an intermediate.
 * See https://github.com/swagger-api/validator-badge/issues/98
 */
var swaggerIoHttpsAgent;

/** Adds our default HTTP Agent to the request options.
 * @private
 */
function getSwaggerIoAgent() {
  if (!swaggerIoHttpsAgent) {
    var certsPath = path.join(__dirname, 'certs');
    swaggerIoHttpsAgent = readdirP(certsPath)
      .then(function(certNames) {
        return Promise.all(
          certNames.map(function(certName) {
            var certPath = path.join(certsPath, certName);
            return readFileP(certPath, {encoding: 'utf8'});
          })
        );
      })
      .then(function(certs) {
        // Note: Using undocumented API to use both root and loaded certs.
        //       Specifying options.ca skips root certs, which could cause cert
        //       verification to fail if online.swagger.io changed certs.
        var secureContext = tls.createSecureContext();
        certs.forEach(function(cert) {
          secureContext.context.addCACert(cert);
        });
        return new https.Agent({
          keepAlive: true,
          secureContext: secureContext
        });
      });
  }

  return swaggerIoHttpsAgent;
}

/** Combines HTTP headers objects.
 * With the capitalization and value of the last occurrence.
 * @private
 */
function combineHeaders() {
  var combinedLower = {};
  var combined = {};
  var args = Array.prototype.slice.call(arguments);
  args.reverse();
  args.forEach(function(headers) {
    if (headers) {
      Object.keys(headers).forEach(function(name) {
        var nameLower = name.toLowerCase();
        if (!hasOwnProperty.call(combinedLower, nameLower)) {
          combinedLower[nameLower] = true;
          combined[name] = headers[name];
        }
      });
    }
  });
  return combined;
}

/** Makes an HTTP(S) request and parses the JSON response.
 * @private
 */
function requestJson(options, callback) {
  var proto = options.protocol === 'https:' ? https :
    options.protocol === 'http:' ? http :
    null;
  if (!proto) {
    callback(new Error('Unsupported protocol "' + options.protocol +
                       '" for validator URL'));
    return;
  }

  var req = proto.request(options)
    .once('error', callback)
    .once('response', function(res) {
      res.on('error', callback);
      var bodyData = [];
      res.on('data', function(data) { bodyData.push(data); });
      res.on('end', function() {
        var resBody = Buffer.concat(bodyData);
        var errBody, resBodyObj;
        try {
          resBodyObj = JSON.parse(resBody.toString());
        } catch (errJson) {
          errBody = new SyntaxError('Error parsing server response as JSON: ' +
                                    errJson.message);
        }

        if (res.statusCode >= 300) {
          var errMessage = 'HTTP ' + res.statusCode;
          if (res.statusMessage) {
            errMessage += ': ' + res.statusMessage;
          }
          var err = new Error(errMessage);
          err.statusCode = res.statusCode;
          err.statusMessage = res.statusMessage;
          err.headers = res.headers;
          err.trailers = res.trailers;
          err.body = resBodyObj !== undefined ? resBodyObj : resBody;
          callback(err);
        } else {
          callback(errBody, resBodyObj);
        }
      });
    });

  var body = options.body;
  if (typeof body === 'string' || Buffer.isBuffer(body)) {
    req.end(body);
  } else {
    body.on('error', function(err) {
      req.abort();
      callback(err);
    });
    body.pipe(req);
  }
}

/** Validation options
 *
 * @typedef {{
 *   err: (stream.Writable|undefined),
 *   request: (Object|undefined),
 *   verbosity: (number|undefined)
 * }} ValidateOptions
 * @property {stream.Writable=} err Stream to which errors (and non-output
 * status messages) are written. (default: process.stderr)
 * @property {Object=} request Options passed to http.request().
 * @property {number=} verbosity Amount of output to produce.  Larger numbers
 * produce more output.
 */
// var ValidateOptions;

/** Validates an OpenAPI/Swagger API specification.
 *
 * @param {string|!Buffer|!stream.Readable} spec OpenAPI/Swagger API
 * specification content.
 * @param {ValidateOptions=} options Validation options.
 * @param {?function(Error, Object=)=} callback Callback for the validation
 * results object.
 * @return {Promise<Object>|undefined} If callback is not given,
 * a Promise with the validation results or Error.
 */
function validate(spec, options, callback) {
  if (!callback && typeof options === 'function') {
    callback = options;
    options = null;
  }

  if (!callback) {
    return new Promise(function(resolve, reject) {
      validate(spec, options, function(err, result) {
        if (err) { reject(err); } else { resolve(result); }
      });
    });
  }

  if (typeof callback !== 'function') {
    throw new TypeError('callback must be a function');
  }

  try {
    if (spec === undefined ||
        spec === null ||
        (typeof spec !== 'string' &&
         !Buffer.isBuffer(spec) &&
         typeof spec.pipe !== 'function')) {
      throw new TypeError('spec must be a string, Buffer, or Readable');
    }

    if (options !== undefined && typeof options !== 'object') {
      throw new TypeError('options must be an object');
    }
  } catch (err) {
    process.nextTick(function() {
      callback(err);
    });
    return undefined;
  }

  var reqOpts = url.parse(DEFAULT_URL);
  reqOpts.method = 'POST';
  assign(reqOpts, options && options.request);
  reqOpts.headers = combineHeaders(DEFAULT_HEADERS, reqOpts.headers);
  reqOpts.body = spec;

  if (reqOpts.hostname === 'online.swagger.io' &&
      !hasOwnProperty.call(reqOpts, 'agent')) {
    getSwaggerIoAgent()
      .then(function(agent) {
        reqOpts.agent = agent;
        requestJson(reqOpts, callback);
      })
      .catch(callback);
  } else {
    requestJson(reqOpts, callback);
  }

  return undefined;
}

/** Validates an OpenAPI/Swagger API specification file.
 *
 * If not specified, the Content-Type header will be set for .json
 * and .yaml/.yml files.
 *
 * @param {string} specPath Path of OpenAPI/Swagger API specification file.
 * @param {ValidateOptions=} options Validation options.
 * @param {?function(Error, Object=)=} callback Callback for the validation
 * results object.
 * @return {Promise<Object>|undefined} If callback is not given,
 * a Promise with the validation results or Error.
 */
function validateFile(specPath, options, callback) {
  if (!callback && typeof options === 'function') {
    callback = options;
    options = null;
  }

  var headers = options && options.request && options.request.headers;
  var hasContentType = headers && Object.keys(headers).some(function(name) {
    return name.toLowerCase() === 'content-type';
  });
  if (!hasContentType) {
    // Server ignores Content-Type, so not worth depending on a Media Type db.
    var contentType = /\.json$/i.test(specPath) ? 'application/json' :
      /\.ya?ml$/i.test(specPath) ? 'text/x-yaml' :
      null;
    if (contentType) {
      options = assign({}, options);
      options.request = assign({}, options.request);
      options.request.headers = assign({}, options.request.headers);
      options.request.headers['Content-Type'] = contentType;
    }
  }

  var specStream = fs.createReadStream(specPath);
  return validate(specStream, options, callback);
}

module.exports = {
  DEFAULT_HEADERS: DEFAULT_HEADERS,
  DEFAULT_URL: DEFAULT_URL,
  validate: validate,
  validateFile: validateFile
};
<commit_msg>Include response properties on JSON errors<commit_after>/**
 * @copyright Copyright 2017 Kevin Locke <kevin@kevinlocke.name>
 * @license MIT
 */

'use strict';

var assign = require('object-assign');
var fs = require('fs');
var http = require('http');
var https = require('https');
var packageJson = require('./package.json');
var path = require('path');
var pify = require('pify');
var tls = require('tls');
var url = require('url');

var readFileP = pify(fs.readFile);
var readdirP = pify(fs.readdir);

/** Default URL to which validation requests are sent.
 * @const
 */
var DEFAULT_URL = 'https://online.swagger.io/validator/debug';

/** Default headers sent with API requests.
 * @const
 */
var DEFAULT_HEADERS = Object.freeze({
  Accept: 'application/json',
  'User-Agent': packageJson.name + '/' + packageJson.version +
    ' Node.js/' + process.version.slice(1)
});

/** HTTPS Agent for online.swagger.io which can valididate the HTTPS
 * certificate lacking an intermediate.
 * See https://github.com/swagger-api/validator-badge/issues/98
 */
var swaggerIoHttpsAgent;

/** Adds our default HTTP Agent to the request options.
 * @private
 */
function getSwaggerIoAgent() {
  if (!swaggerIoHttpsAgent) {
    var certsPath = path.join(__dirname, 'certs');
    swaggerIoHttpsAgent = readdirP(certsPath)
      .then(function(certNames) {
        return Promise.all(
          certNames.map(function(certName) {
            var certPath = path.join(certsPath, certName);
            return readFileP(certPath, {encoding: 'utf8'});
          })
        );
      })
      .then(function(certs) {
        // Note: Using undocumented API to use both root and loaded certs.
        //       Specifying options.ca skips root certs, which could cause cert
        //       verification to fail if online.swagger.io changed certs.
        var secureContext = tls.createSecureContext();
        certs.forEach(function(cert) {
          secureContext.context.addCACert(cert);
        });
        return new https.Agent({
          keepAlive: true,
          secureContext: secureContext
        });
      });
  }

  return swaggerIoHttpsAgent;
}

/** Combines HTTP headers objects.
 * With the capitalization and value of the last occurrence.
 * @private
 */
function combineHeaders() {
  var combinedLower = {};
  var combined = {};
  var args = Array.prototype.slice.call(arguments);
  args.reverse();
  args.forEach(function(headers) {
    if (headers) {
      Object.keys(headers).forEach(function(name) {
        var nameLower = name.toLowerCase();
        if (!hasOwnProperty.call(combinedLower, nameLower)) {
          combinedLower[nameLower] = true;
          combined[name] = headers[name];
        }
      });
    }
  });
  return combined;
}

/** Makes an HTTP(S) request and parses the JSON response.
 * @private
 */
function requestJson(options, callback) {
  var proto = options.protocol === 'https:' ? https :
    options.protocol === 'http:' ? http :
    null;
  if (!proto) {
    callback(new Error('Unsupported protocol "' + options.protocol +
                       '" for validator URL'));
    return;
  }

  var req = proto.request(options)
    .once('error', callback)
    .once('response', function(res) {
      res.on('error', callback);
      var bodyData = [];
      res.on('data', function(data) { bodyData.push(data); });
      res.on('end', function() {
        var resBody = Buffer.concat(bodyData);
        var err, resBodyObj;
        try {
          resBodyObj = JSON.parse(resBody.toString());
        } catch (errJson) {
          err = new SyntaxError('Error parsing server response as JSON: ' +
                                errJson.message);
        }

        if (res.statusCode >= 300) {
          var errMessage = 'HTTP ' + res.statusCode;
          if (res.statusMessage) {
            errMessage += ': ' + res.statusMessage;
          }
          err = new Error(errMessage);
        }

        if (err) {
          err.statusCode = res.statusCode;
          err.statusMessage = res.statusMessage;
          err.headers = res.headers;
          err.trailers = res.trailers;
          err.body = resBodyObj !== undefined ? resBodyObj : resBody;
          callback(err);
        } else {
          callback(null, resBodyObj);
        }
      });
    });

  var body = options.body;
  if (typeof body === 'string' || Buffer.isBuffer(body)) {
    req.end(body);
  } else {
    body.on('error', function(err) {
      req.abort();
      callback(err);
    });
    body.pipe(req);
  }
}

/** Validation options
 *
 * @typedef {{
 *   err: (stream.Writable|undefined),
 *   request: (Object|undefined),
 *   verbosity: (number|undefined)
 * }} ValidateOptions
 * @property {stream.Writable=} err Stream to which errors (and non-output
 * status messages) are written. (default: process.stderr)
 * @property {Object=} request Options passed to http.request().
 * @property {number=} verbosity Amount of output to produce.  Larger numbers
 * produce more output.
 */
// var ValidateOptions;

/** Validates an OpenAPI/Swagger API specification.
 *
 * @param {string|!Buffer|!stream.Readable} spec OpenAPI/Swagger API
 * specification content.
 * @param {ValidateOptions=} options Validation options.
 * @param {?function(Error, Object=)=} callback Callback for the validation
 * results object.
 * @return {Promise<Object>|undefined} If callback is not given,
 * a Promise with the validation results or Error.
 */
function validate(spec, options, callback) {
  if (!callback && typeof options === 'function') {
    callback = options;
    options = null;
  }

  if (!callback) {
    return new Promise(function(resolve, reject) {
      validate(spec, options, function(err, result) {
        if (err) { reject(err); } else { resolve(result); }
      });
    });
  }

  if (typeof callback !== 'function') {
    throw new TypeError('callback must be a function');
  }

  try {
    if (spec === undefined ||
        spec === null ||
        (typeof spec !== 'string' &&
         !Buffer.isBuffer(spec) &&
         typeof spec.pipe !== 'function')) {
      throw new TypeError('spec must be a string, Buffer, or Readable');
    }

    if (options !== undefined && typeof options !== 'object') {
      throw new TypeError('options must be an object');
    }
  } catch (err) {
    process.nextTick(function() {
      callback(err);
    });
    return undefined;
  }

  var reqOpts = url.parse(DEFAULT_URL);
  reqOpts.method = 'POST';
  assign(reqOpts, options && options.request);
  reqOpts.headers = combineHeaders(DEFAULT_HEADERS, reqOpts.headers);
  reqOpts.body = spec;

  if (reqOpts.hostname === 'online.swagger.io' &&
      !hasOwnProperty.call(reqOpts, 'agent')) {
    getSwaggerIoAgent()
      .then(function(agent) {
        reqOpts.agent = agent;
        requestJson(reqOpts, callback);
      })
      .catch(callback);
  } else {
    requestJson(reqOpts, callback);
  }

  return undefined;
}

/** Validates an OpenAPI/Swagger API specification file.
 *
 * If not specified, the Content-Type header will be set for .json
 * and .yaml/.yml files.
 *
 * @param {string} specPath Path of OpenAPI/Swagger API specification file.
 * @param {ValidateOptions=} options Validation options.
 * @param {?function(Error, Object=)=} callback Callback for the validation
 * results object.
 * @return {Promise<Object>|undefined} If callback is not given,
 * a Promise with the validation results or Error.
 */
function validateFile(specPath, options, callback) {
  if (!callback && typeof options === 'function') {
    callback = options;
    options = null;
  }

  var headers = options && options.request && options.request.headers;
  var hasContentType = headers && Object.keys(headers).some(function(name) {
    return name.toLowerCase() === 'content-type';
  });
  if (!hasContentType) {
    // Server ignores Content-Type, so not worth depending on a Media Type db.
    var contentType = /\.json$/i.test(specPath) ? 'application/json' :
      /\.ya?ml$/i.test(specPath) ? 'text/x-yaml' :
      null;
    if (contentType) {
      options = assign({}, options);
      options.request = assign({}, options.request);
      options.request.headers = assign({}, options.request.headers);
      options.request.headers['Content-Type'] = contentType;
    }
  }

  var specStream = fs.createReadStream(specPath);
  return validate(specStream, options, callback);
}

module.exports = {
  DEFAULT_HEADERS: DEFAULT_HEADERS,
  DEFAULT_URL: DEFAULT_URL,
  validate: validate,
  validateFile: validateFile
};
<|endoftext|>


<commit_before>
var util = require("util");
var mdeps = require('module-deps');
var concatStream = require('concat-stream');
var EventEmitter = require("events").EventEmitter;

function BundleManager(bundles) {
    var self = this;

    // Wrap bundles to objects containing modules
    this.bundles = bundles.map(function(bundle) {
        var bWrap = { bundle: bundle };
        self.resolveModules(bWrap);
        return bWrap;
    });

}

util.inherits(BundleManager, EventEmitter);

/**
 * Find out all dependencies of a bundle
 **/
BundleManager.prototype.resolveModules = function(bWrap) {
    var self = this;

    if (bWrap.bundle._pending === 0) {
        // Dependencies can be resolved only when bundle.files is populated
        mdeps(bWrap.bundle.files).pipe(concatStream(function(err, modules) {
            bWrap.modules = modules;
            if (self.areModulesReady()) self.emit("modules-ready");
        }));
    }
    else {
        // If not ready wait until it is
        bWrap.bundle.once("_ready", this.resolveModules.bind(this, bWrap));
    }
};

BundleManager.prototype.areModulesReady = function() {
    return this.bundles.every(function(bWrap) {
        return bWrap.modules;
    });
};

BundleManager.prototype.externalize = function(_cb) {

    if (!this.areModulesReady()) {
        return this.once("modules-ready", this.externalize.bind(this, _cb));
    }

    // Make sure the callback is called only once
    var cb = function(err) {
        _cb(err);
        _cb = function() {};
    };

    this.on("error", cb);

    var parent = this.bundles[0].bundle;
    var parentModules = this.bundles[0].modules;
    var externals = this.bundles.slice(1);

    externals.forEach(function(ext) {

        // Create tree of parent modules without the external bundle modules
        var filteredParent = parentModules.filter(function(parentDep) {
            return !ext.modules.some(function(extModule) {
                return parentDep.id === extModule.id;
            });
        });

        // Walk through each in the external bundle
        ext.modules.forEach(function(extModule) {

            // Whether the parent bundle has a require call to this module
            var parentDepends = filteredParent.some(function(parentModule) {
                return Object.keys(parentModule.deps).some(function(depKey) {
                    return parentModule.deps[depKey] === extModule.id;
                });
            });

            if (parentDepends && !ext.bundle.exports[extModule.id]) {
                // Shared module:
                // Parent and the external bundle uses this  module. Make it
                // requireable from the parent bundle and remove it from the
                // external bundle.
                parent.require(extModule.id);
                ext.bundle.external(extModule.id);
            }
            else {
                // Explicitly external bundle:
                // User marked this module as requireable on the external
                // bundle using `externalBundle.require(module)`. Remove
                // the module from the parent bundle even if it has a
                // require call to it. That require call will start working
                // again when this external bundle is added to the dom.
                // This will also remove all inner dependencies of the
                // external module from the parent bundle.
                parent.external(extModule.id);
            }
        });
    });

    cb();
};

module.exports = function(parent, externals, cb) {
    var bm = new BundleManager([parent].concat(externals));
    // var bm = new BundleManager(parent, [].concat(externals));
    bm.externalize(cb);
};

<commit_msg>Emit error from mdeps<commit_after>
var util = require("util");
var mdeps = require('module-deps');
var concatStream = require('concat-stream');
var EventEmitter = require("events").EventEmitter;

function BundleManager(bundles) {
    var self = this;

    // Wrap bundles to objects containing modules
    this.bundles = bundles.map(function(bundle) {
        var bWrap = { bundle: bundle };
        self.resolveModules(bWrap);
        return bWrap;
    });

}

util.inherits(BundleManager, EventEmitter);

BundleManager.prototype.resolveModules = function(bWrap) {
    var self = this;

    if (bWrap.bundle._pending === 0) {
        // Dependencies can be resolved only when bundle.files is populated
        mdeps(bWrap.bundle.files).pipe(concatStream(function(err, modules) {
            if (err) return self.emit("error", err);
            bWrap.modules = modules;
            if (self.areModulesReady()) self.emit("modules-ready");
        }));
    }
    else {
        // If not ready wait until it is
        bWrap.bundle.once("_ready", this.resolveModules.bind(this, bWrap));
    }
};

BundleManager.prototype.areModulesReady = function() {
    return this.bundles.every(function(bWrap) {
        return bWrap.modules;
    });
};

BundleManager.prototype.externalize = function(_cb) {

    if (!this.areModulesReady()) {
        return this.once("modules-ready", this.externalize.bind(this, _cb));
    }

    // Make sure the callback is called only once
    var cb = function(err) {
        _cb(err);
        _cb = function() {};
    };

    this.on("error", cb);

    var parent = this.bundles[0].bundle;
    var parentModules = this.bundles[0].modules;
    var externals = this.bundles.slice(1);

    externals.forEach(function(ext) {

        // Create tree of parent modules without the external bundle modules
        var filteredParent = parentModules.filter(function(parentDep) {
            return !ext.modules.some(function(extModule) {
                return parentDep.id === extModule.id;
            });
        });

        // Walk through each in the external bundle
        ext.modules.forEach(function(extModule) {

            // Whether the parent bundle has a require call to this module
            var parentDepends = filteredParent.some(function(parentModule) {
                return Object.keys(parentModule.deps).some(function(depKey) {
                    return parentModule.deps[depKey] === extModule.id;
                });
            });

            if (parentDepends && !ext.bundle.exports[extModule.id]) {
                // Shared module:
                // Parent and the external bundle uses this  module. Make it
                // requireable from the parent bundle and remove it from the
                // external bundle.
                parent.require(extModule.id);
                ext.bundle.external(extModule.id);
            }
            else {
                // Explicitly external bundle:
                // User marked this module as requireable on the external
                // bundle using `externalBundle.require(module)`. Remove
                // the module from the parent bundle even if it has a
                // require call to it. That require call will start working
                // again when this external bundle is added to the dom.
                // This will also remove all inner dependencies of the
                // external module from the parent bundle.
                parent.external(extModule.id);
            }
        });
    });

    cb();
};

module.exports = function(parent, externals, cb) {
    var bm = new BundleManager([parent].concat(externals));
    // var bm = new BundleManager(parent, [].concat(externals));
    bm.externalize(cb);
};

<|endoftext|>


<commit_before>module.exports = require('./lib/index');
<commit_msg>added export<commit_after>module.exports = require('./lib/index');<|endoftext|>


<commit_before>var re_commas = /,\s*/g,
	re_whitespace = /\s+/,
	re_name = /^(?:[\w\-]|\\.)+/, //https://github.com/jquery/sizzle/blob/master/sizzle.js#L378 /^(?:[\w\u00c0-\uFFFF\-]|\\.)+/
	re_par = /\(.*?\)/,
	re_cleanSelector = / *([>~+]) */g,
	base = function(){ console.log("success"); return true; },
	filters = {
		not: function(next, select){
			var func = parse(select.trim());
			return function(elem){
				if(!func(elem)) return next(elem);
			}
		},
		root: function(next){
			return function(elem){
				if(!elem.parent) return next(elem);
			};
		},
		empty: function(next){
			return function(elem){
				if(!elem.children) return next(elem);
			};
		},
		"only-child": function(next){
			return function(elem){
				if(elem.parent && elem.parent.children.length === 1) return next(elem);
			};
		}/*,
		"nth-child": function(next, num){
			// TODO
			return next;
		}*/
	};

var parse = function(selector){
	if(re_commas.test(selector)){
		selector = selector.split(re_commas).map(parse);
		var num = selector.length;
		return function(element){
			for(var i = 0; i < num; i++){
				if(selector[i](element)) return true;
			}
		};
	}

	selector = selector.trim().replace(re_whitespace, " ").replace(re_cleanSelector, "$1")

	var result = base;

	while(selector !== "") result = walk(result);

	function getName(){
		var sub = selector.match(re_name)[0];
		selector = selector.substr(sub.length);
		return sub;
	}

	function walk(next){
		var firstChar = selector.charAt(0), sub, subselect, regex, bool;
		if(re_name.test(selector)){
			sub = getName();
			return function(elem){
				if(elem.name === sub) return next(elem);
			}
		}
		selector = selector.substr(1);
		if(firstChar === "*") return next;
		if(firstChar === "."){
			regex = new RegExp("(?:^|\\s)"+getName()+"(?:$|\\s)"); //same as [class~=xy]
			return function(elem){
				if(regex.test(elem.attribs["class"])) return next(elem);
			}
		}
		if(firstChar === "#"){
			sub = getName();
			return function(elem){
				if(elem.attribs["id"] === sub) return next(elem);
			}
		}
		if(firstChar === " "){
			return function(elem){
				for(var parent; parent = elem.parent;){
					if(next(parent)) return true;
				}
			};
		}
		if(firstChar === ">"){
			return function(elem){
				if(elem.parent) return next(elem.parent);
			}
		}
		if(firstChar === "+"){
			return function(elem){
				if(elem.parent && elem.parent.children){
					for(var i = 0, j = elem.parent.children.length; i < j; i++){
						if(elem === elem.parent.children[i]) continue;
						if(next(elem.parent.children[i])) return true;
					}
				}
			};
		}
		if(firstChar === "~"){
			return function(elem){
				if(!elem.parent || !elem.parent.children) return;
				var index = elem.parent.children.indexOf(elem);
				while(--index !== -1){
					if(next(elem.parent.children[index])) return true;
				}
			};
		}
		if(firstChar === ":"){
			if(selector.charAt(0) === ":"){
				//pseudo-element
				// TODO
			}
			sub = getName();
			if(selector.charAt(0) === "("){
				subselect = selector.substring(1, selector.indexOf(")", 2));
				selector = selector.substr(subselect.length + 2);
			}
			if(sub in filters) return filters[sub](next, subselect);
			else return next;
		}
		if(firstChar === "["){
			selector = selector.trimLeft();
			sub = getName();
			firstChar = selector.charAt(0);

			if(firstChar === " "){
				firstChar = selector.charAt(1);
				selector = selector.substr(2);
			}
			else selector = selector.substr(1);

			if(firstChar === "]"){
				return function(elem){
					if(sub in elem.attribs) return next(elem);
				};
			}

			subselect = selector.substr(0, selector.indexOf("]")).trim();
			selector = selector.substr(subselect.length + 1);

			if(subselect.substr(-2) === " i"){
				bool = true;
				subselect = subselect.slice(0, -2);
			}

			if(firstChar === "="){
				firstChar = subselect.charAt(0);
				if(firstChar === "\"" || firstChar === "'") subselect = subselect.slice(1, -1);
				return function(elem){
					if(elem.attribs[sub] === subselect) return next(elem);
				};
			}

			if(subselect.charAt(0) !== "="){
				//ignore it
				return next;
			}

			if(subselect.charAt(1) === "\"" || subselect.charAt(1) === "'"){
				subselect = subselect.slice(2, -1);
			} else {
				subselect = subselect.substr(1).trim();
			}

				 if(firstChar === "|") subselect = "^"+subselect+"(?:$|-)";
			else if(firstChar === "~") subselect = "(?:^|\\s)"+subselect+"(?:$|\\s)";
			else if(firstChar === "^") subselect = "^"+subselect;
			else if(firstChar === "$") subselect = subselect + "$";
			else if(firstChar === "*") /*subselect = subselect*/;
			else throw Error("op not supported: " + firstChar);

			if(bool) regex = new RegExp(subselect, "i");
			else regex = new RegExp(subselect);

			return function(elem){
				if(sub in elem.attribs && regex.test(elem.attribs[sub])) return next(elem);
			};
		}
		//if nothing was matched, throw an error (otherwise, the parser would enter a loop)
		throw Error("unmatched selector: " + firstChar + selector);
	}
	return result;
}

if(typeof module === "object") module.exports = parse;<commit_msg>Restructured code, made it modal<commit_after>var re_commas = /,\s*/g,
    re_whitespace = /\s+/,
    re_name = /^(?:[\w\-]|\\.)+/, //https://github.com/jquery/sizzle/blob/master/sizzle.js#L378 /^(?:[\w\u00c0-\uFFFF\-]|\\.)+/
    re_par = /\(.*?\)/,
    re_cleanSelector = / *([>~+]) */g,
    filters = {
        not: function(next, select){
        	var func = (new Parser(select, next)).getFunc();
        	return function(elem){
        		if(!func(elem)) return next;
        	};
        },
        root: function(next){
        	return function(elem){
        		if(!elem.parent) return next(elem);
        	};
        },
        empty: function(next){
        	return function(elem){
        		if(!elem.children || elem.children.length === 0) return next(elem);
        	};
        },
        "only-child": function(next){
        	return function(elem){
        		if(elem.parent && elem.parent.children.length === 1) return next(elem);
        	};
        }/*,
        "nth-child": function(next, num){
        	// TODO
        	return next;
        }*/
    };

var parse = function(selector, cb){
	if(re_commas.test(selector)){
		//TODO move this to the parser
		selector = selector.split(re_commas).map(parse);
		var num = selector.length;
		return function(elem){
			for(var i = 0; i < num; i++){
				if(selector[i](elem)) return cb ? cb(elem) : true;
			}
		};
	}

	var p = new Parser(selector, cb);
	return p.getFunc();
}

var Parser = function(selector, cb){
	this._selector = selector;
	if(typeof cb === "function") this.func = cb;

	this._clean();
	this._parse();
};

Parser.prototype.func = function(){ return true; };

Parser.prototype.getFunc = function(){
	return this.func;
};

Parser.prototype._clean = function(selector){
	this._selector = this._selector
		.trim()
		.replace(re_whitespace, " ")
		.replace(re_cleanSelector, "$1");
};

Parser.prototype._parse = function(){
	var firstChar;
	while(this._selector !== ""){
		if(re_name.test(this._selector)){
			this._processTag();
		} else {
			firstChar = this._selector.charAt(0);
			this._selector = this._selector.substr(1);
			switch(firstChar){
				case "*": continue; //+
				case "#": this._processId(); break; //+
				case "+": this._processPlus(); break; //+
				case ".": this._processClass(); break; //+
				case " ": this._processSpace(); break; //+
				case "~": this._processTilde(); break; //+
				case ":": this._processColon(); break; //+
				case ">": this._processArrow(); break; //+
				case "[": this._processBracket(); break;
				//otherwise, the parser needs to throw or it would enter a loop
				default: throw Error("Unmatched selector:" + firstChar + this._selector);
			}
		}
	}
};

Parser.prototype._getName = function(){
	var sub = this._selector.match(re_name)[0];
	this._selector = this._selector.substr(sub.length);
	return sub;
};

Parser.prototype._processTag = function(){
	var next = this.func, name = this._getName();
	this.func = function(elem){
		if(elem.name === name) return next(elem);
	};
};

Parser.prototype._processClass = function(){
	this._matchElement("class", this._getName(), false);
};

Parser.prototype._matchElement = function(name, value, ignoreCase){
	this._buildRe(name, "(?:^|\\s)" + value + "(?:$|\\s)", ignoreCase)
};

Parser.prototype._processId = function(){
	this._matchExact("id", this._getName(), false);
};

Parser.prototype._matchExact = function(name, value, ignoreCase){
	this._buildRe(name, "^" + value + "$", ignoreCase);
};

Parser.prototype._buildRe = function(name, value, ignoreCase){
	var next = this.func,
	    regex = ignoreCase ? new RegExp(value, "i") : new RegExp(value);
	this.func = function(elem){
		if(name in elem.attribs && regex.test(elem.attribs[name])) return next(elem);
	};
};

Parser.prototype._processColon = function(){
	var next = this.func, name = this._getName(), subselect;

	/*if(selector.charAt(0) === ":"){
    	//pseudo-element
    	// TODO
    }*/

    if(this._selector.charAt(0) === "("){
    	subselect = this._selector.substring(1, this._selector.indexOf(")", 2));
    	this._selector = this._selector.substr(subselect.length + 2);
    }
    if(name in filters) this.func = filters[name](next, subselect);
};

Parser.prototype._processPlus = function(){
	var next = this.func;

	this.func = function(elem){
	    if(elem.parent && elem.parent.children){
	    	for(var i = 0, j = elem.parent.children.length; i < j; i++){
	    		if(elem === elem.parent.children[i]) continue;
	    		if(next(elem.parent.children[i])) return true;
	    	}
	    }
	};
};

Parser.prototype._processSpace = function(){
	var next = this.func;

	this.func = function(elem){
	    for(var parent; parent = elem.parent;){
	    	if(next(parent)) return true;
	    }
	};
};

Parser.prototype._processArrow = function(){
	var next = this.func;

	this.func = function(elem){
		if(elem.parent) return next(elem.parent);
	}
};

Parser.prototype._processTilde = function(){
	this.func = function(elem){
		if(!elem.parent || !elem.parent.children) return;
	    var index = elem.parent.children.indexOf(elem);
	    while(--index !== -1){
	    	if(next(elem.parent.children[index])) return true;
	    }
	};
}

Parser.prototype._processBracket = function(){
	var next = this.func;

	if(this._selector.charAt(0) === " ") this._selector = this._selector.substr(1);

	var name = this._getName(),
	    action = this._selector.charAt(0);

	if(action === " "){
		action = this._selector.charAt(1);
		this._selector = this._selector.substr(2);
	}
	else this._selector = this._selector.substr(1);

	if(action === "]"){
		return function(elem){
			if(name in elem.attribs) return next(elem);
		};
	}

	var value = this._selector.substr(0, this._selector.indexOf("]"));
	this._selector = this._selector.substr(value.length + 1);

	value = value.trim();

	if(action !== "="){
	    if(value.charAt(0) !== "=") return;
	    if(value.charAt(1) === " ") value = value.substr(2);
	    else value = value.substr(1)
	} else {
		if(value.charAt(1) === " ") value = value.substr(1);
	}

	var i = value.substr(-2) === " i";
	if(i) value = value.slice(0, -2);

	if(value.charAt(0) === "\"") value = value.substr(1, value.indexOf("\"", 1));
	if(value.charAt(0) === "\'") value = value.substr(1, value.indexOf("\'", 1));

	switch(action){
		case "=": return this._matchExact(name, value, i);
		case "~": return this._matchElement(name, value, i);
		case "*": return this._buildRe(name, value, i);
		case "$": return this._buildRe(name, value + "$", i);
		case "^": return this._buildRe(name, "^" + value, i);
		case "|": return this._buildRe(name, "^" + value + "(?:$|-)", i);
		default: return; // ignore it
	}
};

if(typeof module === "object") module.exports = parse;<|endoftext|>


<commit_before>/**
 * The authenticate module is responsible to getting the authorization header from the request and attaching
 * the token to the request. If the credentials are not supplied then the request should fail and not proceed
 * any further.
 *
 */
var authToken = function(httpRequest, httpResponse, next){
    'use strict';

    var Strings = require('../Strings'),
        Response = require('../Response'),
        strings = new Strings('en'),
        response = new Response(httpResponse);

    if(!httpRequest.bridgetown){
        httpRequest.bridgetown = {};
    }

    function setIdentity(identity){
        httpRequest.bridgetown.identity = identity;
        next();
    }

    function setUnauthorized(err){
        err = new Error(strings.group('errors').unauthorized);
        err.errorCode = Response.statusCodes.unauthorized;

        response.writeError(err);
    }

    if(authToken.validate) {
        authToken.validate(httpRequest.bridgetown.token).then(setIdentity).fail(setUnauthorized);
    }
};

module.exports = authToken;<commit_msg>Updating Auth Token to return full bridgetown obj.<commit_after>/**
 * The authenticate module is responsible to getting the authorization header from the request and attaching
 * the token to the request. If the credentials are not supplied then the request should fail and not proceed
 * any further.
 *
 */
var authToken = function(httpRequest, httpResponse, next){
    'use strict';

    var Strings = require('../Strings'),
        Response = require('../Response'),
        strings = new Strings('en'),
        response = new Response(httpResponse);

    if(!httpRequest.bridgetown){
        httpRequest.bridgetown = {};
    }

    function setIdentity(identity){
        httpRequest.bridgetown.identity = identity;
        next();
    }

    function setUnauthorized(err){
        err = new Error(strings.group('errors').unauthorized);
        err.errorCode = Response.statusCodes.unauthorized;

        response.writeError(err);
    }

    if(authToken.validate) {
        authToken.validate({
            token: httpRequest.bridgetown.token,
            method: httpRequest.bridgetown.method
        }).then(setIdentity).fail(setUnauthorized);
    }
};

module.exports = authToken;<|endoftext|>


<commit_before>/**
 * Author: Jeff Whelpley
 * Date: 10/19/14
 *
 * This module is used to render a page with jangular
 */
var Q           = require('q');
var _           = require('lodash');
var jangular    = require('jangular');

/**
 * Get a particular layout
 * @param appName
 * @param layoutName
 * @param dependencies
 */
function renderLayout(appName, layoutName, dependencies) {
    var layout = this.pancakes.cook('app/' + appName + '/layouts/' + layoutName + '.layout');
    var layoutView = this.pancakes.cook(layout.view, { dependencies: dependencies });
    return jangular.render(layoutView, dependencies.model, { strip: false });
}

/**
 * Render sideview
 *
 *     TODO: these fns are in jng.directives. need to refactor to make this NOT a class
 *
 * @param appName
 * @param initialModel
 * @param routeInfo
 */
function renderSideview(appName, initialModel, routeInfo) {
    var sideviewName = routeInfo.sideview || 'default';
    var sideview = this.pancakes.cook('app/' + appName + '/partials/' + appName +
                                        '.sideview.' + sideviewName + '.partial');
    var me = this;

    var modelDeps = {
        currentScope:   sideview.defaults || {},
        initialModel:   initialModel,
        routeInfo:      routeInfo
    };

    // call the sideview model allowing it to make another database call
    return Q.when(this.pancakes.cook(sideview.model, { dependencies: modelDeps }))
        .then(function (model) {

            // this is similar to both jng.pages renderPage() and jng.directives
            // as well as ng.uipart.template (for client side pages and partials)
            me.attachToScope(model, sideview.attachToScope);

            // generate the partial view
            var viewDeps = { model: model, subviews: me.getSubviews(sideview.subviews) };
            _.extend(viewDeps, me.getJangularDeps());
            var view = me.pancakes.cook(sideview.view, { dependencies: viewDeps });
            return jangular.render(view, model, { strip: routeInfo.strip });
        });
}

/**
 * Render the page. There are 4 potentially levels of rendering that goes
 * on in order to render one page:
 *      1) Subviews - The lowest level; get rolled up to the view
 *      2) View - The main page content
 *      3) Layout - View gets rolled up into a layout
 *      4) Wrapper - Layout or View can get rolled up into a wrapper
 *
 * Note: layouts and wrappers are essentially the same but as a matter of practice
 * we are limiting it to those two levels of rollups. Any other depth on the page
 * is taken care of by subcomponents (i.e. directives)
 *
 * @param routeInfo
 * @param page
 * @param model
 * @returns {*}
 */
function renderPage(routeInfo, page, model) {
    var subviews = {};
    var appName = routeInfo.appName;
    var jangularDeps = this.getJangularDeps();
    var isLayout = routeInfo.layout && routeInfo.layout !== 'none' &&
        routeInfo.wrapper && routeInfo.wrapper !== 'none';

    // passing in model with two diff aliases for diff situations
    // initialModel used by sideview to designate value from page model
    var pageDeps = _.extend({ model: model, routeInfo: routeInfo }, jangularDeps);
    var me = this;

    // sideview may make an additional database call, so need to call async
    return this.renderSideview(appName, model, routeInfo)
        .then(function (sideview) {

            // make some angular-specific modifications to the model before we render
            me.setDefaults(model, page.defaults, null);
            me.applyPresets(model, page.defaults, page.presets);
            me.attachToScope(model, page.attachToScope);
            me.addFiltersToModel(model, routeInfo.appName);

            // if any subviews, put them in an object
            _.each(page.subviews, function (subview, subviewName) {
                subviews[subviewName] = me.pancakes.cook(subview, { dependencies: jangularDeps });
            });

            // get the view
            _.extend(pageDeps, jangularDeps, { subviews: subviews });
            var view = me.pancakes.cook(page.view, { dependencies: pageDeps });
            var renderedPage = jangular.render(view, model, { strip: routeInfo.strip });

            // if layout exists, need to put the page content within the layout
            if (isLayout) {
                _.extend(pageDeps, { pageContent: renderedPage, sideviewContent: sideview });
                renderedPage = me.renderLayout(appName, routeInfo.layout, pageDeps);
            }

            // if page wrapper exists, put rendered page in that
            if (isLayout) {
                _.extend(pageDeps, { pageContent: renderedPage, routeInfo: routeInfo });
                renderedPage = me.renderLayout(appName, routeInfo.wrapper, pageDeps);
            }

            return renderedPage;
        });
}

// expose functions
module.exports = {
    renderLayout: renderLayout,
    renderPage: renderPage,
    renderSideview: renderSideview
};
<commit_msg>Fix for activeUser on server for sideview<commit_after>/**
 * Author: Jeff Whelpley
 * Date: 10/19/14
 *
 * This module is used to render a page with jangular
 */
var Q           = require('q');
var _           = require('lodash');
var jangular    = require('jangular');

/**
 * Get a particular layout
 * @param appName
 * @param layoutName
 * @param dependencies
 */
function renderLayout(appName, layoutName, dependencies) {
    var layout = this.pancakes.cook('app/' + appName + '/layouts/' + layoutName + '.layout');
    var layoutView = this.pancakes.cook(layout.view, { dependencies: dependencies });
    return jangular.render(layoutView, dependencies.model, { strip: false });
}

/**
 * Render sideview
 *
 *     TODO: these fns are in jng.directives. need to refactor to make this NOT a class
 *
 * @param appName
 * @param initialModel
 * @param routeInfo
 */
function renderSideview(appName, initialModel, routeInfo) {
    var sideviewName = routeInfo.sideview || 'default';
    var sideview = this.pancakes.cook('app/' + appName + '/partials/' + appName +
                                        '.sideview.' + sideviewName + '.partial');
    var me = this;

    var user = initialModel && initialModel.user;
    var activeUser = user ? {
        _id: user._id,
        name: user.username,
        role: user.role,
        user: user
    } : {};

    var modelDeps = {
        currentScope:   sideview.defaults || {},
        initialModel:   initialModel,
        routeInfo:      routeInfo,
        activeUser:     activeUser
    };

    // call the sideview model allowing it to make another database call
    return Q.when(this.pancakes.cook(sideview.model, { dependencies: modelDeps }))
        .then(function (model) {

            // this is similar to both jng.pages renderPage() and jng.directives
            // as well as ng.uipart.template (for client side pages and partials)
            me.attachToScope(model, sideview.attachToScope);

            // generate the partial view
            var viewDeps = { model: model, subviews: me.getSubviews(sideview.subviews) };
            _.extend(viewDeps, me.getJangularDeps());
            var view = me.pancakes.cook(sideview.view, { dependencies: viewDeps });
            return jangular.render(view, model, { strip: routeInfo.strip });
        });
}

/**
 * Render the page. There are 4 potentially levels of rendering that goes
 * on in order to render one page:
 *      1) Subviews - The lowest level; get rolled up to the view
 *      2) View - The main page content
 *      3) Layout - View gets rolled up into a layout
 *      4) Wrapper - Layout or View can get rolled up into a wrapper
 *
 * Note: layouts and wrappers are essentially the same but as a matter of practice
 * we are limiting it to those two levels of rollups. Any other depth on the page
 * is taken care of by subcomponents (i.e. directives)
 *
 * @param routeInfo
 * @param page
 * @param model
 * @returns {*}
 */
function renderPage(routeInfo, page, model) {
    var subviews = {};
    var appName = routeInfo.appName;
    var jangularDeps = this.getJangularDeps();
    var isLayout = routeInfo.layout && routeInfo.layout !== 'none' &&
        routeInfo.wrapper && routeInfo.wrapper !== 'none';

    // passing in model with two diff aliases for diff situations
    // initialModel used by sideview to designate value from page model
    var pageDeps = _.extend({ model: model, routeInfo: routeInfo }, jangularDeps);
    var me = this;

    // sideview may make an additional database call, so need to call async
    return this.renderSideview(appName, model, routeInfo)
        .then(function (sideview) {

            // make some angular-specific modifications to the model before we render
            me.setDefaults(model, page.defaults, null);
            me.applyPresets(model, page.defaults, page.presets);
            me.attachToScope(model, page.attachToScope);
            me.addFiltersToModel(model, routeInfo.appName);

            // if any subviews, put them in an object
            _.each(page.subviews, function (subview, subviewName) {
                subviews[subviewName] = me.pancakes.cook(subview, { dependencies: jangularDeps });
            });

            // get the view
            _.extend(pageDeps, jangularDeps, { subviews: subviews });
            var view = me.pancakes.cook(page.view, { dependencies: pageDeps });
            var renderedPage = jangular.render(view, model, { strip: routeInfo.strip });

            // if layout exists, need to put the page content within the layout
            if (isLayout) {
                _.extend(pageDeps, { pageContent: renderedPage, sideviewContent: sideview });
                renderedPage = me.renderLayout(appName, routeInfo.layout, pageDeps);
            }

            // if page wrapper exists, put rendered page in that
            if (isLayout) {
                _.extend(pageDeps, { pageContent: renderedPage, routeInfo: routeInfo });
                renderedPage = me.renderLayout(appName, routeInfo.wrapper, pageDeps);
            }

            return renderedPage;
        });
}

// expose functions
module.exports = {
    renderLayout: renderLayout,
    renderPage: renderPage,
    renderSideview: renderSideview
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Mitbbs-bot-blocker
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  Manages and blocks bot generated content. Inspired by Smalltalk80's original GM script, http://userscripts-mirror.org/scripts/review/78633
// @author       术版小吃
// @match        http://www.mitbbs.com/*
// @match        https://www.mitbbs.com/*
// @grant        GM_addStyle
// ==/UserScript==

const storageKey = 'mitbbs.blocklist'

function getBlocklist () {
  let blockList = localStorage.getItem(storageKey)
  if (blockList === null) {
    setBlocklist([])
    blockList = localStorage.getItem(storageKey)
  }
  return JSON.parse(blockList)
}

function setBlocklist (idNameList) {
  // remove duplicate items
  idNameList = [...new Set(idNameList)]
  localStorage.setItem(storageKey, JSON.stringify(idNameList))
}

function getBlockFlag () {
  let blockFlag = localStorage.getItem(storageKey + '.flag')
  if (blockFlag === null) {
    setBlockFlag(0)
    blockFlag = localStorage.getItem(storageKey + '.flag')
  }
  //  js, just being js
  return parseInt(blockFlag)
}

function setBlockFlag (flag) {
  localStorage.setItem(storageKey + '.flag', flag)
}

function changePostVisibility () {
  let blockList = getBlocklist()
  let flag = getBlockFlag()
  // if list is not empty
  let counter = 0
  if (blockList) {
    let taolunDiv = document.querySelector('td.taolun_leftright tbody')
    // yeah yeah yeah magic number, whatever
    // this will miss the first one though, nice try langfang coder
    let userIDtdNodeList = taolunDiv.querySelectorAll('td:nth-child(5)')
    userIDtdNodeList.forEach(function (td) {
      // damn, now i miss jquery/zepto
      let id = td.querySelector('a.news') ? td.querySelector('a.news').innerHTML : null
      //  yeah, nested if statements
      if (blockList.indexOf(id) > -1) {
        if (flag) {
          td.parentNode.style.display = 'none'
          counter += 1
        } else {
          td.parentNode.style.display = ''
        }
      }
    })
    counter = flag ? counter : 0
    document.getElementById('blockCounter').innerHTML = counter
  }
}

function toggleBlockedContent () {
  document.getElementById('isBlocking').checked ? setBlockFlag(1) : setBlockFlag(0)
  changePostVisibility()
}

function changeBlockListVisibility () {
  let notVisible = document.getElementById('blockListPop').style.display === 'none'
  if (notVisible) {
    document.getElementById('blockListInput').value = getBlocklist().join()
    document.getElementById('blockListPop').style.display = ''
  } else {
    document.getElementById('blockListPop').style.display = 'none'
  }
}

function updateBlockList () {
  let newBlockList = document.getElementById('blockListInput').value
  //  remove line break, space, trailing comma
  newBlockList = newBlockList.replace(/(\r\n|\n|\r)/gm, '').replace(/\s/g, '').replace(/,+$/, '')
  newBlockList = newBlockList.split(',')
  setBlocklist(newBlockList)

  // re-filter existing content
  toggleBlockedContent()
}

function hideBlockList () {
  document.getElementById('blockListPop').style.display = 'none'
}

function prepPage () {
  if (getBlockFlag()) {
    document.getElementById('isBlocking').checked = true
    toggleBlockedContent()
  }
}

function pageOnLoad () {
  let baseUrl = window.location.href
  let isArticlePage = baseUrl.indexOf('article') > -1
  //  build blocker control gui
  let blockerDiv = document.createElement('div')
  blockerDiv.innerHTML = '<button id="showBlocklist">黑名单</button><input type="checkbox" id="isBlocking" />'
  blockerDiv.style.cssText = 'position:fixed; bottom:2em; right:0.5em; width:9em; padding:0.5em; border-radius:0.25em; background-color:#D7EAF9; box-shadow:2px 2px 4px 0px rgba(0,0,0,0.5); text-align:center; cursor:pointer;'
  document.body.appendChild(blockerDiv)

  document.getElementById('showBlocklist').addEventListener('click', changeBlockListVisibility)
  document.getElementById('blockCounter').style.cssText = 'padding:0 4px; font-weight:bold'
  document.getElementById('isBlocking').addEventListener('change', toggleBlockedContent)

  //  block list
  let blockListDiv = document.createElement('div')
  blockListDiv.setAttribute('id', 'blockListPop')
  blockListDiv.innerHTML = '修改ID，用逗号分隔,大小写敏感！' +
    '
' +
    '<textarea rows="10" cols="40" id="blockListInput"></textarea>' +
    '
' +
    '<button id="updateBlockList">Update</button><button id="closePop">Close</button>'
  blockListDiv.style.cssText = 'position:fixed; bottom:5.3em; right:0.5em; padding:0.5em; border-radius:0.25em; background-color:#D7EAF9; box-shadow:2px 2px 4px 0px rgba(0,0,0,0.5); text-align:center; display:none'
  document.body.appendChild(blockListDiv)

  document.getElementById('updateBlockList').addEventListener('click', updateBlockList)
  document.getElementById('closePop').addEventListener('click', hideBlockList)

  prepPage()
}

pageOnLoad()
<commit_msg>1. Add new function changeReplyVisibility, which adds a block button to post menu 2. Add support to block replies on post page. 3. Add two todos, will finish them in next version.<commit_after>// ==UserScript==
// @name         Mitbbs-bot-blocker
// @namespace    http://tampermonkey.net/
// @version      0.4
// @description  Manages and blocks bot generated content. Inspired by Smalltalk80's original GM script, http://userscripts-mirror.org/scripts/review/78633
// @author       术版小吃
// @match        http://www.mitbbs.com/*
// @match        https://www.mitbbs.com/*
// @grant        GM_addStyle
// ==/UserScript==

const storageKey = 'mitbbs.blocklist'

function getBlocklist () {
  let blockList = localStorage.getItem(storageKey)
  if (blockList === null) {
    setBlocklist([])
    blockList = localStorage.getItem(storageKey)
  }
  return JSON.parse(blockList)
}

function setBlocklist (idNameList) {
  // remove duplicate items
  idNameList = [...new Set(idNameList)]
  localStorage.setItem(storageKey, JSON.stringify(idNameList))
}

function getBlockFlag () {
  let blockFlag = localStorage.getItem(storageKey + '.flag')
  if (blockFlag === null) {
    setBlockFlag(0)
    blockFlag = localStorage.getItem(storageKey + '.flag')
  }
  //  js, just being js
  return parseInt(blockFlag)
}

function setBlockFlag (flag) {
  localStorage.setItem(storageKey + '.flag', flag)
}

function changePostVisibility () {
  let blockList = getBlocklist()
  let flag = getBlockFlag()
  // if list is not empty
  let counter = 0
  if (blockList) {
    let taolunDiv = document.querySelector('td.taolun_leftright tbody')
    // yeah yeah yeah magic number, whatever
    // this will miss the first one though, nice try langfang coder
    let userIDtdNodeList = taolunDiv.querySelectorAll('td:nth-child(5)')
    userIDtdNodeList.forEach(td => {
      // damn, now i miss jquery/zepto
      let id = td.querySelector('a.news') ? td.querySelector('a.news').innerHTML : null
      //  yeah, nested if statements
      if (blockList.indexOf(id) > -1) {
        if (flag) {
          td.parentNode.style.display = 'none'
          counter += 1
        } else {
          td.parentNode.style.display = ''
        }
      }
    })
    counter = flag ? counter : 0
    document.getElementById('blockCounter').innerHTML = counter
  }
}

function changeReplyVisibility () {
  //  now we on individual post page
  let blockList = getBlocklist()
  let flag = getBlockFlag()
  let counter = 0
  let sideBarBG = document.querySelectorAll('td.wenzhang_bg')
  sideBarBG.forEach(reply => {
    let post = reply.parentElement.parentElement.parentElement.parentElement.parentElement
    //  another magic number!
    let userMenu = post.querySelector('td.jiahui-4 td[width="83%"]')
    let userID = post.querySelector('td.wenzhang strong a').innerHTML
    let hasButton = userMenu.lastChild.innerHTML !== undefined
    if (!hasButton) {
      let blockButton = document.createElement('span')
      blockButton.setAttribute('class', 'buttonHolder')
      blockButton.innerHTML = '  <button class="addToBlock" title="' + userID + '">屏蔽！</button>'
      userMenu.appendChild(blockButton)
    }
    if (blockList.indexOf(userID) > -1) {
      if (flag) {
        post.style.display = 'none'
        counter += 1
      } else {
        post.style.display = ''
      }
    }
    counter = flag ? counter : 0
    document.getElementById('blockCounter').innerHTML = counter
  })

  let allBlockButton = document.querySelectorAll('.addToBlock')
  Array.from(allBlockButton).forEach(button => {
    let userID = button.getAttribute('title')
    button.addEventListener('click', () => {
      let yesBlock = confirm('Block ' + userID + ' ?')
      if (yesBlock) {
        blockList.push(userID)
        setBlocklist(blockList)
        document.getElementById('blockListInput').value = getBlocklist().join()
        toggleBlockedContent()
      }
    })
  })
}

//  TODO: use isArticlePage to conditionally run toggleBlockedContent
//  TODO: fix bug, content not showing up when id is removed from the blocklistPop

function toggleBlockedContent () {
  document.getElementById('isBlocking').checked ? setBlockFlag(1) : setBlockFlag(0)
  changePostVisibility()
  changeReplyVisibility()
}

function changeBlockListVisibility () {
  let notVisible = document.getElementById('blockListPop').style.display === 'none'
  if (notVisible) {
    document.getElementById('blockListInput').value = getBlocklist().join()
    document.getElementById('blockListPop').style.display = ''
  } else {
    document.getElementById('blockListPop').style.display = 'none'
  }
}

function updateBlockList () {
  let newBlockList = document.getElementById('blockListInput').value
  //  remove line break, space, trailing comma
  newBlockList = newBlockList.replace(/(\r\n|\n|\r)/gm, '').replace(/\s/g, '').replace(/,+$/, '')
  newBlockList = newBlockList.split(',')
  setBlocklist(newBlockList)

  // re-filter existing content
  toggleBlockedContent()
}

function hideBlockList () {
  document.getElementById('blockListPop').style.display = 'none'
}

function prepPage () {
  if (getBlockFlag()) {
    document.getElementById('isBlocking').checked = true
    toggleBlockedContent()
  }
}

function pageOnLoad () {
  let baseUrl = window.location.href
  let isArticlePage = baseUrl.indexOf('article') > -1
  //  build blocker control gui
  let blockerDiv = document.createElement('div')
  blockerDiv.innerHTML = '<button id="showBlocklist">黑名单</button><input type="checkbox" id="isBlocking" />'
  blockerDiv.style.cssText = 'position:fixed; bottom:2em; right:0.5em; width:9em; padding:0.5em; border-radius:0.25em; background-color:#D7EAF9; box-shadow:2px 2px 4px 0px rgba(0,0,0,0.5); text-align:center; cursor:pointer;'
  document.body.appendChild(blockerDiv)

  document.getElementById('showBlocklist').addEventListener('click', changeBlockListVisibility)
  document.getElementById('blockCounter').style.cssText = 'padding:0 4px; font-weight:bold'
  document.getElementById('isBlocking').addEventListener('change', toggleBlockedContent)

  //  block list
  let blockListDiv = document.createElement('div')
  blockListDiv.setAttribute('id', 'blockListPop')
  blockListDiv.innerHTML = '修改ID，用逗号分隔,大小写敏感！' +
    '
' +
    '<textarea rows="10" cols="40" id="blockListInput"></textarea>' +
    '
' +
    '<button id="updateBlockList">Update</button><button id="closePop">Close</button>'
  blockListDiv.style.cssText = 'position:fixed; bottom:5.3em; right:0.5em; padding:0.5em; border-radius:0.25em; background-color:#D7EAF9; box-shadow:2px 2px 4px 0px rgba(0,0,0,0.5); text-align:center; display:none'
  document.body.appendChild(blockListDiv)

  document.getElementById('updateBlockList').addEventListener('click', updateBlockList)
  document.getElementById('closePop').addEventListener('click', hideBlockList)

  prepPage()
}

pageOnLoad()
<|endoftext|>


<commit_before>// requestss
var logger = require('minilogger');
var request = require('request');
var fs = require('fs');
var log = new logger();

// 'public' variables
var schema = {};
var pricelist = {};
var schemaByDefindex = {};
var getAttribute = {};

var callAPI = function (url, callback) {
  request.get(
    {
      pool:{
        maxSockets: 500
      },
      uri: url,
      timeout: 1000*20
    },
    function (error, response, body) {
	if ((error != null) || (response.statusCode != 200) || (response == null)) {
	    log.error('call failed, retrying ' + error);
	    callAPI(url, callback);
	    return;
	} else {
	    try {
            log.info('call success')
            var result = JSON.parse(body);
          } catch (e) {
            log.error('error parsing the api call');
            callAPI(url, callback);
            return;
          }
          callback(result);
	}
    }
  );
};

var getAttributes = function (schema) {
  for (var i = schema.attribute_controlled_attached_particles.length - 1; i >= 0; i--) {
    getAttribute[schema.attribute_controlled_attached_particles[i].id] = schema.attribute_controlled_attached_particles[i];
    log.debug(getAttribute[36].name);
  }
  log.debug('attributes created');
  return getAttribute;
};

var getSchemaItem = function (item) {
  return schemaByDefindex[item.defindex];
};
var createSchemaByDef = function (schema) {
  for (var i = schema.items.length - 1; i >= 0; i--) {
    schemaByDefindex[schema.items[i].defindex] = schema.items[i];
  }
};

var createItemById = function (inv) {
  var itemById = {};
  for (var i = inv.items.length -1; i >= 0; i--) {
    itemById[inv.items[i].id] = inv.items[i];
  }
  return itemById;
};

var getItemPrice = function (itemInfo) {
  var schemaItem = getSchemaItem(itemInfo);
  var itemname = schemaItem.item_name;
  if (schemaItem.item_class == "supply_crate") {
    for (var i = schemaItem.attributes.length -1; i >= 0 ; i--) {
      if (schemaItem.attributes[i]["class"] == "supply_crate_series") {
        priceindex = schemaItem.attributes[i].value;
      }
    }
  } else if (itemname == "Chemistry Set") {
    if (itemInfo.attributes[0].quality == 14) {
      itemname == "Collectors " + schemaByDefindex[itemInfo.attributes[0].itemdef].item_name + " " + itemname;
    } else {

    }
  }

  else if (
             (itemname.indexOf('Fabricator') > -1) ||
             (itemname.indexOf('Strangifier') > -1)
             ) {
    //code
  }
};

var insertPriceAlternates = function (prices) {
	var pricesKeys = Object.keys(prices);
	for (var i = pricesKeys.length - 1; i >= 0; i--) {
		if( prices[pricesKeys[i]].hasOwnProperty('alt_defindex') ) {
			var defAlts = Object.keys(prices[pricesKeys[i]].alt_defindex);
			for (var j = defAlts.length - 1; j >= 0; j--) {
				prices[prices[pricesKeys[i]].alt_defindex[defAlts[j].toString()]] = prices[pricesKeys[i]]
			};
		}
	};
	return prices;
};

//synchronous function - find specific item price
	//defindex = number of defindex to get prices of
	//quality = number of quality
	//priceindex = {cratenumber -or- unusual effect number }else{ 0 }
var getSpecificPrice = function (defindex, quality, priceindex) {
	try {
		var itemCurrent = prices[defindex][quality][priceindex].current;
	} catch (e) {
		return { unit:'', value:'N/A' }
	}
	if(itemCurrent.currency == 'usd' && exchange != null) {
		itemCurrent = convertCurrency({unit: itemCurrent.currency, value: itemCurrent.value}, 'earbuds')
	}
	var itemValue = itemCurrent.value.toFixed(2);
	var itemUnit = itemCurrent.currency || itemCurrent.unit;
	return { unit: itemUnit, value: itemValue };
};

var convertCurrency = function (price, newCurr) {
	if(price.value != 'N/A') {
		return {unit: newCurr, value: (price.value * exchange[price.unit][newCurr])};
	} else {
		return {unit: newCurr, value: 'N/A'};
	}
};

var getInventoryWorth = function (inv) {
	var total = {
		metal: 0,
		keys: 0,
		earbuds: 0,
		usd: 0
	};

	for (var i = inv.items.length - 1; i >= 0; i--) {
		var itemPrice = getItemPrice(inv.items[i]);
		itemPrice = convertCurrency(itemPrice, 'metal');

		if(typeof itemPrice.value == 'number') {
			total.metal += itemPrice.value;
		}
	};

	for (var i = Object.keys(total).length - 1; i >= 0; i--) {
		total[Object.keys(total)[i]] = convertCurrency({
			unit: 'metal',
			value: total.metal
		}, Object.keys(total)[i])
	};

	return total;
};

var updateCurrencyValues = function () {
	var refined = 5002;
	var key = 5021;
	var earbuds = 143;
	var currencies = {};

	var usdinref = getSpecificPrice(refined,6,0).value
	var refinkey = getSpecificPrice(key,6,0).value
	var keyinbud = getSpecificPrice(earbuds,6,0).value
	currencies = {
		'metal': {
			'metal': 1,
			'keys': 1/refinkey,
			'usd': usdinref,
			'earbuds': 1/(refinkey*keyinbud)
		},
		'keys': {
			'metal': refinkey,
			'keys': 1,
			'usd': refinkey*usdinref,
			'earbuds': 1/keyinbud
		},
		'usd': {
			'metal': 1/usdinref,
			'keys': 1/(usdinref*refinkey),
			'usd': 1,
			'earbuds': 1/(usdinref*refinkey*keyinbud)
		},
		'earbuds': {
			'metal': refinkey*keyinbud,
			'keys': keyinbud,
			'usd': usdinref*refinkey*keyinbud,
			'earbuds': 1
		},
		'N/A': {
			'metal': 1,
			'keys': 1,
			'usd': 1,
			'earbuds': 1
		}
	};
	log.info('Currency exchange updated');
	return currencies;
};

var createLookups = function (schema, callback) {
	schemaByDefindex = {};
	for (var i = schema.items.length - 1; i >= 0; i--) {
		schemaByDefindex[schema.items[i].defindex] = schema.items[i];
	};

	qualitiesByIndex = {};
	for (var i = Object.keys(schema.qualities).length - 1; i >= 0; i--) {
		qualitiesByIndex[schema.qualities[Object.keys(schema.qualities)[i]]] = schema.qualityNames[Object.keys(schema.qualities)[i]];
	};

	originsByIndex = {};
	for (var i = schema.originNames.length - 1; i >= 0; i--) {
		originsByIndex[schema.originNames[i].origin] = schema.originNames[i].name;
	};

	attributesByDefindex = {};
	for (var i = schema.attributes.length - 1; i >= 0; i--) {
		attributesByDefindex[schema.attributes[i].defindex] = schema.attributes[i];
	};

	particlesByIndex = {};
	for (var i = schema.attribute_controlled_attached_particles.length - 1; i >= 0; i--) {
		particlesByIndex[schema.attribute_controlled_attached_particles[i].id] = schema.attribute_controlled_attached_particles[i];
	};
	callback();
};

var loadBPTF = function (apikey, force, callback) {
  var bptfURL = "http://backpack.tf/api/IGetPrices/v4/?key="+ apikey;
  var cache = './bptf.cache';
  if (force) {
    if (fs.existsSync(cache)) {
      fs.unlinkSync(cache);
    }
    log.info('Downloading bptf prices');
    callAPI(bptfURL, function(result) {
      pricelist = result.response;
      fs.writeFileSync(cache, JSON.stringify(pricelist));
      callback(pricelist);
      return;
    });
  } else {
    try {
      pricelist = JSON.parse(fs.readFileSync(cache));
      log.info('Price list parsed ' + cache);
    } catch (e) {
      log.error('Price list parsing error, retrying');
      log.error(e.message);
      loadBPTF(apikey, true, callback);
      return;
    }
    callback(pricelist);
    return;
  }
};

var loadSchema = function (apikey, game, lang, force, callback) {
  var schemaURL = "http://api.steampowered.com/IEconItems_" + game + "/GetSchema/v0001/?key=" + apikey + "&language=" + lang;
  log.info(schemaURL);
  var cache = './schema.cache';
  if (force) {
    if (fs.existsSync(cache)) {
      fs.unlinkSync(cache);
    }
    log.info('Downloading schema');
    callAPI(schemaURL, function(result) {
      schemaD = result.result;
      fs.writeFileSync(cache, JSON.stringify(schemaD));
      callback(schemaD);
      return;
    });
  } else {
    try {
      schemaD = JSON.parse(fs.readFileSync(cache));
      log.info('Schema parsed '+cache);
		} catch (e) {
      log.error("Schema error, retrying parser");
			log.error(e.message);
			loadSchema(apikey, game, lang, true, callback);
			return;
		}
    callback(schemaD);
    return;
  }
};

var loadInventory = function (apikey, game, sid, callback) {
  var invURL = "http://api.steampowered.com/IEconItems_"+ game +"/GetPlayerItems/v0001/?key=" + apikey + "&steamid=" + sid + "&inventory=yes";
  log.info('Downloading inventory: ' + sid);
  callAPI(invURL, function (result) {
			inventory = result.result;
			callback(inventory, sid);
			return;
		});
};

var loadFriends = function (apikey, sid, calback) {
  var friendURL = "http://api.steampowered.com/ISteamUser/GetFriendList/v0001/?key="+ apikey + "&steamid="+ sid +"&relationship=friend";
  callAPI(friendURL, function (result) {
			friends = result.friendlist.friends;
			callback(friends, sid);
			return;
		});
};

var isP2P = function (inventory) {
	var P2P = false;
	if(inventory.num_backpack_slots >= 300){
		P2P = true;
	}
	return P2P;
};

exports.isP2P = isP2P;
exports.loadSchema = loadSchema;
exports.loadInventory = loadInventory;
exports.loadFriends = loadFriends;
exports.loadBPTF = loadBPTF;
exports.getItemPrice = getItemPrice;
exports.getSpecificPrice = getSpecificPrice;
exports.updateCurrencyValues = updateCurrencyValues;
exports.convertCurrency = convertCurrency;
exports.getAttributes = getAttributes;<commit_msg>removed timeout from callapi<commit_after>// requestss
var logger = require('minilogger');
var request = require('request');
var fs = require('fs');
var log = new logger();

// 'public' variables
var schema = {};
var pricelist = {};
var schemaByDefindex = {};
var getAttribute = {};

var callAPI = function (url, callback) {
  request.get(
    {
      pool:{
        maxSockets: 500
      },
      uri: url
    },
    function (error, response, body) {
	if ((error != null) || (response.statusCode != 200) || (response == null)) {
	    log.error('call failed, retrying ' + error);
	    callAPI(url, callback);
	    return;
	} else {
	    try {
            log.info('call success')
            var result = JSON.parse(body);
          } catch (e) {
            log.error('error parsing the api call');
            callAPI(url, callback);
            return;
          }
          callback(result);
	}
    }
  );
};

var getAttributes = function (schema) {
  for (var i = schema.attribute_controlled_attached_particles.length - 1; i >= 0; i--) {
    getAttribute[schema.attribute_controlled_attached_particles[i].id] = schema.attribute_controlled_attached_particles[i];
    log.debug(getAttribute[36].name);
  }
  log.debug('attributes created');
  return getAttribute;
};

var getSchemaItem = function (item) {
  return schemaByDefindex[item.defindex];
};
var createSchemaByDef = function (schema) {
  for (var i = schema.items.length - 1; i >= 0; i--) {
    schemaByDefindex[schema.items[i].defindex] = schema.items[i];
  }
};

var createItemById = function (inv) {
  var itemById = {};
  for (var i = inv.items.length -1; i >= 0; i--) {
    itemById[inv.items[i].id] = inv.items[i];
  }
  return itemById;
};

var getItemPrice = function (itemInfo) {
  var schemaItem = getSchemaItem(itemInfo);
  var itemname = schemaItem.item_name;
  if (schemaItem.item_class == "supply_crate") {
    for (var i = schemaItem.attributes.length -1; i >= 0 ; i--) {
      if (schemaItem.attributes[i]["class"] == "supply_crate_series") {
        priceindex = schemaItem.attributes[i].value;
      }
    }
  } else if (itemname == "Chemistry Set") {
    if (itemInfo.attributes[0].quality == 14) {
      itemname == "Collectors " + schemaByDefindex[itemInfo.attributes[0].itemdef].item_name + " " + itemname;
    } else {

    }
  }

  else if (
             (itemname.indexOf('Fabricator') > -1) ||
             (itemname.indexOf('Strangifier') > -1)
             ) {
    //code
  }
};

var insertPriceAlternates = function (prices) {
	var pricesKeys = Object.keys(prices);
	for (var i = pricesKeys.length - 1; i >= 0; i--) {
		if( prices[pricesKeys[i]].hasOwnProperty('alt_defindex') ) {
			var defAlts = Object.keys(prices[pricesKeys[i]].alt_defindex);
			for (var j = defAlts.length - 1; j >= 0; j--) {
				prices[prices[pricesKeys[i]].alt_defindex[defAlts[j].toString()]] = prices[pricesKeys[i]]
			};
		}
	};
	return prices;
};

//synchronous function - find specific item price
	//defindex = number of defindex to get prices of
	//quality = number of quality
	//priceindex = {cratenumber -or- unusual effect number }else{ 0 }
var getSpecificPrice = function (defindex, quality, priceindex) {
	try {
		var itemCurrent = prices[defindex][quality][priceindex].current;
	} catch (e) {
		return { unit:'', value:'N/A' }
	}
	if(itemCurrent.currency == 'usd' && exchange != null) {
		itemCurrent = convertCurrency({unit: itemCurrent.currency, value: itemCurrent.value}, 'earbuds')
	}
	var itemValue = itemCurrent.value.toFixed(2);
	var itemUnit = itemCurrent.currency || itemCurrent.unit;
	return { unit: itemUnit, value: itemValue };
};

var convertCurrency = function (price, newCurr) {
	if(price.value != 'N/A') {
		return {unit: newCurr, value: (price.value * exchange[price.unit][newCurr])};
	} else {
		return {unit: newCurr, value: 'N/A'};
	}
};

var getInventoryWorth = function (inv) {
	var total = {
		metal: 0,
		keys: 0,
		earbuds: 0,
		usd: 0
	};

	for (var i = inv.items.length - 1; i >= 0; i--) {
		var itemPrice = getItemPrice(inv.items[i]);
		itemPrice = convertCurrency(itemPrice, 'metal');

		if(typeof itemPrice.value == 'number') {
			total.metal += itemPrice.value;
		}
	};

	for (var i = Object.keys(total).length - 1; i >= 0; i--) {
		total[Object.keys(total)[i]] = convertCurrency({
			unit: 'metal',
			value: total.metal
		}, Object.keys(total)[i])
	};

	return total;
};

var updateCurrencyValues = function () {
	var refined = 5002;
	var key = 5021;
	var earbuds = 143;
	var currencies = {};

	var usdinref = getSpecificPrice(refined,6,0).value
	var refinkey = getSpecificPrice(key,6,0).value
	var keyinbud = getSpecificPrice(earbuds,6,0).value
	currencies = {
		'metal': {
			'metal': 1,
			'keys': 1/refinkey,
			'usd': usdinref,
			'earbuds': 1/(refinkey*keyinbud)
		},
		'keys': {
			'metal': refinkey,
			'keys': 1,
			'usd': refinkey*usdinref,
			'earbuds': 1/keyinbud
		},
		'usd': {
			'metal': 1/usdinref,
			'keys': 1/(usdinref*refinkey),
			'usd': 1,
			'earbuds': 1/(usdinref*refinkey*keyinbud)
		},
		'earbuds': {
			'metal': refinkey*keyinbud,
			'keys': keyinbud,
			'usd': usdinref*refinkey*keyinbud,
			'earbuds': 1
		},
		'N/A': {
			'metal': 1,
			'keys': 1,
			'usd': 1,
			'earbuds': 1
		}
	};
	log.info('Currency exchange updated');
	return currencies;
};

var createLookups = function (schema, callback) {
	schemaByDefindex = {};
	for (var i = schema.items.length - 1; i >= 0; i--) {
		schemaByDefindex[schema.items[i].defindex] = schema.items[i];
	};

	qualitiesByIndex = {};
	for (var i = Object.keys(schema.qualities).length - 1; i >= 0; i--) {
		qualitiesByIndex[schema.qualities[Object.keys(schema.qualities)[i]]] = schema.qualityNames[Object.keys(schema.qualities)[i]];
	};

	originsByIndex = {};
	for (var i = schema.originNames.length - 1; i >= 0; i--) {
		originsByIndex[schema.originNames[i].origin] = schema.originNames[i].name;
	};

	attributesByDefindex = {};
	for (var i = schema.attributes.length - 1; i >= 0; i--) {
		attributesByDefindex[schema.attributes[i].defindex] = schema.attributes[i];
	};

	particlesByIndex = {};
	for (var i = schema.attribute_controlled_attached_particles.length - 1; i >= 0; i--) {
		particlesByIndex[schema.attribute_controlled_attached_particles[i].id] = schema.attribute_controlled_attached_particles[i];
	};
	callback();
};

var loadBPTF = function (apikey, force, callback) {
  var bptfURL = "http://backpack.tf/api/IGetPrices/v4/?key="+ apikey;
  var cache = './bptf.cache';
  if (force) {
    if (fs.existsSync(cache)) {
      fs.unlinkSync(cache);
    }
    log.info('Downloading bptf prices');
    callAPI(bptfURL, function(result) {
      pricelist = result.response;
      fs.writeFileSync(cache, JSON.stringify(pricelist));
      callback(pricelist);
      return;
    });
  } else {
    try {
      pricelist = JSON.parse(fs.readFileSync(cache));
      log.info('Price list parsed ' + cache);
    } catch (e) {
      log.error('Price list parsing error, retrying');
      log.error(e.message);
      loadBPTF(apikey, true, callback);
      return;
    }
    callback(pricelist);
    return;
  }
};

var loadTF2Schema = function (apikey, lang, force, callback) {
  var schemaURL = "http://api.steampowered.com/IEconItems_440/GetSchema/v0001/?key=" + apikey + "&language=" + lang;
  log.info(schemaURL);
  var cache = './schema.cache';
  if (force) {
    if (fs.existsSync(cache)) {
      fs.unlinkSync(cache);
    }
    log.info('Downloading schema');
    callAPI(schemaURL, function(result) {
      schemaD = result.result;
      fs.writeFileSync(cache, JSON.stringify(schemaD));
      callback(schemaD);
      return;
    });
  } else {
    try {
      schemaD = JSON.parse(fs.readFileSync(cache));
      log.info('Schema parsed '+cache);
		} catch (e) {
      log.error("Schema error, retrying parser");
			log.error(e.message);
			loadSchema(apikey, game, lang, true, callback);
			return;
		}
    callback(schemaD);
    return;
  }
};

var loadCSGOSchema = function (apikey, lang, force, callback) {
  var schemaURL = "http://api.steampowered.com/IEconItems_730/GetSchema/v2/?key=" + apikey + "&language=" + lang;
  log.info(schemaURL);
  var cache = './schema.cache';
  if (force) {
    if (fs.existsSync(cache)) {
      fs.unlinkSync(cache);
    }
    log.info('Downloading schema');
    callAPI(schemaURL, function(result) {
      schemaD = result.result;
      fs.writeFileSync(cache, JSON.stringify(schemaD));
      callback(schemaD);
      return;
    });
  } else {
    try {
      schemaD = JSON.parse(fs.readFileSync(cache));
      log.info('Schema parsed '+cache);
		} catch (e) {
      log.error("Schema error, retrying parser");
			log.error(e.message);
			loadSchema(apikey, game, lang, true, callback);
			return;
		}
    callback(schemaD);
    return;
  }
};

var loadInventory = function (apikey, game, sid, callback) {
  var invURL = "http://api.steampowered.com/IEconItems_"+ game +"/GetPlayerItems/v0001/?key=" + apikey + "&steamid=" + sid + "&inventory=yes";
  log.info('Downloading inventory: ' + sid);
  callAPI(invURL, function (result) {
			inventory = result.result;
			callback(inventory, sid);
			return;
		});
};

var loadFriends = function (apikey, sid, calback) {
  var friendURL = "http://api.steampowered.com/ISteamUser/GetFriendList/v0001/?key="+ apikey + "&steamid="+ sid +"&relationship=friend";
  callAPI(friendURL, function (result) {
			friends = result.friendlist.friends;
			callback(friends, sid);
			return;
		});
};

var isP2P = function (inventory) {
	var P2P = false;
	if(inventory.num_backpack_slots >= 300){
		P2P = true;
	}
	return P2P;
};

exports.isP2P = isP2P;
exports.loadSchema = loadSchema;
exports.loadInventory = loadInventory;
exports.loadFriends = loadFriends;
exports.loadBPTF = loadBPTF;
exports.getItemPrice = getItemPrice;
exports.getSpecificPrice = getSpecificPrice;
exports.updateCurrencyValues = updateCurrencyValues;
exports.convertCurrency = convertCurrency;
exports.getAttributes = getAttributes;<|endoftext|>


<commit_before>'use strict';

var fs = require("fs");
var path = require("path");
var temp = require("temp").track();
var loaderUtils = require("loader-utils");
var elmCompiler = require("node-elm-compiler");

var defaultOptions = {
    debug: false,
    optimize: false
};

var getFiles = function(options) {
    var files = options && options.files;

    if (files === undefined) return [this.resourcePath];

    if (!Array.isArray(files)) {
        throw new Error('files option must be an array');
    }

    if (files.length === 0) {
        throw new Error("You specified the 'files' option but didn't list any files");
    }

    delete options.files;
    return files;
};

var getOptions = function() {
    var globalOptions = this.options
        ? this.options.elm || {}
        : this.query.elm || {};
    var loaderOptions = loaderUtils.getOptions(this) || {};
    return Object.assign({}, defaultOptions, globalOptions, loaderOptions);
};

var _addDependencies = function(dependency) {
    this.addDependency(dependency);
};

var _addDirDependency = function(dirs){
    dirs.forEach(this.addContextDependency.bind(this));
};

var isFlagSet = function(args, flag) {
    return typeof args[flag] !== "undefined" && args[flag];
};

/* Takes a working dir, tries to read elm.json, then grabs all the modules from in there
*/
var filesToWatch = function(cwd){
    var readFile = fs.readFileSync(path.join(cwd, "elm.json"), 'utf8');
    var elmPackage = JSON.parse(readFile);

    var paths = elmPackage["source-directories"].map(function(dir){
        return path.join(cwd, dir);
    });

    return paths;
};

var dependenciesFor = function(resourcePath, files) {
    return findAllDependencies(files)
        .then(function (dependencies) {
            return unique(dependencies.concat(remove(resourcePath, files)));
        });
}

var findAllDependencies = function(files) {
    return Promise.all(files.map(
        function(f) { return elmCompiler.findAllDependencies(f) }
    )).then(flatten);
}

module.exports = function() {
    this.cacheable && this.cacheable();

    var callback = this.async();
    if (!callback) {
        throw 'elm-webpack-loader currently only supports async mode.';
    }

    // bind helper functions to `this`
    var addDependencies = _addDependencies.bind(this);
    var addDirDependency = _addDirDependency.bind(this);
    var emitError = this.emitError.bind(this);

    var options = getOptions.call(this);
    var files = getFiles.call(this, options);
    var resourcePath = this.resourcePath;

    var promises = [];

    var compiler = this._compiler;

    // we only need to track deps if we are in watch mode
    // otherwise, we trust elm to do it's job
    if (compiler.options.watch) {
        // we can do a glob to track deps we care about if cwd is set
        if (typeof options.cwd !== "undefined" && options.cwd !== null){
            // watch elm.json
            var elmPackage = path.join(options.cwd, "elm.json");
            addDependencies(elmPackage);
            var dirs = filesToWatch(options.cwd);
            // watch all the dirs in elm.json
            addDirDependency.bind(this)(dirs);
        }

        // find all the deps, adding them to the watch list if we successfully parsed everything
        // otherwise return an error which is currently ignored
        var dependencies = dependenciesFor(resourcePath, files).then(function(dependencies){
            // add each dependency to the tree
            dependencies.map(addDependencies);
            return { kind: 'success', result: true };
        }).catch(function(v){
            emitError(v);
            return { kind: 'error', error: v };
        })

        promises.push(dependencies);
    }

    var compilation = compile(files, options)
        .then(function(v) { return { kind: 'success', result: v }; })
        .catch(function(v) { return { kind: 'error', error: v }; });

    promises.push(compilation);

    Promise.all(promises)
        .then(function(results) {
            var output = results[results.length - 1]; // compilation output is always last

            if (output.kind === 'success') {
                callback(null, output.result);
            } else {
                if (typeof output.error === 'string') {
                    output.error = new Error(output.error);
                }

                output.error.message = 'Compiler process exited with error ' + output.error.message;
                output.error.stack = null;
                callback(output.error);
            }
        }).catch(function(err){
            callback(err);
        });
}

// Functions pulled and modified from node-elm-compiler:

// this was called compileToString
// - altered to log output to console instead to retain formatting
function compile(sources, options) {
    var suffix = getSuffix(options.output, '.js');
    return new Promise(function (resolve, reject) {
        temp.open({ suffix: suffix }, function (err, info) {
            if (err) {
                return reject(err);
            }
            options.output = info.path;
            options.processOpts = { stdio: 'inherit' };

            var compiler;

            try {
                compiler = elmCompiler.compile(sources, options);
            }
            catch (compileError) {
                return reject(compileError);
            }

            compiler.on("close", function (exitCode) {
                if (exitCode !== 0) {
                    return reject('Compilation failed');
                }
                else if (options.verbose) {
                    console.log(output);
                }
                fs.readFile(info.path, { encoding: "utf8" }, function (err, data) {
                    return err ? reject(err) : resolve(data);
                });
            });
        });
    });
}

function getSuffix(outputPath, defaultSuffix) {
    if (outputPath) {
        return path.extname(outputPath) || defaultSuffix;
    }
    else {
        return defaultSuffix;
    }
}

// HELPERS

function flatten(arrayOfArrays) {
    return arrayOfArrays.reduce(function(flattened, array) {
        return flattened.concat(array)
    }, []);
}

function unique(items) {
    return items.filter(function(item, index, array) {
        return array.indexOf(item) === index;
    });
}

function remove(condemned, items) {
    return items.filter(function(item) {
        return item !== condemned;
    });
}
<commit_msg>Default options now depends on the compiler mode.<commit_after>"use strict";

var fs = require("fs");
var path = require("path");
var temp = require("temp").track();
var loaderUtils = require("loader-utils");
var elmCompiler = require("node-elm-compiler");

var getFiles = function(options) {
    var files = options && options.files;

    if (files === undefined) return [this.resourcePath];

    if (!Array.isArray(files)) {
        throw new Error("files option must be an array");
    }

    if (files.length === 0) {
        throw new Error("You specified the 'files' option but didn't list any files");
    }

    delete options.files;
    return files;
};

var getOptions = function(mode) {
    var defaultOptions = {
        debug: mode === "development",
        verbose: mode === "development",
        optimize: mode === "production",
    };

    var globalOptions = this.options
        ? this.options.elm || {}
        : this.query.elm || {};

    var loaderOptions = loaderUtils.getOptions(this) || {};

    return Object.assign({}, defaultOptions, globalOptions, loaderOptions);
};

var _addDependencies = function(dependency) {
    this.addDependency(dependency);
};

var _addDirDependency = function(dirs){
    dirs.forEach(this.addContextDependency.bind(this));
};

var isFlagSet = function(args, flag) {
    return typeof args[flag] !== "undefined" && args[flag];
};

/* Takes a working dir, tries to read elm.json, then grabs all the modules from in there
*/
var filesToWatch = function(cwd){
    var readFile = fs.readFileSync(path.join(cwd, "elm.json"), "utf8");
    var elmPackage = JSON.parse(readFile);

    var paths = elmPackage["source-directories"].map(function(dir){
        return path.join(cwd, dir);
    });

    return paths;
};

var dependenciesFor = function(resourcePath, files) {
    return findAllDependencies(files)
        .then(function (dependencies) {
            return unique(dependencies.concat(remove(resourcePath, files)));
        });
}

var findAllDependencies = function(files) {
    return Promise.all(files.map(
        function(f) { return elmCompiler.findAllDependencies(f) }
    )).then(flatten);
}

module.exports = function() {
    this.cacheable && this.cacheable();

    var callback = this.async();
    if (!callback) {
        throw "elm-webpack-loader currently only supports async mode.";
    }

    var compiler = this._compiler;

    // bind helper functions to `this`
    var addDependencies = _addDependencies.bind(this);
    var addDirDependency = _addDirDependency.bind(this);
    var emitError = this.emitError.bind(this);

    var options = getOptions.call(this, compiler.options.mode);
    var files = getFiles.call(this, options);
    var resourcePath = this.resourcePath;

    var promises = [];

    // we only need to track deps if we are in watch mode
    // otherwise, we trust elm to do it's job
    if (compiler.options.watch) {
        // we can do a glob to track deps we care about if cwd is set
        if (typeof options.cwd !== "undefined" && options.cwd !== null){
            // watch elm.json
            var elmPackage = path.join(options.cwd, "elm.json");
            addDependencies(elmPackage);
            var dirs = filesToWatch(options.cwd);
            // watch all the dirs in elm.json
            addDirDependency.bind(this)(dirs);
        }

        // find all the deps, adding them to the watch list if we successfully parsed everything
        // otherwise return an error which is currently ignored
        var dependencies = dependenciesFor(resourcePath, files).then(function(dependencies){
            // add each dependency to the tree
            dependencies.map(addDependencies);
            return { kind: "success", result: true };
        }).catch(function(v){
            emitError(v);
            return { kind: "error", error: v };
        })

        promises.push(dependencies);
    }

    var compilation = compile(files, options)
        .then(function(v) { return { kind: "success", result: v }; })
        .catch(function(v) { return { kind: "error", error: v }; });

    promises.push(compilation);

    Promise.all(promises)
        .then(function(results) {
            var output = results[results.length - 1]; // compilation output is always last

            if (output.kind === "success") {
                callback(null, output.result);
            } else {
                if (typeof output.error === "string") {
                    output.error = new Error(output.error);
                }

                output.error.message = "Compiler process exited with error " + output.error.message;
                output.error.stack = null;
                callback(output.error);
            }
        }).catch(function(err){
            callback(err);
        });
}

// Functions pulled and modified from node-elm-compiler:

// this was called compileToString
// - altered to log output to console instead to retain formatting
function compile(sources, options) {
    var suffix = getSuffix(options.output, ".js");
    return new Promise(function (resolve, reject) {
        temp.open({ suffix: suffix }, function (err, info) {
            if (err) {
                return reject(err);
            }
            options.output = info.path;
            options.processOpts = { stdio: "inherit" };

            var compiler;

            try {
                compiler = elmCompiler.compile(sources, options);
            }
            catch (compileError) {
                return reject(compileError);
            }

            compiler.on("close", function (exitCode) {
                if (exitCode !== 0) {
                    return reject("Compilation failed");
                }
                else if (options.verbose) {
                    console.log(output);
                }
                fs.readFile(info.path, { encoding: "utf8" }, function (err, data) {
                    return err ? reject(err) : resolve(data);
                });
            });
        });
    });
}

function getSuffix(outputPath, defaultSuffix) {
    if (outputPath) {
        return path.extname(outputPath) || defaultSuffix;
    }
    else {
        return defaultSuffix;
    }
}

// HELPERS

function flatten(arrayOfArrays) {
    return arrayOfArrays.reduce(function(flattened, array) {
        return flattened.concat(array)
    }, []);
}

function unique(items) {
    return items.filter(function(item, index, array) {
        return array.indexOf(item) === index;
    });
}

function remove(condemned, items) {
    return items.filter(function(item) {
        return item !== condemned;
    });
}
<|endoftext|>