<commit_before>var express = require('express')
    , mongoose = require('mongoose')
    , UserImport = require('./lib/user-import-niche')
    , UserImportSummary = require('./lib/user-import-summary')
    , dslogger = require('./lib/dslogger')
    ;

/**
 * Initialize the logging mechanism. Defines filename to write to and whether
 * or not to also log to the console.
 */
dslogger.init('mb-logging-api-server', false);

/**
 * Parse command line arguments.
 *
 * -port -p
 *   Allows the caller to set the port that this app should run on.
 */
var listenForPort = false;
var overridePort = false;
var defaultPort = 4766;

process.argv.forEach(function(val, idx, arr) {
  if (listenForPort) {
    listenForPort = false;
    overridePort = parseInt(val);
  }

  if (val === '-port' || val === '-p') {
    listenForPort = true;
  }
});

/**
 * Express Setup
 */
var app = express();

app.configure(function() {
  // Replaces express.bodyParser() - parses request body and populates request.body
  app.use(express.urlencoded());
  app.use(express.json());

  // Checks request.body for HTTP method override
  app.use(express.methodOverride());

  // Perform route lookup based on url and HTTP method
  app.use(app.router);

  // Show all errors in development
  app.use(express.errorHandler({dumpException: true, showStack: true}));
});

/**
 * Start server.
 */
var port = overridePort || process.env.MB_LOGGING_API_PORT || defaultPort;
app.listen(port, function() {
  console.log('Message Broker Logging API server listening on port %d in %s mode.', port, app.settings.env);
});

/**
 * Mongo setup and config.
 */
var mongoUri = 'mongodb://localhost/mb-logging';
mongoose.connect(mongoUri);
mongoose.connection.on('error', function(err) {
  console.log('Unable to connect to the Mongo database (%s). Check to make sure the database is running.', mongoUri);
  process.exit();
});

var userImportModel;
var userImportCollectionName = 'userimport-niche';
var userImportSummaryModel;
var userImportSummaryCollectionName = 'userimport-summary';
mongoose.connection.once('open', function() {

  // User import logging schema for existing entries
  var userImportLoggingSchema = new mongoose.Schema({
    logged_date : { type: Date, default: Date.now },
    phone : {
      number : { type : String, trim : true },
      status : { type : String, trim : true }
    },
    email : {
      address : { type : String, trim : true },
      status : { type : String, trim : true },
      acquired : { type: Date, default: Date.now }
    },
    drupal : {
      email : { type : String, trim : true },
      uid : { type : Number }
    }
  });
  userImportLoggingSchema.set('autoIndex', false);
  // Logging model
  userImportModel = mongoose.model(userImportCollectionName, userImportLoggingSchema);

  // User import logging schema for summary reports
  var userImportSummarySchema = new mongoose.Schema({
    logged_date : { type: Date, default: Date.now },
    target_CSV_file : { type : String, trim : true },
    signup_count : { type : Number },
    skipped : { type : Number }
  });
  userImportSummarySchema.set('autoIndex', false);
  // Logging summary model
  userImportSummaryModel = mongoose.model(userImportSummaryCollectionName, userImportSummarySchema);

  console.log("Connection to Mongo (%s) succeeded! Ready to go...\n\n", mongoUri);
});

/**
 * Routes
 */

/**
 * GET /api - report basic details about the API
 * GET /api/v1
 */
app.get('/api', function(req, res) {
  res.send(200, 'Message Broker Logging API (mb-logging-api). Available versions: v1 (/api/v1) See https://github.com/DoSomething/mb-logging-api for the related git repository.');
});
app.get('/api/v1', function(req, res) {
  res.send(200, 'Message Broker Logging API (mb-logging-api). Version 1.x.x, see wiki (https://github.com/DoSomething/mb-logging-api/wiki) for documentation');
});

/**
 * POST to /api/v1/imports
 *
 * @param type string
 *   ex. &type=user : The type of import, helps to define what collection the
 *   POST is added to.
 *
 * @param exists integer
 *   &exists=1 : Flag to log entries of existing Drupal, Mailchimp and Mobile
 *   Commons users
 *
 * @param source string
 *   &source=niche : Unique name to identify the source of the import data.
 */
app.post('/api/v1/imports', function(req, res) {
  if (req.body.type === undefined || req.body.exists === undefined || req.body.source === undefined ||
      (req.body.email === undefined && req.body.phone === undefined && req.body.drupal_uid === undefined)) {
    res.send(400, 'Type, exists and source not specified or no email, phone or Drupal uid specified.');
    dslogger.error('POST /api/v1/imports request. No type, exists and source not specified or no email, phone or Drupal uid specified.');
  }
  else {
    var userImport = new UserImport(userImportModel);
    userImport.post(req, res);
  }
});

/**
 * POST to /api/v1/imports/summaries
 * @param type string
 *   ex. &type=user : The type of import.
 *
 * @param source string
 *   &source=niche : Unique name to identify the source of the import data.
 */
app.post('/api/v1/imports/summaries', function(req, res) {
  if (req.body.type === undefined || req.body.source === undefined ||
      req.body.target_CSV_file === undefined || req.body.signup_count === undefined || req.body.skipped === undefined) {
    res.send(400, 'Type or source not specified or no target CSV file, signup count and skipped values specified.');
    dslogger.error('POST /api/v1/imports/summaries request. Type or source not specified or no target CSV file, signup count and skipped values specified.');
  }
  else {
    var userImportSummary = new UserImportSummary(userImportSummaryModel);
    userImportSummary.post(req, res);
  }
});
<commit_msg>Adjusts userImportSummarySchema to support source field<commit_after>var express = require('express')
    , mongoose = require('mongoose')
    , UserImport = require('./lib/user-import-niche')
    , UserImportSummary = require('./lib/user-import-summary')
    , dslogger = require('./lib/dslogger')
    ;

/**
 * Initialize the logging mechanism. Defines filename to write to and whether
 * or not to also log to the console.
 */
dslogger.init('mb-logging-api-server', false);

/**
 * Parse command line arguments.
 *
 * -port -p
 *   Allows the caller to set the port that this app should run on.
 */
var listenForPort = false;
var overridePort = false;
var defaultPort = 4766;

process.argv.forEach(function(val, idx, arr) {
  if (listenForPort) {
    listenForPort = false;
    overridePort = parseInt(val);
  }

  if (val === '-port' || val === '-p') {
    listenForPort = true;
  }
});

/**
 * Express Setup
 */
var app = express();

app.configure(function() {
  // Replaces express.bodyParser() - parses request body and populates request.body
  app.use(express.urlencoded());
  app.use(express.json());

  // Checks request.body for HTTP method override
  app.use(express.methodOverride());

  // Perform route lookup based on url and HTTP method
  app.use(app.router);

  // Show all errors in development
  app.use(express.errorHandler({dumpException: true, showStack: true}));
});

/**
 * Start server.
 */
var port = overridePort || process.env.MB_LOGGING_API_PORT || defaultPort;
app.listen(port, function() {
  console.log('Message Broker Logging API server listening on port %d in %s mode.', port, app.settings.env);
});

/**
 * Mongo setup and config.
 */
var mongoUri = 'mongodb://localhost/mb-logging';
mongoose.connect(mongoUri);
mongoose.connection.on('error', function(err) {
  console.log('Unable to connect to the Mongo database (%s). Check to make sure the database is running.', mongoUri);
  process.exit();
});

var userImportModel;
var userImportCollectionName = 'userimport-niche';
var userImportSummaryModel;
var userImportSummaryCollectionName = 'userimport-summary';
mongoose.connection.once('open', function() {

  // User import logging schema for existing entries
  var userImportLoggingSchema = new mongoose.Schema({
    logged_date : { type: Date, default: Date.now },
    phone : {
      number : { type : String, trim : true },
      status : { type : String, trim : true }
    },
    email : {
      address : { type : String, trim : true },
      status : { type : String, trim : true },
      acquired : { type: Date, default: Date.now }
    },
    drupal : {
      email : { type : String, trim : true },
      uid : { type : Number }
    }
  });
  userImportLoggingSchema.set('autoIndex', false);
  // Logging model
  userImportModel = mongoose.model(userImportCollectionName, userImportLoggingSchema);

  // User import logging schema for summary reports
  var userImportSummarySchema = new mongoose.Schema({
    logged_date : { type: Date, default: Date.now },
    target_CSV_file : { type : String, trim : true },
    signup_count : { type : Number },
    skipped : { type : Number },
    source : {
      type : String,
      lowercase : 1,
      trim : true,
      enum: ['niche.com']
    },
  });
  userImportSummarySchema.set('autoIndex', false);
  // Logging summary model
  userImportSummaryModel = mongoose.model(userImportSummaryCollectionName, userImportSummarySchema);

  console.log("Connection to Mongo (%s) succeeded! Ready to go...\n\n", mongoUri);
});

/**
 * Routes
 */

/**
 * GET /api - report basic details about the API
 * GET /api/v1
 */
app.get('/api', function(req, res) {
  res.send(200, 'Message Broker Logging API (mb-logging-api). Available versions: v1 (/api/v1) See https://github.com/DoSomething/mb-logging-api for the related git repository.');
});
app.get('/api/v1', function(req, res) {
  res.send(200, 'Message Broker Logging API (mb-logging-api). Version 1.x.x, see wiki (https://github.com/DoSomething/mb-logging-api/wiki) for documentation');
});

/**
 * POST to /api/v1/imports
 *
 * @param type string
 *   ex. &type=user : The type of import, helps to define what collection the
 *   POST is added to.
 *
 * @param exists integer
 *   &exists=1 : Flag to log entries of existing Drupal, Mailchimp and Mobile
 *   Commons users
 *
 * @param source string
 *   &source=niche : Unique name to identify the source of the import data.
 */
app.post('/api/v1/imports', function(req, res) {
  if (req.body.type === undefined || req.body.exists === undefined || req.body.source === undefined ||
      (req.body.email === undefined && req.body.phone === undefined && req.body.drupal_uid === undefined)) {
    res.send(400, 'Type, exists and source not specified or no email, phone or Drupal uid specified.');
    dslogger.error('POST /api/v1/imports request. No type, exists and source not specified or no email, phone or Drupal uid specified.');
  }
  else {
    var userImport = new UserImport(userImportModel);
    userImport.post(req, res);
  }
});

/**
 * POST to /api/v1/imports/summaries
 * @param type string
 *   ex. &type=user : The type of import.
 *
 * @param source string
 *   &source=niche : Unique name to identify the source of the import data.
 */
app.post('/api/v1/imports/summaries', function(req, res) {
  if (req.body.type === undefined || req.body.source === undefined ||
      req.body.target_CSV_file === undefined || req.body.signup_count === undefined || req.body.skipped === undefined) {
    res.send(400, 'Type or source not specified or no target CSV file, signup count and skipped values specified.');
    dslogger.error('POST /api/v1/imports/summaries request. Type or source not specified or no target CSV file, signup count and skipped values specified.');
  }
  else {
    var userImportSummary = new UserImportSummary(userImportSummaryModel);
    userImportSummary.post(req, res);
  }
});
<|endoftext|>


