<commit_before>'use strict';

var major = require('./package.json').version.split('.').shift()
  , Registry = require('npm-registry')
  , resolve = require('./resolve')
  , licenses = require('licenses')
  , Pagelet = require('pagelet')
  , Contour = require('contour')
  , moment = require('moment')
  , brand = Contour.get('npm')
  , async = require('async')
  , ms = require('ms');

Pagelet.extend({
  //
  // Specify the locations of our UI components.
  //
  view: 'view.ejs',       // The template that gets rendered.
  css:  'css.styl',       // All CSS required to render this component.
  js:   'client.js',      // Progressive enhancements for the UI.
  resolve: resolve,       // Expose the resolver so it can be overridden.

  //
  // External dependencies that should be included on the page using a regular
  // script tag. This dependency is needed for the `package.js` client file.
  //
  dependencies: [
    '//code.jquery.com/jquery-2.1.0.min.js',
    brand.normalize,
    brand.global,
    brand.grid,
    brand.icons,
    brand.typography,
    brand.animations,
    brand.tables
  ],

  /**
   * The different expirations:
   *
   * - latest: This expires the latest version number of a given package.
   * - data: This expires the resolved data for a given version number.
   *
   * @type {Object}
   * @api public
   */
  expire: {
    latest: ms('1 hours') / 1000,
    data: ms('7 days') / 1000
  },

  /**
   * There are parts of page that could require Github API access. As you might
   * know there is rate limiting in place for API calls. Unauthorized calls are
   * 60 RPH (requests per hour) and authorized is 5000 RPH. You can create an
   * authorized GitHulk instance which we will be used instead of a default
   * unauthorized GitHulk.
   *
   * @type {Githulk|Null}
   * @api public
   */
  githulk: null,

  /**
   * The default registry we should use when resolving package information.
   *
   * @type {String}
   * @api public
   */
  registry: Registry.mirrors.nodejitsu,

  /**
   * Return the cache key for a given module. By default we are prefixing the
   * names with the major version number of this module. As we want to be able
   * to change the structure of the data without creating potential cache
   * conflicts. In addition to that this prevent potential dictionary attacks
   * where people use __proto__ as package name.
   *
   * @param {String} name The name of the module.
   * @param {String} version The version number of the module.
   * @returns {String} The cache key.
   * @api public
   */
  key: function key(name, version) {
    return 'v'+ major +':'+ name +'@'+ version;
  },

  /**
   * Do we have a dedicated dependencies pagelet?
   *
   * @type {Boolean}
   * @api public
   */
  dependenciesPagelet: false,

  /**
   * Final post processing step on the data before it gets rendered.
   *
   * @param {Object} data The resolved data from cache or directly from the resolver.
   * @returns {Object} data Modified data.
   * @api private
   */
  postprocess: function postproces(data) {
    //
    // Make all dates human readable.
    //
    if (data.package.time) Object.keys(data.package.time).forEach(function (time) {
      var date = data.package.time[time];

      if ('string' !== typeof date && date.full) date = date.full;

      data.package.time[time] = {
        human: moment(date).format('MMM Do YYYY'),
        ago: moment(date).fromNow(),
        full: date
      };
    });

    ['created', 'modified'].forEach(function (time) {
      var date = data.package[time];

      if ('string' !== typeof date && date.full) date = date.full;

      data.package[time] = {
        human: moment(date).format('MMM Do YYYY'),
        ago: moment(date).fromNow(),
        full: date
      };
    });

    //
    // Not yet fetched if stats is undefined.
    //
    data.stats = data.stats || { downloads: 'Unknown' };

    //
    // Expose helper method.
    //
    data.licenses = licenses.info;

    return data;
  },

  /**
   * Get the latest version of a module.
   *
   * @param {String} name The name of the module.
   * @param {Function} fn The callback.
   * @api private
   */
  latest: function latest(name, fn) {
    var key = this.key(name, 'latest')
      , pagelet = this;

    this.fireforget('get', key, function cached(err, data) {
      if (!err && data) return fn(err, data);

      var registry = 'string' !== typeof pagelet.registry
        ? pagelet.registry
        : new Registry({ registry: pagelet.registry });

      registry.packages.get(name +'/latest', function latest(err, data) {
        if (err) return fn(err);

        if (Array.isArray(data)) data = data[0];
        pagelet.fireforget('set', key, data.version, pagelet.expire.latest);

        fn(undefined, data.version);
      });
    });
  },

  /**
   * Simple wrapper around a possible cache interface.
   *
   * @param {String} method The cache method we went to invoke.
   * @param {String} key The key we want to retrieve.
   * @param {Object} obj The data we want to store.
   * @param {Number} expire Optional expiration for the set data.
   * @param {Function} fn An optional callback.
   * @api private
   */
  fireforget: function (method, key, obj, expire, fn) {
    if ('function' === typeof obj) {
      fn = obj;
      obj = null;
    }

    if ('function' === typeof expire) {
      fn = expire;
      expire = 0;
    }

    fn = fn || function nope() {};

    var pagelet = this;

    //
    // Force asynchronous execution of cache retrieval without starving I/O
    //
    (
      global.setImmediate   // Only available since node 0.10
      ? global.setImmediate
      : global.setTimeout
    )(function immediate() {
      if (key && pagelet.cache) {
        if ('get' === method) {
          if (pagelet.cache.get.length === 1) {
            return fn(undefined, pagelet.cache.get(key));
          } else {
            return pagelet.cache.get(key, fn);
          }
        } else if ('set' === method) {
          if (pagelet.cache.set.length === 2) {
            return fn(undefined, pagelet.cache.set(key, obj));
          } else {
            if (!expire) return pagelet.cache.set(key, obj, fn);
            return pagelet.cache.set(key, obj, expire, fn);
          }
        }
      }

      //
      // Nothing, no cache or matching methods.
      //
      fn();
    });

    return this;
  },

  /**
   * Get the current download stats for the given package.
   *
   * @param {String} name The name of the package.
   * @param {Function} next Completion callback.
   * @api private
   */
  downloads: function downloads(name, next) {
    var npm = this.resolve.clients(this).npm;

    if (!npm.downloads) return next(undefined, { downloads: 0 });

    npm.downloads.totals('last-day', name, function handle(err, data) {
      next(err, data = Array.isArray(data) ? data[0] : data);
    });
  },

  /**
   * Prepare the data for rendering. All the data that is send to the callback
   * is exposed in the template.
   *
   * @param {Function} render Completion callback.
   * @api private
   */
  get: function get(render) {
    var name = this.params.name
      , pagelet = this
      , key;

    async.parallel({
      data: function datas(next) {
        pagelet.latest(name, function latest(err, version) {
          if (err) return next(err);

          key = pagelet.key(name, version);

          pagelet.fireforget('get', key, function cached(err, data) {
            if (!err && data) return next(err, data);

            //
            // No data or an error, resolve the data structure and attempt to
            // store it again.
            //
            pagelet.resolve(name, {
              registry: pagelet.registry,
              githulk: pagelet.githulk
            }, function resolved(err, data) {
              //
              // Store and forget, we should delay the rendering procedure any
              // longer as manually resolving took to damn much time.
              //
              if (!err && data) pagelet.fireforget('set', key, data, pagelet.expire.data);
              if (!data && !err) err = new Error('Missing data, resolving failed');

              next(err, data);
            });
          });
        });
      },
      stats: this.downloads.bind(this, name)
    }, function next(err, dataset) {
      if (err) return render(err);

      var data = dataset.data;
      data.stats = dataset.stats;
      data.dependenciesPagelet = pagelet.dependenciesPagelet;

      render(undefined, pagelet.postprocess(data));
    });
  },

  /**
   * Add some extra pagelets to the page so we can spead the loading time of
   * this page better.
   *
   * @type {Object}
   * @api private
   */
  pagelets: {
    sparklet: require('sparklet').extend({
      xaxis: true,
      yaxis: true,

      fetch: function fetch(next) {
        var name = this.params.name;

        resolve.clients().npm.downloads.range('last-month', name, function downloads(err, data) {
          data = Array.isArray(data) ? data[0] : data;
          if (err) return next(err);
          if (!data.downloads) console.error('ERR: No data.downloads for '+ name);

          return next(err, (data.downloads || []).map(function map(row) {
            return {
              value: row.downloads,
              date: row.day
            };
          }));
        });
      }
    })
  }
}).on(module);

