<commit_before>'use strict';

// MODULES //

var debug = require( 'debug' )( 'gh-pages:benchmarks-html' );
var resolve = require( 'path' ).resolve;
var writeFile = require( 'fs' ).writeFile;
var mustache = require( 'mustache' );
var prefix = require( './stdlib.js' );
var isString = require( prefix+'@stdlib/utils/is-string' ).isPrimitive;
var isFunction = require( prefix+'@stdlib/utils/is-function' );
var readFileSync = require( prefix+'@stdlib/fs/read-file' ).sync;
var cwd = require( prefix+'@stdlib/utils/cwd' );
var copy = require( prefix+'@stdlib/utils/copy' );
var defaults = require( './defaults.json' );
var validate = require( './validate.js' );

// VARIABLES //

var template = resolve( __dirname, '..', 'static/index.html' );
template = readFileSync( template, {
	'encoding': 'utf8'
});

// MAIN //

/**
* Generates an HTML file for running benchmarks.
*
* @param {string} bundle - bundle file path
* @param {string} out - output file path
* @param {Options} [options] - options
* @param {string} [options.title] - HTML title
* @param {Callback} clbk - callback to invoke after generating file
* @throws {TypeError} first argument must be a string
* @throws {TypeError} second argument must be a string
* @throws {TypeError} options argument must be an object
* @throws {TypeError} must provide valid options
* @throws {TypeError} callback argument must be a function
*/
function build( bundle, out, options, clbk ) {
	var wopts;
	var opts;
	var view;
	var html;
	var err;
	var dir;
	var cb;

	if ( !isString( bundle ) ) {
		throw new TypeError( 'invalid input argument. First argument must be a string. Value: `'+bundle+'`.' );
	}
	if ( !isString( out ) ) {
		throw new TypeError( 'invalid input argument. Second argument must be a string. Value: `'+out+'`.' );
	}
	opts = copy( defaults );
	if ( arguments.length < 4 ) {
		cb = options;
	} else {
		cb = clbk;
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	if ( !isFunction( cb ) ) {
		throw new TypeError( 'invalid input argument. Callback argument must be a function. Value: `'+cb+'`.' );
	}
	dir = cwd();
	debug( 'Current working directory: %s', dir );

	out = resolve( dir, out );
	debug( 'Destination filepath: %s', out );

	view = {
		'title': opts.title,
		'bundle': bundle
	};
	debug( 'Render options: %s', JSON.stringify( view ) );

	debug( 'Rendering...' );
	html = mustache.render( template, view );
	debug( 'Finished rendering.' );

	debug( 'Writing to file...' );
	wopts = {
		'encoding': 'utf8'
	};
	writeFile( out, html, wopts, onWrite );

	/**
	* Callback invoked upon writing to file.
	*
	* @private
	* @param {(Error|null)} error - error object
	*/
	function onWrite( error ) {
		if ( error ) {
			debug( 'Encountered an error when writing to file: %s', error.message );
			return done( error );
		}
		debug( 'Successfully wrote to file.' );
		done();
	} // end FUNCTION onWrite()

	/**
	* Callback invoked once finished.
	*
	* @private
	* @param {(Error|null)} error - error object
	*/
	function done( error ) {
		if ( error ) {
			return cb( error );
		}
		cb();
	} // end FUNCTION done()
} // end FUNCTION build()

// EXPORTS //

module.exports = build;
<commit_msg>Update parameter description<commit_after>'use strict';

// MODULES //

var debug = require( 'debug' )( 'gh-pages:benchmarks-html' );
var resolve = require( 'path' ).resolve;
var writeFile = require( 'fs' ).writeFile;
var mustache = require( 'mustache' );
var prefix = require( './stdlib.js' );
var isString = require( prefix+'@stdlib/utils/is-string' ).isPrimitive;
var isFunction = require( prefix+'@stdlib/utils/is-function' );
var readFileSync = require( prefix+'@stdlib/fs/read-file' ).sync;
var cwd = require( prefix+'@stdlib/utils/cwd' );
var copy = require( prefix+'@stdlib/utils/copy' );
var defaults = require( './defaults.json' );
var validate = require( './validate.js' );

// VARIABLES //

var template = resolve( __dirname, '..', 'static/index.html' );
template = readFileSync( template, {
	'encoding': 'utf8'
});

// MAIN //

/**
* Generates an HTML file for running benchmarks.
*
* @param {string} bundle - bundle URL
* @param {string} out - output file path
* @param {Options} [options] - options
* @param {string} [options.title] - HTML title
* @param {Callback} clbk - callback to invoke after generating file
* @throws {TypeError} first argument must be a string
* @throws {TypeError} second argument must be a string
* @throws {TypeError} options argument must be an object
* @throws {TypeError} must provide valid options
* @throws {TypeError} callback argument must be a function
*/
function build( bundle, out, options, clbk ) {
	var wopts;
	var opts;
	var view;
	var html;
	var err;
	var dir;
	var cb;

	if ( !isString( bundle ) ) {
		throw new TypeError( 'invalid input argument. First argument must be a string. Value: `'+bundle+'`.' );
	}
	if ( !isString( out ) ) {
		throw new TypeError( 'invalid input argument. Second argument must be a string. Value: `'+out+'`.' );
	}
	opts = copy( defaults );
	if ( arguments.length < 4 ) {
		cb = options;
	} else {
		cb = clbk;
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	if ( !isFunction( cb ) ) {
		throw new TypeError( 'invalid input argument. Callback argument must be a function. Value: `'+cb+'`.' );
	}
	dir = cwd();
	debug( 'Current working directory: %s', dir );

	out = resolve( dir, out );
	debug( 'Destination filepath: %s', out );

	view = {
		'title': opts.title,
		'bundle': bundle
	};
	debug( 'Render options: %s', JSON.stringify( view ) );

	debug( 'Rendering...' );
	html = mustache.render( template, view );
	debug( 'Finished rendering.' );

	debug( 'Writing to file...' );
	wopts = {
		'encoding': 'utf8'
	};
	writeFile( out, html, wopts, onWrite );

	/**
	* Callback invoked upon writing to file.
	*
	* @private
	* @param {(Error|null)} error - error object
	*/
	function onWrite( error ) {
		if ( error ) {
			debug( 'Encountered an error when writing to file: %s', error.message );
			return done( error );
		}
		debug( 'Successfully wrote to file.' );
		done();
	} // end FUNCTION onWrite()

	/**
	* Callback invoked once finished.
	*
	* @private
	* @param {(Error|null)} error - error object
	*/
	function done( error ) {
		if ( error ) {
			return cb( error );
		}
		cb();
	} // end FUNCTION done()
} // end FUNCTION build()

// EXPORTS //

module.exports = build;
<|endoftext|>


<commit_before>'use strict';
var fs = require('fs');

var mongoNb = process.env.SOAJS_MONGO_NB || 1;
mongoNb = parseInt(mongoNb);
var mongoRsName = process.env.SOAJS_MONGO_RSNAME || "rs_soajs";
var mongoPrefix = process.env.SOAJS_MONGO_PREFIX || "";

var profileLocation = process.env.SOAJS_PROFILE_LOC || "/opt/soajs/FILES/profiles/";

var lib = {
    "writeSingle": function (param, cb) {
        console.log("writing single profile @" + param.loc);
        var wstream = fs.createWriteStream(param.loc + param.profileFileName);

        wstream.write('\'use strict\';\n');
        wstream.write('module.exports = {\n');
        wstream.write('    "name": "core_provision",\n');
        wstream.write('    "prefix": "' + mongoPrefix + '",\n');
        wstream.write('    "servers": [\n');

        for (var i = 1; i <= param.count; i++) {
            if (process.env[param.ipEnvName + i]) {
                wstream.write('        {\n');
                wstream.write('                 "host": "' + process.env[param.ipEnvName + i] + '",\n');
                wstream.write('                 "port": ' + (process.env[param.portEnvName + i] || param.portDefault) + '\n');
                if (i === param.count)
                    wstream.write('        }\n');
                else
                    wstream.write('        },\n');
            }
            else
                console.log("ERROR: Unable to find environment variable " + param.ipEnvName + i);
        }

        wstream.write('    ],\n');

        if (process.env.SOAJS_MONGO_USERNAME && process.env.SOAJS_MONGO_PASSWORD) {
            wstream.write('    "credentials": {\n');
            wstream.write('        "username": "' + process.env.SOAJS_MONGO_USERNAME + '",\n');
            wstream.write('        "password": "' + process.env.SOAJS_MONGO_PASSWORD + '"\n');
            wstream.write('    },\n');
        }
        else
            wstream.write('    "credentials": null,\n');

        wstream.write('    "URLParam": {\n');
        wstream.write('        "maxPoolSize": 2\n');
        wstream.write('    },\n');
        wstream.write('    "extraParam": {\n');
        wstream.write('        "db": {\n');
        wstream.write('            "bufferMaxEntries": 0\n');
        wstream.write('       }\n');
        wstream.write('    }\n');
        wstream.write('};\n');

        wstream.end();
        return cb(null);
    },
    "writeReplica": function (param, cb) {
        console.log("writing replica profile @" + param.loc);
        var wstream = fs.createWriteStream(param.loc + param.profileFileName);

        wstream.write('\'use strict\';\n');
        wstream.write('module.exports = {\n');
        wstream.write('    "name": "core_provision",\n');
        wstream.write('    "prefix": "' + mongoPrefix + '",\n');
        wstream.write('    "servers": [\n');

        for (var i = 1; i <= param.count; i++) {
            if (process.env[param.ipEnvName + i]) {
                wstream.write('        {\n');
                wstream.write('                 "host": "' + process.env[param.ipEnvName + i] + '",\n');
                wstream.write('                 "port": ' + (process.env[param.portEnvName + i] || param.portDefault) + '\n');
                if (i === param.count)
                    wstream.write('        }\n');
                else
                    wstream.write('        },\n');
            }
            else
                console.log("ERROR: Unable to find environment variable " + param.ipEnvName + i);
        }

        wstream.write('    ],\n');

        if (process.env.SOAJS_MONGO_USERNAME && process.env.SOAJS_MONGO_PASSWORD) {
            wstream.write('    "credentials": {\n');
            wstream.write('        "username": "' + process.env.SOAJS_MONGO_USERNAME + '",\n');
            wstream.write('        "password": "' + process.env.SOAJS_MONGO_PASSWORD + '"\n');
            wstream.write('    },\n');
        }
        else
            wstream.write('    "credentials": null,\n');

        wstream.write('    "URLParam": {\n');
        wstream.write('        "maxPoolSize": 2,\n');
        wstream.write('        "readPreference": "secondaryPreferred",\n');
        wstream.write('        "replicaSet": "' + param.rsName + '",\n');
        wstream.write('        "w": "majority",\n');
        wstream.write('        "ha": true\n');
        wstream.write('    },\n');
        wstream.write('    "extraParam": {\n');
        wstream.write('        "db": {\n');
        wstream.write('            "bufferMaxEntries": 0\n');
        wstream.write('       },\n');
        wstream.write('       "replSet": {\n');
        wstream.write('            "ha": true\n');
        wstream.write('        }\n');
        wstream.write('    }\n');
        wstream.write('};\n');

        wstream.end();
        return cb(null);
    }
};

if (mongoNb === 1) {
    lib.writeSingle({
        "profileFileName": 'profile.js',
        "loc": profileLocation,
        "count": mongoNb,
        "ipEnvName": "SOAJS_MONGO_IP_",
        "portEnvName": "SOAJS_MONGO_PORT_",
        "portDefault": 27017,
        "ssl": process.env.SOAJS_MONGO_SSL || false
    }, function (err) {
        console.log("PROFILE SINGLE DONE.");
    });
} else if (mongoNb > 1) {
    lib.writeReplica({
        "profileFileName": 'profile.js',
        "loc": profileLocation,
        "count": mongoNb,
        "ipEnvName": "SOAJS_MONGO_IP_",
        "portEnvName": "SOAJS_MONGO_PORT_",
        "portDefault": 27017,
        "ssl": process.env.SOAJS_MONGO_SSL || false,
        "rsName": mongoRsName
    }, function (err) {
        console.log("PROFILE REPLICA DONE.");
    });
} else {
    console.log("ERROR: PROFILE CREATION FAILED. Environment variable SOAJS_MONGO_NB must be integer [" + mongoNb + "]");
}
<commit_msg>add authSource to urlParams if ENV set<commit_after>'use strict';
var fs = require('fs');

var mongoNb = process.env.SOAJS_MONGO_NB || 1;
mongoNb = parseInt(mongoNb);
var mongoRsName = process.env.SOAJS_MONGO_RSNAME || "rs_soajs";
var mongoPrefix = process.env.SOAJS_MONGO_PREFIX || "";

var profileLocation = process.env.SOAJS_PROFILE_LOC || "/opt/soajs/FILES/profiles/";

var lib = {
    "writeSingle": function (param, cb) {
        console.log("writing single profile @" + param.loc);
        var wstream = fs.createWriteStream(param.loc + param.profileFileName);

        wstream.write('\'use strict\';\n');
        wstream.write('module.exports = {\n');
        wstream.write('    "name": "core_provision",\n');
        wstream.write('    "prefix": "' + mongoPrefix + '",\n');
        wstream.write('    "servers": [\n');

        for (var i = 1; i <= param.count; i++) {
            if (process.env[param.ipEnvName + i]) {
                wstream.write('        {\n');
                wstream.write('                 "host": "' + process.env[param.ipEnvName + i] + '",\n');
                wstream.write('                 "port": ' + (process.env[param.portEnvName + i] || param.portDefault) + '\n');
                if (i === param.count)
                    wstream.write('        }\n');
                else
                    wstream.write('        },\n');
            }
            else
                console.log("ERROR: Unable to find environment variable " + param.ipEnvName + i);
        }

        wstream.write('    ],\n');

        if (process.env.SOAJS_MONGO_USERNAME && process.env.SOAJS_MONGO_PASSWORD) {
            wstream.write('    "credentials": {\n');
            wstream.write('        "username": "' + process.env.SOAJS_MONGO_USERNAME + '",\n');
            wstream.write('        "password": "' + process.env.SOAJS_MONGO_PASSWORD + '"\n');
            wstream.write('    },\n');
        }
        else
            wstream.write('    "credentials": null,\n');

        wstream.write('    "URLParam": {\n');
        wstream.write('        "maxPoolSize": 2\n');
        wstream.write('    },\n');
        wstream.write('    "extraParam": {\n');
        wstream.write('        "db": {\n');
        wstream.write('            "bufferMaxEntries": 0\n');
        wstream.write('       }\n');
        wstream.write('    }\n');
        wstream.write('};\n');

        wstream.end();
        return cb(null);
    },
    "writeReplica": function (param, cb) {
        console.log("writing replica profile @" + param.loc);
        var wstream = fs.createWriteStream(param.loc + param.profileFileName);

        wstream.write('\'use strict\';\n');
        wstream.write('module.exports = {\n');
        wstream.write('    "name": "core_provision",\n');
        wstream.write('    "prefix": "' + mongoPrefix + '",\n');
        wstream.write('    "servers": [\n');

        for (var i = 1; i <= param.count; i++) {
            if (process.env[param.ipEnvName + i]) {
                wstream.write('        {\n');
                wstream.write('                 "host": "' + process.env[param.ipEnvName + i] + '",\n');
                wstream.write('                 "port": ' + (process.env[param.portEnvName + i] || param.portDefault) + '\n');
                if (i === param.count)
                    wstream.write('        }\n');
                else
                    wstream.write('        },\n');
            }
            else
                console.log("ERROR: Unable to find environment variable " + param.ipEnvName + i);
        }

        wstream.write('    ],\n');

        if (process.env.SOAJS_MONGO_USERNAME && process.env.SOAJS_MONGO_PASSWORD) {
            wstream.write('    "credentials": {\n');
            wstream.write('        "username": "' + process.env.SOAJS_MONGO_USERNAME + '",\n');
            wstream.write('        "password": "' + process.env.SOAJS_MONGO_PASSWORD + '"\n');
            wstream.write('    },\n');
        }
        else
            wstream.write('    "credentials": null,\n');

        wstream.write('    "URLParam": {\n');
        if (process.env.SOAJS_MONGO_AUTH_DB)
            wstream.write('        "authSource": "' + process.env.SOAJS_MONGO_AUTH_DB + '",\n');
        wstream.write('        "maxPoolSize": 2,\n');
        wstream.write('        "readPreference": "secondaryPreferred",\n');
        wstream.write('        "replicaSet": "' + param.rsName + '",\n');
        wstream.write('        "w": "majority",\n');
        wstream.write('        "ha": true\n');
        wstream.write('    },\n');
        wstream.write('    "extraParam": {\n');
        wstream.write('        "db": {\n');
        wstream.write('            "bufferMaxEntries": 0\n');
        wstream.write('       },\n');
        wstream.write('       "replSet": {\n');
        wstream.write('            "ha": true\n');
        wstream.write('        }\n');
        wstream.write('    }\n');
        wstream.write('};\n');

        wstream.end();
        return cb(null);
    }
};

if (mongoNb === 1) {
    lib.writeSingle({
        "profileFileName": 'profile.js',
        "loc": profileLocation,
        "count": mongoNb,
        "ipEnvName": "SOAJS_MONGO_IP_",
        "portEnvName": "SOAJS_MONGO_PORT_",
        "portDefault": 27017,
        "ssl": process.env.SOAJS_MONGO_SSL || false
    }, function (err) {
        console.log("PROFILE SINGLE DONE.");
    });
} else if (mongoNb > 1) {
    lib.writeReplica({
        "profileFileName": 'profile.js',
        "loc": profileLocation,
        "count": mongoNb,
        "ipEnvName": "SOAJS_MONGO_IP_",
        "portEnvName": "SOAJS_MONGO_PORT_",
        "portDefault": 27017,
        "ssl": process.env.SOAJS_MONGO_SSL || false,
        "rsName": mongoRsName
    }, function (err) {
        console.log("PROFILE REPLICA DONE.");
    });
} else {
    console.log("ERROR: PROFILE CREATION FAILED. Environment variable SOAJS_MONGO_NB must be integer [" + mongoNb + "]");
}
<|endoftext|>


<commit_before>var drf_lemma = window.location.pathname.split('/').pop().split('.')[0] ;
var drf_sourcepath = $("meta[name='dcterms.source']").attr("content");

if ( $( "body" ).hasClass( "noedit" ) ) {
    drf_noedit = true ;
}

if (typeof drf_new != 'undefined' && drf_lemma != '404error' ) {

    drf_sourcepath_prefill = drf_new.sourcepath + drf_new.prefill ;
    drf_sourcepath_write = drf_new.sourcepath + drf_lemma + drf_new.sourceextension ;
    drf_noedit = false ;

} else {
    drf_sourcepath_write = drf_sourcepath ;
    drf_sourcepath_prefill = drf_sourcepath + '?v=' + Math.random() ; // force reload TODO mv
}

jQuery(document).ready(function() {

    $( "#footer" ).load( "template/drf-formwebedit.html", function() {

        $('#drf-edit').click( function() {

            $(this).hide();
            $('.drf-webedit').show();
            $('.drf-webedit').find('textarea').load( drf_sourcepath_prefill );

            if ( drf_noedit ) {
                $( '.drf-webedit' ).find('button').replaceWith('edit is veiled');
            } else {
                webeditSend( ); // init after replaceWith
            }
         });

        var intermission ;
        $( '.drf-webedit' ).find('textarea').keyup( function() {
            window.clearTimeout( intermission );
            intermission = window.setTimeout( 'render()' , 3000);
        });
    });
});

function webeditSend ( ) {
    $( '.drf-webedit' ).submit( function(event) {
        event.preventDefault();
        $.ajax({
            url: '_drf/make.php',
            type: 'POST',
            data: $(this).serialize() + '&drf_sourcepath=' + drf_sourcepath_write ,
            success: function(){
                $( '#successmsg' ).show() ;
                location.reload(true);
            },
            error:function(){
                $( '#errormsg' ).show();
            }
        });
    });

}
function render () {
    $('#main').html( Markdown( $( '.drf-webedit' ).find('textarea').val() ) );
};
<commit_msg>sort, 404 as special case<commit_after>var drf_lemma = window.location.pathname.split('/').pop().split('.')[0] ;
var drf_noedit = false ;
var drf_sourcepath_write = drf_sourcepath_prefill = $("meta[name='dcterms.source']").attr("content");

if ( $( "body" ).hasClass( "noedit" ) ) {
    drf_noedit = true ;
}

if (typeof drf_new != 'undefined' && drf_lemma != '404error' ) {

    drf_sourcepath_prefill = drf_new.sourcepath + drf_new.prefill ;
    drf_sourcepath_write = drf_new.sourcepath + drf_lemma + drf_new.sourceextension ;
    drf_noedit = false ;

}

jQuery(document).ready(function() {

    $( "#footer" ).load( "template/drf-formwebedit.html", function() {

        $('#drf-edit').click( function() {

            $(this).hide();
            $('.drf-webedit').show();
            $('.drf-webedit').find('textarea').load( drf_sourcepath_prefill  + '?v=' + Math.random() ); // force reload

            if ( drf_noedit ) {
                $( '.drf-webedit' ).find('button').replaceWith('edit is veiled');
            } else {
                webeditSend( ); // init after replaceWith
            }
         });

        var intermission ;
        $( '.drf-webedit' ).find('textarea').keyup( function() {
            window.clearTimeout( intermission );
            intermission = window.setTimeout( 'render()' , 3000);
        });
    });
});

function webeditSend ( ) {
    $( '.drf-webedit' ).submit( function(event) {
        event.preventDefault();
        $.ajax({
            url: '_drf/make.php',
            type: 'POST',
            data: $(this).serialize() + '&drf_sourcepath=' + drf_sourcepath_write ,
            success: function(){
                $( '#successmsg' ).show() ;
                location.reload(true);
            },
            error:function(){
                $( '#errormsg' ).show();
            }
        });
    });

}
function render () {
    $('#main').html( Markdown( $( '.drf-webedit' ).find('textarea').val() ) );
};
<|endoftext|>


<commit_before>/*****************
* special anonymous behavior so that visitors can
* manipulate their work
*
*/

// If our app has a Blaze, override the {{currentUser}} helper to deal guest logins
if (Package.blaze) {
  /**
   * @global
   * @name  currentUser
   * @isHelper true
   * @summary Calls [Meteor.user()](#meteor_user). Use `{{#if currentUser}}` to check whether the user is logged in.
   * Where "logged in" means: The user has has authenticated (e.g. through providing credentials)
   */
  Package.blaze.Blaze.Template.registerHelper('currentUser', function () {
    var user = Meteor.user();
    if (user &&
        typeof user.profile !== 'undefined' &&
        typeof user.profile.guest !== 'undefined' &&
        user.profile.guest){
        // a guest login is not a real login where the user is authenticated.
        // This allows the account-base "Sign-in" to still appear
      return null;
    }else{
      return Meteor.user();
    }
  });
}

	//no non-logged in users
	/* you might need to limit this to avoid flooding the user db */
	Meteor.loginVisitor = function (email) {
		AccountsGuest.forced = true;
		if (!Meteor.userId()) {
			Meteor.call('createGuest', email, function (error, result) {
				if (error) {
					console.log('Error in creating Guest ' + error);
					return false;
				}
				/* if a simple "true" is returned, we are in a disabled mode */
				if(result === true){
					return true;
				}
				Meteor.loginWithPassword(result.email, result.password, function(err){
					if(err){
						console.log('Error logging in '+err);
						return false;
					}
				});
				return true;
			});
		}
	}

Deps.autorun(function () {

	if (Meteor.userId()) {
		//			console.log('this is '+Meteor.userId());
	} else {
		if (AccountsGuest.forced === true){
			Meteor.loginVisitor();
		}
	}
});
<commit_msg>Maybe a fix for a race conditions. Maybe completely wrong. Consider again..<commit_after>/*****************
* special anonymous behavior so that visitors can
* manipulate their work
*
*/

// If our app has a Blaze, override the {{currentUser}} helper to deal guest logins
if (Package.blaze) {
  /**
   * @global
   * @name  currentUser
   * @isHelper true
   * @summary Calls [Meteor.user()](#meteor_user). Use `{{#if currentUser}}` to check whether the user is logged in.
   * Where "logged in" means: The user has has authenticated (e.g. through providing credentials)
   */
  Package.blaze.Blaze.Template.registerHelper('currentUser', function () {
    var user = Meteor.user();
    if (user &&
        typeof user.profile !== 'undefined' &&
        typeof user.profile.guest !== 'undefined' &&
        user.profile.guest){
        // a guest login is not a real login where the user is authenticated.
        // This allows the account-base "Sign-in" to still appear
      return null;
    }else{
      return Meteor.user();
    }
  });
}

	//no non-logged in users
	/* you might need to limit this to avoid flooding the user db */
	Meteor.loginVisitor = function (email) {
		AccountsGuest.forced = true;
		if (!Meteor.userId()) {
			Meteor.call('createGuest', email, function (error, result) {
				if (error) {
					console.log('Error in creating Guest ' + error);
					return false;
				}
				/* if a simple "true" is returned, we are in a disabled mode */
				if(result === true){
					return true;
				}
				Meteor.loginWithPassword(result.email, result.password, function(err){
					if(err){
						console.log('Error logging in '+err);
						return false;
					}
				});
				return true;
			});
		}
	}

Meteor.startup(function(){
		Deps.autorun(function () {

			if (Meteor.userId()) {
				//			console.log('this is '+Meteor.userId());
			} else {
				if (AccountsGuest.forced === true){
					Meteor.loginVisitor();
				}
			}
		});
});
<|endoftext|>


<commit_before>import { T } from '../helpers/twitterConnect';
import { postTweet } from '../helpers/twitterActions';
import { getRandomJoke } from '../helpers/helpers';

const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY;
const GOOGLE_CUSTOM_SEARCH_ID = process.env.GOOGLE_CUSTOM_SEARCH_ID;

const URL_GOOGLE_CS = 'https://www.googleapis.com/customsearch/v1';
const SHORTENED_LINK_LENGTH = 23;

function trackMentions(twitterHandler) {
  let stream = T.stream('statuses/filter', {track:twitterHandler});

  stream.on('tweet', function(tweet) {
    let asker = `@${tweet.user.screen_name}`;
    let tweetId = tweet.id_str;
    replyTweetWithJoke(asker, tweetId);
  });
}

async function replyTweetWithJoke(asker, tweetId) {
  // let images = await imageSearch('Chuck Norris Portrait');
  // let imageLink = images[randomNumber(0, 9)].image.thumbnailLink;
  // let imageLink = images[randomNumber(0, 9)].link;
  let randomJoke = await getRandomJoke(140 - asker.length/* - SHORTENED_LINK_LENGTH*/);
  let tweet = `${asker} ${randomJoke}`;
  // postTweetMedia(tweet, new Buffer(imageLink).toString('base64'));
  postTweet(tweet, tweetId);
}

function imageSearch(query) {
  query = query.replace(/ /g, '+');
  let url = `${URL_GOOGLE_CS}?key=${GOOGLE_API_KEY}&cx=${GOOGLE_CUSTOM_SEARCH_ID}&q=${query}&searchType=image&imgColorType=color`;

  return new Promise(function(resolve, reject) {
    request({
      url: url,
      method: 'GET',
    }, function(err, res) {
      if(err) {
        return err;
      }
      let { items } = JSON.parse(res.body);
      resolve(items);
    });
  });
}

function replyMentions() {
  trackMentions('@ChuckieNorrisie');
}

module.exports = {
  replyMentions: replyMentions
};<commit_msg>Removed all the Google related stuff<commit_after>import { T } from '../helpers/twitterConnect';
import { postTweet } from '../helpers/twitterActions';
import { getRandomJoke } from '../helpers/helpers';

function trackMentions(twitterHandler) {
  let stream = T.stream('statuses/filter', {track:twitterHandler});

  stream.on('tweet', function(tweet) {
    let asker = `@${tweet.user.screen_name}`;
    let tweetId = tweet.id_str;
    replyTweetWithJoke(asker, tweetId);
  });
}

async function replyTweetWithJoke(asker, tweetId) {
  let randomJoke = await getRandomJoke(140 - asker.length);
  let tweet = `${asker} ${randomJoke}`;
  postTweet(tweet, tweetId);
}

function replyMentions() {
  trackMentions('@ChuckieNorrisie');
}

module.exports = {
  replyMentions: replyMentions
};<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

import ErrorText from './ErrorText';
import HelpText from './HelpText';
import WarningText from './WarningText';

class ValidationText extends PureComponent {
  render() {
    const { error, inverse, help, warning } = this.props;

    if (error) {
      return <ErrorText inverse={inverse}>{error}</ErrorText>
    }

    if (warning) {
      return <WarningText inverse={inverse}>{warning}</WarningText>
    }

    if (help) {
      return <HelpText inverse={inverse}>{help}</HelpText>
    }

    return null;
  }
}

ValidationText.propTypes = {
  error: PropTypes.node,
  help: PropTypes.node,
  inverse: PropTypes.bool,
  warning: PropTypes.node,
};

export default ValidationText;
<commit_msg>Lint fix<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

import ErrorText from './ErrorText';
import HelpText from './HelpText';
import WarningText from './WarningText';

class ValidationText extends PureComponent {
  render() {
    const { error, inverse, help, warning } = this.props;

    if (error) {
      return <ErrorText inverse={inverse}>{error}</ErrorText>;
    }

    if (warning) {
      return <WarningText inverse={inverse}>{warning}</WarningText>;
    }

    if (help) {
      return <HelpText inverse={inverse}>{help}</HelpText>;
    }

    return null;
  }
}

ValidationText.propTypes = {
  error: PropTypes.node,
  help: PropTypes.node,
  inverse: PropTypes.bool,
  warning: PropTypes.node,
};

export default ValidationText;
<|endoftext|>


<commit_before>import _R from 'ramda';
import React, { Component, PropTypes } from 'react';
import { FilterMenu } from 'components';
import { connect } from 'react-redux';
import { RecBox } from 'components';
import { bindActionCreators } from 'redux';
import { sortCountry } from 'redux/modules/sort';
import Helmet from 'react-helmet';

const getVisibleCards = (cards, filters, country, routes) => {
  let cardsToShow = cards;
  let onlyIssuerKeysToFilter = {}; // eslint-disable-line prefer-const

  const { onlyShowIssuer, hiddenCardKeys} = filters;

  if (Object.keys(hiddenCardKeys).length) {
    cardsToShow = cardsToShow.filter(ca => !hiddenCardKeys.hasOwnProperty(ca.cardKey));
  }

  if (filters.noFteOnly === true) {
    cardsToShow = cardsToShow.filter(ca => ca.ftf === 0.0);
  }

  const allNotSame = filters.annualFeeWaivedOnly !== filters.annualFeeLess100Only || filters.annualFeeLess100Only !== filters.annualFee100MoreOnly;

  if (allNotSame) {
    cardsToShow = cardsToShow.filter((ca) => {
      let showCard = false;

      if (filters.annualFeeWaivedOnly && (ca.annualFeeWaived === true || ca.annualFee === 0)) {
        showCard = true;
      }

      if (filters.annualFeeLess100Only && ca.annualFee < 100) {
        showCard = true;
      }

      if (filters.annualFee100MoreOnly && ca.annualFee >= 100) {
        showCard = true;
      }

      return showCard;
    });
  }

  for (let key in onlyShowIssuer) {  // eslint-disable-line prefer-const
    if (onlyShowIssuer[key] === true) {
      onlyIssuerKeysToFilter[key] = true;
    }
  }

  if (Object.keys(onlyIssuerKeysToFilter).length > 0) {
    cardsToShow = cardsToShow.filter(ca => onlyIssuerKeysToFilter[ca.issuerName] === true);
  }

  const curAwardRoutes = routes.countryAwardRoutes[country];
  const curCashRoutes = routes.countryCashRoutes[country];

  const plus = (aa, bb) => aa + bb;
  const numPointsFn = ro => ro.numberOfPointsReq;
  const cashFn = ro => ro.cashReq;

  cardsToShow.forEach((ca) => {
    const rewardProviver = ca.rewardProvider;
    ca.awardRedeemPerc = 0;
    ca.cashRedeemPerc = 0;
    ca.bestRedeemPerc = 0;

    ca.awardRoutesForSort = curAwardRoutes[rewardProviver] || [];

    if (ca.canConvToCash) {
      const cashRouteList = _R.map(cashFn, curCashRoutes);
      const averageCash = _R.reduce(plus, 0, cashRouteList) / curCashRoutes.length;

      ca.cashRedeemPerc = (ca.curBonusPts * ca.travelConvRate) / averageCash;
      ca.cashRoutesForSort = curCashRoutes;
    }

    if (ca.awardRoutesForSort.length) {
      const numPointsRouteList = _R.map(numPointsFn, ca.awardRoutesForSort);
      const averageNumPoints = _R.reduce(plus, 0, numPointsRouteList) / ca.awardRoutesForSort.length;
      ca.awardRedeemPerc = ca.curBonusPts / averageNumPoints;
    }

    ca.bestRedeemPerc = ca.awardRedeemPerc > ca.cashRedeemPerc ? ca.awardRedeemPerc : ca.cashRedeemPerc;
  });

  const hasNoRoutes = ca => !ca.awardRoutesForSort.length && !ca.canConvToCash;
  cardsToShow = _R.reject(hasNoRoutes, cardsToShow);

  cardsToShow.sort((ca, cb) => { return (cb.bestRedeemPerc - ca.bestRedeemPerc);});

  cardsToShow.forEach((ca, ind) => { ca.curRank = ind + 1; });

  return cardsToShow;
};

@connect(
  state => (
    {
      cards: state.cards,
      filter: state.filter,
      sort: state.sort,
      routes: state.routes,
      view: state.view
    }
  ),
  dispatch => bindActionCreators({ sortCountry }, dispatch)
)

export default class Credit extends Component {
  static propTypes = {
    cards: PropTypes.object,
    filter: PropTypes.object,
    sort: PropTypes.object,
    routes: PropTypes.object,
    params: PropTypes.object,
    sortCountry: PropTypes.func,
    view: PropTypes.object
  };

  state = {
    currentCountry: ''
  };

  componentWillMount() {
    const { sortCountry } = this.props; // eslint-disable-line no-shadow
    this.setState({
      currentCountry: this.props.params.countryName
    });
    sortCountry(this.state.currentCountry, true);
  }

  render() {
    const { all } = this.props.cards;
    const { filter, routes, sort, view } = this.props;
    const possibleCards = getVisibleCards(all, filter, this.state.currentCountry, routes);

    sort.currentNumCards = possibleCards.length;
    const visibleCards = possibleCards.slice(0, 5);

    const styles = require('./CardComparison.scss');
    const pencil = require('./pencil.png');

    const addnFilterClass = view.showFilterMenu ? '' : ' ' + styles.hide_col;
    const addnResultsClass = view.showFilterMenu ? ' ' + styles.hide_col : '';

    return (

        <Helmet title={'Best Card for Free Flights to ' + this.state.currentCountry}/>

              <FilterMenu country={this.state.currentCountry}/>

                How does this work?

                    Best Cards for Free Flights to

                      {this.state.currentCountry}

                    Showing 3 of {sort.currentNumCards} cards

              {visibleCards && visibleCards.length &&

                  {visibleCards.map((card) => {
                    return (
                      <RecBox card={card} />
                    );
                  })}

              }

    );
  }
}
<commit_msg>Show 5 cards<commit_after>import _R from 'ramda';
import React, { Component, PropTypes } from 'react';
import { FilterMenu } from 'components';
import { connect } from 'react-redux';
import { RecBox } from 'components';
import { bindActionCreators } from 'redux';
import { sortCountry } from 'redux/modules/sort';
import Helmet from 'react-helmet';

const getVisibleCards = (cards, filters, country, routes) => {
  let cardsToShow = cards;
  let onlyIssuerKeysToFilter = {}; // eslint-disable-line prefer-const

  const { onlyShowIssuer, hiddenCardKeys} = filters;

  if (Object.keys(hiddenCardKeys).length) {
    cardsToShow = cardsToShow.filter(ca => !hiddenCardKeys.hasOwnProperty(ca.cardKey));
  }

  if (filters.noFteOnly === true) {
    cardsToShow = cardsToShow.filter(ca => ca.ftf === 0.0);
  }

  const allNotSame = filters.annualFeeWaivedOnly !== filters.annualFeeLess100Only || filters.annualFeeLess100Only !== filters.annualFee100MoreOnly;

  if (allNotSame) {
    cardsToShow = cardsToShow.filter((ca) => {
      let showCard = false;

      if (filters.annualFeeWaivedOnly && (ca.annualFeeWaived === true || ca.annualFee === 0)) {
        showCard = true;
      }

      if (filters.annualFeeLess100Only && ca.annualFee < 100) {
        showCard = true;
      }

      if (filters.annualFee100MoreOnly && ca.annualFee >= 100) {
        showCard = true;
      }

      return showCard;
    });
  }

  for (let key in onlyShowIssuer) {  // eslint-disable-line prefer-const
    if (onlyShowIssuer[key] === true) {
      onlyIssuerKeysToFilter[key] = true;
    }
  }

  if (Object.keys(onlyIssuerKeysToFilter).length > 0) {
    cardsToShow = cardsToShow.filter(ca => onlyIssuerKeysToFilter[ca.issuerName] === true);
  }

  const curAwardRoutes = routes.countryAwardRoutes[country];
  const curCashRoutes = routes.countryCashRoutes[country];

  const plus = (aa, bb) => aa + bb;
  const numPointsFn = ro => ro.numberOfPointsReq;
  const cashFn = ro => ro.cashReq;

  cardsToShow.forEach((ca) => {
    const rewardProviver = ca.rewardProvider;
    ca.awardRedeemPerc = 0;
    ca.cashRedeemPerc = 0;
    ca.bestRedeemPerc = 0;

    ca.awardRoutesForSort = curAwardRoutes[rewardProviver] || [];

    if (ca.canConvToCash) {
      const cashRouteList = _R.map(cashFn, curCashRoutes);
      const averageCash = _R.reduce(plus, 0, cashRouteList) / curCashRoutes.length;

      ca.cashRedeemPerc = (ca.curBonusPts * ca.travelConvRate) / averageCash;
      ca.cashRoutesForSort = curCashRoutes;
    }

    if (ca.awardRoutesForSort.length) {
      const numPointsRouteList = _R.map(numPointsFn, ca.awardRoutesForSort);
      const averageNumPoints = _R.reduce(plus, 0, numPointsRouteList) / ca.awardRoutesForSort.length;
      ca.awardRedeemPerc = ca.curBonusPts / averageNumPoints;
    }

    ca.bestRedeemPerc = ca.awardRedeemPerc > ca.cashRedeemPerc ? ca.awardRedeemPerc : ca.cashRedeemPerc;
  });

  const hasNoRoutes = ca => !ca.awardRoutesForSort.length && !ca.canConvToCash;
  cardsToShow = _R.reject(hasNoRoutes, cardsToShow);

  cardsToShow.sort((ca, cb) => { return (cb.bestRedeemPerc - ca.bestRedeemPerc);});

  cardsToShow.forEach((ca, ind) => { ca.curRank = ind + 1; });

  return cardsToShow;
};

@connect(
  state => (
    {
      cards: state.cards,
      filter: state.filter,
      sort: state.sort,
      routes: state.routes,
      view: state.view
    }
  ),
  dispatch => bindActionCreators({ sortCountry }, dispatch)
)

export default class Credit extends Component {
  static propTypes = {
    cards: PropTypes.object,
    filter: PropTypes.object,
    sort: PropTypes.object,
    routes: PropTypes.object,
    params: PropTypes.object,
    sortCountry: PropTypes.func,
    view: PropTypes.object
  };

  state = {
    currentCountry: ''
  };

  componentWillMount() {
    const { sortCountry } = this.props; // eslint-disable-line no-shadow
    this.setState({
      currentCountry: this.props.params.countryName
    });
    sortCountry(this.state.currentCountry, true);
  }

  render() {
    const { all } = this.props.cards;
    const { filter, routes, sort, view } = this.props;
    const possibleCards = getVisibleCards(all, filter, this.state.currentCountry, routes);

    sort.currentNumCards = possibleCards.length;
    const numCardsToShow = 5;
    const visibleCards = possibleCards.slice(0, numCardsToShow);

    const styles = require('./CardComparison.scss');
    const pencil = require('./pencil.png');

    const addnFilterClass = view.showFilterMenu ? '' : ' ' + styles.hide_col;
    const addnResultsClass = view.showFilterMenu ? ' ' + styles.hide_col : '';

    return (

        <Helmet title={'Best Card for Free Flights to ' + this.state.currentCountry}/>

              <FilterMenu country={this.state.currentCountry}/>

                How does this work?

                    Best Cards for Free Flights to

                      {this.state.currentCountry}

                    Showing {numCardsToShow} of {sort.currentNumCards} cards

              {visibleCards && visibleCards.length &&

                  {visibleCards.map((card) => {
                    return (
                      <RecBox card={card} />
                    );
                  })}

              }

    );
  }
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { push } from 'react-router-redux'
import shallowCompare from 'react-addons-shallow-compare'
import { set } from 'lodash'
import OnboardingCategories from '../components/onboarding/OnboardingCategories'
import { ONBOARDING_VERSION } from '../constants/application_types'
import { trackEvent } from '../actions/analytics'
import { getCategories } from '../actions/discover'
import { followCategories, saveProfile } from '../actions/profile'
import { selectCategories } from '../selectors'

const CATEGORIES_NEEDED = 3

function mapStateToProps(state, props) {
  const catLevels = selectCategories(state, props)
  return {
    categories: catLevels.primary.concat(catLevels.secondary, catLevels.tertiary),
  }
}

function hasSelectedCategoriesNeeded(state) {
  return state.categoryIds.length < CATEGORIES_NEEDED
}

class OnboardingCategoriesContainer extends Component {

  static propTypes = {
    categories: PropTypes.array,
    dispatch: PropTypes.func.isRequired,
  }

  static childContextTypes = {
    nextLabel: PropTypes.string,
    onDoneClick: PropTypes.func,
    onNextClick: PropTypes.func.isRequired,
  }

  getChildContext() {
    const { categoryIds } = this.state
    let nextLabel = ''
    if (CATEGORIES_NEEDED > categoryIds.length) {
      nextLabel = `Pick ${CATEGORIES_NEEDED - categoryIds.length}`
    } else {
      nextLabel = 'Create Your Profile'
    }
    return {
      nextLabel,
      onDoneClick: hasSelectedCategoriesNeeded(this.state) ? null : this.onDoneClick,
      onNextClick: this.onNextClick,
    }
  }

  componentWillMount() {
    const { dispatch } = this.props
    dispatch(getCategories())
    this.state = { categoryIds: [] }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState)
  }

  onCategoryClick = (id) => {
    const ids = [...this.state.categoryIds]
    const index = ids.indexOf(id)
    if (index === -1) {
      ids.push(id)
    } else {
      ids.splice(index, 1)
    }
    this.setState({ categoryIds: ids })
  }

  onDoneClick = () => {
    const { dispatch } = this.props
    dispatch(saveProfile({ web_onboarding_version: ONBOARDING_VERSION }))
    dispatch(trackEvent('Onboarding.Categories.Done.Clicked'))
    const action = followCategories(this.state.categoryIds)
    set(action, 'meta.successAction', push('/following'))
    dispatch(action)
  }

  onNextClick = () => {
    const { dispatch } = this.props
    dispatch(saveProfile({ web_onboarding_version: ONBOARDING_VERSION }))
    dispatch(followCategories(this.state.categoryIds))
    dispatch(push('/onboarding/settings'))
  }

  render() {
    const { categories } = this.props
    const isNextDisabled = hasSelectedCategoriesNeeded(this.state)
    return (
      <OnboardingCategories
        categories={categories}
        isNextDisabled={isNextDisabled}
        onCategoryClick={this.onCategoryClick}
      />
    )
  }
}

export default connect(mapStateToProps)(OnboardingCategoriesContainer)

<commit_msg>Add Categories.Completed tracking event - Also send the number of categories followed as an optional data attribute for the Onboarding 2.0 dashboard.<commit_after>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { push } from 'react-router-redux'
import shallowCompare from 'react-addons-shallow-compare'
import { set } from 'lodash'
import OnboardingCategories from '../components/onboarding/OnboardingCategories'
import { ONBOARDING_VERSION } from '../constants/application_types'
import { trackEvent } from '../actions/analytics'
import { getCategories } from '../actions/discover'
import { followCategories, saveProfile } from '../actions/profile'
import { selectCategories } from '../selectors'

const CATEGORIES_NEEDED = 3

function mapStateToProps(state, props) {
  const catLevels = selectCategories(state, props)
  return {
    categories: catLevels.primary.concat(catLevels.secondary, catLevels.tertiary),
  }
}

function hasSelectedCategoriesNeeded(state) {
  return state.categoryIds.length < CATEGORIES_NEEDED
}

class OnboardingCategoriesContainer extends Component {

  static propTypes = {
    categories: PropTypes.array,
    dispatch: PropTypes.func.isRequired,
  }

  static childContextTypes = {
    nextLabel: PropTypes.string,
    onDoneClick: PropTypes.func,
    onNextClick: PropTypes.func.isRequired,
  }

  getChildContext() {
    const { categoryIds } = this.state
    let nextLabel = ''
    if (CATEGORIES_NEEDED > categoryIds.length) {
      nextLabel = `Pick ${CATEGORIES_NEEDED - categoryIds.length}`
    } else {
      nextLabel = 'Create Your Profile'
    }
    return {
      nextLabel,
      onDoneClick: hasSelectedCategoriesNeeded(this.state) ? null : this.onDoneClick,
      onNextClick: this.onNextClick,
    }
  }

  componentWillMount() {
    const { dispatch } = this.props
    dispatch(getCategories())
    this.state = { categoryIds: [] }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState)
  }

  onCategoryClick = (id) => {
    const ids = [...this.state.categoryIds]
    const index = ids.indexOf(id)
    if (index === -1) {
      ids.push(id)
    } else {
      ids.splice(index, 1)
    }
    this.setState({ categoryIds: ids })
  }

  onDoneClick = () => {
    const { dispatch } = this.props
    const categoryIds = this.state.categoryIds
    dispatch(saveProfile({ web_onboarding_version: ONBOARDING_VERSION }))
    dispatch(trackEvent('Onboarding.Categories.Done.Clicked',
                        { categories: categoryIds.length }))
    const action = followCategories(categoryIds)
    set(action, 'meta.successAction', push('/following'))
    dispatch(action)
  }

  onNextClick = () => {
    const { dispatch } = this.props
    const categoryIds = this.state.categoryIds
    dispatch(saveProfile({ web_onboarding_version: ONBOARDING_VERSION }))
    dispatch(trackEvent('Onboarding.Settings.Categories.Completed',
                        { categories: categoryIds.length }))
    dispatch(followCategories(categoryIds))
    dispatch(push('/onboarding/settings'))
  }

  render() {
    const { categories } = this.props
    const isNextDisabled = hasSelectedCategoriesNeeded(this.state)
    return (
      <OnboardingCategories
        categories={categories}
        isNextDisabled={isNextDisabled}
        onCategoryClick={this.onCategoryClick}
      />
    )
  }
}

export default connect(mapStateToProps)(OnboardingCategoriesContainer)

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

var localConnection;
var remoteConnection;
var sendChannel;
var receiveChannel;
var pcConstraint;
var bitrateDiv = document.querySelector('div#bitrate');
var fileInput = document.querySelector('input#fileInput');
var downloadAnchor = document.querySelector('a#download');
var sendProgress = document.querySelector('progress#sendProgress');
var receiveProgress = document.querySelector('progress#receiveProgress');
var statusMessage = document.querySelector('span#status');

var receiveBuffer = [];
var receivedSize = 0;

var bytesPrev = 0;
var timestampPrev = 0;
var timestampStart;
var statsInterval = null;
var bitrateMax = 0;
var fileType = '';

fileInput.addEventListener('change', createConnection, false);

function createConnection() {
  var servers = null;
  pcConstraint = null;

  // Add localConnection to global scope to make it visible
  // from the browser console.
  window.localConnection = localConnection = new RTCPeerConnection(servers,
      pcConstraint);
  trace('Created local peer connection object localConnection');

  sendChannel = localConnection.createDataChannel('sendDataChannel', {ordered: true});
  sendChannel.binaryType = 'arraybuffer';
  trace('Created send data channel');

  sendChannel.onopen = onSendChannelStateChange;
  sendChannel.onclose = onSendChannelStateChange;
  localConnection.onicecandidate = iceCallback1;

  localConnection.createOffer(gotDescription1, onCreateSessionDescriptionError);
  // Add remoteConnection to global scope to make it visible
  // from the browser console.
  window.remoteConnection = remoteConnection = new RTCPeerConnection(servers,
      pcConstraint);
  trace('Created remote peer connection object remoteConnection');

  remoteConnection.onicecandidate = iceCallback2;
  remoteConnection.ondatachannel = receiveChannelCallback;

  fileInput.disabled = true;
}

function onCreateSessionDescriptionError(error) {
  trace('Failed to create session description: ' + error.toString());
}

function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint8Array(buf));
}