<commit_before>var Obv = require('obv')
var Drain = require('pull-stream/sinks/drain')

module.exports = function (reduce) {
  return function (log, name) { //name is where this view is mounted
    var acc, since = Obv()
    since.set(-1)
    return {
      since: since,
      methods: {get: 'async'},
      get: function (path, cb) {
        cb(null, acc)
      },
      createSink: function (cb) {
        return Drain(function (data) {
          acc = reduce(acc, data.value, data.seq)
          since.set(data.seq)
        }, cb)
      },
      destroy: function (cb) {
        acc = null; since.set(null); cb()
      }
    }
  }
}

<commit_msg>implement persistence<commit_after>var Obv = require('obv')
var Drain = require('pull-stream/sinks/drain')
var AtomicFile = require('atomic-file')
var path = require('path')
var deepEqual = require('deep-equal')

module.exports = function (reduce) {
  return function (log, name) { //name is where this view is mounted
    var acc, since = Obv()
    var value = Obv(), _value

    // if the log is persisted,
    // then also save the reduce state.
    // currently saving it every minute, if it's changed.
    // I don't think this is the best way
    // but it's the easiest...
    if(log.dir) {
      var state = AtomicFile(path.join(log.dir, name+'.json'))
      state.get(function (err, data) {
        if(err) since.set(-1)
        else {
          value.set(_value = data.value)
          since.set(data.seq)
        }
      })
      ;(function next() {
        setTimeout(function () {
          if(since.value > 0 && !deepEqual(_value, value.value))
            state.set({seq: since.value, value: _value = value.value}, function () {})
          next()
        }, 1000*60).unref()
      })()
    }
    else
      since.set(-1)

    return {
      since: since,
      value: value,
      methods: {get: 'async'},
      get: function (path, cb) {
        cb(null, value.value)
      },
      createSink: function (cb) {
        return Drain(function (data) {
          value.set(reduce(value.value, data.value, data.seq))
          since.set(data.seq)
        }, cb)
      },
      destroy: function (cb) {
        value.set(null); since.set(-1);
        if(state) state.set(null, cb)
        else cb()
      }
    }
  }
}

<|endoftext|>


<commit_before>const Buffer = require('safe-buffer').Buffer
const utils = require('ethereumjs-util')

module.exports = {
  getBlock: function (blockTag, cb) {
    var hash

    if (Buffer.isBuffer(blockTag)) {
      hash = utils.sha3(blockTag)
    } else if (Number.isInteger(blockTag)) {
      hash = utils.sha3(utils.toBuffer(blockTag).toString('hex'))
    } else {
      cb(new Error('Unknown blockTag type'))
    }

    var block = {
      hash: function () {
        return hash
      }
    }

    cb(null, block)
  },

  delBlock: function (hash, cb) {
    cb(null)
  }
}
<commit_msg>Add 0x to blockhash generation in getBlock for fakeBlockchain for consistent hashes<commit_after>const Buffer = require('safe-buffer').Buffer
const utils = require('ethereumjs-util')

module.exports = {
  getBlock: function (blockTag, cb) {
    var hash

    if (Buffer.isBuffer(blockTag)) {
      hash = utils.sha3(blockTag)
    } else if (Number.isInteger(blockTag)) {
      hash = utils.sha3('0x' + utils.toBuffer(blockTag).toString('hex'))
    } else {
      cb(new Error('Unknown blockTag type'))
    }

    var block = {
      hash: function () {
        return hash
      }
    }

    cb(null, block)
  },

  delBlock: function (hash, cb) {
    cb(null)
  }
}
<|endoftext|>