//
// Also expose the `resolve` method on the Pagelet instance so we can use this
// to pre-populate a cache.
//
module.exports.resolve = resolve;
<commit_msg>[fix] safety measure<commit_after>'use strict';

var major = require('./package.json').version.split('.').shift()
  , Registry = require('npm-registry')
  , resolve = require('./resolve')
  , licenses = require('licenses')
  , Pagelet = require('pagelet')
  , Contour = require('contour')
  , moment = require('moment')
  , brand = Contour.get('npm')
  , async = require('async')
  , ms = require('ms');

Pagelet.extend({
  //
  // Specify the locations of our UI components.
  //
  view: 'view.ejs',       // The template that gets rendered.
  css:  'css.styl',       // All CSS required to render this component.
  js:   'client.js',      // Progressive enhancements for the UI.
  resolve: resolve,       // Expose the resolver so it can be overridden.

  //
  // External dependencies that should be included on the page using a regular
  // script tag. This dependency is needed for the `package.js` client file.
  //
  dependencies: [
    '//code.jquery.com/jquery-2.1.0.min.js',
    brand.normalize,
    brand.global,
    brand.grid,
    brand.icons,
    brand.typography,
    brand.animations,
    brand.tables
  ],

  /**
   * The different expirations:
   *
   * - latest: This expires the latest version number of a given package.
   * - data: This expires the resolved data for a given version number.
   *
   * @type {Object}
   * @api public
   */
  expire: {
    latest: ms('1 hours') / 1000,
    data: ms('7 days') / 1000
  },

  /**
   * There are parts of page that could require Github API access. As you might
   * know there is rate limiting in place for API calls. Unauthorized calls are
   * 60 RPH (requests per hour) and authorized is 5000 RPH. You can create an
   * authorized GitHulk instance which we will be used instead of a default
   * unauthorized GitHulk.
   *
   * @type {Githulk|Null}
   * @api public
   */
  githulk: null,

  /**
   * The default registry we should use when resolving package information.
   *
   * @type {String}
   * @api public
   */
  registry: Registry.mirrors.nodejitsu,

  /**
   * Return the cache key for a given module. By default we are prefixing the
   * names with the major version number of this module. As we want to be able
   * to change the structure of the data without creating potential cache
   * conflicts. In addition to that this prevent potential dictionary attacks
   * where people use __proto__ as package name.
   *
   * @param {String} name The name of the module.
   * @param {String} version The version number of the module.
   * @returns {String} The cache key.
   * @api public
   */
  key: function key(name, version) {
    return 'v'+ major +':'+ name +'@'+ version;
  },

  /**
   * Do we have a dedicated dependencies pagelet?
   *
   * @type {Boolean}
   * @api public
   */
  dependenciesPagelet: false,

  /**
   * Final post processing step on the data before it gets rendered.
   *
   * @param {Object} data The resolved data from cache or directly from the resolver.
   * @returns {Object} data Modified data.
   * @api private
   */
  postprocess: function postproces(data) {
    //
    // Make all dates human readable.
    //
    if (data.package.time) Object.keys(data.package.time).forEach(function (time) {
      var date = data.package.time[time];

      if ('string' !== typeof date && date.full) date = date.full;

      data.package.time[time] = {
        human: moment(date).format('MMM Do YYYY'),
        ago: moment(date).fromNow(),
        full: date
      };
    });

    ['created', 'modified'].forEach(function (time) {
      var date = data.package[time];

      if ('string' !== typeof date && date.full) date = date.full;

      data.package[time] = {
        human: moment(date).format('MMM Do YYYY'),
        ago: moment(date).fromNow(),
        full: date
      };
    });

    //
    // Not yet fetched if stats is undefined.
    //
    data.stats = data.stats || { downloads: 'Unknown' };

    //
    // Expose helper method.
    //
    data.licenses = licenses.info;

    return data;
  },

  /**
   * Get the latest version of a module.
   *
   * @param {String} name The name of the module.
   * @param {Function} fn The callback.
   * @api private
   */
  latest: function latest(name, fn) {
    var key = this.key(name, 'latest')
      , pagelet = this;

    this.fireforget('get', key, function cached(err, data) {
      if (!err && data) return fn(err, data);

      var registry = 'string' !== typeof pagelet.registry
        ? pagelet.registry
        : new Registry({ registry: pagelet.registry });

      registry.packages.get(name +'/latest', function latest(err, data) {
        if (err) return fn(err);

        if (Array.isArray(data)) data = data[0];
        pagelet.fireforget('set', key, data.version, pagelet.expire.latest);

        fn(undefined, data.version);
      });
    });
  },

  /**
   * Simple wrapper around a possible cache interface.
   *
   * @param {String} method The cache method we went to invoke.
   * @param {String} key The key we want to retrieve.
   * @param {Object} obj The data we want to store.
   * @param {Number} expire Optional expiration for the set data.
   * @param {Function} fn An optional callback.
   * @api private
   */
  fireforget: function (method, key, obj, expire, fn) {
    if ('function' === typeof obj) {
      fn = obj;
      obj = null;
    }

    if ('function' === typeof expire) {
      fn = expire;
      expire = 0;
    }

    fn = fn || function nope() {};

    var pagelet = this;

    //
    // Force asynchronous execution of cache retrieval without starving I/O
    //
    (
      global.setImmediate   // Only available since node 0.10
      ? global.setImmediate
      : global.setTimeout
    )(function immediate() {
      if (key && pagelet.cache) {
        if ('get' === method) {
          if (pagelet.cache.get.length === 1) {
            return fn(undefined, pagelet.cache.get(key));
          } else {
            return pagelet.cache.get(key, fn);
          }
        } else if ('set' === method) {
          if (pagelet.cache.set.length === 2) {
            return fn(undefined, pagelet.cache.set(key, obj));
          } else {
            if (!expire) return pagelet.cache.set(key, obj, fn);
            return pagelet.cache.set(key, obj, expire, fn);
          }
        }
      }

      //
      // Nothing, no cache or matching methods.
      //
      fn();
    });

    return this;
  },

  /**
   * Get the current download stats for the given package.
   *
   * @param {String} name The name of the package.
   * @param {Function} next Completion callback.
   * @api private
   */
  downloads: function downloads(name, next) {
    var npm = this.resolve.clients(this).npm;

    if (!npm.downloads) return next(undefined, { downloads: 0 });

    npm.downloads.totals('last-day', name, function handle(err, data) {
      next(err, data = Array.isArray(data) ? data[0] : data);
    });
  },

  /**
   * Prepare the data for rendering. All the data that is send to the callback
   * is exposed in the template.
   *
   * @param {Function} render Completion callback.
   * @api private
   */
  get: function get(render) {
    var name = this.params.name
      , pagelet = this
      , key;

    //
    // Defensive fallback if the parameter was parsed to undefined value.
    //
    if (!name) return render(new Error('Missing package name, resolving failed'));

    async.parallel({
      data: function datas(next) {
        pagelet.latest(name, function latest(err, version) {
          if (err) return next(err);

          key = pagelet.key(name, version);

          pagelet.fireforget('get', key, function cached(err, data) {
            if (!err && data) return next(err, data);

            //
            // No data or an error, resolve the data structure and attempt to
            // store it again.
            //
            pagelet.resolve(name, {
              registry: pagelet.registry,
              githulk: pagelet.githulk
            }, function resolved(err, data) {
              //
              // Store and forget, we should delay the rendering procedure any
              // longer as manually resolving took to damn much time.
              //
              if (!err && data) pagelet.fireforget('set', key, data, pagelet.expire.data);
              if (!data && !err) err = new Error('Missing data, resolving failed');

              next(err, data);
            });
          });
        });
      },
      stats: this.downloads.bind(this, name)
    }, function next(err, dataset) {
      if (err) return render(err);

      var data = dataset.data;
      data.stats = dataset.stats;
      data.dependenciesPagelet = pagelet.dependenciesPagelet;

      render(undefined, pagelet.postprocess(data));
    });
  },

  /**
   * Add some extra pagelets to the page so we can spead the loading time of
   * this page better.
   *
   * @type {Object}
   * @api private
   */
  pagelets: {
    sparklet: require('sparklet').extend({
      xaxis: true,
      yaxis: true,

      fetch: function fetch(next) {
        var name = this.params.name;

        resolve.clients().npm.downloads.range('last-month', name, function downloads(err, data) {
          data = Array.isArray(data) ? data[0] : data;
          if (err) return next(err);
          if (!data.downloads) console.error('ERR: No data.downloads for '+ name);

          return next(err, (data.downloads || []).map(function map(row) {
            return {
              value: row.downloads,
              date: row.day
            };
          }));
        });
      }
    })
  }
}).on(module);

//
// Also expose the `resolve` method on the Pagelet instance so we can use this
// to pre-populate a cache.
//
module.exports.resolve = resolve;

{'fraction_non_alphanumeric': 0.12800994251980735, 'fraction_numerical': 0.003003469525141111, 'mean_word_length': 2.1820728291316525, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 2, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6549012', 'n_tokens_mistral': 5854, 'n_tokens_neox': 5632, 'n_words': 1841}