function str2ab(str) {
  var buf = new ArrayBuffer(str.length); // 2 bytes for each char
  var bufView = new Uint8Array(buf);
  for (var i=0, strLen=str.length; i<strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}

function sendData() {
  var file = fileInput.files[0];
  receiveBuffer = [];
  trace('file is ' + [file.name, file.size, file.type,
      file.lastModifiedDate].join(' '));

  // Handle 0 size files.
  statusMessage.textContent = '';
  downloadAnchor.textContent = '';
  if (file.size === 0) {
    bitrateDiv.innerHTML = '';
    statusMessage.textContent = 'File is empty, please select a non-empty file';
    closeDataChannels();
    return;
  }
  sendProgress.max = file.size;
  receiveProgress.max = file.size;
  fileType = file.type.length > 0 ? file.type : 'text/plain';
  var chunkSize = 512 * 32;
  var bufferFullThreshold = 5 * chunkSize;
  var sliceFile = function(offset) {
    var reader = new window.FileReader();
    reader.onload = (function() {
      return function(e) {
        var packet = new Int8Array(e.target.result, 0, e.target.result.byteLength);
        packet = ab2str(packet.buffer);
        if (sendChannel.bufferedAmount > bufferFullThreshold) {
          setTimeout(sliceFile, 250, offset);
          return;
        }
        sendChannel.send(packet);
        if (file.size > offset + e.target.result.byteLength) {
          window.setTimeout(sliceFile, 0, offset + chunkSize);
        }
        sendProgress.value = offset + e.target.result.byteLength;
      };
    })(file);
    var slice = file.slice(offset, offset + chunkSize);
    reader.readAsArrayBuffer(slice);
  };
  sliceFile(0);
}

function closeDataChannels() {
  trace('Closing data channels');
  sendChannel.close();
  trace('Closed data channel with label: ' + sendChannel.label);
  if (receiveChannel) {
    receiveChannel.close();
    trace('Closed data channel with label: ' + receiveChannel.label);
  }
  localConnection.close();
  remoteConnection.close();
  localConnection = null;
  remoteConnection = null;
  trace('Closed peer connections');

  // re-enable the file select
  fileInput.disabled = false;
}

function gotDescription1(desc) {
  localConnection.setLocalDescription(desc);
  trace('Offer from localConnection \n' + desc.sdp);
  remoteConnection.setRemoteDescription(desc);
  remoteConnection.createAnswer(gotDescription2,
      onCreateSessionDescriptionError);
}

function gotDescription2(desc) {
  remoteConnection.setLocalDescription(desc);
  trace('Answer from remoteConnection \n' + desc.sdp);
  localConnection.setRemoteDescription(desc);
}

function iceCallback1(event) {
  trace('local ice callback');
  if (event.candidate) {
    remoteConnection.addIceCandidate(event.candidate,
        onAddIceCandidateSuccess, onAddIceCandidateError);
    trace('Local ICE candidate: \n' + event.candidate.candidate);
  }
}

function iceCallback2(event) {
  trace('remote ice callback');
  if (event.candidate) {
    localConnection.addIceCandidate(event.candidate,
        onAddIceCandidateSuccess, onAddIceCandidateError);
    trace('Remote ICE candidate: \n ' + event.candidate.candidate);
  }
}

function onAddIceCandidateSuccess() {
  trace('AddIceCandidate success.');
}

function onAddIceCandidateError(error) {
  trace('Failed to add Ice Candidate: ' + error.toString());
}

function receiveChannelCallback(event) {
  trace('Receive Channel Callback');
  receiveChannel = event.channel;
  receiveChannel.binaryType = 'arraybuffer';
  receiveChannel.onmessage = onReceiveMessageCallback;
  if (receiveChannel.readyState === 'open') {
    onReceiveChannelStateChange();
  } else {
    receiveChannel.onopen = onReceiveChannelStateChange;
  }
  receiveChannel.onclose = onReceiveChannelStateChange;

  receivedSize = 0;
  bitrateMax = 0;
  downloadAnchor.textContent = '';
  downloadAnchor.removeAttribute('download');
  if (downloadAnchor.href) {
    URL.revokeObjectURL(downloadAnchor.href);
    downloadAnchor.removeAttribute('href');
  }
  trySending();
}

function onReceiveMessageCallback(event) {
  // trace('Received Message ' + event.data.byteLength);
  var packet = str2ab(event.data);
  // var packet = event.data;
  receiveBuffer.push(packet);
  receivedSize += packet.byteLength;

  receiveProgress.value = receivedSize;

  // we are assuming that our signaling protocol told
  // about the expected file size (and name, hash, etc).
  var file = fileInput.files[0];
  if (receivedSize >= file.size) {
    var received = new window.Blob(receiveBuffer, {type: fileType});

    downloadAnchor.href = URL.createObjectURL(received);
    downloadAnchor.download = file.name;
    downloadAnchor.textContent =
      'Click to download \'' + file.name + '\' (' + file.size + ' bytes)';
    downloadAnchor.style.display = 'block';

    if (statsInterval) {
      window.clearInterval(statsInterval);
      statsInterval = null;
    }

    closeDataChannels();

    var bitrate = Math.round(receivedSize * 8 /
        ((new Date()).getTime() - timestampStart));
    bitrateDiv.innerHTML = 'Average Bitrate: ' +
        bitrate + ' kbits/sec (max: ' + bitrateMax + ' kbits/sec)';
  }
}

function onSendChannelStateChange() {
  var readyState = sendChannel.readyState;
  trace('Send channel state is: ' + readyState);
  trySending();
}

function onReceiveChannelStateChange() {
  var readyState = receiveChannel.readyState;
  trace('Receive channel state is: ' + readyState);
  if (readyState === 'open') {
    timestampStart = (new Date()).getTime();
    timestampPrev = timestampStart;
    statsInterval = window.setInterval(displayStats, 500);
  }
}

function trySending() {
  if (sendChannel && sendChannel.readyState === 'open' &&
    receiveChannel && receiveChannel.readyState === 'open') {
    sendData();
  }
}

// display bitrate statistics.
function displayStats() {
  if (remoteConnection &&
    remoteConnection.iceConnectionState === 'connected') {
    // TODO: once https://code.google.com/p/webrtc/issues/detail?id=4321
    // lands those stats should be preferrred over the connection stats.
    remoteConnection.getStats(null, function(stats) {
      if (statsInterval === null) {
        // file was already completely sent
        return;
      }
      for (var key in stats) {
        var res = stats[key];
        if (res.type === 'googCandidatePair' &&
            res.googActiveConnection === 'true') {
          // calculate current bitrate
          var bytesNow = res.bytesReceived;
          var bitrate = Math.round((bytesNow - bytesPrev) * 8 /
              (res.timestamp - timestampPrev));
          // display(bitrate);
          bitrateDiv.innerHTML = 'Current Bitrate: ' +
              bitrate + ' kbits/sec';
          timestampPrev = res.timestamp;
          bytesPrev = bytesNow;
          if (bitrate > bitrateMax) {
            bitrateMax = bitrate;
          }
        }
      }
    }, function(e) {console.log('GetStats failure ', e);});
  }
}
<commit_msg>TWP-426 re-using array buffer for the datachannel<commit_after>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

var localConnection;
var remoteConnection;
var sendChannel;
var receiveChannel;
var pcConstraint;
var bitrateDiv = document.querySelector('div#bitrate');
var fileInput = document.querySelector('input#fileInput');
var downloadAnchor = document.querySelector('a#download');
var sendProgress = document.querySelector('progress#sendProgress');
var receiveProgress = document.querySelector('progress#receiveProgress');
var statusMessage = document.querySelector('span#status');

var receiveBuffer = [];
var receivedSize = 0;

var bytesPrev = 0;
var timestampPrev = 0;
var timestampStart;
var statsInterval = null;
var bitrateMax = 0;
var fileType = '';

fileInput.addEventListener('change', createConnection, false);

function createConnection() {
  var servers = null;
  pcConstraint = null;

  // Add localConnection to global scope to make it visible
  // from the browser console.
  window.localConnection = localConnection = new RTCPeerConnection(servers,
      pcConstraint);
  trace('Created local peer connection object localConnection');

  sendChannel = localConnection.createDataChannel('sendDataChannel', {ordered: true});
  sendChannel.binaryType = 'arraybuffer';
  trace('Created send data channel');

  sendChannel.onopen = onSendChannelStateChange;
  sendChannel.onclose = onSendChannelStateChange;
  localConnection.onicecandidate = iceCallback1;

  localConnection.createOffer(gotDescription1, onCreateSessionDescriptionError);
  // Add remoteConnection to global scope to make it visible
  // from the browser console.
  window.remoteConnection = remoteConnection = new RTCPeerConnection(servers,
      pcConstraint);
  trace('Created remote peer connection object remoteConnection');

  remoteConnection.onicecandidate = iceCallback2;
  remoteConnection.ondatachannel = receiveChannelCallback;

  fileInput.disabled = true;
}

function onCreateSessionDescriptionError(error) {
  trace('Failed to create session description: ' + error.toString());
}

function sendData() {
  var file = fileInput.files[0];
  receiveBuffer = [];
  trace('file is ' + [file.name, file.size, file.type,
      file.lastModifiedDate].join(' '));

  // Handle 0 size files.
  statusMessage.textContent = '';
  downloadAnchor.textContent = '';
  if (file.size === 0) {
    bitrateDiv.innerHTML = '';
    statusMessage.textContent = 'File is empty, please select a non-empty file';
    closeDataChannels();
    return;
  }
  sendProgress.max = file.size;
  receiveProgress.max = file.size;
  fileType = file.type.length > 0 ? file.type : 'text/plain';
  var chunkSize = 512 * 32;
  var bufferFullThreshold = 5 * chunkSize;
  var sliceFile = function(offset) {
    var reader = new window.FileReader();
    reader.onload = (function() {
      return function(e) {
        var packet = new Int8Array(e.target.result, 0, e.target.result.byteLength);
        if (sendChannel.bufferedAmount > bufferFullThreshold) {
          setTimeout(sliceFile, 150, offset);
          return;
        }
        sendChannel.send(packet);
        if (file.size > offset + e.target.result.byteLength) {
          window.setTimeout(sliceFile, 0, offset + chunkSize);
        }
        sendProgress.value = offset + e.target.result.byteLength;
      };
    })(file);
    var slice = file.slice(offset, offset + chunkSize);
    reader.readAsArrayBuffer(slice);
  };
  sliceFile(0);
}

function closeDataChannels() {
  trace('Closing data channels');
  sendChannel.close();
  trace('Closed data channel with label: ' + sendChannel.label);
  if (receiveChannel) {
    receiveChannel.close();
    trace('Closed data channel with label: ' + receiveChannel.label);
  }
  localConnection.close();
  remoteConnection.close();
  localConnection = null;
  remoteConnection = null;
  trace('Closed peer connections');

  // re-enable the file select
  fileInput.disabled = false;
}

function gotDescription1(desc) {
  localConnection.setLocalDescription(desc);
  trace('Offer from localConnection \n' + desc.sdp);
  remoteConnection.setRemoteDescription(desc);
  remoteConnection.createAnswer(gotDescription2,
      onCreateSessionDescriptionError);
}

function gotDescription2(desc) {
  remoteConnection.setLocalDescription(desc);
  trace('Answer from remoteConnection \n' + desc.sdp);
  localConnection.setRemoteDescription(desc);
}

function iceCallback1(event) {
  trace('local ice callback');
  if (event.candidate) {
    remoteConnection.addIceCandidate(event.candidate,
        onAddIceCandidateSuccess, onAddIceCandidateError);
    trace('Local ICE candidate: \n' + event.candidate.candidate);
  }
}

function iceCallback2(event) {
  trace('remote ice callback');
  if (event.candidate) {
    localConnection.addIceCandidate(event.candidate,
        onAddIceCandidateSuccess, onAddIceCandidateError);
    trace('Remote ICE candidate: \n ' + event.candidate.candidate);
  }
}

function onAddIceCandidateSuccess() {
  trace('AddIceCandidate success.');
}

function onAddIceCandidateError(error) {
  trace('Failed to add Ice Candidate: ' + error.toString());
}

function receiveChannelCallback(event) {
  trace('Receive Channel Callback');
  receiveChannel = event.channel;
  receiveChannel.binaryType = 'arraybuffer';
  receiveChannel.onmessage = onReceiveMessageCallback;
  if (receiveChannel.readyState === 'open') {
    onReceiveChannelStateChange();
  } else {
    receiveChannel.onopen = onReceiveChannelStateChange;
  }
  receiveChannel.onclose = onReceiveChannelStateChange;

  receivedSize = 0;
  bitrateMax = 0;
  downloadAnchor.textContent = '';
  downloadAnchor.removeAttribute('download');
  if (downloadAnchor.href) {
    URL.revokeObjectURL(downloadAnchor.href);
    downloadAnchor.removeAttribute('href');
  }
  trySending();
}

function onReceiveMessageCallback(event) {
  // trace('Received Message ' + event.data.byteLength);
  var packet = new Int8Array(event.data);
  receiveBuffer.push(packet);
  receivedSize += packet.byteLength;

  receiveProgress.value = receivedSize;

  // we are assuming that our signaling protocol told
  // about the expected file size (and name, hash, etc).
  var file = fileInput.files[0];
  if (receivedSize >= file.size) {
    var received = new window.Blob(receiveBuffer, {type: fileType});

    downloadAnchor.href = URL.createObjectURL(received);
    downloadAnchor.download = file.name;
    downloadAnchor.textContent =
      'Click to download \'' + file.name + '\' (' + file.size + ' bytes)';
    downloadAnchor.style.display = 'block';

    if (statsInterval) {
      window.clearInterval(statsInterval);
      statsInterval = null;
    }

    closeDataChannels();

    var bitrate = Math.round(receivedSize * 8 /
        ((new Date()).getTime() - timestampStart));
    bitrateDiv.innerHTML = 'Average Bitrate: ' +
        bitrate + ' kbits/sec (max: ' + bitrateMax + ' kbits/sec)';
  }
}

function onSendChannelStateChange() {
  var readyState = sendChannel.readyState;
  trace('Send channel state is: ' + readyState);
  trySending();
}

function onReceiveChannelStateChange() {
  var readyState = receiveChannel.readyState;
  trace('Receive channel state is: ' + readyState);
  if (readyState === 'open') {
    timestampStart = (new Date()).getTime();
    timestampPrev = timestampStart;
    statsInterval = window.setInterval(displayStats, 500);
  }
}

function trySending() {
  if (sendChannel && sendChannel.readyState === 'open' &&
    receiveChannel && receiveChannel.readyState === 'open') {
    sendData();
  }
}

// display bitrate statistics.
function displayStats() {
  if (remoteConnection &&
    remoteConnection.iceConnectionState === 'connected') {
    // TODO: once https://code.google.com/p/webrtc/issues/detail?id=4321
    // lands those stats should be preferrred over the connection stats.
    remoteConnection.getStats(null, function(stats) {
      if (statsInterval === null) {
        // file was already completely sent
        return;
      }
      for (var key in stats) {
        var res = stats[key];
        if (res.type === 'googCandidatePair' &&
            res.googActiveConnection === 'true') {
          // calculate current bitrate
          var bytesNow = res.bytesReceived;
          var bitrate = Math.round((bytesNow - bytesPrev) * 8 /
              (res.timestamp - timestampPrev));
          // display(bitrate);
          bitrateDiv.innerHTML = 'Current Bitrate: ' +
              bitrate + ' kbits/sec';
          timestampPrev = res.timestamp;
          bytesPrev = bytesNow;
          if (bitrate > bitrateMax) {
            bitrateMax = bitrate;
          }
        }
      }
    }, function(e) {console.log('GetStats failure ', e);});
  }
}
<|endoftext|>


<commit_before>module.exports.makePackageConfig = (packageJson) => {
  const packageBaseName = packageJson.name.replace("@jspsych/", "");

  return {
    resetModules: true,
    testEnvironment: "jsdom",
    testEnvironmentOptions: {
      fetchExternalResources: true,
      pretendToBeVisual: true,
    },
    testURL: "http://localhost/",
    transform: {
      "\\.js$": ["babel-jest", { configFile: "@jspsych/config/babel.test.config.js" }],
    },
    displayName: packageBaseName,
  };
};
<commit_msg>Highlight plugin projects in jest test runs<commit_after>module.exports.makePackageConfig = (packageJson) => {
  const packageBaseName = packageJson.name.replace("@jspsych/", "");

  return {
    resetModules: true,
    testEnvironment: "jsdom",
    testEnvironmentOptions: {
      fetchExternalResources: true,
      pretendToBeVisual: true,
    },
    testURL: "http://localhost/",
    transform: {
      "\\.js$": ["babel-jest", { configFile: "@jspsych/config/babel.test.config.js" }],
    },
    displayName: {
      name: packageBaseName,
      color: packageBaseName === "jspsych" ? "white" : "cyanBright",
    },
  };
};
<|endoftext|>


<commit_before>const config = require('./config')
const BugsnagEvent = require('./event')
const BugsnagBreadcrumb = require('./breadcrumb')
const BugsnagSession = require('./session')
const { map, includes } = require('./lib/es-utils')
const inferReleaseStage = require('./lib/infer-release-stage')
const isError = require('./lib/iserror')
const runCallbacks = require('./lib/callback-runner')

const LOG_USAGE_ERR_PREFIX = 'Usage error.'
const REPORT_USAGE_ERR_PREFIX = 'Bugsnag usage error.'

class BugsnagClient {
  constructor (notifier) {
    if (!notifier || !notifier.name || !notifier.version || !notifier.url) {
      throw new Error('`notifier` argument is required')
    }

    // notifier id
    this.notifier = notifier

    // configure() should be called before notify()
    this._configured = false

    // intialise opts and config
    this._opts = {}
    this.config = {}

    // // i/o
    this._delivery = { sendSession: () => {}, sendEvent: () => {} }
    this._logger = { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} }

    // plugins
    this._plugins = {}

    this._session = null

    this.breadcrumbs = []

    // setable props
    this.app = {}
    this.context = undefined
    this.device = undefined
    this.metaData = undefined
    this.request = undefined
    this.user = {}

    // expose internal constructors
    this.BugsnagClient = BugsnagClient
    this.BugsnagEvent = BugsnagEvent
    this.BugsnagBreadcrumb = BugsnagBreadcrumb
    this.BugsnagSession = BugsnagSession

    const self = this
    const notify = this.notify
    this.notify = function () {
      return notify.apply(self, arguments)
    }
  }

  setOptions (opts) {
    this._opts = { ...this._opts, ...opts }
  }

  configure (partialSchema = config.schema) {
    const conf = config.mergeDefaults(this._opts, partialSchema)
    const validity = config.validate(conf, partialSchema)

    if (!validity.valid === true) throw new Error(generateConfigErrorMessage(validity.errors))

    // update and elevate some special options if they were passed in at this point
    if (typeof conf.onError === 'function') conf.onError = [conf.onError]
    if (conf.appVersion) this.app.version = conf.appVersion
    if (conf.appType) this.app.type = conf.appType
    if (conf.metaData) this.metaData = conf.metaData
    if (conf.user) this.user = conf.user
    if (conf.logger) this.logger(conf.logger)

    // merge with existing config
    this.config = { ...this.config, ...conf }

    this._configured = true

    return this
  }

  use (plugin, ...args) {
    if (!this._configured) throw new Error('client not configured')
    if (plugin.configSchema) this.configure(plugin.configSchema)
    const result = plugin.init(this, ...args)
    // JS objects are not the safest way to store arbitrarily keyed values,
    // so bookend the key with some characters that prevent tampering with
    // stuff like __proto__ etc. (only store the result if the plugin had a
    // name)
    if (plugin.name) this._plugins[`~${plugin.name}~`] = result
    return this
  }

  getPlugin (name) {
    return this._plugins[`~${name}~`]
  }

  delivery (d) {
    this._delivery = d(this)
    return this
  }

  logger (l, sid) {
    this._logger = l
    return this
  }

  sessionDelegate (s) {
    this._sessionDelegate = s
    return this
  }

  startSession () {
    if (!this._sessionDelegate) {
      this._logger.warn('No session implementation is installed')
      return this
    }
    return this._sessionDelegate.startSession(this)
  }

  leaveBreadcrumb (message, metadata, type) {
    if (!this._configured) throw new Error('client not configured')

    // coerce bad values so that the defaults get set
    message = typeof message === 'string' ? message : ''
    type = typeof type === 'string' ? type : 'manual'
    metadata = typeof metadata === 'object' && metadata !== null ? metadata : {}

    // if no message, discard
    if (!message) return

    // check the breadcrumb is the list of enabled types
    if (!this.config.enabledBreadcrumbTypes || !includes(this.config.enabledBreadcrumbTypes, type)) return

    const crumb = new BugsnagBreadcrumb(message, metadata, type)

    // push the valid crumb onto the queue and maintain the length
    this.breadcrumbs.push(crumb)
    if (this.breadcrumbs.length > this.config.maxBreadcrumbs) {
      this.breadcrumbs = this.breadcrumbs.slice(this.breadcrumbs.length - this.config.maxBreadcrumbs)
    }

    return this
  }

  notify (error, onError, cb = () => {}) {
    if (!this._configured) throw new Error('client not configured')

    // releaseStage can be set via config.releaseStage or client.app.releaseStage
    const releaseStage = inferReleaseStage(this)

    // ensure we have an error (or a reasonable object representation of an error)
    const { err, errorFramesToSkip } = normaliseError(error, this._logger)

    // create an event from the error, if it isn't one already
    const event = BugsnagEvent.ensureEvent(err, errorFramesToSkip, 2)

    event.app = { ...{ releaseStage }, ...event.app, ...this.app }
    event.context = event.context || this.context || undefined
    event.device = { ...event.device, ...this.device }
    event.request = { ...event.request, ...this.request }
    event.user = { ...event.user, ...this.user }
    event.metaData = { ...event.metaData, ...this.metaData }
    event.breadcrumbs = this.breadcrumbs.slice(0)

    if (this._session) {
      this._session.trackError(event)
      event.session = this._session
    }

    // exit early if events should not be sent on the current releaseStage
    if (this.config.enabledReleaseStages.length > 0 && !includes(this.config.enabledReleaseStages, releaseStage)) {
      this._logger.warn('Event not sent due to releaseStage/enabledReleaseStages configuration')
      return cb(null, event)
    }

    const originalSeverity = event.severity

    const onError = [].concat(opts.onError).concat(this.config.onError)
    const onCallbackError = err => {
      // errors in callbacks are tolerated but we want to log them out
      this._logger.error('Error occurred in onError callback, continuing anyway…')
      this._logger.error(err)
    }

    runCallbacks(onError, event, onCallbackError, (err, shouldSend) => {
      if (err) onCallbackError(err)

      if (!shouldSend) {
        this._logger.debug('Event not sent due to onError callback')
        return cb(null, event)
      }

      // only leave a crumb for the error if actually got sent
      BugsnagClient.prototype.leaveBreadcrumb.call(this, event.errorClass, {
        errorClass: event.errorClass,
        errorMessage: event.errorMessage,
        severity: event.severity
      }, 'error')

      if (originalSeverity !== event.severity) {
        event._handledState.severityReason = { type: 'userCallbackSetSeverity' }
      }

      this._delivery.sendEvent({
        apiKey: event.apiKey || this.config.apiKey,
        notifier: this.notifier,
        events: [event]
      }, (err) => cb(err, event))
    })
  }
}