<commit_before>define(['marionette', 'modules/blstats/models/histogram', 'utils',
        'jquery',
        'jquery.flot',
        'jquery.flot.resize',
        'jquery.flot.tickrotor',
], function(Marionette, Histogram, utils, $) {

    return Marionette.ItemView.extend({
        template: _.template('

<%=title%>
'),

        templateHelpers: function() {
            return {
                title: this.getOption('title')
            }
        },

        initialize: function(options) {
            this.$el.css('opactiy', 0)
            this.collection.listenTo(this.collection, 'change:data', this.render)
        },

        onRender: function() {
            var options = {
                xaxis: {
                    tickDecimals: 0,
                    rotateTicks: 45,
                },
                bars: {
                    show: true,
                },
                grid: {
                  borderWidth: 0,
                },
                yaxes: [{}, { position: 'right' }],
            }

            var f = this.collection.first()
            if (!f.get('data')) return
            var ticks = []
            var i = 0
            _.each(f.get('data'), function(v, bin) {
                ticks.push([i, i % 2 == 0 ? bin : ''])
                i++
            })
            options.xaxis.ticks = ticks

            var data = []
            this.collection.each(function(s) {
                var series = { data: [], label: s.get('label') }
                var i = 0
                _.each(s.get('data'), function(v, bin) {
                    series.data.push([i, parseFloat(v)])
                    i++
                })

                data.push(series)
            })

            console.log(data)
            if (data.length) {
                $.plot(this.$el.find('#visit_pie'), data, options)
                this.$el.css('opacity', 1)
            }
        },

  })

})
<commit_msg>make histogram zoomable, add tooltip, rationalise ticks<commit_after>define(['marionette', 'modules/blstats/models/histogram', 'utils',
        'jquery',
        'jquery.flot',
        'jquery.flot.resize',
        'jquery.flot.tickrotor',
], function(Marionette, Histogram, utils, $) {

    return Marionette.ItemView.extend({
        template: _.template('

<%=title%>
'),

        events: {
            'plotselected': 'zoom',
            'dblclick': 'reset',
        },

        zoom: function(e, ranges) {
                var opts = this.plot.getOptions()
                opts.xaxes[0].min = ranges.xaxis.from
                opts.xaxes[0].max = ranges.xaxis.to

                this.plot.setupGrid()
                this.plot.draw()
                this.plot.clearSelection()
        },

        reset: function(e) {
            this.zoom(e, {
                xaxis: {
                    from: null, to: null
                },
            })
        },

        templateHelpers: function() {
            return {
                title: this.getOption('title')
            }
        },

        initialize: function(options) {
            this.$el.css('opactiy', 0)
            this.collection.listenTo(this.collection, 'change:data', this.render)
        },

        getToolTip: function(lab, x, y, item) {
            console.log(lab, x, y, item)
            var f = this.collection.first()
            return lab+': '+Object.keys(f.get('data'))[x]
        },

        onRender: function() {
            var options = {
                xaxis: {
                    tickDecimals: 0,
                    rotateTicks: 45,
                },
                bars: {
                    show: true,
                },
                grid: {
                  borderWidth: 0,
                  hoverable: true,
                },

                selection: { mode: 'x' },
                tooltipOpts: { content: this.getToolTip.bind(this) },
                tooltip: true,

                yaxes: [{}, { position: 'right' }],
            }

            var f = this.collection.first()
            if (!f.get('data')) return
            var ticks = []
            var i = 0
            var int = Math.floor(Object.keys(f.get('data')).length/15)
            _.each(f.get('data'), function(v, bin) {
                ticks.push([i, i % int == 0 ? bin : ''])
                i++
            })
            options.xaxis.ticks = ticks

            var data = []
            this.collection.each(function(s) {
                var series = { data: [], label: s.get('label') }
                var i = 0
                _.each(s.get('data'), function(v, bin) {
                    series.data.push([i, parseFloat(v)])
                    i++
                })

                data.push(series)
            })

            if (data.length) {
                this.plot = $.plot(this.$el.find('#visit_pie'), data, options)
                this.$el.css('opacity', 1)
            }
        },

  })

})
<|endoftext|>


<commit_before>/* jslint browser: true */

define([
	'squire',
	'handlebars',
	'jquery',
	'jquery-ui',
	'select2',
	'module',
	'backbone.stickit',
	'utils/DynamicSelect2',
	'views/BaseView',
	'hbs!hb_templates/contributorTabRow',
	'models/PublicationContributorModel',
	'models/PublicationContributorCollection'
], function(Squire, Handlebars, $, jqueryUi, select2, module, stickit, DynamicSelect2, BaseView, hbTemplate, PublicationContributorModel, PublicationContributorCollection) {
	"use strict";

	describe('ContributorRowView', function() {

		var ContributorRowView, testView, testModel, testCollection;
		var injector;

		beforeEach(function(done) {
			$('body').append('

');

			testModel = new PublicationContributorModel();
			testCollection = new PublicationContributorCollection();

			injector = new Squire();
			injector.mock('jquery', $); // Needed to spy on select2
			injector.mock('jquery-ui', jqueryUi);
			injector.mock('select2', select2);
			injector.mock('module', module);
			injector.mock('backbone.stickit', stickit);
			injector.mock('utils/DynamicSelect2', DynamicSelect2);
			injector.mock('views/BaseView', BaseView);
			injector.mock('hbs!hb_templates/contributorTabRow', hbTemplate);

			injector.require(['views/ContributorRowView'], function(view) {
				ContributorRowView = view;
				done();
			});
		});

		afterEach(function() {
			injector.remove();
			testView.remove();
			$('#test-div').remove();
		});

		describe('Tests for render', function() {
			beforeEach(function() {
				testView = new ContributorRowView({
					el : '#test-div',
					model : testModel,
					collection : testCollection
				});
				testModel.set({
					affiliation: {
						id: 1,
						text: 'Affiliation 1'
					},
					rank : 1,
					contributorId: 10,
					text: 'Contributor 10',
					corporation: false
				});
				testCollection.add(testModel);

				spyOn($.fn, 'select2');
			});

			it('Expects that the select2\'s are initialized', function() {
				testView.render();
				expect($.fn.select2.calls.count()).toBe(2);

				expect(testView.$('.contributor-type-input').val()).toEqual('people');
				expect(testView.$('.contributor-name-input').val()).toEqual('10');
			});

			it('Expects that the contributor name selects2 url function result changes depending on the corporation property', function() {
				var getUrl;

				testView.render();
				getUrl = $.fn.select2.calls.argsFor(1)[0].ajax.url;
				expect(getUrl()).toEqual('test_lookup/people');

				testModel.set('corporation', true);
				expect(getUrl()).toEqual('test_lookup/corporations');
			});

			it('Expects affliation to be set to the value in the model', function() {
				testView.render();
				expect(testView.$('.affiliation-input').val()).toEqual('Affiliation 1');
			});
		});

		describe('Tests for DOM event handlers', function() {
			beforeEach(function() {
				testView = new ContributorRowView({
					el : '#test-div',
					model : testModel,
					collection : testCollection
				});
				testModel.set({
					affiliation: {
						id: 1,
						text: 'Affiliation 1'
					},
					rank : 1,
					contributorId: 10,
					text: 'Contributor 10',
					corporation: false
				});
				testCollection.add(testModel);

			});

			it('Expects selecting a type to update corporations in model', function() {
				var ev = {
					currentTarget : {
						value : 'corporations'
					}
				};
				testView.selectType(ev);
				expect(testModel.get('corporation')).toBe(true);

				ev.currentTarget.value = 'people';
				testView.selectType(ev);
				expect(testModel.get('corporation')).toBe(false);
			});

			it('Expects selecting a contributor name fetches the contributor after setting the contributor Id', function() {
				var ev = {
					currentTarget : {
						value : 11
					}
				};
				spyOn(testModel, 'fetch');
				testView.selectName(ev);
				expect(testModel.get('contributorId')).toEqual(11);
				expect(testModel.fetch).toHaveBeenCalled();
			});

			it('Expects when the order is changed that the collection is updated', function() {
				spyOn(testCollection, 'updateModelRank');
				testView.updateOrder({}, 2);
				expect(testCollection.updateModelRank.calls.argsFor(0)).toEqual([testModel, 3]);
			});

			it('Expects the model to be removed from the collection if the row is deleted', function() {
				spyOn(testCollection, 'remove');
				testView.deleteRow();
				expect(testCollection.remove.calls.argsFor(0)).toEqual([testModel]);
			});

			// Temporarily disable this test as we will be linking to the old MyPubs app until the edit
			// contributors page has been implemented in the new app.
			xit('Expects that if the edit link is clicked a new window is opened to edit the contributor', function() {
				spyOn(window, 'open');
				testView.clickEditLink();
				expect(window.open.calls.argsFor(0)[0]).toContain('#contributor/10');
			});
		});

		describe('Tests for model event handlers', function() {
			beforeEach(function() {
				testView = new ContributorRowView({
					el : '#test-div',
					model : testModel,
					collection : testCollection
				});
				testModel.set({
					affiliation: {
						id: 1,
						text: 'Affiliation 1'
					},
					rank : 1,
					contributorId: 10,
					text: 'Contributor 10',
					corporation: false
				});
				testCollection.add(testModel);

				testView.render();
			});

			it('Expects the type select to be updated if the corporation property is changed', function() {
				testModel.set('corporation', true);
				expect(testView.$('.contributor-type-input').val()).toEqual('corporations');
			});

			it('Expects the contributor name to be updated if the text property is changed', function() {
				testModel.set({
					contributorId: 11,
					text : 'New Contributor'
				});
				expect(testView.$('.contributor-name-input').val()).toEqual('11');
			});

		});
	});

});<commit_msg>Preload the dependencies.<commit_after>/* jslint browser: true */

define([
	'squire',
	'handlebars',
	'jquery',
	'jquery-ui',
	'select2',
	'module',
	'backbone.stickit',
	'utils/DynamicSelect2',
	'views/BaseView',
	'hbs!hb_templates/contributorTabRow',
	'models/PublicationContributorModel',
	'models/PublicationContributorCollection'
], function(Squire, Handlebars, $, jqueryUi, select2, module, stickit, DynamicSelect2, BaseView, hbTemplate, PublicationContributorModel, PublicationContributorCollection) {
	"use strict";

	describe('ContributorRowView', function() {

		var ContributorRowView, testView, testModel, testCollection;
		var injector;

		beforeEach(function(done) {
			$('body').append('

');

			testModel = new PublicationContributorModel();
			testCollection = new PublicationContributorCollection();

			injector = new Squire();
			injector.mock('handlebars', Handlebars);
			injector.mock('jquery', $); // Needed to spy on select2
			injector.mock('jquery-ui', jqueryUi);
			injector.mock('select2', select2);
			injector.mock('module', module);
			injector.mock('backbone.stickit', stickit);
			injector.mock('utils/DynamicSelect2', DynamicSelect2);
			injector.mock('views/BaseView', BaseView);
			injector.mock('hbs!hb_templates/contributorTabRow', hbTemplate);

			injector.require(['views/ContributorRowView'], function(view) {
				ContributorRowView = view;
				done();
			});
		});

		afterEach(function() {
			injector.remove();
			testView.remove();
			$('#test-div').remove();
		});

		describe('Tests for render', function() {
			beforeEach(function() {
				testView = new ContributorRowView({
					el : '#test-div',
					model : testModel,
					collection : testCollection
				});
				testModel.set({
					affiliation: {
						id: 1,
						text: 'Affiliation 1'
					},
					rank : 1,
					contributorId: 10,
					text: 'Contributor 10',
					corporation: false
				});
				testCollection.add(testModel);

				spyOn($.fn, 'select2');
			});

			it('Expects that the select2\'s are initialized', function() {
				testView.render();
				expect($.fn.select2.calls.count()).toBe(2);

				expect(testView.$('.contributor-type-input').val()).toEqual('people');
				expect(testView.$('.contributor-name-input').val()).toEqual('10');
			});

			it('Expects that the contributor name selects2 url function result changes depending on the corporation property', function() {
				var getUrl;

				testView.render();
				getUrl = $.fn.select2.calls.argsFor(1)[0].ajax.url;
				expect(getUrl()).toEqual('test_lookup/people');

				testModel.set('corporation', true);
				expect(getUrl()).toEqual('test_lookup/corporations');
			});

			it('Expects affliation to be set to the value in the model', function() {
				testView.render();
				expect(testView.$('.affiliation-input').val()).toEqual('Affiliation 1');
			});
		});

		describe('Tests for DOM event handlers', function() {
			beforeEach(function() {
				testView = new ContributorRowView({
					el : '#test-div',
					model : testModel,
					collection : testCollection
				});
				testModel.set({
					affiliation: {
						id: 1,
						text: 'Affiliation 1'
					},
					rank : 1,
					contributorId: 10,
					text: 'Contributor 10',
					corporation: false
				});
				testCollection.add(testModel);

			});

			it('Expects selecting a type to update corporations in model', function() {
				var ev = {
					currentTarget : {
						value : 'corporations'
					}
				};
				testView.selectType(ev);
				expect(testModel.get('corporation')).toBe(true);

				ev.currentTarget.value = 'people';
				testView.selectType(ev);
				expect(testModel.get('corporation')).toBe(false);
			});

			it('Expects selecting a contributor name fetches the contributor after setting the contributor Id', function() {
				var ev = {
					currentTarget : {
						value : 11
					}
				};
				spyOn(testModel, 'fetch');
				testView.selectName(ev);
				expect(testModel.get('contributorId')).toEqual(11);
				expect(testModel.fetch).toHaveBeenCalled();
			});

			it('Expects when the order is changed that the collection is updated', function() {
				spyOn(testCollection, 'updateModelRank');
				testView.updateOrder({}, 2);
				expect(testCollection.updateModelRank.calls.argsFor(0)).toEqual([testModel, 3]);
			});

			it('Expects the model to be removed from the collection if the row is deleted', function() {
				spyOn(testCollection, 'remove');
				testView.deleteRow();
				expect(testCollection.remove.calls.argsFor(0)).toEqual([testModel]);
			});

			// Temporarily disable this test as we will be linking to the old MyPubs app until the edit
			// contributors page has been implemented in the new app.
			xit('Expects that if the edit link is clicked a new window is opened to edit the contributor', function() {
				spyOn(window, 'open');
				testView.clickEditLink();
				expect(window.open.calls.argsFor(0)[0]).toContain('#contributor/10');
			});
		});

		describe('Tests for model event handlers', function() {
			beforeEach(function() {
				testView = new ContributorRowView({
					el : '#test-div',
					model : testModel,
					collection : testCollection
				});
				testModel.set({
					affiliation: {
						id: 1,
						text: 'Affiliation 1'
					},
					rank : 1,
					contributorId: 10,
					text: 'Contributor 10',
					corporation: false
				});
				testCollection.add(testModel);

				testView.render();
			});

			it('Expects the type select to be updated if the corporation property is changed', function() {
				testModel.set('corporation', true);
				expect(testView.$('.contributor-type-input').val()).toEqual('corporations');
			});

			it('Expects the contributor name to be updated if the text property is changed', function() {
				testModel.set({
					contributorId: 11,
					text : 'New Contributor'
				});
				expect(testView.$('.contributor-name-input').val()).toEqual('11');
			});

		});
	});

});<|endoftext|>


<commit_before><commit_msg>Dismiss modal confirm dialog with enter key<commit_after><|endoftext|>


<commit_before>'use strict';
var curl = require('request'),
  url = require('url'),
  async = require('async'),
  crypto = require('crypto'),
  redis = require('redis'),
  MobileAgent = require('mobile-agent');

/**
 * @module express-view-cache
 */

/**
 * @class EVC
 * @classdesc
 * This class accepts redis connection parameters as constructor, and builds Caching Middleware
 * by method { link EVC#cachingMiddleware }
 * @see EVC#cachingMiddleware
 */

function EVC(options) {
  var config = {},
    redisClient,
    o,
    cacheKey = crypto.createHash('md5').update('I_WANNA_TEA_AND_MEAT' + (Math.random() * Date.now())).digest('hex').toString();

  if (typeof options === 'string') {
    o = url.parse(options);
    if (o.protocol === 'redis:') {
      config.host = o.hostname || 'localhost';
      config.port = o.port || 6379;
      config.pass = o.auth ? o.auth[1] : null;
      config.appPort = process.env.PORT || 3000;
    } else {
      throw new Error('ExpressViewCache - unable to parse ' + o + ' as redis connection string!');
    }
  } else {
    config = {
      'host': options.host || 'localhost',
      'port': options.port || 6379,
      'pass': options.pass,
      'client': options.client,
      'appPort': options.appPort || process.env.PORT || 3000
    };
  }

  redisClient = config.client || redis.createClient(config.port, config.host, {
    'auth_pass': config.pass,
    'return_buffers': true
  });

  /**
   * @method EVC#cachingMiddleware
   * @param {Number} [ttlInMilliSeconds=30000]
   * @param {Array} queryParams cache based on query parameter
   * @param {Boolean} [isResponsive=true]
   * @return {function} function(req, res, next){...}
   */

  this.cachingMiddleware = function (ttlInMilliSeconds,queryParams,followRedirection, isResponsive) {
    ttlInMilliSeconds = parseInt(ttlInMilliSeconds, 10) || 30000;
    isResponsive = typeof isResponsive === "undefined" ? false : isResponsive;

    return function (req, res, next) {
      if (req.method === 'GET' && req.headers.express_view_cache !== cacheKey) {
        var urlToUse = req.originalUrl;

        var responsiveSuffix = '';
          // get device type (mobile/desktop)
        if (!isResponsive) {
            responsiveSuffix = isMobile(req) ? ':mobile' : ':desktop';
        }

        var query = req.query;
        if(queryParams) {
          if(queryParams.length===0){
            urlToUse=req.originalUrl.split("?")[0];
          } else {
            var queryParamsFinal="";
            var count = 0;
            for(var i=0;i<queryParams.length;i++){
              if(query[queryParams[i]]){
                queryParamsFinal+=(count==0?"?":"&")+queryParams[i]+"="+query[queryParams[i]];
                count++;
              }
            }
            if(req.originalUrl.indexOf("?")){
              urlToUse=req.originalUrl.split("?")[0]+queryParamsFinal;
            } else {
              urlToUse=req.originalUrl+queryParamsFinal;
            }
          }
        }

        var key = urlToUse,
            responsiveKey = urlToUse + responsiveSuffix,
          data = {};
          console.log("key used in caching module================="+ key);
        async.waterfall([
          function (cb) {
            async.parallel({
              'dataFound': function (clb) {
                redisClient.hgetall(responsiveKey, clb);
              },
              'age': function (clb) {
                redisClient.ttl(responsiveKey, clb);
              }
            }, function (error, obj) {
              if (error) {
                cb(error);
              } else {
                cb(null, obj.dataFound, obj.age);
              }
            });
          },
          function (dataFound, age, cb) {
            if (dataFound) {
              data.Expires = new Date(Date.now() + age).toUTCString();
              data['Last-Modified'] = new Date(dataFound.savedAt).toUTCString();
              data['Content-Type'] = dataFound.contentType;
              data.statusCode = dataFound.statusCode;
              data.content = dataFound.content;
              data.cookie = dataFound.cookie;
              cb(null, true);
            } else {
              var headers = req.headers;
              var flagFollowRedirection = false;
              if(followRedirection){
                flagFollowRedirection = followRedirection;
              }
              headers.express_view_cache = cacheKey;
              curl({
                'method': 'GET',
                'headers': headers,
                'url': 'http://localhost:' + config.appPort + key,
                'followRedirect': flagFollowRedirection
              }, function (error, response, body) {
                if (error) {
                  cb(error);
                } else {
                  data.Expires = new Date(Date.now() + ttlInMilliSeconds).toUTCString();
                  data['Last-Modified'] = new Date().toUTCString();
                  data['Content-Type'] = response.headers['content-type'];
                  data.statusCode = response.statusCode;
                  data.content = body;
                  if(data.statusCode===301) {
                    data.redirectUrl = response.headers.location;
                  }

                  data['cookie'] = response.headers['set-cookie'];

                  cb(error, false);
                }
              });
            }
          },

          function (hit, cb) {
            if (hit) {
              cb(null);
            } else {
              async.series([
                function (clb) {
                  if(data.statusCode == 200){
                    redisClient.hmset(responsiveKey, {
                      'savedAt': new Date(),
                      'contentType': data['Content-Type'],
                      'statusCode': data.statusCode,
                      'content': data.content,
                      'cookie': data.cookie
                    }, clb);
                  }else{
                    clb();
                  }
                },
                function (clb) {
                  redisClient.expire(responsiveKey, Math.floor(ttlInMilliSeconds / 1000), clb);
                }
              ], cb);
            }
          }
        ], function (error) {
          if (error) {
            next(error);
          } else {
            if(data.statusCode===301) {
                return res.redirect(301,data.redirectUrl);
              } else {
                res.setHeader('Set-Cookie', data.cookie);
                res.set('Expires', data.Expires);
                res.set('Last-Modified', data['Last-Modified']);
                res.set('Content-Type', data['Content-Type']);
                res.status(data.statusCode);

                res.send(data.content);
            }
          }
        });
      } else {
        next();
      }
    };
  };
  return this;
}

/**
 * Returns boolean value for whether the client is using mobile/desktop browser
 * @param  {Object}  req
 * @return {Boolean} isMobile[true/false]
 */
function isMobile(req) {
    var agent = MobileAgent(req.headers["user-agent"]);
    return agent.Mobile;
}

module.exports = exports = function (config) {
  return new EVC(config);
};
<commit_msg>fix how cookies are sent from caching<commit_after>'use strict';
var curl = require('request'),
  url = require('url'),
  async = require('async'),
  crypto = require('crypto'),
  redis = require('redis'),
  MobileAgent = require('mobile-agent');

/**
 * @module express-view-cache
 */

/**
 * @class EVC
 * @classdesc
 * This class accepts redis connection parameters as constructor, and builds Caching Middleware
 * by method { link EVC#cachingMiddleware }
 * @see EVC#cachingMiddleware
 */

function EVC(options) {
  var config = {},
    redisClient,
    o,
    cacheKey = crypto.createHash('md5').update('I_WANNA_TEA_AND_MEAT' + (Math.random() * Date.now())).digest('hex').toString();

  if (typeof options === 'string') {
    o = url.parse(options);
    if (o.protocol === 'redis:') {
      config.host = o.hostname || 'localhost';
      config.port = o.port || 6379;
      config.pass = o.auth ? o.auth[1] : null;
      config.appPort = process.env.PORT || 3000;
    } else {
      throw new Error('ExpressViewCache - unable to parse ' + o + ' as redis connection string!');
    }
  } else {
    config = {
      'host': options.host || 'localhost',
      'port': options.port || 6379,
      'pass': options.pass,
      'client': options.client,
      'appPort': options.appPort || process.env.PORT || 3000
    };
  }

  redisClient = config.client || redis.createClient(config.port, config.host, {
    'auth_pass': config.pass,
    'return_buffers': true
  });

  /**
   * @method EVC#cachingMiddleware
   * @param {Number} [ttlInMilliSeconds=30000]
   * @param {Array} queryParams cache based on query parameter
   * @param {Boolean} [isResponsive=true]
   * @return {function} function(req, res, next){...}
   */

  this.cachingMiddleware = function (ttlInMilliSeconds,queryParams,followRedirection, isResponsive) {
    ttlInMilliSeconds = parseInt(ttlInMilliSeconds, 10) || 30000;
    isResponsive = typeof isResponsive === "undefined" ? false : isResponsive;

    return function (req, res, next) {

      if (req.method === 'GET' && req.headers.express_view_cache !== cacheKey) {
        var urlToUse = req.originalUrl;

        var responsiveSuffix = '';
          // get device type (mobile/desktop)
        if (!isResponsive) {
            responsiveSuffix = isMobile(req) ? ':mobile' : ':desktop';
        }

        var query = req.query;
        if(queryParams) {
          if(queryParams.length===0){
            urlToUse=req.originalUrl.split("?")[0];
          } else {
            var queryParamsFinal="";
            var count = 0;
            for(var i=0;i<queryParams.length;i++){
              if(query[queryParams[i]]){
                queryParamsFinal+=(count==0?"?":"&")+queryParams[i]+"="+query[queryParams[i]];
                count++;
              }
            }
            if(req.originalUrl.indexOf("?")){
              urlToUse=req.originalUrl.split("?")[0]+queryParamsFinal;
            } else {
              urlToUse=req.originalUrl+queryParamsFinal;
            }
          }
        }

        var key = urlToUse,
            responsiveKey = urlToUse + responsiveSuffix,
          data = {};
          console.log("key used in caching module================="+ key);
        async.waterfall([
          function (cb) {
            async.parallel({
              'dataFound': function (clb) {
                redisClient.hgetall(responsiveKey, clb);
              },
              'age': function (clb) {
                redisClient.ttl(responsiveKey, clb);
              }
            }, function (error, obj) {
              if (error) {
                cb(error);
              } else {
                cb(null, obj.dataFound, obj.age);
              }
            });
          },
          function (dataFound, age, cb) {
            if (dataFound) {
              data.Expires = new Date(Date.now() + age).toUTCString();
              data['Last-Modified'] = new Date(dataFound.savedAt).toUTCString();
              data['Content-Type'] = dataFound.contentType;
              data.statusCode = dataFound.statusCode;
              data.content = dataFound.content;
              data.cookie = res._headers['set-cookie'];
              cb(null, true);
            } else {
              var headers = req.headers;
              var flagFollowRedirection = false;
              if(followRedirection){
                flagFollowRedirection = followRedirection;
              }
              headers.express_view_cache = cacheKey;
              curl({
                'method': 'GET',
                'headers': headers,
                'url': 'http://localhost:' + config.appPort + req.originalUrl,
                'followRedirect': flagFollowRedirection
              }, function (error, response, body) {
                if (error) {
                  cb(error);
                } else {
                  data.Expires = new Date(Date.now() + ttlInMilliSeconds).toUTCString();
                  data['Last-Modified'] = new Date().toUTCString();
                  data['Content-Type'] = response.headers['content-type'];
                  data.statusCode = response.statusCode;
                  data.content = body;
                  if(data.statusCode===301) {
                    data.redirectUrl = response.headers.location;
                  }

                  data['cookie'] = response.headers['set-cookie'];

                  cb(error, false);
                }
              });
            }
          },

          function (hit, cb) {
            if (hit) {
              cb(null);
            } else {
              async.series([
                function (clb) {
                  if(data.statusCode == 200){
                    redisClient.hmset(responsiveKey, {
                      'savedAt': new Date(),
                      'contentType': data['Content-Type'],
                      'statusCode': data.statusCode,
                      'content': data.content
                    }, clb);
                  }else{
                    clb();
                  }
                },
                function (clb) {
                  redisClient.expire(responsiveKey, Math.floor(ttlInMilliSeconds / 1000), clb);
                }
              ], cb);
            }
          }
        ], function (error) {
          if (error) {
            next(error);
          } else {
            if(data.statusCode===301) {
                return res.redirect(301,data.redirectUrl);
              } else {
                res.setHeader('Set-Cookie', data.cookie);
                res.set('Expires', data.Expires);
                res.set('Last-Modified', data['Last-Modified']);
                res.set('Content-Type', data['Content-Type']);
                res.status(data.statusCode);

                res.send(data.content);
            }
          }
        });
      } else {
        next();
      }
    };
  };
  return this;
}

/**
 * Returns boolean value for whether the client is using mobile/desktop browser
 * @param  {Object}  req
 * @return {Boolean} isMobile[true/false]
 */
function isMobile(req) {
    var agent = MobileAgent(req.headers["user-agent"]);
    return agent.Mobile;
}

module.exports = exports = function (config) {
  return new EVC(config);
};
<|endoftext|>


<commit_before><commit_msg>ライブラリ(timeline.js)更新<commit_after><|endoftext|>


<commit_before>// returns random gif from imgur.com

exports.config = null;

exports.get = function (callback) {
    var request = require('request'),
        async = require('async');

    var options = {
        url: 'https://api.imgur.com/3/gallery/random/random/'+Math.round(Math.random()*50).toString(),
        timeout: 10000,
        headers: {
            'User-Agent': 'GVTV via node-request',
            'Authorization': 'Client-ID '+exports.config.imgur.client_id
        }
    };

    async.waterfall([
        function (cb) {
            getCache(options.url, function (err, cacheData) {
                if (err) return cb(err);
                cb(null, cacheData);
            });
        },
        function (cacheData, cb) {
            if (!cacheData) {
                request.get(options, function (err, res, body) {
                    if (err) {
                        return cb(err, null, 'imgur');
                    }
                    var result;
                    try {
                        result = JSON.parse(body);
                    } catch (e) {
                        return cb(e);
                    }
                    if (result.data) {
                        var animated = [];
                        for (var i in result.data) {
                            if (result.data[i].animated) {
                                animated.push(result.data[i]);
                            }
                        }
                        setCache(options.url, { created: new Date().getTime(), ttl: 3600, data: animated }, cb);
                    } else {
                       cb(new Error('imgur: no data'));
                    }
                });
            } else {
                cb(null, cacheData);
            }
        },
        function (cacheData, cb) {
            if (cacheData.data && cacheData.data.length>0) {
                var selectedImage = cacheData.data.pop();
                setCache(options.url, cacheData, function (err) {
                    cb(err, selectedImage.link, 'imgur');
                });
            } else {
                cb(new Error('imgur: cache empty'), null, 'imgur');
            }
        }
    ],
    function (err, selectedImage) {
        callback(err, selectedImage, 'imgur');
    });
};

function getCache(url, callback) {
    var async = require('async'),
        path = require('path'),
        fs = require('fs'),
        config = exports.config;
    async.waterfall([
        function (cb) {
            var cachePath = path.join(config.imgur.cache_dir, getKey(url));
            fs.exists(cachePath, function (exists) {
                if (exists) {
                    //console.log('found in cache', cachePath);
                    cb(null, cachePath);
                } else {
                    //console.log('not in cache', cachePath);
                    cb(null, null);
                }
            });
        },
        function (cachePath, cb) {
            if (cachePath==null) return cb(null, null);
            //console.log('fetching from cache', cachePath);
            var resource = require('../resource');
            resource.getResource(cachePath, function (err, cacheEntry) {
                if (err) return cb(err, null);
                if ((new Date().getTime()-cacheEntry.created)*0.001>cacheEntry.ttl) {
                    //console.log('cache expired', cachePath);
                    cb(null, null);
                } else {
                    cb(null, cacheEntry);
                }
            });
        }
    ],
    function (err, cacheEntry) {
        callback(err, cacheEntry);
    });
}

function setCache(url, payload, callback) {
    var path = require('path'),
        config = exports.config;
    var cachePath = path.join(config.imgur.cache_dir, getKey(url));
    var resource = require('../resource');
    resource.setResource(cachePath, payload, function (err) {
        //console.log('set cache', cachePath);
        callback(err, payload);
    });
}

function getKey(url) {
    return url.replace(/\W+/g, '_');
}<commit_msg>iterate over imgur result pages<commit_after>// returns random gif from imgur.com

var pageIndex = 0,
    maxPages = 50,
    baseUrl = 'https://api.imgur.com/3/gallery/random/random/';

exports.config = null;

exports.get = function (callback) {
    var request = require('request'),
        async = require('async');

    pageIndex = 0;

    var options = {
        url: baseUrl+pageIndex.toString(),
        timeout: 10000,
        headers: {
            'User-Agent': 'GVTV via node-request',
            'Authorization': 'Client-ID '+exports.config.imgur.client_id
        }
    };

    async.waterfall([
        function (cb) {
            getNextPage(options, cb);
        },
        function (cacheData, cb) {
            if (!cacheData) {
                request.get(options, function (err, res, body) {
                    if (err) {
                        return cb(err, null, 'imgur');
                    }
                    var result;
                    try {
                        result = JSON.parse(body);
                    } catch (e) {
                        return cb(e);
                    }
                    if (result.data) {
                        var animated = [];
                        for (var i in result.data) {
                            if (result.data[i].animated) {
                                animated.push(result.data[i]);
                            }
                        }
                        setCache(options.url, { created: new Date().getTime(), ttl: 3600, data: animated }, cb);
                    } else {
                       cb(new Error('imgur: no data'));
                    }
                });
            } else {
                cb(null, cacheData);
            }
        },
        function (cacheData, cb) {
            if (cacheData.data && cacheData.data.length>0) {
                var selectedImage = cacheData.data.pop();
                setCache(options.url, cacheData, function (err) {
                    cb(err, selectedImage.link, 'imgur');
                });
            } else {
                cb(new Error('imgur: cache empty'), null, 'imgur');
            }
        }
    ],
    function (err, selectedImage) {
        callback(err, selectedImage, 'imgur');
    });
};

function getCache(url, callback) {
    var async = require('async'),
        path = require('path'),
        fs = require('fs'),
        config = exports.config;
    async.waterfall([
        function (cb) {
            var cachePath = path.join(config.imgur.cache_dir, getKey(url));
            fs.exists(cachePath, function (exists) {
                if (exists) {
                    //console.log('found in cache', cachePath);
                    cb(null, cachePath);
                } else {
                    //console.log('not in cache', cachePath);
                    cb(null, null);
                }
            });
        },
        function (cachePath, cb) {
            if (cachePath==null) return cb(null, null);
            //console.log('fetching from cache', cachePath);
            var resource = require('../resource');
            resource.getResource(cachePath, function (err, cacheEntry) {
                if (err) return cb(err, null);
                if ((new Date().getTime()-cacheEntry.created)*0.001>cacheEntry.ttl) {
                    //console.log('cache expired', cachePath);
                    cb(null, null);
                } else {
                    cb(null, cacheEntry);
                }
            });
        }
    ],
    function (err, cacheEntry) {
        callback(err, cacheEntry);
    });
}

function setCache(url, payload, callback) {
    var path = require('path'),
        config = exports.config;
    var cachePath = path.join(config.imgur.cache_dir, getKey(url));
    var resource = require('../resource');
    resource.setResource(cachePath, payload, function (err) {
        //console.log('set cache', cachePath);
        callback(err, payload);
    });
}

function getKey(url) {
    return url.replace(/\W+/g, '_');
}

function getNextPage(options, callback) {
    getCache(options.url, function (err, cacheData) {
        if (err) return cb(err);
        if (!cacheData) {
            callback(null, null);
        } else if (cacheData.data && cacheData.data.length>0) {
            callback(null, cacheData);
        } else {
            pageIndex += 1;
            if (pageIndex < maxPages) {
                options.url = baseUrl+pageIndex.toString();
                setTimeout(function () {
                    getNextPage(options, callback);
                });
            } else {
                callback(new Error('imgur: cache empty'), null, 'imgur');
            }
        }
    });
}<|endoftext|>


<commit_before>
var MAX_CHARS = 80
var colors = require( 'chalk' )
var wordwrap = require( 'wordwrap')( MAX_CHARS )

module.exports = {
  PrettyError: PrettyError,
  create: create,
}

function create( message, props ) {
  return new PrettyError( message, props )
}

function PrettyError( message, props ) {
  Error.captureStackTrace( this, this.constructor )
  this.message = message
  this.name = props.name + 'Error'
  this.errname = props.name
  this.code = props.code || 0
  this.describe = props.describe
  this.explain = props.explain || ''
  this.example = props.example || ''
}
PrettyError.prototype = Object.create( Error.prototype, PrettyError.prototype )
PrettyError.prototype.constructor = PrettyError

PrettyError.prototype.toString = function() {
  var message = fmtHeader( this.message )
  message += fmtDescribe( this.describe )

  if ( this.explain ) {
    message += fmtExplain( this.explain )
  }

  if ( this.example ) {
    message += fmtExample( this.example )
  }

  return message
}

function fmtHeader( message ) {
  var message = truncate( message, ( MAX_CHARS - 17 ) )
  return colors.cyan( '\n==== Error: ' + message + ' ====\n' )
}

function fmtDescribe( description ) {
  return colors.yellow( '\n' + wordwrap( description ) + '\n' )
}

function fmtExplain( explanation ) {
  return '\n' + wordwrap( explanation ) + '\n'
}

function fmtExample( example ) {
  var fmt = '\n---- Example '
  var max = MAX_CHARS - fmt.length
  for ( var i = 0; i <= max; i++ ) {
    fmt += '-'
  }
  fmt += '\n\n'
  fmt += wordwrap( example )
  return fmt + '\n'
}

function fmtStack( stack ) {
  console.log( '\n\nStack:\n\n' + stack )
}

function truncate( string, maxlen ) {
  var maxlen = maxlen || MAX_CHARS
  var msglen = maxlen - 3
  if ( string.length > maxlen ){
    return string.substring( 0, msglen ) + '...';
  }
  else {
    return string;
  }
}
<commit_msg>Add support for printing filepath and error codes when provided<commit_after>var MAX_CHARS = 80
var colors = require( 'chalk' )
var wordwrap = require( 'wordwrap')( MAX_CHARS )

module.exports = {
  PrettyError: PrettyError,
  create: create,
}

function create( message, props ) {
  return new PrettyError( message, props )
}

function PrettyError( message, props ) {
  Error.captureStackTrace( this, this.constructor )
  this.message = message
  this.name = props.name + 'Error'
  this.errname = props.name
  this.code = props.code || 0
  this.describe = props.describe
  this.explain = props.explain || ''
  this.example = props.example || ''
  this.filepath = props.filepath || ''
}
PrettyError.prototype = Object.create( Error.prototype, PrettyError.prototype )
PrettyError.prototype.constructor = PrettyError

PrettyError.prototype.toString = function() {
  var message = fmtHeader( this.message )
  message += fmtDescribe( this.describe )

  if ( this.explain ) {
    message += fmtExplain( this.explain )
  }

  if ( this.example ) {
    message += fmtExample( this.example )
  }

  message += fmtInfo( this.code, this.file )

  return message
}

function fmtHeader( message ) {
  var message = truncate( message, ( MAX_CHARS - 17 ) )
  return colors.cyan( '\n==== ERROR: ' + message + ' ====\n' )
}

function fmtDescribe( description ) {
  return colors.yellow( '\n' + wordwrap( description ) + '\n' )
}

function fmtExplain( explanation ) {
  return '\n' + wordwrap( explanation ) + '\n'
}

function fmtExample( example ) {
  var fmt = getDivider( 'EXAMPLE' ) + '\n'
  fmt += wordwrap( example )
  return fmt + '\n'
}

function fmtInfo( code, filepath ) {
  if ( !code && !filepath )  { return '' }

  var fmt = '\n' + getDivider()
  if ( code ) {
    fmt += 'Code:\t' + code + '\n'
  }
  if ( filepath ) {
    fmt += 'Path:\t' + filepath + '\n'
  }
  return colors.blue( fmt + getDivider() )
}

/**
 * Return a divider with an optional title
 * @param  {string} [title] A title for the divider.
 * @return {string}       A divider with an optional title.
 */
function getDivider( title ) {
  var divider = title ? '\n---- ' + title + ' ' : ''
  var len = MAX_CHARS - divider.length
  for ( var i = 0; i < len; i++ ) {
    divider += '-'
  }
  return divider + '\n'
}

function truncate( string, maxlen ) {
  var maxlen = maxlen || MAX_CHARS
  var msglen = maxlen - 3
  if ( string.length > maxlen ){
    return string.substring( 0, msglen ) + '...';
  }
  else {
    return string;
  }
}
<|endoftext|>


<commit_before><commit_msg>Add sokuon to everything<commit_after><|endoftext|>


<commit_before>var path = require('path');
var through = require('through2');
var cheerio = require('cheerio');
var gutil = require('gulp-util');
var fs = require('fs');
var dateformat = require('dateformat');
var url = require('url');
var _ = require('lodash');
var crypto = require('crypto');

var fileverCache = {};

module.exports = function(options) {

    var defaultOptions = {
        cwd: '',
        base: '',
        suffix: 'v',
        fileTypes: ['js', 'css', 'img'],
        hashLength: 8,
        dateFormat: 'yyyymmddHHMM',
        revType: 'hash',
        transformPath: function(orgPath, rev) {
            var reg = new RegExp('((\\?|\\&|\\&amp\\;)' + options.suffix + '=)([^&\\s]+)', 'gi');
            var newpath = orgPath;
            if (reg.test(orgPath)) {
                newpath = orgPath.replace(reg, '$1' + rev);
            } else {
                newpath += ((orgPath.indexOf('?') > -1 ? '&' : '?') + options.suffix + '=' + rev);
            }
            return newpath;
        },
        elementAttributes: {
            js: {
                name: 'script',
                src: 'src'
            },
            css: {
                name: 'link[rel="stylesheet"]',
                src: 'href'
            },
            img: {
                name: 'img',
                src: 'src'
            }
        }
    };

    options = _.assign(defaultOptions, options);

    return through.obj(function(file, enc, cb) {
        if (options.cwd !== '') {
            gutil.log(gutil.colors.red('options.cwd is obsoleted, use options.base or set gulp.src(path, {cwd:mycwd}) instead'));
            return;
        }

        gutil.log('==== begin rev:' + gutil.colors.cyan(file.path));
        if (file.isNull()) {
            this.push(file);
            return cb();
        }

        if (file.isStream()) {
            this.emit('error', new gutil.PluginError('gulp-rev-easy', 'Streaming is not supported'));
            return cb();
        }

        try {
            var $ = cheerio.load(file.contents.toString(), {
                decodeEntities: false
            });

            var baseDir = options.base;

            if (baseDir === '')
                baseDir = file.cwd;

            for (var i = 0; i < options.fileTypes.length; i++) {
                var fileType = options.fileTypes[i];
                var attributes = options.elementAttributes[fileType];

                var $assets = $(attributes.name);
                for (var j = 0; j < $assets.length; j++) {
                    var $asset = $assets.eq(j);

                    var src = $asset.attr(attributes.src);

                    if (src && !src.match(/.*(\/\/).*/)) {
                        var revv = '';

                        if (options.revType == 'hash') {
                            var srcpath = url.parse(src).pathname;

                            //if is a /a/b/c/i.png path need a basedir
                            if ((/^\/{1}[^\/]+/gi).test(srcpath))
                                filepath = path.join(baseDir, srcpath);
                            else
                                filepath = path.join(path.dirname(file.path), srcpath);

                            if (fs.existsSync(filepath)) {

                                if (fileverCache[filepath] !== undefined) {
                                    revv = fileverCache[filepath];
                                    gutil.log(gutil.colors.green(filepath + ' found in cache'));
                                } else {
                                    revv = crypto
                                        .createHash('md5')
                                        .update(
                                            fs.readFileSync(filepath, {
                                                encoding: 'utf8'
                                            }))
                                        .digest('hex').substring(0, options.hashLength);
                                }
                                fileverCache[filepath] = revv;
                            } else {
                                gutil.log(gutil.colors.red(filepath + ' not found'));
                            }
                        } else {
                            revv = dateformat(new Date(), options.dateFormat);
                        }

                        if (revv !== '') {
                            var newname = options.transformPath(src, revv);
                            $asset.attr(attributes.src, newname);
                            gutil.log(src + ' --> ', gutil.colors.green(newname));
                        } else {
                            gutil.log(gutil.colors.blue('ignore:rev is empty'), src);
                        }
                    }
                }
            }
            file.contents = new Buffer($.html());

            gutil.log(fileverCache);
            gutil.log('==== end rev:' + gutil.colors.cyan(file.path));
        } catch (err) {
            this.emit('error', new gutil.PluginError('gulp-rev-easy', err));
        }

        this.push(file);
        return cb();
    });
};
<commit_msg>1.修改一些语法格式；<commit_after>var path = require('path');
var through = require('through2');
var cheerio = require('cheerio');
var gutil = require('gulp-util');
var fs = require('fs');
var dateformat = require('dateformat');
var url = require('url');
var _ = require('lodash');
var crypto = require('crypto');

var fileverCache = {};

module.exports = function(options) {

    var defaultOptions = {
        cwd: '',
        base: '',
        suffix: 'v',
        fileTypes: ['js', 'css', 'img'],
        hashLength: 8,
        dateFormat: 'yyyymmddHHMM',
        revType: 'hash',
        transformPath: function(orgPath, rev) {
            var reg = new RegExp('((\\?|\\&|\\&amp\\;)' + options.suffix + '=)([^&\\s]+)', 'gi');
            var newpath = orgPath;
            if (reg.test(orgPath)) {
                newpath = orgPath.replace(reg, '$1' + rev);
            } else {
                newpath += ((orgPath.indexOf('?') > -1 ? '&' : '?') + options.suffix + '=' + rev);
            }
            return newpath;
        },
        elementAttributes: {
            js: {
                name: 'script',
                src: 'src'
            },
            css: {
                name: 'link[rel="stylesheet"]',
                src: 'href'
            },
            img: {
                name: 'img',
                src: 'src'
            }
        }
    };

    options = _.assign(defaultOptions, options);

    return through.obj(function(file, enc, cb) {
        if (options.cwd !== '') {
            gutil.log(gutil.colors.red('options.cwd is obsoleted, use options.base or set gulp.src(path, {cwd:mycwd}) instead'));
            return;
        }

        gutil.log('==== begin rev:' + gutil.colors.cyan(file.path));
        if (file.isNull()) {
            this.push(file);
            return cb();
        }

        if (file.isStream()) {
            this.emit('error', new gutil.PluginError('gulp-rev-easy', 'Streaming is not supported'));
            return cb();
        }

        try {
            var $ = cheerio.load(file.contents.toString(), {
                decodeEntities: false
            });

            var baseDir = options.base;

            if (baseDir === '') {
                baseDir = file.cwd;
            }

            for (var i = 0; i < options.fileTypes.length; i++) {
                var fileType = options.fileTypes[i];
                var attributes = options.elementAttributes[fileType];

                var $assets = $(attributes.name);
                for (var j = 0; j < $assets.length; j++) {
                    var $asset = $assets.eq(j);

                    var src = $asset.attr(attributes.src);

                    if (src && !src.match(/.*(\/\/).*/)) {
                        var revv = '';

                        if (options.revType === 'hash') {
                            var srcpath = url.parse(src).pathname;
                            var filepath = null;

                            //if is a /a/b/c/i.png path need a basedir
                            if ((/^\/{1}[^\/]+/gi).test(srcpath)) {
                                filepath = path.join(baseDir, srcpath);
                            } else {
                                filepath = path.join(path.dirname(file.path), srcpath);
                            }

                            if (fs.existsSync(filepath)) {

                                if (fileverCache[filepath] !== undefined) {
                                    revv = fileverCache[filepath];
                                    gutil.log(gutil.colors.green(filepath + ' found in cache'));
                                } else {
                                    revv = crypto
                                        .createHash('md5')
                                        .update(
                                            fs.readFileSync(filepath, {
                                                encoding: 'utf8'
                                            }))
                                        .digest('hex').substring(0, options.hashLength);
                                }
                                fileverCache[filepath] = revv;
                            } else {
                                gutil.log(gutil.colors.red(filepath + ' not found'));
                            }
                        } else {
                            revv = dateformat(new Date(), options.dateFormat);
                        }

                        if (revv !== '') {
                            var newname = options.transformPath(src, revv);
                            $asset.attr(attributes.src, newname);
                            gutil.log(src + ' --> ', gutil.colors.green(newname));
                        } else {
                            gutil.log(gutil.colors.blue('ignore:rev is empty'), src);
                        }
                    }
                }
            }
            file.contents = new Buffer($.html());

            gutil.log(fileverCache);
            gutil.log('==== end rev:' + gutil.colors.cyan(file.path));
        } catch (err) {
            this.emit('error', new gutil.PluginError('gulp-rev-easy', err));
        }

        this.push(file);
        return cb();
    });
};
<|endoftext|>


<commit_before>// Copyright 2017 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview The interface for module managers. The default implementation
 * is goog.module.ModuleManager.
 */

goog.provide('goog.loader.AbstractModuleManager');
goog.provide('goog.loader.AbstractModuleManager.CallbackType');
goog.provide('goog.loader.AbstractModuleManager.FailureType');

goog.require('goog.Disposable');
goog.require('goog.module.AbstractModuleLoader');
goog.require('goog.module.ModuleInfo');
goog.require('goog.module.ModuleLoadCallback');

/**
 * The ModuleManager keeps track of all modules in the environment.
 * Since modules may not have their code loaded, we must keep track of them.
 * @abstract
 * @constructor
 * @struct
 * @extends {goog.Disposable}
 */
goog.loader.AbstractModuleManager = function() {
  goog.loader.AbstractModuleManager.base(this, 'constructor');

  /**
   * The module context needed for module initialization.
   * @private {?Object}
   */
  this.moduleContext_ = null;

  /**
   * A loader for the modules that implements loadModules(ids, moduleInfoMap,
   * opt_successFn, opt_errorFn, opt_timeoutFn, opt_forceReload) method.
   * @private {?goog.module.AbstractModuleLoader}
   */
  this.loader_ = null;
};
goog.inherits(goog.loader.AbstractModuleManager, goog.Disposable);

/**
 * The type of callbacks that can be registered with the module manager,.
 * @enum {string}
 */
goog.loader.AbstractModuleManager.CallbackType = {
  /**
   * Fired when an error has occurred.
   */
  ERROR: 'error',

  /**
   * Fired when it becomes idle and has no more module loads to process.
   */
  IDLE: 'idle',

  /**
   * Fired when it becomes active and has module loads to process.
   */
  ACTIVE: 'active',

  /**
   * Fired when it becomes idle and has no more user-initiated module loads to
   * process.
   */
  USER_IDLE: 'userIdle',

  /**
   * Fired when it becomes active and has user-initiated module loads to
   * process.
   */
  USER_ACTIVE: 'userActive'
};

/**
 * The possible reasons for a module load failure callback being fired.
 * @enum {number}
 */
goog.loader.AbstractModuleManager.FailureType = {
  /** 401 Status. */
  UNAUTHORIZED: 0,

  /** Error status (not 401) returned multiple times. */
  CONSECUTIVE_FAILURES: 1,

  /** Request timeout. */
  TIMEOUT: 2,

  /** 410 status, old code gone. */
  OLD_CODE_GONE: 3,

  /** The onLoad callbacks failed. */
  INIT_ERROR: 4
};

/**
 * A non-HTTP status code indicating a corruption in loaded module.
 * This should be used by a ModuleLoader as a replacement for the HTTP code
 * given to the error handler function to indicated that the module was
 * corrupted.
 * This will set the forceReload flag on the loadModules method when retrying
 * module loading.
 * @type {number}
 */
goog.loader.AbstractModuleManager.CORRUPT_RESPONSE_STATUS_CODE = 8001;

/**
 * Sets the batch mode as enabled or disabled for the module manager.
 * @param {boolean} enabled Whether the batch mode is to be enabled or not.
 */
goog.loader.AbstractModuleManager.prototype.setBatchModeEnabled = function(
    enabled) {};

/**
 * Sets the concurrent loading mode as enabled or disabled for the module
 * manager. Requires a moduleloader implementation that supports concurrent
 * loads. The default {@see goog.module.ModuleLoader} does not.
 * @param {boolean} enabled
 */
goog.loader.AbstractModuleManager.prototype.setConcurrentLoadingEnabled =
    function(enabled) {};

/**
 * Sets the module info for all modules. Should only be called once.
 *
 * @param {!Object<!Array<string>>} infoMap An object that contains a mapping
 *    from module id (String) to list of required module ids (Array).
 */
goog.loader.AbstractModuleManager.prototype.setAllModuleInfo = function(
    infoMap) {};

/**
 * Sets the module info for all modules. Should only be called once. Also
 * marks modules that are currently being loaded.
 *
 * @param {string=} opt_info A string representation of the module dependency
 *      graph, in the form: module1:dep1,dep2/module2:dep1,dep2 etc.
 *     Where depX is the base-36 encoded position of the dep in the module list.
 * @param {!Array<string>=} opt_loadingModuleIds A list of moduleIds that
 *     are currently being loaded.
 */
goog.loader.AbstractModuleManager.prototype.setAllModuleInfoString = function(
    opt_info, opt_loadingModuleIds) {};

/**
 * Gets a module info object by id.
 * @param {string} id A module identifier.
 * @return {!goog.module.ModuleInfo} The module info.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.getModuleInfo = function(id) {};

/**
 * Sets the module uris.
 * @param {!Object<string, !Array<!goog.html.TrustedResourceUrl>>} moduleUriMap
 *     The map of id/uris pairs for each module.
 */
goog.loader.AbstractModuleManager.prototype.setModuleTrustedUris = function(
    moduleUriMap) {};

/**
 * Gets the application-specific module loader.
 * @return {?goog.module.AbstractModuleLoader} An object that has a
 *     loadModules(ids, moduleInfoMap, opt_successFn, opt_errFn,
 *         opt_timeoutFn, opt_forceReload) method.
 */
goog.loader.AbstractModuleManager.prototype.getLoader = function() {
  return this.loader_;
};

/**
 * Sets the application-specific module loader.
 * @param {!goog.module.AbstractModuleLoader} loader An object that has a
 *     loadModules(ids, moduleInfoMap, opt_successFn, opt_errFn,
 *         opt_timeoutFn, opt_forceReload) method.
 */
goog.loader.AbstractModuleManager.prototype.setLoader = function(loader) {
  this.loader_ = loader;
};

/**
 * Gets the module context to use to initialize the module.
 * @return {?Object} The context.
 */
goog.loader.AbstractModuleManager.prototype.getModuleContext = function() {
  return this.moduleContext_;
};

/**
 * Sets the module context to use to initialize the module.
 * @param {!Object} context The context.
 */
goog.loader.AbstractModuleManager.prototype.setModuleContext = function(
    context) {
  this.moduleContext_ = context;
};

/**
 * Determines if the ModuleManager is active
 * @return {boolean} TRUE iff the ModuleManager is active (i.e., not idle).
 */
goog.loader.AbstractModuleManager.prototype.isActive = function() {
  return false;
};

/**
 * Determines if the ModuleManager is user active
 * @return {boolean} TRUE iff the ModuleManager is user active (i.e., not idle).
 */
goog.loader.AbstractModuleManager.prototype.isUserActive = function() {
  return false;
};

/**
 * Preloads a module after a short delay.
 *
 * @param {string} id The id of the module to preload.
 * @param {number=} opt_timeout The number of ms to wait before adding the
 *     module id to the loading queue (defaults to 0 ms). Note that the module
 *     will be loaded asynchronously regardless of the value of this parameter.
 * @return {!IThenable}
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.preloadModule = function(
    id, opt_timeout) {};

/**
 * Prefetches a JavaScript module and its dependencies, which means that the
 * module will be downloaded, but not evaluated. To complete the module load,
 * the caller should also call load or execOnLoad after prefetching the module.
 *
 * @param {string} id The id of the module to prefetch.
 */
goog.loader.AbstractModuleManager.prototype.prefetchModule = function(id) {
  throw new Error('prefetchModule is not implemented.');
};

/**
 * Records that a module was loaded. Also initiates loading the next module if
 * any module requests are queued. This method is called by code that is
 * generated and appended to each dynamic module's code at compilation time.
 *
 * @param {string} id A module id.
 */
goog.loader.AbstractModuleManager.prototype.setLoaded = function(id) {};

/**
 * Gets whether a module is currently loading or in the queue, waiting to be
 * loaded.
 * @param {string} id A module id.
 * @return {boolean} TRUE iff the module is loading.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.isModuleLoading = function(id) {};

/**
 * Requests that a function be called once a particular module is loaded.
 * Client code can use this method to safely call into modules that may not yet
 * be loaded. For consistency, this method always calls the function
 * asynchronously -- even if the module is already loaded. Initiates loading of
 * the module if necessary, unless opt_noLoad is true.
 *
 * @param {string} moduleId A module id.
 * @param {!Function} fn Function to execute when the module has loaded.
 * @param {!Object=} opt_handler Optional handler under whose scope to execute
 *     the callback.
 * @param {boolean=} opt_noLoad TRUE iff not to initiate loading of the module.
 * @param {boolean=} opt_userInitiated TRUE iff the loading of the module was
 *     user initiated.
 * @param {boolean=} opt_preferSynchronous TRUE iff the function should be
 *     executed synchronously if the module has already been loaded.
 * @return {!goog.module.ModuleLoadCallback} A callback wrapper that exposes
 *     an abort and execute method.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.execOnLoad = function(
    moduleId, fn, opt_handler, opt_noLoad, opt_userInitiated,
    opt_preferSynchronous) {};

/**
 * Loads a module, returning an IThenable for keeping track of the result.
 *
 * @param {string} moduleId A module id.
 * @param {boolean=} opt_userInitiated If the load is a result of a user action.
 * @return {!IThenable} A deferred object.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.load = function(
    moduleId, opt_userInitiated) {};

/**
 * Loads a list of modules, returning a map of IThenables for keeping track of
 * the results.
 *
 * @param {!Array<string>} moduleIds A list of module ids.
 * @param {boolean=} opt_userInitiated If the load is a result of a user action.
 * @return {!Object<string, !IThenable>} A mapping from id (String)
 *     to deferred objects that will callback or errback when the load for that
 *     id is finished.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.loadMultiple = function(
    moduleIds, opt_userInitiated) {};

/**
 * Method called just before a module code is loaded.
 * @param {string} id Identifier of the module.
 */
goog.loader.AbstractModuleManager.prototype.beforeLoadModuleCode = function(
    id) {};

/**
 * Method called just after module code is loaded
 * @param {string} id Identifier of the module.
 */
goog.loader.AbstractModuleManager.prototype.afterLoadModuleCode = function(
    id) {};

/**
 * Register an initialization callback for the currently loading module. This
 * should only be called by script that is executed during the evaluation of
 * a module's javascript. This is almost equivalent to calling the function
 * inline, but ensures that all the code from the currently loading module
 * has been loaded. This makes it cleaner and more robust than calling the
 * function inline.
 *
 * If this function is called from the base module (the one that contains
 * the module manager code), the callback is held until #setAllModuleInfo
 * is called, or until #setModuleContext is called, whichever happens first.
 *
 * @param {!Function} fn A callback function that takes a single argument
 *    which is the module context.
 * @param {!Object=} opt_handler Optional handler under whose scope to execute
 *     the callback.
 */
goog.loader.AbstractModuleManager.prototype.registerInitializationCallback =
    function(fn, opt_handler) {};

/**
 * Register a late initialization callback for the currently loading module.
 * Callbacks registered via this function are executed similar to
 * {@see registerInitializationCallback}, but they are fired after all
 * initialization callbacks are called.
 *
 * @param {!Function} fn A callback function that takes a single argument
 *    which is the module context.
 * @param {!Object=} opt_handler Optional handler under whose scope to execute
 *     the callback.
 */
goog.loader.AbstractModuleManager.prototype.registerLateInitializationCallback =
    function(fn, opt_handler) {};

/**
 * Sets the constructor to use for the module object for the currently
 * loading module. The constructor should derive from
 * {@see goog.module.BaseModule}.
 * @param {!Function} fn The constructor function.
 */
goog.loader.AbstractModuleManager.prototype.setModuleConstructor = function(
    fn) {};

/**
 * The function to call if the module manager is in error.
 * @param {!goog.loader.AbstractModuleManager.CallbackType|!Array<
 *     !goog.loader.AbstractModuleManager.CallbackType>} types The callback
 *         type.
 * @param {!Function} fn The function to register as a callback.
 */
goog.loader.AbstractModuleManager.prototype.registerCallback = function(
    types, fn) {};
<commit_msg>Rollforward of cl/184296093 (05f1bbc55), now that cl/184330869 fixed the issue:<commit_after>// Copyright 2017 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview The interface for module managers. The default implementation
 * is goog.module.ModuleManager.
 */

goog.provide('goog.loader.AbstractModuleManager');
goog.provide('goog.loader.AbstractModuleManager.CallbackType');
goog.provide('goog.loader.AbstractModuleManager.FailureType');

goog.require('goog.Disposable');
goog.require('goog.module.AbstractModuleLoader');
goog.require('goog.module.ModuleInfo');
goog.require('goog.module.ModuleLoadCallback');

/**
 * The ModuleManager keeps track of all modules in the environment.
 * Since modules may not have their code loaded, we must keep track of them.
 * @abstract
 * @constructor
 * @struct
 * @extends {goog.Disposable}
 */
goog.loader.AbstractModuleManager = function() {
  goog.loader.AbstractModuleManager.base(this, 'constructor');

  /**
   * The module context needed for module initialization.
   * @private {?Object}
   */
  this.moduleContext_ = null;

  /**
   * A loader for the modules that implements loadModules(ids, moduleInfoMap,
   * opt_successFn, opt_errorFn, opt_timeoutFn, opt_forceReload) method.
   * @private {?goog.module.AbstractModuleLoader}
   */
  this.loader_ = null;
};
goog.inherits(goog.loader.AbstractModuleManager, goog.Disposable);

/**
 * The type of callbacks that can be registered with the module manager,.
 * @enum {string}
 */
goog.loader.AbstractModuleManager.CallbackType = {
  /**
   * Fired when an error has occurred.
   */
  ERROR: 'error',

  /**
   * Fired when it becomes idle and has no more module loads to process.
   */
  IDLE: 'idle',

  /**
   * Fired when it becomes active and has module loads to process.
   */
  ACTIVE: 'active',

  /**
   * Fired when it becomes idle and has no more user-initiated module loads to
   * process.
   */
  USER_IDLE: 'userIdle',

  /**
   * Fired when it becomes active and has user-initiated module loads to
   * process.
   */
  USER_ACTIVE: 'userActive'
};

/**
 * The possible reasons for a module load failure callback being fired.
 * @enum {number}
 */
goog.loader.AbstractModuleManager.FailureType = {
  /** 401 Status. */
  UNAUTHORIZED: 0,

  /** Error status (not 401) returned multiple times. */
  CONSECUTIVE_FAILURES: 1,

  /** Request timeout. */
  TIMEOUT: 2,

  /** 410 status, old code gone. */
  OLD_CODE_GONE: 3,

  /** The onLoad callbacks failed. */
  INIT_ERROR: 4
};

/**
 * A non-HTTP status code indicating a corruption in loaded module.
 * This should be used by a ModuleLoader as a replacement for the HTTP code
 * given to the error handler function to indicated that the module was
 * corrupted.
 * This will set the forceReload flag on the loadModules method when retrying
 * module loading.
 * @type {number}
 */
goog.loader.AbstractModuleManager.CORRUPT_RESPONSE_STATUS_CODE = 8001;

/**
 * Sets the batch mode as enabled or disabled for the module manager.
 * @param {boolean} enabled Whether the batch mode is to be enabled or not.
 */
goog.loader.AbstractModuleManager.prototype.setBatchModeEnabled = function(
    enabled) {};

/**
 * Sets the concurrent loading mode as enabled or disabled for the module
 * manager. Requires a moduleloader implementation that supports concurrent
 * loads. The default {@see goog.module.ModuleLoader} does not.
 * @param {boolean} enabled
 */
goog.loader.AbstractModuleManager.prototype.setConcurrentLoadingEnabled =
    function(enabled) {};

/**
 * Sets the module info for all modules. Should only be called once.
 *
 * @param {!Object<!Array<string>>} infoMap An object that contains a mapping
 *    from module id (String) to list of required module ids (Array).
 */
goog.loader.AbstractModuleManager.prototype.setAllModuleInfo = function(
    infoMap) {};

/**
 * Sets the module info for all modules. Should only be called once. Also
 * marks modules that are currently being loaded.
 *
 * @param {string=} opt_info A string representation of the module dependency
 *      graph, in the form: module1:dep1,dep2/module2:dep1,dep2 etc.
 *     Where depX is the base-36 encoded position of the dep in the module list.
 * @param {!Array<string>=} opt_loadingModuleIds A list of moduleIds that
 *     are currently being loaded.
 */
goog.loader.AbstractModuleManager.prototype.setAllModuleInfoString = function(
    opt_info, opt_loadingModuleIds) {};

/**
 * Gets a module info object by id.
 * @param {string} id A module identifier.
 * @return {!goog.module.ModuleInfo} The module info.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.getModuleInfo = function(id) {};

/**
 * Sets the module uris.
 * @param {!Object<string, !Array<!goog.html.TrustedResourceUrl>>} moduleUriMap
 *     The map of id/uris pairs for each module.
 */
goog.loader.AbstractModuleManager.prototype.setModuleTrustedUris = function(
    moduleUriMap) {};

/**
 * Gets the application-specific module loader.
 * @return {?goog.module.AbstractModuleLoader} An object that has a
 *     loadModules(ids, moduleInfoMap, opt_successFn, opt_errFn,
 *         opt_timeoutFn, opt_forceReload) method.
 */
goog.loader.AbstractModuleManager.prototype.getLoader = function() {
  return this.loader_;
};

/**
 * Sets the application-specific module loader.
 * @param {!goog.module.AbstractModuleLoader} loader An object that has a
 *     loadModules(ids, moduleInfoMap, opt_successFn, opt_errFn,
 *         opt_timeoutFn, opt_forceReload) method.
 */
goog.loader.AbstractModuleManager.prototype.setLoader = function(loader) {
  this.loader_ = loader;
};

/**
 * Gets the module context to use to initialize the module.
 * @return {?Object} The context.
 */
goog.loader.AbstractModuleManager.prototype.getModuleContext = function() {
  return this.moduleContext_;
};

/**
 * Sets the module context to use to initialize the module.
 * @param {!Object} context The context.
 */
goog.loader.AbstractModuleManager.prototype.setModuleContext = function(
    context) {
  this.moduleContext_ = context;
};

/**
 * Determines if the ModuleManager is active
 * @return {boolean} TRUE iff the ModuleManager is active (i.e., not idle).
 */
goog.loader.AbstractModuleManager.prototype.isActive = function() {
  return false;
};

/**
 * Determines if the ModuleManager is user active
 * @return {boolean} TRUE iff the ModuleManager is user active (i.e., not idle).
 */
goog.loader.AbstractModuleManager.prototype.isUserActive = function() {
  return false;
};

/**
 * Preloads a module after a short delay.
 *
 * @param {string} id The id of the module to preload.
 * @param {number=} opt_timeout The number of ms to wait before adding the
 *     module id to the loading queue (defaults to 0 ms). Note that the module
 *     will be loaded asynchronously regardless of the value of this parameter.
 * @return {!IThenable}
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.preloadModule = function(
    id, opt_timeout) {};

/**
 * Prefetches a JavaScript module and its dependencies, which means that the
 * module will be downloaded, but not evaluated. To complete the module load,
 * the caller should also call load or execOnLoad after prefetching the module.
 *
 * @param {string} id The id of the module to prefetch.
 */
goog.loader.AbstractModuleManager.prototype.prefetchModule = function(id) {
  throw new Error('prefetchModule is not implemented.');
};

/**
 * Records that a module was loaded. Also initiates loading the next module if
 * any module requests are queued. This method is called by code that is
 * generated and appended to each dynamic module's code at compilation time.
 *
 * @param {string} id A module id.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.setLoaded = function(id) {};

/**
 * Gets whether a module is currently loading or in the queue, waiting to be
 * loaded.
 * @param {string} id A module id.
 * @return {boolean} TRUE iff the module is loading.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.isModuleLoading = function(id) {};

/**
 * Requests that a function be called once a particular module is loaded.
 * Client code can use this method to safely call into modules that may not yet
 * be loaded. For consistency, this method always calls the function
 * asynchronously -- even if the module is already loaded. Initiates loading of
 * the module if necessary, unless opt_noLoad is true.
 *
 * @param {string} moduleId A module id.
 * @param {!Function} fn Function to execute when the module has loaded.
 * @param {!Object=} opt_handler Optional handler under whose scope to execute
 *     the callback.
 * @param {boolean=} opt_noLoad TRUE iff not to initiate loading of the module.
 * @param {boolean=} opt_userInitiated TRUE iff the loading of the module was
 *     user initiated.
 * @param {boolean=} opt_preferSynchronous TRUE iff the function should be
 *     executed synchronously if the module has already been loaded.
 * @return {!goog.module.ModuleLoadCallback} A callback wrapper that exposes
 *     an abort and execute method.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.execOnLoad = function(
    moduleId, fn, opt_handler, opt_noLoad, opt_userInitiated,
    opt_preferSynchronous) {};

/**
 * Loads a module, returning an IThenable for keeping track of the result.
 *
 * @param {string} moduleId A module id.
 * @param {boolean=} opt_userInitiated If the load is a result of a user action.
 * @return {!IThenable} A deferred object.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.load = function(
    moduleId, opt_userInitiated) {};

/**
 * Loads a list of modules, returning a map of IThenables for keeping track of
 * the results.
 *
 * @param {!Array<string>} moduleIds A list of module ids.
 * @param {boolean=} opt_userInitiated If the load is a result of a user action.
 * @return {!Object<string, !IThenable>} A mapping from id (String)
 *     to deferred objects that will callback or errback when the load for that
 *     id is finished.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.loadMultiple = function(
    moduleIds, opt_userInitiated) {};

/**
 * Method called just before module code is loaded.
 * @param {string} id Identifier of the module.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.beforeLoadModuleCode = function(
    id) {};

/**
 * Method called just after module code is loaded
 * @param {string} id Identifier of the module.
 * @abstract
 */
goog.loader.AbstractModuleManager.prototype.afterLoadModuleCode = function(
    id) {};

/**
 * Register an initialization callback for the currently loading module. This
 * should only be called by script that is executed during the evaluation of
 * a module's javascript. This is almost equivalent to calling the function
 * inline, but ensures that all the code from the currently loading module
 * has been loaded. This makes it cleaner and more robust than calling the
 * function inline.
 *
 * If this function is called from the base module (the one that contains
 * the module manager code), the callback is held until #setAllModuleInfo
 * is called, or until #setModuleContext is called, whichever happens first.
 *
 * @param {!Function} fn A callback function that takes a single argument
 *    which is the module context.
 * @param {!Object=} opt_handler Optional handler under whose scope to execute
 *     the callback.
 */
goog.loader.AbstractModuleManager.prototype.registerInitializationCallback =
    function(fn, opt_handler) {};

/**
 * Register a late initialization callback for the currently loading module.
 * Callbacks registered via this function are executed similar to
 * {@see registerInitializationCallback}, but they are fired after all
 * initialization callbacks are called.
 *
 * @param {!Function} fn A callback function that takes a single argument
 *    which is the module context.
 * @param {!Object=} opt_handler Optional handler under whose scope to execute
 *     the callback.
 */
goog.loader.AbstractModuleManager.prototype.registerLateInitializationCallback =
    function(fn, opt_handler) {};

/**
 * Sets the constructor to use for the module object for the currently
 * loading module. The constructor should derive from
 * {@see goog.module.BaseModule}.
 * @param {!Function} fn The constructor function.
 */
goog.loader.AbstractModuleManager.prototype.setModuleConstructor = function(
    fn) {};

/**
 * The function to call if the module manager is in error.
 * @param {!goog.loader.AbstractModuleManager.CallbackType|!Array<
 *     !goog.loader.AbstractModuleManager.CallbackType>} types The callback
 *         type.
 * @param {!Function} fn The function to register as a callback.
 */
goog.loader.AbstractModuleManager.prototype.registerCallback = function(
    types, fn) {};
<|endoftext|>