const normaliseError = (error, logger) => {
  const synthesizedErrorFramesToSkip = 3

  const createAndLogUsageError = reason => {
    const msg = generateNotifyUsageMessage(reason)
    logger.warn(`${LOG_USAGE_ERR_PREFIX} ${msg}`)
    return new Error(`${REPORT_USAGE_ERR_PREFIX} ${msg}`)
  }

  let err
  let errorFramesToSkip = 0
  switch (typeof error) {
    case 'string':
      err = new Error(String(error))
      errorFramesToSkip = synthesizedErrorFramesToSkip
      break
    case 'number':
    case 'boolean':
      err = new Error(String(error))
      break
    case 'function':
      err = createAndLogUsageError('function')
      break
    case 'object':
      if (error !== null && (isError(error) || error.__isBugsnagEvent)) {
        err = error
      } else if (error !== null && hasNecessaryFields(error)) {
        err = new Error(error.message || error.errorMessage)
        err.name = error.name || error.errorClass
        errorFramesToSkip = synthesizedErrorFramesToSkip
      } else {
        err = createAndLogUsageError(error === null ? 'null' : 'unsupported object')
      }
      break
    default:
      err = createAndLogUsageError('nothing')
  }
  return { err, errorFramesToSkip }
}

const hasNecessaryFields = error =>
  (typeof error.name === 'string' || typeof error.errorClass === 'string') &&
  (typeof error.message === 'string' || typeof error.errorMessage === 'string')

const generateConfigErrorMessage = errors =>
  `Bugsnag configuration error\n${map(errors, (err) => `"${err.key}" ${err.message} \n    got ${stringify(err.value)}`).join('\n\n')}`

const generateNotifyUsageMessage = actual =>
  `notify(err) expected an error, got ${actual}`

const stringify = val => typeof val === 'object' ? JSON.stringify(val) : String(val)

module.exports = BugsnagClient
<commit_msg>refactor: Redefining a const<commit_after>const config = require('./config')
const BugsnagEvent = require('./event')
const BugsnagBreadcrumb = require('./breadcrumb')
const BugsnagSession = require('./session')
const { map, includes } = require('./lib/es-utils')
const inferReleaseStage = require('./lib/infer-release-stage')
const isError = require('./lib/iserror')
const runCallbacks = require('./lib/callback-runner')

const LOG_USAGE_ERR_PREFIX = 'Usage error.'
const REPORT_USAGE_ERR_PREFIX = 'Bugsnag usage error.'

class BugsnagClient {
  constructor (notifier) {
    if (!notifier || !notifier.name || !notifier.version || !notifier.url) {
      throw new Error('`notifier` argument is required')
    }

    // notifier id
    this.notifier = notifier

    // configure() should be called before notify()
    this._configured = false

    // intialise opts and config
    this._opts = {}
    this.config = {}

    // // i/o
    this._delivery = { sendSession: () => {}, sendEvent: () => {} }
    this._logger = { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} }

    // plugins
    this._plugins = {}

    this._session = null

    this.breadcrumbs = []

    // setable props
    this.app = {}
    this.context = undefined
    this.device = undefined
    this.metaData = undefined
    this.request = undefined
    this.user = {}

    // expose internal constructors
    this.BugsnagClient = BugsnagClient
    this.BugsnagEvent = BugsnagEvent
    this.BugsnagBreadcrumb = BugsnagBreadcrumb
    this.BugsnagSession = BugsnagSession

    const self = this
    const notify = this.notify
    this.notify = function () {
      return notify.apply(self, arguments)
    }
  }

  setOptions (opts) {
    this._opts = { ...this._opts, ...opts }
  }

  configure (partialSchema = config.schema) {
    const conf = config.mergeDefaults(this._opts, partialSchema)
    const validity = config.validate(conf, partialSchema)

    if (!validity.valid === true) throw new Error(generateConfigErrorMessage(validity.errors))

    // update and elevate some special options if they were passed in at this point
    if (typeof conf.onError === 'function') conf.onError = [conf.onError]
    if (conf.appVersion) this.app.version = conf.appVersion
    if (conf.appType) this.app.type = conf.appType
    if (conf.metaData) this.metaData = conf.metaData
    if (conf.user) this.user = conf.user
    if (conf.logger) this.logger(conf.logger)

    // merge with existing config
    this.config = { ...this.config, ...conf }

    this._configured = true

    return this
  }

  use (plugin, ...args) {
    if (!this._configured) throw new Error('client not configured')
    if (plugin.configSchema) this.configure(plugin.configSchema)
    const result = plugin.init(this, ...args)
    // JS objects are not the safest way to store arbitrarily keyed values,
    // so bookend the key with some characters that prevent tampering with
    // stuff like __proto__ etc. (only store the result if the plugin had a
    // name)
    if (plugin.name) this._plugins[`~${plugin.name}~`] = result
    return this
  }

  getPlugin (name) {
    return this._plugins[`~${name}~`]
  }

  delivery (d) {
    this._delivery = d(this)
    return this
  }

  logger (l, sid) {
    this._logger = l
    return this
  }

  sessionDelegate (s) {
    this._sessionDelegate = s
    return this
  }

  startSession () {
    if (!this._sessionDelegate) {
      this._logger.warn('No session implementation is installed')
      return this
    }
    return this._sessionDelegate.startSession(this)
  }

  leaveBreadcrumb (message, metadata, type) {
    if (!this._configured) throw new Error('client not configured')

    // coerce bad values so that the defaults get set
    message = typeof message === 'string' ? message : ''
    type = typeof type === 'string' ? type : 'manual'
    metadata = typeof metadata === 'object' && metadata !== null ? metadata : {}

    // if no message, discard
    if (!message) return

    // check the breadcrumb is the list of enabled types
    if (!this.config.enabledBreadcrumbTypes || !includes(this.config.enabledBreadcrumbTypes, type)) return

    const crumb = new BugsnagBreadcrumb(message, metadata, type)

    // push the valid crumb onto the queue and maintain the length
    this.breadcrumbs.push(crumb)
    if (this.breadcrumbs.length > this.config.maxBreadcrumbs) {
      this.breadcrumbs = this.breadcrumbs.slice(this.breadcrumbs.length - this.config.maxBreadcrumbs)
    }

    return this
  }

  notify (error, onError, cb = () => {}) {
    if (!this._configured) throw new Error('client not configured')

    // releaseStage can be set via config.releaseStage or client.app.releaseStage
    const releaseStage = inferReleaseStage(this)

    // ensure we have an error (or a reasonable object representation of an error)
    const { err, errorFramesToSkip } = normaliseError(error, this._logger)

    // create an event from the error, if it isn't one already
    const event = BugsnagEvent.ensureEvent(err, errorFramesToSkip, 2)

    event.app = { ...{ releaseStage }, ...event.app, ...this.app }
    event.context = event.context || this.context || undefined
    event.device = { ...event.device, ...this.device }
    event.request = { ...event.request, ...this.request }
    event.user = { ...event.user, ...this.user }
    event.metaData = { ...event.metaData, ...this.metaData }
    event.breadcrumbs = this.breadcrumbs.slice(0)

    if (this._session) {
      this._session.trackError(event)
      event.session = this._session
    }

    // exit early if events should not be sent on the current releaseStage
    if (this.config.enabledReleaseStages.length > 0 && !includes(this.config.enabledReleaseStages, releaseStage)) {
      this._logger.warn('Event not sent due to releaseStage/enabledReleaseStages configuration')
      return cb(null, event)
    }

    const originalSeverity = event.severity

    const onCallbackError = err => {
      // errors in callbacks are tolerated but we want to log them out
      this._logger.error('Error occurred in onError callback, continuing anyway…')
      this._logger.error(err)
    }

    const callbacks = [].concat(onError).concat(this.config.onError)
    runCallbacks(callbacks, event, onCallbackError, (err, shouldSend) => {
      if (err) onCallbackError(err)

      if (!shouldSend) {
        this._logger.debug('Event not sent due to onError callback')
        return cb(null, event)
      }

      // only leave a crumb for the error if actually got sent
      BugsnagClient.prototype.leaveBreadcrumb.call(this, event.errorClass, {
        errorClass: event.errorClass,
        errorMessage: event.errorMessage,
        severity: event.severity
      }, 'error')

      if (originalSeverity !== event.severity) {
        event._handledState.severityReason = { type: 'userCallbackSetSeverity' }
      }

      this._delivery.sendEvent({
        apiKey: event.apiKey || this.config.apiKey,
        notifier: this.notifier,
        events: [event]
      }, (err) => cb(err, event))
    })
  }
}

const normaliseError = (error, logger) => {
  const synthesizedErrorFramesToSkip = 3

  const createAndLogUsageError = reason => {
    const msg = generateNotifyUsageMessage(reason)
    logger.warn(`${LOG_USAGE_ERR_PREFIX} ${msg}`)
    return new Error(`${REPORT_USAGE_ERR_PREFIX} ${msg}`)
  }

  let err
  let errorFramesToSkip = 0
  switch (typeof error) {
    case 'string':
      err = new Error(String(error))
      errorFramesToSkip = synthesizedErrorFramesToSkip
      break
    case 'number':
    case 'boolean':
      err = new Error(String(error))
      break
    case 'function':
      err = createAndLogUsageError('function')
      break
    case 'object':
      if (error !== null && (isError(error) || error.__isBugsnagEvent)) {
        err = error
      } else if (error !== null && hasNecessaryFields(error)) {
        err = new Error(error.message || error.errorMessage)
        err.name = error.name || error.errorClass
        errorFramesToSkip = synthesizedErrorFramesToSkip
      } else {
        err = createAndLogUsageError(error === null ? 'null' : 'unsupported object')
      }
      break
    default:
      err = createAndLogUsageError('nothing')
  }
  return { err, errorFramesToSkip }
}

const hasNecessaryFields = error =>
  (typeof error.name === 'string' || typeof error.errorClass === 'string') &&
  (typeof error.message === 'string' || typeof error.errorMessage === 'string')

const generateConfigErrorMessage = errors =>
  `Bugsnag configuration error\n${map(errors, (err) => `"${err.key}" ${err.message} \n    got ${stringify(err.value)}`).join('\n\n')}`

const generateNotifyUsageMessage = actual =>
  `notify(err) expected an error, got ${actual}`

const stringify = val => typeof val === 'object' ? JSON.stringify(val) : String(val)

module.exports = BugsnagClient
<|endoftext|>