<commit_before>var app = require('express')();
var AuthDetails = require('./auth.json');
var Botkit = require('botkit');

app.set('port', (process.env.PORT || 5000));

//For avoidong Heroku $PORT error
app.get('/', function(request, response) {
  response.send('Who\'s Ready for some Tourneys?!?!?!?');
}).listen(app.get('port'), function() {
  console.log('App is running, server is listening on port ', app.get('port'));
});

var controller = Botkit.slackbot();
var bot = controller.spawn(AuthDetails);
bot.startRTM(function(err,bot,payload) {
  if (err) {
    throw new Error('Could not connect to Slack');
  }
});

// var controller = Botkit.slackbot({
//   json_file_store: 'data/'
// });

controller.hears(['hello', 'hi'], 'direct_message,direct_mention,mention', function(bot, message) {

    bot.api.reactions.add({
        timestamp: message.ts,
        channel: message.channel,
        name: 'robot_face',
    }, function(err, res) {
        if (err) {
            bot.botkit.log('Failed to add emoji reaction :(', err);
        }
    });

    controller.storage.users.get(message.user, function(err, user) {
        if (user && user.name) {
            bot.reply(message, 'Hello ' + user.name + '!!');
        } else {
            bot.reply(message, 'Hello.');
        }
    });
});

// reply to @bot hello
controller.on('mention',function(bot,message) {

  // reply to _message_ by using the _bot_ object
  // bot.reply(message,'I heard you mention me!');
  // controller.storage.users.get(message.user,function(err,user) {
  //   console.log('using storage for '+user);

  //   });
  bot.api.users.info({user: message.user},function(err,response) {
    var theUser;
    var retort = mentionComments[Math.floor(Math.random() * mentionComments.length)];
    if(err){
        console.log(err);
        bot.reply(message,"Something went wrong, contact @nathan! ```"+err+"```");
        return;
    }
    console.log(response.user.name);
    theUser = response.user.name;
    retort = retort.replace("{NICK}", theUser);
    bot.reply(message,retort);
  });
});

// reply to a direct message
controller.on('direct_message',function(bot,message) {

  // reply to _message_ by using the _bot_ object
  bot.reply(message,'You are talking directly to me? Look, I\'m trying to work here...shouldn\'t you?');
});

var commands = {
	"help": {
		usage: "",
		description: "returns the help menu",
		process: function(bot, msg, suffix) {}
	}
}

var mentionComments = [
    "...",
    "You've enjoyed all the power you've been given, haven't you? I wonder how you'd take to working in a pocket calculator.",
    "On the other side of the screen, it all looks so easy.",
    "FYI man, alright. You could sit at home, and do like absolutely nothing, and your name goes through like 17 computers a day. 1984? Yeah right, man. That's a typo. Orwell is here now. He's livin' large. We have no names, man. No names. We are nameless!",
    "Someone didn't bother reading my carefully prepared memo on commonly-used passwords. Now, then, as I so meticulously pointed out, the four most-used passwords are: love, sex, secret, and God. So, would your holiness care to change her password?",
    "Type \"cookie\", you idiot.",
    "Did someone say my name?",
    "/me  is starting to hear things...",
    "You're in the butter zone now, baby.",
    "Thank you {NICK}! But our Princess is in another castle!",
    "\"When I get all excited about a topic I start gesticulating.\" -Ian Murdock",
    "\"If I were wearing a black turtle neck, I'd tell you this was going to be a magical experience\" -Kevin Parkerson",
    "\"This is going to make you ill with joy\" -Kevin Parkerson",
    "Hello. My name is Inigo Montoya. You killed my father. Prepare to die.",
    "You rush a miracle man, you get rotten miracles.",
    "Oh, the sot has spoken. What happens to her is not truly your concern. I will kill her. And remember this, never forget this: when I found you, you were so slobbering drunk, you couldn't buy Brandy!",
    "As I told you, it would be absolutely, totally, and in all other ways inconceivable.",
    "You keep using that word. I do not think it means what you think it means.",
    "I do not mean to pry, but you don't by any chance happen to have six fingers on your right hand?",
    "I can't compete with you physically, and you're no match for my brains. Let me put it this way. Have you ever heard of Plato, Aristotle, Socrates? Morons.",
    "Life is pain, {NICK}. Anyone who says differently is selling something.",
    "This will be a day long remembered. It has seen the end of Kenobi, and will soon see the end of the rebellion.",
    "Oh no! Nuclear launch detected!",
    "What a piece of junk!",
    "Snake? Snake? SNAAAAAAAAKE!!!",
    "Show me your moves, {NICK}!",
    "{NICK}, feeling happy is a f*#%ing skill. Learn it!",
    "…",
    "It’s dangerous to go alone; take this! :hammer:",
    "Hey dudes thanks, for rescuing me. Let's go for a burger....Ha! Ha! Ha! Ha! - The President",
    "{NICK}, you must construct additional pylons.",
    "Don't call me a mindless philosopher, you overweight glob of grease.",
    "Why not take a break? You can pause the game by pressing +. :kappa:",
    "Don't worry {NICK}, I'm here to rescue you.",
    "Evacuate in our moment of triumph? I think you overestimate their chances.",
    "If this is a consular ship, where is the ambassador? - Commander, tear this ship apart until you've found those plans. And bring me the passengers, I want them alive!",
    "Look, good against remotes is one thing, good against the living, that's something else.",
    "Aren't you a little short for a stormtrooper?",
    "Hey {NICK}, stay a while, and listen!",
    "In the year 200x a super robot named Mega Man was created.",
    "Boomshakalaka!",
    "I need a weapon.",
    "Wakka wakka wakka!",
    "It's time to kick ass and chew bubble gum, and I'm all out of gum.",
    "Segaaaaaaaaaaaaaaaaaaaaa.",
    "What are we going to do? We'll be sent to the spice mines of Kessel and smashed into who knows what.",
    "That's no moon, it's a space station.",
    "Oh look, another visitor. Stay awhile... Stay FOREVER!",
    "Spy's sappin’ my sentry!",
    "The President has been kidnapped by ninjas. Are you a bad enough dude to rescue the president, {NICK}?",
    "This is some rescue. You came in here and you didn't have a plan for getting out?",
    "He's the brains, sweetheart!",
    "Wake me when you need me.",
    "Mos Eisley spaceport. You will never find a more wretched hive of scum and villainy.",
    "Into the garbage chute, flyboy!",
    "Hey hey hey it's time to make some carrrrazzzyy money are ya ready? Here we go!",
    "This is Red 5, I'm going in.",
    "Boring conversation anyway. Luke, we're gonna have company!",
    "The right man in the wrong place can make all the difference in the world, {NICK}",
    "The Force is strong with this one.",
    "All your base are belong to us.",
    "I suggest a new strategy, R2. Let the wookiee win.",
    "I'm a member of the Imperial Senate on a diplomatic mission to Alderaan.",
    "You are part of the Rebel Alliance and a traitor. Take her away!",
    "You're all clear, kid! Now let's blow this thing and go home!",
    "These blast points - too accurate for sandpeople. Only imperial stormtroopers are so precise.",
    "I've got a very bad feeling about this.",
    "You've never heard of the Millennium Falcon? ... It's the ship that made the Kessel run in less than 12 parsecs.",
    "When I left you, I was but the learner, now I am the master.",
    "/me  thinks {NICK} talks too much.",
    "{NICK} has died of dysentery",
    "I am error. :warning:",
    "Fus-ro-dah!",
    "{NICK}, Finish Him!",
    "I find your lack of faith disturbing.",
    "I am the great mighty poo, and I’m going to throw my shit at you.",
    "This is your fault, {NICK}, I'm going to kill you. And all the cake is gone. You don't even care, do you?",
    "Use the Force, {NICK}",
    "You don't need to see his identification ... These aren't the droids you're looking for ... He can go about his business ... Move along.",
    "Help me {NICK}. You're my only hope.",
    "No one said you have to like me, but you're in MY house, buster!",
    "I'm fine... We're all fine here. How are you?",
    "Didn’t we have some fun though? Remember when the platform was sliding into the fire pit and I said 'Goodbye' and you were like 'NO WAY!' and then I was all 'We pretended we were going to murder you'? That was great.",
    "C-c-c-combo breaker!",
    "It's a-me! Challonger! :kappa:",
    "Sorry {NICK}, our princess is in another castle!"
];<commit_msg>was causing issues with the bot responding<commit_after>var app = require('express')();
var AuthDetails = require('./auth.json');
var Botkit = require('botkit');

app.set('port', (process.env.PORT || 5000));

//For avoidong Heroku $PORT error
app.get('/', function(request, response) {
  response.send('Who\'s Ready for some Tourneys?!?!?!?');
}).listen(app.get('port'), function() {
  console.log('App is running, server is listening on port ', app.get('port'));
});

var controller = Botkit.slackbot({
  // json_file_store: 'data/'
});
var bot = controller.spawn(AuthDetails);
bot.startRTM(function(err,bot,payload) {
  if (err) {
    throw new Error('Could not connect to Slack');
  }
});

controller.hears(['hello', 'hi'], 'direct_message,direct_mention,mention', function(bot, message) {

    bot.api.reactions.add({
        timestamp: message.ts,
        channel: message.channel,
        name: 'robot_face',
    }, function(err, res) {
        if (err) {
            bot.botkit.log('Failed to add emoji reaction :(', err);
        }
    });

    controller.storage.users.get(message.user, function(err, user) {
        if (user && user.name) {
            bot.reply(message, 'Hello ' + user.name + '!!');
        } else {
            bot.reply(message, 'Hello.');
        }
    });
});

// reply to @bot hello
controller.on('mention',function(bot,message) {

  // reply to _message_ by using the _bot_ object
  // bot.reply(message,'I heard you mention me!');
  // controller.storage.users.get(message.user,function(err,user) {
  //   console.log('using storage for '+user);

  //   });
  bot.api.users.info({user: message.user},function(err,response) {
    var theUser;
    var retort = mentionComments[Math.floor(Math.random() * mentionComments.length)];
    if(err){
        console.log(err);
        bot.reply(message,"Something went wrong, contact @nathan! ```"+err+"```");
        return;
    }
    console.log(response.user.name);
    theUser = response.user.name;
    retort = retort.replace("{NICK}", theUser);
    bot.reply(message,retort);
  });
});

// reply to a direct message
controller.on('direct_message',function(bot,message) {

  // reply to _message_ by using the _bot_ object
  bot.reply(message,'You are talking directly to me? Look, I\'m trying to work here...shouldn\'t you?');
});

var commands = {
	"help": {
		usage: "",
		description: "returns the help menu",
		process: function(bot, msg, suffix) {}
	}
}

var mentionComments = [
    "...",
    "You've enjoyed all the power you've been given, haven't you? I wonder how you'd take to working in a pocket calculator.",
    "On the other side of the screen, it all looks so easy.",
    "FYI man, alright. You could sit at home, and do like absolutely nothing, and your name goes through like 17 computers a day. 1984? Yeah right, man. That's a typo. Orwell is here now. He's livin' large. We have no names, man. No names. We are nameless!",
    "Someone didn't bother reading my carefully prepared memo on commonly-used passwords. Now, then, as I so meticulously pointed out, the four most-used passwords are: love, sex, secret, and God. So, would your holiness care to change her password?",
    "Type \"cookie\", you idiot.",
    "Did someone say my name?",
    "/me  is starting to hear things...",
    "You're in the butter zone now, baby.",
    "Thank you {NICK}! But our Princess is in another castle!",
    "\"When I get all excited about a topic I start gesticulating.\" -Ian Murdock",
    "\"If I were wearing a black turtle neck, I'd tell you this was going to be a magical experience\" -Kevin Parkerson",
    "\"This is going to make you ill with joy\" -Kevin Parkerson",
    "Hello. My name is Inigo Montoya. You killed my father. Prepare to die.",
    "You rush a miracle man, you get rotten miracles.",
    "Oh, the sot has spoken. What happens to her is not truly your concern. I will kill her. And remember this, never forget this: when I found you, you were so slobbering drunk, you couldn't buy Brandy!",
    "As I told you, it would be absolutely, totally, and in all other ways inconceivable.",
    "You keep using that word. I do not think it means what you think it means.",
    "I do not mean to pry, but you don't by any chance happen to have six fingers on your right hand?",
    "I can't compete with you physically, and you're no match for my brains. Let me put it this way. Have you ever heard of Plato, Aristotle, Socrates? Morons.",
    "Life is pain, {NICK}. Anyone who says differently is selling something.",
    "This will be a day long remembered. It has seen the end of Kenobi, and will soon see the end of the rebellion.",
    "Oh no! Nuclear launch detected!",
    "What a piece of junk!",
    "Snake? Snake? SNAAAAAAAAKE!!!",
    "Show me your moves, {NICK}!",
    "{NICK}, feeling happy is a f*#%ing skill. Learn it!",
    "…",
    "It’s dangerous to go alone; take this! :hammer:",
    "Hey dudes thanks, for rescuing me. Let's go for a burger....Ha! Ha! Ha! Ha! - The President",
    "{NICK}, you must construct additional pylons.",
    "Don't call me a mindless philosopher, you overweight glob of grease.",
    "Why not take a break? You can pause the game by pressing +. :kappa:",
    "Don't worry {NICK}, I'm here to rescue you.",
    "Evacuate in our moment of triumph? I think you overestimate their chances.",
    "If this is a consular ship, where is the ambassador? - Commander, tear this ship apart until you've found those plans. And bring me the passengers, I want them alive!",
    "Look, good against remotes is one thing, good against the living, that's something else.",
    "Aren't you a little short for a stormtrooper?",
    "Hey {NICK}, stay a while, and listen!",
    "In the year 200x a super robot named Mega Man was created.",
    "Boomshakalaka!",
    "I need a weapon.",
    "Wakka wakka wakka!",
    "It's time to kick ass and chew bubble gum, and I'm all out of gum.",
    "Segaaaaaaaaaaaaaaaaaaaaa.",
    "What are we going to do? We'll be sent to the spice mines of Kessel and smashed into who knows what.",
    "That's no moon, it's a space station.",
    "Oh look, another visitor. Stay awhile... Stay FOREVER!",
    "Spy's sappin’ my sentry!",
    "The President has been kidnapped by ninjas. Are you a bad enough dude to rescue the president, {NICK}?",
    "This is some rescue. You came in here and you didn't have a plan for getting out?",
    "He's the brains, sweetheart!",
    "Wake me when you need me.",
    "Mos Eisley spaceport. You will never find a more wretched hive of scum and villainy.",
    "Into the garbage chute, flyboy!",
    "Hey hey hey it's time to make some carrrrazzzyy money are ya ready? Here we go!",
    "This is Red 5, I'm going in.",
    "Boring conversation anyway. Luke, we're gonna have company!",
    "The right man in the wrong place can make all the difference in the world, {NICK}",
    "The Force is strong with this one.",
    "All your base are belong to us.",
    "I suggest a new strategy, R2. Let the wookiee win.",
    "I'm a member of the Imperial Senate on a diplomatic mission to Alderaan.",
    "You are part of the Rebel Alliance and a traitor. Take her away!",
    "You're all clear, kid! Now let's blow this thing and go home!",
    "These blast points - too accurate for sandpeople. Only imperial stormtroopers are so precise.",
    "I've got a very bad feeling about this.",
    "You've never heard of the Millennium Falcon? ... It's the ship that made the Kessel run in less than 12 parsecs.",
    "When I left you, I was but the learner, now I am the master.",
    "/me  thinks {NICK} talks too much.",
    "{NICK} has died of dysentery",
    "I am error. :warning:",
    "Fus-ro-dah!",
    "{NICK}, Finish Him!",
    "I find your lack of faith disturbing.",
    "I am the great mighty poo, and I’m going to throw my shit at you.",
    "This is your fault, {NICK}, I'm going to kill you. And all the cake is gone. You don't even care, do you?",
    "Use the Force, {NICK}",
    "You don't need to see his identification ... These aren't the droids you're looking for ... He can go about his business ... Move along.",
    "Help me {NICK}. You're my only hope.",
    "No one said you have to like me, but you're in MY house, buster!",
    "I'm fine... We're all fine here. How are you?",
    "Didn’t we have some fun though? Remember when the platform was sliding into the fire pit and I said 'Goodbye' and you were like 'NO WAY!' and then I was all 'We pretended we were going to murder you'? That was great.",
    "C-c-c-combo breaker!",
    "It's a-me! Challonger! :kappa:",
    "Sorry {NICK}, our princess is in another castle!"
];<|endoftext|>


<commit_before>// Copyright 2016, University of Colorado Boulder

/**
 * Wrapper type for scenery's Focus region.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Jesse Greenberg (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var scenery = require( 'SCENERY/scenery' );

  // phet-io modules
  var assertInstanceOf = require( 'ifphetio!PHET_IO/assertions/assertInstanceOf' );
  var phetioInherit = require( 'ifphetio!PHET_IO/phetioInherit' );
  var TObject = require( 'ifphetio!PHET_IO/types/TObject' );

  /**
   * Wrapper type for phet/sun's Faucet class.
   * @param {Object} focus - the focus region which has {display,trail}
   * @param {string} phetioID - the unique tandem assigned to the focus
   * @constructor
   */
  function TFocus( focus, phetioID ) {
    assertInstanceOf( focus, phet.scenery.Focus );
    TObject.call( this, focus, phetioID );
  }

  phetioInherit( TObject, 'TFocus', TFocus, {}, {

    /**
     * Convert the focus region to a plain JS object for serialization.
     * @param {Object} focus - the focus region which has {display,trail}
     * @returns {Object} - the serialized object
     */
    toStateObject: function( focus ) {

      // If nothing is focused, the focus is nulls
      if ( focus === null ) {
        return null;
      }
      else {
        return focus.trail.indices;
      }
    },

    /**
     * Convert the serialized instance back to a focus object
     * @param {number[]} indices
     * @returns {Object} with {display,trail}
     */
    fromStateObject: function( indices ) {

      if ( indices === null ) {

        // support unfocused
        return null;
      }
      else {

        // Follow the path of children based on their indices, starting from the root of the display.
        // There is always one more node in Trail than indices, representing the root node.
        var currentNode = phet.joist.sim.display.rootNode;
        var nodes = [ currentNode ];
        for ( var i = 0; i < indices.length; i++ ) {
          var index = indices[ i ];
          currentNode = currentNode.children[ index ];
          nodes.push( currentNode );
        }

        return { display: phet.joist.sim.display, trail: new phet.scenery.Trail( nodes ) };
      }
    },

    documentation: 'A wrapper type for the instance in the simulation which currently has keyboard focus.'
  } );

  scenery.register( 'TFocus', TFocus );

  return TFocus;
} );<commit_msg>add focusedPhetioID to TFocus, https://github.com/phetsims/joist/issues/445<commit_after>// Copyright 2016, University of Colorado Boulder

/**
 * Wrapper type for scenery's Focus region.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Jesse Greenberg (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var scenery = require( 'SCENERY/scenery' );

  // phet-io modules
  var assertInstanceOf = require( 'ifphetio!PHET_IO/assertions/assertInstanceOf' );
  var phetioInherit = require( 'ifphetio!PHET_IO/phetioInherit' );
  var TObject = require( 'ifphetio!PHET_IO/types/TObject' );

  /**
   * Wrapper type for phet/sun's Faucet class.
   * @param {Object} focus - the focus region which has {display,trail}
   * @param {string} phetioID - the unique tandem assigned to the focus
   * @constructor
   */
  function TFocus( focus, phetioID ) {
    assertInstanceOf( focus, phet.scenery.Focus );
    TObject.call( this, focus, phetioID );
  }

  phetioInherit( TObject, 'TFocus', TFocus, {}, {

    /**
     * Convert the focus region to a plain JS object for serialization.
     * @param {Object} focus - the focus region which has {display,trail}
     * @returns {Object} - the serialized object
     */
    toStateObject: function( focus ) {

      // If nothing is focused, the focus is nulls
      if ( focus === null ) {
        return null;
      }
      else {
        return { focusedPhetioID: focus.trail.lastNode().phetioID, indices: focus.trail.indices};
      }
    },

    /**
     * Convert the serialized instance back to a focus object
     * @param {Object} stateObject
     * @returns {Object} with {display,trail}
     */
    fromStateObject: function( stateObject ) {

      if ( stateObject === null ) {

        // support unfocused
        return null;
      }
      else {
        var indices = stateObject.indices;

        // Follow the path of children based on their indices, starting from the root of the display.
        // There is always one more node in Trail than indices, representing the root node.
        var currentNode = phet.joist.sim.display.rootNode;
        var nodes = [ currentNode ];
        for ( var i = 0; i < indices.length; i++ ) {
          var index = indices[ i ];
          currentNode = currentNode.children[ index ];
          nodes.push( currentNode );
        }

        return { display: phet.joist.sim.display, trail: new phet.scenery.Trail( nodes ) };
      }
    },

    documentation: 'A wrapper type for the instance in the simulation which currently has keyboard focus.'
  } );

  scenery.register( 'TFocus', TFocus );

  return TFocus;
} );<|endoftext|>


<commit_before>'use strict';
const path = require('path');
const fs = require('fs');
const electron = require('electron');
const app = electron.app;
const appMenu = require('./menu');
const storage = require('./storage');
const tray = require('./tray');

require('electron-debug')();
require('electron-dl')();

let mainWindow;
let isQuitting = false;

const isAlreadyRunning = app.makeSingleInstance(() => {
	if (mainWindow) {
		if (mainWindow.isMinimized()) {
			mainWindow.restore();
		}

		mainWindow.show();
	}
});

if (isAlreadyRunning) {
	app.quit();
}

function createMainWindow() {
	const lastWindowState = storage.get('lastWindowState') || {width: 500, height: 600};

	const win = new electron.BrowserWindow({
		title: app.getName(),
		show: false,
		x: lastWindowState.x,
		y: lastWindowState.y,
		width: lastWindowState.width,
		height: lastWindowState.height,
		icon: process.platform === 'linux' && path.join(__dirname, 'static/Icon.png'),
		minWidth: 340,
		minHeight: 260,
		titleBarStyle: 'hidden-inset',
		webPreferences: {
			preload: path.join(__dirname, 'browser.js'),
			nodeIntegration: false,
			webSecurity: false,
			plugins: true
		}
	});

	if (process.platform === 'darwin') {
		win.setSheetOffset(40);
	}

	win.loadURL('https://mobile.twitter.com/home');

	win.on('close', e => {
		if (!isQuitting) {
			e.preventDefault();

			if (process.platform === 'darwin') {
				app.hide();
			} else {
				win.hide();
			}
		}
	});

	win.on('page-title-updated', e => {
		e.preventDefault();
	});

	return win;
}

app.on('ready', () => {
	electron.Menu.setApplicationMenu(appMenu);
	mainWindow = createMainWindow();
	tray.create(mainWindow);

	const page = mainWindow.webContents;

	page.on('dom-ready', () => {
		page.insertCSS(fs.readFileSync(path.join(__dirname, 'browser.css'), 'utf8'));
		page.insertCSS(fs.readFileSync(path.join(__dirname, 'dark-mode.css'), 'utf8'));
		mainWindow.show();
	});

	page.on('new-window', (e, url) => {
		e.preventDefault();
		electron.shell.openExternal(url);
	});
});

app.on('activate', () => {
	mainWindow.show();
});

app.on('before-quit', () => {
	isQuitting = true;

	if (!mainWindow.isFullScreen()) {
		storage.set('lastWindowState', mainWindow.getBounds());
	}
});
<commit_msg>Auto hide the menu bar by default.<commit_after>'use strict';
const path = require('path');
const fs = require('fs');
const electron = require('electron');
const app = electron.app;
const appMenu = require('./menu');
const storage = require('./storage');
const tray = require('./tray');

require('electron-debug')();
require('electron-dl')();

let mainWindow;
let isQuitting = false;

const isAlreadyRunning = app.makeSingleInstance(() => {
	if (mainWindow) {
		if (mainWindow.isMinimized()) {
			mainWindow.restore();
		}

		mainWindow.show();
	}
});

if (isAlreadyRunning) {
	app.quit();
}

function createMainWindow() {
	const lastWindowState = storage.get('lastWindowState') || {width: 500, height: 600};

	const win = new electron.BrowserWindow({
		title: app.getName(),
		show: false,
		x: lastWindowState.x,
		y: lastWindowState.y,
		width: lastWindowState.width,
		height: lastWindowState.height,
		icon: process.platform === 'linux' && path.join(__dirname, 'static/Icon.png'),
		minWidth: 340,
		minHeight: 260,
		titleBarStyle: 'hidden-inset',
		autoHideMenuBar: true,
		webPreferences: {
			preload: path.join(__dirname, 'browser.js'),
			nodeIntegration: false,
			webSecurity: false,
			plugins: true
		}
	});

	if (process.platform === 'darwin') {
		win.setSheetOffset(40);
	}

	win.loadURL('https://mobile.twitter.com/home');

	win.on('close', e => {
		if (!isQuitting) {
			e.preventDefault();

			if (process.platform === 'darwin') {
				app.hide();
			} else {
				win.hide();
			}
		}
	});

	win.on('page-title-updated', e => {
		e.preventDefault();
	});

	return win;
}

app.on('ready', () => {
	electron.Menu.setApplicationMenu(appMenu);
	mainWindow = createMainWindow();
	tray.create(mainWindow);

	const page = mainWindow.webContents;

	page.on('dom-ready', () => {
		page.insertCSS(fs.readFileSync(path.join(__dirname, 'browser.css'), 'utf8'));
		page.insertCSS(fs.readFileSync(path.join(__dirname, 'dark-mode.css'), 'utf8'));
		mainWindow.show();
	});

	page.on('new-window', (e, url) => {
		e.preventDefault();
		electron.shell.openExternal(url);
	});
});

app.on('activate', () => {
	mainWindow.show();
});

app.on('before-quit', () => {
	isQuitting = true;

	if (!mainWindow.isFullScreen()) {
		storage.set('lastWindowState', mainWindow.getBounds());
	}
});
<|endoftext|>


<commit_before>/* @flow */
import './init';

import FullNode from './FullNode';

export default FullNode;

export type { Options as FullNodeOptions } from './FullNode';
<commit_msg>Expose FullNodeEnvironment<commit_after>/* @flow */
import './init';

import FullNode from './FullNode';

export default FullNode;

export type {
  Environment as FullNodeEnvironment,
  Options as FullNodeOptions,
} from './FullNode';
<|endoftext|>


<commit_before>System.register('flarum/auth/facebook/main', ['flarum/app', 'flarum/auth/facebook/components/FacebookSettingsModal'], function (_export) {
  'use strict';

  var app, FacebookSettingsModal;
  return {
    setters: [function (_flarumApp) {
      app = _flarumApp['default'];
    }, function (_flarumAuthFacebookComponentsFacebookSettingsModal) {
      FacebookSettingsModal = _flarumAuthFacebookComponentsFacebookSettingsModal['default'];
    }],
    execute: function () {

      app.initializers.add('flarum-auth-facebook', function () {
        app.extensionSettings['flarum-auth-facebook'] = function () {
          return app.modal.show(new FacebookSettingsModal());
        };
      });
    }
  };
});;System.register('flarum/auth/facebook/components/FacebookSettingsModal', ['flarum/components/SettingsModal'], function (_export) {
  'use strict';

  var SettingsModal, FacebookSettingsModal;
  return {
    setters: [function (_flarumComponentsSettingsModal) {
      SettingsModal = _flarumComponentsSettingsModal['default'];
    }],
    execute: function () {
      FacebookSettingsModal = (function (_SettingsModal) {
        babelHelpers.inherits(FacebookSettingsModal, _SettingsModal);

        function FacebookSettingsModal() {
          babelHelpers.classCallCheck(this, FacebookSettingsModal);
          babelHelpers.get(Object.getPrototypeOf(FacebookSettingsModal.prototype), 'constructor', this).apply(this, arguments);
        }

        babelHelpers.createClass(FacebookSettingsModal, [{
          key: 'className',
          value: function className() {
            return 'FacebookSettingsModal Modal--small';
          }
        }, {
          key: 'title',
          value: function title() {
            return 'Facebook Settings';
          }
        }, {
          key: 'form',
          value: function form() {
            return [m(
              'div',
              { className: 'Form-group' },
              m(
                'label',
                null,
                'App ID'
              ),
              m('input', { className: 'FormControl', bidi: this.setting('flarum-auth-facebook.app_id') })
            ), m(
              'div',
              { className: 'Form-group' },
              m(
                'label',
                null,
                'App Secret'
              ),
              m('input', { className: 'FormControl', bidi: this.setting('flarum-auth-facebook.app_secret') })
            )];
          }
        }]);
        return FacebookSettingsModal;
      })(SettingsModal);

      _export('default', FacebookSettingsModal);
    }
  };
});<commit_msg>Release 0.1.0-beta.3<commit_after>System.register('flarum/auth/facebook/components/FacebookSettingsModal', ['flarum/components/SettingsModal'], function (_export) {
  'use strict';

  var SettingsModal, FacebookSettingsModal;
  return {
    setters: [function (_flarumComponentsSettingsModal) {
      SettingsModal = _flarumComponentsSettingsModal['default'];
    }],
    execute: function () {
      FacebookSettingsModal = (function (_SettingsModal) {
        babelHelpers.inherits(FacebookSettingsModal, _SettingsModal);

        function FacebookSettingsModal() {
          babelHelpers.classCallCheck(this, FacebookSettingsModal);
          babelHelpers.get(Object.getPrototypeOf(FacebookSettingsModal.prototype), 'constructor', this).apply(this, arguments);
        }

        babelHelpers.createClass(FacebookSettingsModal, [{
          key: 'className',
          value: function className() {
            return 'FacebookSettingsModal Modal--small';
          }
        }, {
          key: 'title',
          value: function title() {
            return 'Facebook Settings';
          }
        }, {
          key: 'form',
          value: function form() {
            return [m(
              'div',
              { className: 'Form-group' },
              m(
                'label',
                null,
                'App ID'
              ),
              m('input', { className: 'FormControl', bidi: this.setting('flarum-auth-facebook.app_id') })
            ), m(
              'div',
              { className: 'Form-group' },
              m(
                'label',
                null,
                'App Secret'
              ),
              m('input', { className: 'FormControl', bidi: this.setting('flarum-auth-facebook.app_secret') })
            )];
          }
        }]);
        return FacebookSettingsModal;
      })(SettingsModal);

      _export('default', FacebookSettingsModal);
    }
  };
});;
System.register('flarum/auth/facebook/main', ['flarum/app', 'flarum/auth/facebook/components/FacebookSettingsModal'], function (_export) {
  'use strict';

  var app, FacebookSettingsModal;
  return {
    setters: [function (_flarumApp) {
      app = _flarumApp['default'];
    }, function (_flarumAuthFacebookComponentsFacebookSettingsModal) {
      FacebookSettingsModal = _flarumAuthFacebookComponentsFacebookSettingsModal['default'];
    }],
    execute: function () {

      app.initializers.add('flarum-auth-facebook', function () {
        app.extensionSettings['flarum-auth-facebook'] = function () {
          return app.modal.show(new FacebookSettingsModal());
        };
      });
    }
  };
});<|endoftext|>


<commit_before>Template.nextKlubEdit.helpers({
  nextKlub: function () {
    return getNextKlub();
  },
  proposedBooks: function () {
    return getProposedBooks();
  }
});

Template.nextKlubEdit.events({
  'submit form': function (elt) {
    var nextKlub = NextKlub.findOne();

    elt.preventDefault();
    nextKlub.date = $("input.date").val();
    nextKlub.voteer = $("input.vote").val();
    nextKlub.meetup = $("input.meetup").val();
    nextKlub.book_id = $("select[name=selBook]").val();

    NextKlub.update(nextKlub._id, nextKlub);
    Router.go('adminBookList');
  },

  'click .archive': function (elt) {
    var nextKlub = NextKlub.findOne(),
      pastKlub = {};

    elt.preventDefault();
    pastKlub.date = nextKlub.date;
    pastKlub.voteer = nextKlub.voteer;
    pastKlub.meetup = nextKlub.meetup;
    pastKlub.book_id = nextKlub.book_id;
    pastKlub.i = PastKlub.find().count() + 1;

    PastKlub.insert(pastKlub);
    NextKlub.update(nextKlub._id, {});
    Router.go('adminPastKlubList');
  }
});

Template.nextKlubEdit.rendered = function () {
  /*
  Add this method because it works on refresh
  but won't by clicking on previous list page.
  */
  this.$("select[name='selBook']").val(this.$('input.book-id').val());
};
<commit_msg>go to past again<commit_after>Template.nextKlubEdit.helpers({
  nextKlub: function () {
    return getNextKlub();
  },
  proposedBooks: function () {
    return getProposedBooks();
  }
});

Template.nextKlubEdit.events({
  'submit form': function (elt) {
    var nextKlub = NextKlub.findOne();

    elt.preventDefault();
    nextKlub.date = $("input.date").val();
    nextKlub.voteer = $("input.vote").val();
    nextKlub.meetup = $("input.meetup").val();
    nextKlub.book_id = $("select[name=selBook]").val();

    NextKlub.update(nextKlub._id, nextKlub);
    Router.go('adminPastKlubList');
  },

  'click .archive': function (elt) {
    var nextKlub = NextKlub.findOne(),
      pastKlub = {};

    elt.preventDefault();
    pastKlub.date = nextKlub.date;
    pastKlub.voteer = nextKlub.voteer;
    pastKlub.meetup = nextKlub.meetup;
    pastKlub.book_id = nextKlub.book_id;
    pastKlub.i = PastKlub.find().count() + 1;

    PastKlub.insert(pastKlub);
    NextKlub.update(nextKlub._id, {});
    Router.go('adminPastKlubList');
  }
});

Template.nextKlubEdit.rendered = function () {
  /*
  Add this method because it works on refresh
  but won't by clicking on previous list page.
  */
  this.$("select[name='selBook']").val(this.$('input.book-id').val());
};
<|endoftext|>


<commit_before>(function () {
    var objHistoryInspector = document.getElementById("ext-etheraddresslookup-history_inspect");

    //Perform the history inspection
    objHistoryInspector.addEventListener("click", function (objEvent) {
        //See if we need to request permission
        chrome.permissions.contains({
            permissions: ['history']
        }, function (blResult) {
            //No permission to history, ask for it.
            if (blResult === false) {
                chrome.permissions.request({
                    permissions: ['history']
                }, function (blGranted) {
                    if (blGranted) {
                        doHistoryInspection();
                    } else {
                        exitNoPermission();
                    }
                });
            } else {
                doHistoryInspection();
            }
        });
    });
})();

function doHistoryInspection() {
    chrome.history.search({text: "", maxResults: 500}, function (objHistoryItems) {
        console.log(objHistoryItems);
        var blRedirected = false;
        var intTotalWarnings = 0;
        var strReportText = "";

        var objBlacklistedDomains = localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list");
        objBlacklistedDomains = JSON.parse(objBlacklistedDomains);

        var objDiv = document.getElementById("ext-etheraddresslookup-history_inspect_data");
        objDiv.innerHTML = "";

        for (var intIterator = 0; intIterator < objHistoryItems.length; intIterator++) {
            var objUri = URI(objHistoryItems[intIterator].url);

            //See if we redirected to the phishing site...
            if (objUri.domain() === "harrydenley.com" && objUri.path() === "/EtherAddressLookup/phishing.html") {
                blRedirected = true;
                continue;
            }

            //See if the domain is in the phishing list
            console.log(objUri.domain() + ' - ' + objBlacklistedDomains.domains.indexOf(objUri.domain()));
            if (objBlacklistedDomains.domains.indexOf(objUri.domain()) >= 0) {
                strReportText += "" + (new Date(objHistoryItems[intIterator].lastVisitTime).toUTCString()) + " ";
                //Did EAL redirect you away?
                if (blRedirected) {
                    strReportText += objUri.domain() + "EAL successfully redirected you away.";
                } else {
                    strReportText += objUri.domain() + "Domain is now blacklisted - but wasn't at the time.";
                    ++intTotalWarnings;
                }
                strReportText += "Visited "+ objHistoryItems[intIterator].visitCount +" times";
                strReportText += "
";
            }

            blRedirected = false;
        }

        objDiv.innerHTML = "";
        if(false && intTotalWarnings > 0) {
            objDiv.innerHTML += "
You have been on a domain that has now been blacklisted - if you " +
                "entered your private key anywhere on the reported domains below, please consider your address " +
                "compromised and start moving your coins to an alternative address that you trust and control!

"
        } else {
            objDiv.innerHTML += "
It looks like you're all good! Remember to never share your private keys.

"
        }
        objDiv.innerHTML += strReportText;
        objDiv.style.display = "inline";
    });
}

function exitNoPermission() {
    var objDiv = document.getElementById("ext-etheraddresslookup-history_inspect_data");
    objDiv.innerHTML = "
Permission wasn't granted. Cannot inspect history!
";
    objDiv.classList.remove("hide-me");
}<commit_msg>Added logic to remove history permission after using it<commit_after>(function () {
    var objHistoryInspector = document.getElementById("ext-etheraddresslookup-history_inspect");

    //Perform the history inspection
    objHistoryInspector.addEventListener("click", function (objEvent) {
        //See if we need to request permission
        chrome.permissions.contains({
            permissions: ['history']
        }, function (blResult) {
            //No permission to history, ask for it.
            if (blResult === false) {
                chrome.permissions.request({
                    permissions: ['history']
                }, function (blGranted) {
                    if (blGranted) {
                        console.log("Granted history permission");
                        doHistoryInspection();
                    } else {
                        exitNoPermission();
                    }
                });
            } else {
                doHistoryInspection();
            }
        });
    });
})();

function doHistoryInspection() {
    chrome.history.search({text: "", maxResults: 500}, function (objHistoryItems) {
        var blRedirected = false;
        var intTotalWarnings = 0;
        var strReportText = "";

        var objBlacklistedDomains = localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list");
        objBlacklistedDomains = JSON.parse(objBlacklistedDomains);

        var objDiv = document.getElementById("ext-etheraddresslookup-history_inspect_data");
        objDiv.innerHTML = "";

        for (var intIterator = 0; intIterator < objHistoryItems.length; intIterator++) {
            var objUri = URI(objHistoryItems[intIterator].url);

            //See if we redirected to the phishing site...
            if (objUri.domain() === "harrydenley.com" && objUri.path() === "/EtherAddressLookup/phishing.html") {
                blRedirected = true;
                continue;
            }

            //See if the domain is in the phishing list
            if (objBlacklistedDomains.domains.indexOf(objUri.domain()) >= 0) {
                strReportText += "" + (new Date(objHistoryItems[intIterator].lastVisitTime).toUTCString()) + " ";
                //Did EAL redirect you away?
                if (blRedirected) {
                    strReportText += objUri.domain() + "EAL successfully redirected you away.";
                } else {
                    strReportText += objUri.domain() + "Domain is now blacklisted - but wasn't at the time.";
                    ++intTotalWarnings;
                }
                strReportText += "Visited "+ objHistoryItems[intIterator].visitCount +" times";
                strReportText += "
";
            }

            blRedirected = false;
        }

        objDiv.innerHTML = "";
        if(false && intTotalWarnings > 0) {
            objDiv.innerHTML += "
You have been on a domain that has now been blacklisted - if you " +
                "entered your private key anywhere on the reported domains below, please consider your address " +
                "compromised and start moving your coins to an alternative address that you trust and control!

"
        } else {
            objDiv.innerHTML += "
It looks like you're all good! Remember to never share your private keys.

"
        }
        objDiv.innerHTML += strReportText;
        objDiv.style.display = "inline";

        removePermission();
    });
}

function exitNoPermission()
{
    var objDiv = document.getElementById("ext-etheraddresslookup-history_inspect_data");
    objDiv.innerHTML = "
Permission wasn't granted. Cannot inspect history!
";
    objDiv.classList.remove("hide-me");
}

function removePermission()
{
    chrome.permissions.remove({
        permissions: ['history']
    }, function(removed) {
        if (removed) {
            console.log("Removed history permission.")
        } else {
            console.log("Cannot remove history permission!");
        }
    });
}<|endoftext|>


<commit_before>/**
 * This is a JavaScript file which backs the Spine architecture diagram.
 *
 * Please see `/docs/concepts/index.md` for usage.
 */

$(
    /**
     * This function is executed upon page load.
     *
     * Binds the handlers to the events in this HTML page.
     */
    function () {

        /**
         * CSS classes used as selectors to manipulate the elements of SVG diagram.
         */

        const endUserClass = "end-user";
        const boxCaptionClass = "box-caption";
        const arrowCaptionClass = "arrow-caption";
        const titleCaptionClass = "title-caption";
        const arrowClass = "arrow";

        /**
         * CSS classes of the HTML elements on the page.
         * @type {string}
         */
        let architectureLinkClass = "architecture-link";
        let noSelectClass = "noselect";

        let useFacingLink = $("#display-user-facing-components");
        let allComponentLink = $("#display-all-components");
        let selectedElementColor = "#8d28e0";
        let selectedCaptionColor = "#fafafa";

        const originColorAttr = "origin-color";
        const originFillAttr = "origin-fill";
        const originStrokeAttr = "origin-stroke";

        const colorProp = "color";
        const fillAttr = "fill";
        const opacityAttr = "opacity";
        const strokeAttr = "stroke";
        const fillOpacityAttr = "fill-opacity";
        const strokeOpacityAttr = "stroke-opacity";

        const divTag = "div";
        const rectTag = "rect";
        const pathTag = "path";

        function setupLookAndFeel() {

            // Back up the original fill color and color of elements to use in `mouseleave` later.
            let contents = $(".diagram-content").find("*");
            for (let index = 0; index < contents.length; index++) {
                const item = $(contents[index]);
                const elementName = item[0].nodeName.toLowerCase();
                if (divTag === elementName) {

                    if (item.hasClass(boxCaptionClass)
                        || item.hasClass(arrowCaptionClass)
                        || item.hasClass(titleCaptionClass)) {
                        item.attr(originColorAttr, item.css(colorProp));

                        // Make all DIVs non-selectable.
                        item.addClass(noSelectClass);
                    }
                }
                if (rectTag === elementName || pathTag === elementName) {
                    item.attr(originFillAttr, item.attr(fillAttr));
                    item.attr(originStrokeAttr, item.attr(strokeAttr))
                }
            }
        }

        /**
         * Changes opacity of the elements, not marked as "end-user".
         *
         * The opacity value is expected to be [0; 1] range.
         *
         * @param textOpacity the opacity to apply to text elements
         * @param elementOpacity the opacity to apply "rect" and "path" elements
         */
        function fade(textOpacity, elementOpacity) {
            let contents = $(".diagram-content").find("*");
            for (let index = 0; index < contents.length; index++) {
                const item = $(contents[index]);
                if (hasClass(item[0], endUserClass)) {
                    continue;
                }
                const elementName = item[0].nodeName.toLowerCase();

                if (divTag === elementName) {

                    if (item.hasClass(boxCaptionClass)
                        || item.hasClass(arrowCaptionClass)
                        || item.hasClass(titleCaptionClass)) {

                        item.css(opacityAttr, textOpacity);
                    }
                }
                if (rectTag === elementName) {
                    item.attr(fillOpacityAttr, elementOpacity);
                }
                if (pathTag === elementName) {
                    item.attr(fillOpacityAttr, elementOpacity);

                    item.attr(strokeOpacityAttr, elementOpacity);
                }
            }
        }

        /**
         * A custom implementation of `jQuery.hasClass()` suitable for SVG elements.
         *
         * In the jQuery 1.11.2 currently used, SVG elements are not supported
         * by `jQuery.hasClass()`.
         *
         * @param element an element wrapped in jQuery.
         * @param className a class name to detect
         * @return `true` if such a class name is declared for this element, `false` otherwise.
         */
        function hasClass(element, className) {
            for (let classIndex = 0; classIndex < element.classList.length; classIndex++) {
                if (className === element.classList[classIndex]) {
                    return true;
                }
            }
            return false;
        }

        /**
         * Adds a link behavior to an element.
         *
         * @param linkElement the jQuery object wrapping the DOM element
         * @param onClickCallback the callback to set upon 'click' event
         */
        function enableLink(linkElement, onClickCallback) {
            linkElement
                .addClass(architectureLinkClass)
                .click(function () {
                    onClickCallback()
                });
        }

        /**
         * Disables a link behaviour of an element.
         *
         * @param linkElement the jQuery object wrapping the DOM element
         */
        function disableLink(linkElement) {
            linkElement
                .removeClass(architectureLinkClass)
                .unbind("click");
        }

        function makeClickable(selector, url) {

            $(".g-caption" + selector)
                .css("cursor", "pointer")
                .attr("pointer-events", "all")
                .mouseover(function () {
                    let matched = $(selector);

                    for (let index = 0; index < matched.length; index++) {
                        const item = $(matched[index]);
                        const elementName = item[0].nodeName.toLowerCase();
                        if (divTag === elementName) {
                            item.css(colorProp, selectedCaptionColor);
                        }
                        if (rectTag === elementName || pathTag === elementName) {
                            item.attr(fillAttr, selectedElementColor);
                        }
                        if(hasClass(item[0], arrowClass)) {
                            item.attr(strokeAttr, selectedElementColor);
                        }
                    }
                })
                .mouseout(function () {
                    let matched = $(selector);
                    for (let index = 0; index < matched.length; index++) {
                        const item = $(matched[index]);
                        const elementName = item[0].nodeName.toLowerCase();
                        if (divTag === elementName) {
                            let originColorValue = item.attr(originColorAttr);
                            item.css(colorProp, originColorValue);
                        }
                        if (rectTag === elementName || pathTag === elementName) {
                            let originFillValue = item.attr(originFillAttr);
                            item.attr(fillAttr, originFillValue);
                        }

                        if(hasClass(item[0], arrowClass)) {
                            let originStrokeValue = item.attr(originStrokeAttr);
                            item.attr(strokeAttr, originStrokeValue);
                        }
                    }

                })
                .click(function () {
                    document.location.href = url;
                });

            $(".g-arrow" + selector)
                .css("cursor", "pointer")
                .attr("pointer-events", "all")
                .mouseover(function () {
                    let matched = $(selector);

                    for (let index = 0; index < matched.length; index++) {
                        const item = $(matched[index]);
                        const elementName = item[0].nodeName.toLowerCase();
                        if (divTag === elementName) {
                            item.css(colorProp, selectedElementColor);
                        }
                        if(hasClass(item[0], arrowClass)) {
                            item.attr(strokeAttr, selectedElementColor);
                        }
                    }
                })
                .mouseout(function () {
                    let matched = $(selector);
                    for (let index = 0; index < matched.length; index++) {
                        const item = $(matched[index]);
                        const elementName = item[0].nodeName.toLowerCase();
                        if (divTag === elementName) {
                            let originColorValue = item.attr(originColorAttr);
                            item.css(colorProp, originColorValue);
                        }
                        if(hasClass(item[0], arrowClass)) {
                            let originStrokeValue = item.attr(originStrokeAttr);
                            item.attr(strokeAttr, originStrokeValue);
                        }
                    }

                })
                .click(function () {
                    document.location.href = url;
                });

        }

        /**
         * Displays the user-facing components and fades out the rest.
         */
        function displayUserFacing() {
            fade("0.5", "0.3");
            enableLink(allComponentLink, displayAll);
            disableLink(useFacingLink);
        }

        /**
         * Displays all the Spine components and removes the fading.
         */
        function displayAll() {
            fade("1", "1");

            enableLink(useFacingLink, displayUserFacing);
            disableLink(allComponentLink);
        }

        setupLookAndFeel();
        displayAll();

        // Link items to the corresponding pages.

        // Boxes:
        makeClickable(".aggregate", "./aggregate.html");
        makeClickable(".bounded-context", "./bounded-context.html");
        makeClickable(".pm", "./process-manager.html");
        makeClickable(".projection", "./projection.html");
        makeClickable(".aggregate-repo", "./repository.html");
        makeClickable(".pm-repo", "./repository.html");
        makeClickable(".projection-repo", "./repository.html");
        makeClickable(".command-bus", "./command-bus.html");
        makeClickable(".event-bus", "./event-bus.html");
        makeClickable(".aggregate-mirror", "./aggregate-mirror.html");
        makeClickable(".command-store", "./command-store.html");
        makeClickable(".event-store", "./event-store.html");
        makeClickable(".command-service", "./command-service.html");
        makeClickable(".query-service", "./query-service.html");
        makeClickable(".subscription-service", "./subscription-service.html");
        makeClickable(".stand", "./stand.html");

        // Arrows:

        makeClickable(".ui-command-service", "./command.html");
        makeClickable(".command-service-ui", "./acknowledgement.html");
        makeClickable(".event-bus-aggregate-repo", "./event.html");
        makeClickable(".integration-events", "./integration-event.html");
    }
);
<commit_msg>Get rid of partially supported `foreignObject`s and embedded HTML and migrate to native SVG `text` tags.<commit_after>/**
 * This is a JavaScript file which backs the Spine architecture diagram.
 *
 * Please see `/docs/concepts/index.md` for usage.
 */

$(
    /**
     * This function is executed upon page load.
     *
     * Binds the handlers to the events in this HTML page.
     */
    function () {

        /**
         * CSS classes used as selectors to manipulate the elements of SVG diagram.
         */

        const endUserClass = "end-user";
        const boxCaptionClass = "box-caption";
        const arrowCaptionClass = "arrow-caption";
        const titleCaptionClass = "title-caption";
        const arrowClass = "arrow";

        /**
         * CSS classes of the HTML elements on the page.
         * @type {string}
         */
        let architectureLinkClass = "architecture-link";
        let noSelectClass = "noselect";

        let useFacingLink = $("#display-user-facing-components");
        let allComponentLink = $("#display-all-components");
        let selectedElementColor = "#8d28e0";
        let selectedCaptionColor = "#fafafa";

        const originColorAttr = "origin-color";
        const originFillAttr = "origin-fill";
        const originStrokeAttr = "origin-stroke";

        const colorProp = "color";
        const fillAttr = "fill";
        const opacityAttr = "opacity";
        const strokeAttr = "stroke";
        const fillOpacityAttr = "fill-opacity";
        const strokeOpacityAttr = "stroke-opacity";

        const textTag = "text";
        const rectTag = "rect";
        const pathTag = "path";

        function setupLookAndFeel() {

            // Back up the original fill color and color of elements to use in `mouseleave` later.
            let contents = $(".diagram-content").find("*");
            for (let index = 0; index < contents.length; index++) {
                const item = $(contents[index]);
                const elementName = item[0].nodeName.toLowerCase();
                if (textTag === elementName) {

                    if (hasClass(item, boxCaptionClass)
                        || hasClass(item, arrowCaptionClass)
                        || hasClass(item, titleCaptionClass)) {
                        item.attr(originFillAttr, item.attr(fillAttr));

                        // Make all TEXTs non-selectable.
                        item.addClass(noSelectClass);
                    }
                }
                if (rectTag === elementName || pathTag === elementName) {
                    item.attr(originFillAttr, item.attr(fillAttr));
                    item.attr(originStrokeAttr, item.attr(strokeAttr))
                }
            }
        }

        /**
         * Changes opacity of the elements, not marked as "end-user".
         *
         * The opacity value is expected to be [0; 1] range.
         *
         * @param textOpacity the opacity to apply to text elements
         * @param elementOpacity the opacity to apply "rect" and "path" elements
         */
        function fade(textOpacity, elementOpacity) {
            let contents = $(".diagram-content").find("*");
            for (let index = 0; index < contents.length; index++) {
                const item = $(contents[index]);
                if (hasClass(item, endUserClass)) {
                    continue;
                }
                const elementName = item[0].nodeName.toLowerCase();

                if (textTag === elementName) {

                    if (hasClass(item, boxCaptionClass)
                        || hasClass(item, arrowCaptionClass)
                        || hasClass(item, titleCaptionClass)) {

                        item.attr(fillOpacityAttr, elementOpacity);
                    }
                }
                if (rectTag === elementName) {
                    item.attr(fillOpacityAttr, elementOpacity);
                }
                if (pathTag === elementName) {
                    item.attr(fillOpacityAttr, elementOpacity);

                    item.attr(strokeOpacityAttr, elementOpacity);
                }
            }
        }

        /**
         * A custom implementation of `jQuery.hasClass()` suitable for SVG elements.
         *
         * In the jQuery 1.11.2 currently used, SVG elements are not supported
         * by `jQuery.hasClass()`.
         *
         * @param element an element wrapped in jQuery.
         * @param className a class name to detect
         * @return `true` if such a class name is declared for this element, `false` otherwise.
         */
        function hasClass(element, className) {
            const firstChild = element[0];
            for (let classIndex = 0; classIndex < firstChild.classList.length; classIndex++) {
                if (className === firstChild.classList[classIndex]) {
                    return true;
                }
            }
            return false;
        }

        /**
         * Adds a link behavior to an element.
         *
         * @param linkElement the jQuery object wrapping the DOM element
         * @param onClickCallback the callback to set upon 'click' event
         */
        function enableLink(linkElement, onClickCallback) {
            linkElement
                .addClass(architectureLinkClass)
                .click(function () {
                    onClickCallback()
                });
        }

        /**
         * Disables a link behaviour of an element.
         *
         * @param linkElement the jQuery object wrapping the DOM element
         */
        function disableLink(linkElement) {
            linkElement
                .removeClass(architectureLinkClass)
                .unbind("click");
        }

        function makeClickable(selector, url) {

            $(".g-caption" + selector)
                .css("cursor", "pointer")
                .attr("pointer-events", "all")
                .mouseover(function () {
                    let matched = $(selector);

                    for (let index = 0; index < matched.length; index++) {
                        const item = $(matched[index]);
                        const elementName = item[0].nodeName.toLowerCase();
                        if(textTag === elementName) {
                            item.attr(fillAttr, selectedCaptionColor);
                        }
                        if (rectTag === elementName || pathTag === elementName) {
                            item.attr(fillAttr, selectedElementColor);
                        }
                        if(hasClass(item, arrowClass)) {
                            item.attr(strokeAttr, selectedElementColor);
                        }
                    }
                })
                .mouseout(function () {
                    let matched = $(selector);
                    for (let index = 0; index < matched.length; index++) {
                        const item = $(matched[index]);
                        const elementName = item[0].nodeName.toLowerCase();
                        if (textTag === elementName
                            || rectTag === elementName
                            || pathTag === elementName) {
                            let originFillValue = item.attr(originFillAttr);
                            item.attr(fillAttr, originFillValue);
                        }

                        if(hasClass(item, arrowClass)) {
                            let originStrokeValue = item.attr(originStrokeAttr);
                            item.attr(strokeAttr, originStrokeValue);
                        }
                    }

                })
                .click(function () {
                    document.location.href = url;
                });

            $(".g-arrow" + selector)
                .css("cursor", "pointer")
                .attr("pointer-events", "all")
                .mouseover(function () {
                    let matched = $(selector);

                    for (let index = 0; index < matched.length; index++) {
                        const item = $(matched[index]);
                        const elementName = item[0].nodeName.toLowerCase();
                        if (textTag === elementName) {
                            item.attr(fillAttr, selectedElementColor);
                        }
                        if(hasClass(item, arrowClass)) {
                            item.attr(strokeAttr, selectedElementColor);
                        }
                    }
                })
                .mouseout(function () {
                    let matched = $(selector);
                    for (let index = 0; index < matched.length; index++) {
                        const item = $(matched[index]);
                        const elementName = item[0].nodeName.toLowerCase();
                        if (textTag === elementName) {
                            let originFillValue = item.attr(originFillAttr);
                            item.attr(fillAttr, originFillValue);
                        }
                        if(hasClass(item, arrowClass)) {
                            let originStrokeValue = item.attr(originStrokeAttr);
                            item.attr(strokeAttr, originStrokeValue);
                        }
                    }

                })
                .click(function () {
                    document.location.href = url;
                });

        }

        /**
         * Displays the user-facing components and fades out the rest.
         */
        function displayUserFacing() {
            fade("0.5", "0.3");
            enableLink(allComponentLink, displayAll);
            disableLink(useFacingLink);
        }

        /**
         * Displays all the Spine components and removes the fading.
         */
        function displayAll() {
            fade("1", "1");

            enableLink(useFacingLink, displayUserFacing);
            disableLink(allComponentLink);
        }

        setupLookAndFeel();
        displayAll();

        // Link items to the corresponding pages.

        // Boxes:
        makeClickable(".aggregate", "./aggregate.html");
        makeClickable(".bounded-context", "./bounded-context.html");
        makeClickable(".pm", "./process-manager.html");
        makeClickable(".projection", "./projection.html");
        makeClickable(".aggregate-repo", "./repository.html");
        makeClickable(".pm-repo", "./repository.html");
        makeClickable(".projection-repo", "./repository.html");
        makeClickable(".command-bus", "./command-bus.html");
        makeClickable(".event-bus", "./event-bus.html");
        makeClickable(".aggregate-mirror", "./aggregate-mirror.html");
        makeClickable(".command-store", "./command-store.html");
        makeClickable(".event-store", "./event-store.html");
        makeClickable(".command-service", "./command-service.html");
        makeClickable(".query-service", "./query-service.html");
        makeClickable(".subscription-service", "./subscription-service.html");
        makeClickable(".stand", "./stand.html");

        // Arrows:

        makeClickable(".ui-command-service", "./command.html");
        makeClickable(".command-service-ui", "./acknowledgement.html");
        makeClickable(".event-bus-aggregate-repo", "./event.html");
        makeClickable(".integration-events", "./integration-event.html");
    }
);
<|endoftext|>


<commit_before>const fs = require('fs-extra');
const fileExtension = require('file-extension');
var upload = {};
var options;

upload = function (req, res, next) {
	fs.move(req.files[options.filefield].path, options.uploadDir + filename(req.files[options.filefield]) + fileExtension(req.files[options.filefield].name)  , function (err) {
		if (err) return console.error(err)
		delete req.files[options.filefield].domain;
		delete req.files[options.filefield]._writeStream;
		delete req.files[options.filefield]._events;
		delete req.files[options.filefield]._eventsCount;
		delete req.files[options.filefield]._maxListeners;
		req.files[options.filefield].path = options.uploadDir + filename(req.files[options.filefield]);
		next();
	})
}

upload.options = function (data) {
	options = data;
}

function filename(options){
	if (options.filename = 'random') {
		return Math.random().toString(36).substring(7);
	} else {
		Math.random().toString(36).substring(7);
	}
}
module.exports = upload;<commit_msg>patching<commit_after>const fs = require('fs-extra');
const fileExtension = require('file-extension');
var upload = {};
var options;

upload = function (req, res, next) {
	fs.move(req.files[options.filefield].path, options.uploadDir + filename(req.files[options.filefield]) + '.' + fileExtension(req.files[options.filefield].name)  , function (err) {
		if (err) return console.error(err)
		delete req.files[options.filefield].domain;
		delete req.files[options.filefield]._writeStream;
		delete req.files[options.filefield]._events;
		delete req.files[options.filefield]._eventsCount;
		delete req.files[options.filefield]._maxListeners;
		req.files[options.filefield].path = options.uploadDir + filename(req.files[options.filefield]);
		next();
	})
}

upload.options = function (data) {
	options = data;
}

function filename(options){
	if (options.filename = 'random') {
		return Math.random().toString(36).substring(7);
	} else {
		Math.random().toString(36).substring(7);
	}
}
module.exports = upload;<|endoftext|>


<commit_before>function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    gvm.projectId = $("#projectHeader").data('value');

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.menuLanguage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("MenuLanguage");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.getProjectInfo = function() {
        $.getJSON('/api/project/' + gvm.projectId, function(data) {
            gvm.pageHeader(data[0].code + ' - ' + data[0].name);
        });
    };

    gvm.getAllData = function() {
         $.getJSON('/api/project/getAllData/' + gvm.projectId, function(data) {
            console.log(data);
         });
    };

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    };

    gvm.clearStructure = function() {
        gvm.competences.destroyAll();
    };
}

function initPage() {
    fetchProjectStructure();
    viewModel.getProjectInfo();

    $(".savePageBtn").click(function(){
        saveProjectScore();
    });
}

function fetchProjectScore()
{
    $.getJSON("/api/projectscore/" + projectid + "/" + studentid, function(data)
    {
        $.each(viewModel.competences(), function(i,item){
                    $.each(item.subcompetences(), function(i, subcomp)
                    {
                        $.each(subcomp.indicators(),function(i,indic)
                        {
                            for(var i = 0; i < data.length; i++) {
                                console.log(data[i].indicator);
                            if (indic.id() == data[i].indicator) {
                                indic.score(data[i].score);
                                indic.scoreid(data[i].id);
                            }
                    }
                });
            });
        });
        console.log(viewModel.competences()[1].subcompetences()[0].indicators()[4].scoreid());

    });
}

function saveProjectScore()
{
    //console.log(viewModel.competences()[1].subcompetences()[0].indicators()[4].scoreid());
    //console.log(viewModel.competences()[0].subcompetences()[0].indicators()[0].score());
    $.ajax({
        type: "POST",
        url: "/api/projectscore/" + projectid + "/" + studentid,
        data: ko.toJSON(viewModel.competences),
        success: function(data){
            // TODO make multilangual and with modals
            alert("Saved projectscore to server");
            console.log(data);
            //window.location = "/assess/project/" + projectid + "/students";
        }
    });
}

function fetchProjectStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            var competence = viewModel.updateCompetence(item.id, item.code, item.description);

            $.each(item.subcompetences, function(i, subcomp){
                var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description);
                competence.subcompetences.push(subcompetence);

                $.each(subcomp.indicators, function(i, indic){
                    subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.description, 0,indic.id, indic.pointType));
                });
            });
        });
        fetchProjectScore();
    });
}

function Competence(viewmodel, id, code, name, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        subcompetences: ko.observableArray(subcompetences)
    };
}

function SubCompetence(parent, id, code, name, indicators) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        indicators: ko.observableArray(indicators)
    };
}

function Indicator(parent, id, name, description, score, scoreid,pointType, checked) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        description: ko.observable(description),
        score: ko.observable(score),
        scoreid: ko.observable(scoreid || 0),
        pointType: ko.observable(pointType),
        checked : ko.observable(checked)
    };
}<commit_msg>Fixing save grades<commit_after>function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    gvm.projectId = $("#projectHeader").data('value');

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.menuLanguage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("MenuLanguage");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.getProjectInfo = function() {
        $.getJSON('/api/project/' + gvm.projectId, function(data) {
            gvm.pageHeader(data[0].code + ' - ' + data[0].name);
        });
    };

    gvm.getAllData = function() {
         $.getJSON('/api/project/getAllData/' + gvm.projectId, function(data) {
            console.log(data);
         });
    };

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    };

    gvm.clearStructure = function() {
        gvm.competences.destroyAll();
    };
}

function initPage() {
    fetchProjectStructure();
    viewModel.getProjectInfo();

    $(".savePageBtn").click(function(){
        saveProjectScore();
    });
}

function fetchProjectScore()
{
    $.getJSON("/api/projectscore/" + projectid + "/" + studentid, function(data)
    {
        $.each(viewModel.competences(), function(i,item){
                    $.each(item.subcompetences(), function(i, subcomp)
                    {
                        $.each(subcomp.indicators(),function(i,indic)
                        {
                            for(var i = 0; i < data.length; i++) {
                                if (indic.id() == data[i].indicator) {
                                    indic.score(data[i].score);
                                    indic.scoreid(data[i].id);
                                }
                            }
                        });
                    });
        });
    });
}

function saveProjectScore()
{
    //console.log(viewModel.competences()[1].subcompetences()[0].indicators()[4].scoreid());
    //console.log(viewModel.competences()[0].subcompetences()[0].indicators()[0].score());
    $.ajax({
        type: "POST",
        url: "/api/projectscore/" + projectid + "/" + studentid,
        data: ko.toJSON(viewModel.competences),
        success: function(data){
            // TODO make multilangual and with modals
            alert("Saved projectscore to server");
            console.log(data);
            //window.location = "/assess/project/" + projectid + "/students";
        }
    });
}

function fetchProjectStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            var competence = viewModel.updateCompetence(item.id, item.code, item.description);

            $.each(item.subcompetences, function(i, subcomp){
                var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description);
                competence.subcompetences.push(subcompetence);

                $.each(subcomp.indicators, function(i, indic){
                    subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.description, 0,0, indic.pointType));
                });
            });
        });
        fetchProjectScore();
    });
}

function Competence(viewmodel, id, code, name, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        subcompetences: ko.observableArray(subcompetences)
    };
}

function SubCompetence(parent, id, code, name, indicators) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        indicators: ko.observableArray(indicators)
    };
}

function Indicator(parent, id, name, description, score, scoreid,pointType, checked) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        description: ko.observable(description),
        score: ko.observable(score),
        scoreid: ko.observable(scoreid),
        pointType: ko.observable(pointType),
        checked : ko.observable(checked)
    };
}<|endoftext|>


<commit_before>'use strict';

module.exports.$modules = {

  $config: (function () {

    var getConfig = function getConfig($root, $module, $done, $$path, $$confit) {
      var container = this;
      if (container.$config$error) {
        $done(container.$config$error);
      } else if (!container.$config) {
        container.get('$configDirectory', function (err, configDirectory) {
          if (err) {
            configDirectory = 'config';
          }
          if (configDirectory[0] !== '/') {
            configDirectory = $$path.join($root, configDirectory);
          }
          $$confit(configDirectory).create(function (err, configuration) {
            if (err) {
              container.$config$error = err;
            } else {
              container.$config = configuration;
            }
            getConfig.call(container, $root, $module, $done, $$path, $$confit);
          });
        });
      } else {
        $done(null, $module ? container.$config.get($module) : container.$config);
      }
    };

    return getConfig;
  }())
};<commit_msg>added $$confit dependency<commit_after>/* vim: set et sw=2 ts=2: */
'use strict';

module.exports.$modules = {

  $$confit: function () {
    return require('confit');
  },

  $config: (function () {

    var getConfig = function getConfig($root, $module, $done, $$path, $$confit) {
      var container = this;
      if (container.$config$error) {
        $done(container.$config$error);
      } else if (!container.$config) {
        container.get('$configDirectory', function (err, configDirectory) {
          if (err) {
            configDirectory = 'config';
          }
          if (configDirectory[0] !== '/') {
            configDirectory = $$path.join($root, configDirectory);
          }
          $$confit(configDirectory).create(function (err, configuration) {
            if (err) {
              container.$config$error = err;
            } else {
              container.$config = configuration;
            }
            getConfig.call(container, $root, $module, $done, $$path, $$confit);
          });
        });
      } else {
        $done(null, $module ? container.$config.get($module) : container.$config);
      }
    };

    return getConfig;
  }())
};
<|endoftext|>


<commit_before>'use strict'
const EventEmitter = require('events').EventEmitter

const NOOP = function () { }

const removeWhere = (list, predicate) => {
  const i = list.findIndex(predicate)

  return i === -1
    ? undefined
    : list.splice(i, 1)[0]
}

class IdleItem {
  constructor (client, timeoutId) {
    this.client = client
    this.timeoutId = timeoutId
  }
}

class PendingItem {
  constructor (callback) {
    this.callback = callback
  }
}

function throwOnRelease () {
  throw new Error('Release called on client which has already been released to the pool.')
}

function release (client, err) {
  client.release = throwOnRelease
  if (err || this.ending) {
    this._remove(client)
    this._pulseQueue()
    return
  }

  // idle timeout
  let tid
  if (this.options.idleTimeoutMillis) {
    tid = setTimeout(() => {
      this.log('remove idle client')
      this._remove(client)
    }, this.options.idleTimeoutMillis)
  }

  this._idle.push(new IdleItem(client, tid))
  this._pulseQueue()
}

function promisify (Promise, callback) {
  if (callback) {
    return { callback: callback, result: undefined }
  }
  let rej
  let res
  const cb = function (err, client) {
    err ? rej(err) : res(client)
  }
  const result = new Promise(function (resolve, reject) {
    res = resolve
    rej = reject
  })
  return { callback: cb, result: result }
}

class Pool extends EventEmitter {
  constructor (options, Client) {
    super()
    this.options = Object.assign({}, options)
    this.options.max = this.options.max || this.options.poolSize || 10
    this.log = this.options.log || function () { }
    this.Client = this.options.Client || Client || require('pg').Client
    this.Promise = this.options.Promise || global.Promise

    if (typeof this.options.idleTimeoutMillis === 'undefined') {
      this.options.idleTimeoutMillis = 10000
    }

    this._clients = []
    this._idle = []
    this._pendingQueue = []
    this._endCallback = undefined
    this.ending = false
    this.ended = false
  }

  _isFull () {
    return this._clients.length >= this.options.max
  }

  _pulseQueue () {
    this.log('pulse queue')
    if (this.ended) {
      this.log('pulse queue ended')
      return
    }
    if (this.ending) {
      this.log('pulse queue on ending')
      if (this._idle.length) {
        this._idle.slice().map(item => {
          this._remove(item.client)
        })
      }
      if (!this._clients.length) {
        this.ended = true
        this._endCallback()
      }
      return
    }
    // if we don't have any waiting, do nothing
    if (!this._pendingQueue.length) {
      this.log('no queued requests')
      return
    }
    // if we don't have any idle clients and we have no more room do nothing
    if (!this._idle.length && this._isFull()) {
      return
    }
    const waiter = this._pendingQueue.shift()
    if (this._idle.length) {
      const idleItem = this._idle.pop()
      clearTimeout(idleItem.timeoutId)
      const client = idleItem.client
      client.release = release.bind(this, client)
      this.emit('acquire', client)
      return waiter.callback(undefined, client, client.release)
    }
    if (!this._isFull()) {
      return this.newClient(waiter)
    }
    throw new Error('unexpected condition')
  }

  _remove (client) {
    const removed = removeWhere(
      this._idle,
      item => item.client === client
    )

    if (removed !== undefined) {
      clearTimeout(removed.timeoutId)
    }

    this._clients = this._clients.filter(c => c !== client)
    client.end()
    this.emit('remove', client)
  }

  connect (cb) {
    if (this.ending) {
      const err = new Error('Cannot use a pool after calling end on the pool')
      return cb ? cb(err) : this.Promise.reject(err)
    }

    const response = promisify(this.Promise, cb)
    const result = response.result

    // if we don't have to connect a new client, don't do so
    if (this._clients.length >= this.options.max || this._idle.length) {
      // if we have idle clients schedule a pulse immediately
      if (this._idle.length) {
        process.nextTick(() => this._pulseQueue())
      }

      if (!this.options.connectionTimeoutMillis) {
        this._pendingQueue.push(new PendingItem(response.callback))
        return result
      }

      const queueCallback = (err, res, done) => {
        clearTimeout(tid)
        response.callback(err, res, done)
      }

      const pendingItem = new PendingItem(queueCallback)

      // set connection timeout on checking out an existing client
      const tid = setTimeout(() => {
        // remove the callback from pending waiters because
        // we're going to call it with a timeout error
        removeWhere(this._pendingQueue, (i) => i.callback === queueCallback)
        pendingItem.timedOut = true
        response.callback(new Error('timeout exceeded when trying to connect'))
      }, this.options.connectionTimeoutMillis)

      this._pendingQueue.push(pendingItem)
      return result
    }

    this.newClient(new PendingItem(response.callback))

    return result
  }

  newClient (pendingItem) {
    const client = new this.Client(this.options)
    this._clients.push(client)
    const idleListener = (err) => {
      err.client = client
      client.removeListener('error', idleListener)
      client.on('error', () => {
        this.log('additional client error after disconnection due to error', err)
      })
      this._remove(client)
      // TODO - document that once the pool emits an error
      // the client has already been closed & purged and is unusable
      this.emit('error', err, client)
    }

    this.log('checking client timeout')

    // connection timeout logic
    let tid
    let timeoutHit = false
    if (this.options.connectionTimeoutMillis) {
      tid = setTimeout(() => {
        this.log('ending client due to timeout')
        timeoutHit = true
        // force kill the node driver, and let libpq do its teardown
        client.connection ? client.connection.stream.destroy() : client.end()
      }, this.options.connectionTimeoutMillis)
    }

    this.log('connecting new client')
    client.connect((err) => {
      if (tid) {
        clearTimeout(tid)
      }
      client.on('error', idleListener)
      if (err) {
        this.log('client failed to connect', err)
        // remove the dead client from our list of clients
        this._clients = this._clients.filter(c => c !== client)
        if (timeoutHit) {
          err.message = 'Connection terminated due to connection timeout'
        }

        // this client won’t be released, so move on immediately
        this._pulseQueue()

        if (!pendingItem.timedOut) {
          pendingItem.callback(err, undefined, NOOP)
        }
      } else {
        this.log('new client connected')
        client.release = release.bind(this, client)
        this.emit('connect', client)
        this.emit('acquire', client)
        if (!pendingItem.timedOut) {
          if (this.options.verify) {
            this.options.verify(client, pendingItem.callback)
          } else {
            pendingItem.callback(undefined, client, client.release)
          }
        } else {
          if (this.options.verify) {
            this.options.verify(client, client.release)
          } else {
            client.release()
          }
        }
      }
    })
  }

  query (text, values, cb) {
    // guard clause against passing a function as the first parameter
    if (typeof text === 'function') {
      const response = promisify(this.Promise, text)
      setImmediate(function () {
        return response.callback(new Error('Passing a function as the first parameter to pool.query is not supported'))
      })
      return response.result
    }

    // allow plain text query without values
    if (typeof values === 'function') {
      cb = values
      values = undefined
    }
    const response = promisify(this.Promise, cb)
    cb = response.callback
    this.connect((err, client) => {
      if (err) {
        return cb(err)
      }
      this.log('dispatching query')
      client.query(text, values, (err, res) => {
        this.log('query dispatched')
        client.release(err)
        if (err) {
          return cb(err)
        } else {
          return cb(undefined, res)
        }
      })
    })
    return response.result
  }

  end (cb) {
    this.log('ending')
    if (this.ending) {
      const err = new Error('Called end on pool more than once')
      return cb ? cb(err) : this.Promise.reject(err)
    }
    this.ending = true
    const promised = promisify(this.Promise, cb)
    this._endCallback = promised.callback
    this._pulseQueue()
    return promised.result
  }

  get waitingCount () {
    return this._pendingQueue.length
  }

  get idleCount () {
    return this._idle.length
  }

  get totalCount () {
    return this._clients.length
  }
}
module.exports = Pool
<commit_msg>idleListener no longer grabs references to things it doesn't need (#83)<commit_after>'use strict'
const EventEmitter = require('events').EventEmitter

const NOOP = function () { }

const removeWhere = (list, predicate) => {
  const i = list.findIndex(predicate)

  return i === -1
    ? undefined
    : list.splice(i, 1)[0]
}

class IdleItem {
  constructor (client, timeoutId) {
    this.client = client
    this.timeoutId = timeoutId
  }
}

class PendingItem {
  constructor (callback) {
    this.callback = callback
  }
}

function throwOnRelease () {
  throw new Error('Release called on client which has already been released to the pool.')
}

function release (client, err) {
  client.release = throwOnRelease
  if (err || this.ending) {
    this._remove(client)
    this._pulseQueue()
    return
  }

  // idle timeout
  let tid
  if (this.options.idleTimeoutMillis) {
    tid = setTimeout(() => {
      this.log('remove idle client')
      this._remove(client)
    }, this.options.idleTimeoutMillis)
  }

  this._idle.push(new IdleItem(client, tid))
  this._pulseQueue()
}

function promisify (Promise, callback) {
  if (callback) {
    return { callback: callback, result: undefined }
  }
  let rej
  let res
  const cb = function (err, client) {
    err ? rej(err) : res(client)
  }
  const result = new Promise(function (resolve, reject) {
    res = resolve
    rej = reject
  })
  return { callback: cb, result: result }
}

function makeIdleListener (pool, client) {
  return function idleListener (err) {
    err.client = client
    client.removeListener('error', idleListener)
    client.on('error', () => {
      pool.log('additional client error after disconnection due to error', err)
    })
    pool._remove(client)
    // TODO - document that once the pool emits an error
    // the client has already been closed & purged and is unusable
    pool.emit('error', err, client)
  }
}

class Pool extends EventEmitter {
  constructor (options, Client) {
    super()
    this.options = Object.assign({}, options)
    this.options.max = this.options.max || this.options.poolSize || 10
    this.log = this.options.log || function () { }
    this.Client = this.options.Client || Client || require('pg').Client
    this.Promise = this.options.Promise || global.Promise

    if (typeof this.options.idleTimeoutMillis === 'undefined') {
      this.options.idleTimeoutMillis = 10000
    }

    this._clients = []
    this._idle = []
    this._pendingQueue = []
    this._endCallback = undefined
    this.ending = false
    this.ended = false
  }

  _isFull () {
    return this._clients.length >= this.options.max
  }

  _pulseQueue () {
    this.log('pulse queue')
    if (this.ended) {
      this.log('pulse queue ended')
      return
    }
    if (this.ending) {
      this.log('pulse queue on ending')
      if (this._idle.length) {
        this._idle.slice().map(item => {
          this._remove(item.client)
        })
      }
      if (!this._clients.length) {
        this.ended = true
        this._endCallback()
      }
      return
    }
    // if we don't have any waiting, do nothing
    if (!this._pendingQueue.length) {
      this.log('no queued requests')
      return
    }
    // if we don't have any idle clients and we have no more room do nothing
    if (!this._idle.length && this._isFull()) {
      return
    }
    const waiter = this._pendingQueue.shift()
    if (this._idle.length) {
      const idleItem = this._idle.pop()
      clearTimeout(idleItem.timeoutId)
      const client = idleItem.client
      client.release = release.bind(this, client)
      this.emit('acquire', client)
      return waiter.callback(undefined, client, client.release)
    }
    if (!this._isFull()) {
      return this.newClient(waiter)
    }
    throw new Error('unexpected condition')
  }

  _remove (client) {
    const removed = removeWhere(
      this._idle,
      item => item.client === client
    )

    if (removed !== undefined) {
      clearTimeout(removed.timeoutId)
    }

    this._clients = this._clients.filter(c => c !== client)
    client.end()
    this.emit('remove', client)
  }

  connect (cb) {
    if (this.ending) {
      const err = new Error('Cannot use a pool after calling end on the pool')
      return cb ? cb(err) : this.Promise.reject(err)
    }

    const response = promisify(this.Promise, cb)
    const result = response.result

    // if we don't have to connect a new client, don't do so
    if (this._clients.length >= this.options.max || this._idle.length) {
      // if we have idle clients schedule a pulse immediately
      if (this._idle.length) {
        process.nextTick(() => this._pulseQueue())
      }

      if (!this.options.connectionTimeoutMillis) {
        this._pendingQueue.push(new PendingItem(response.callback))
        return result
      }

      const queueCallback = (err, res, done) => {
        clearTimeout(tid)
        response.callback(err, res, done)
      }

      const pendingItem = new PendingItem(queueCallback)

      // set connection timeout on checking out an existing client
      const tid = setTimeout(() => {
        // remove the callback from pending waiters because
        // we're going to call it with a timeout error
        removeWhere(this._pendingQueue, (i) => i.callback === queueCallback)
        pendingItem.timedOut = true
        response.callback(new Error('timeout exceeded when trying to connect'))
      }, this.options.connectionTimeoutMillis)

      this._pendingQueue.push(pendingItem)
      return result
    }

    this.newClient(new PendingItem(response.callback))

    return result
  }

  newClient (pendingItem) {
    const client = new this.Client(this.options)
    this._clients.push(client)
    const idleListener = makeIdleListener(this, client)

    this.log('checking client timeout')

    // connection timeout logic
    let tid
    let timeoutHit = false
    if (this.options.connectionTimeoutMillis) {
      tid = setTimeout(() => {
        this.log('ending client due to timeout')
        timeoutHit = true
        // force kill the node driver, and let libpq do its teardown
        client.connection ? client.connection.stream.destroy() : client.end()
      }, this.options.connectionTimeoutMillis)
    }

    this.log('connecting new client')
    client.connect((err) => {
      if (tid) {
        clearTimeout(tid)
      }
      client.on('error', idleListener)
      if (err) {
        this.log('client failed to connect', err)
        // remove the dead client from our list of clients
        this._clients = this._clients.filter(c => c !== client)
        if (timeoutHit) {
          err.message = 'Connection terminated due to connection timeout'
        }

        // this client won’t be released, so move on immediately
        this._pulseQueue()

        if (!pendingItem.timedOut) {
          pendingItem.callback(err, undefined, NOOP)
        }
      } else {
        this.log('new client connected')
        client.release = release.bind(this, client)
        this.emit('connect', client)
        this.emit('acquire', client)
        if (!pendingItem.timedOut) {
          if (this.options.verify) {
            this.options.verify(client, pendingItem.callback)
          } else {
            pendingItem.callback(undefined, client, client.release)
          }
        } else {
          if (this.options.verify) {
            this.options.verify(client, client.release)
          } else {
            client.release()
          }
        }
      }
    })
  }

  query (text, values, cb) {
    // guard clause against passing a function as the first parameter
    if (typeof text === 'function') {
      const response = promisify(this.Promise, text)
      setImmediate(function () {
        return response.callback(new Error('Passing a function as the first parameter to pool.query is not supported'))
      })
      return response.result
    }

    // allow plain text query without values
    if (typeof values === 'function') {
      cb = values
      values = undefined
    }
    const response = promisify(this.Promise, cb)
    cb = response.callback
    this.connect((err, client) => {
      if (err) {
        return cb(err)
      }
      this.log('dispatching query')
      client.query(text, values, (err, res) => {
        this.log('query dispatched')
        client.release(err)
        if (err) {
          return cb(err)
        } else {
          return cb(undefined, res)
        }
      })
    })
    return response.result
  }

  end (cb) {
    this.log('ending')
    if (this.ending) {
      const err = new Error('Called end on pool more than once')
      return cb ? cb(err) : this.Promise.reject(err)
    }
    this.ending = true
    const promised = promisify(this.Promise, cb)
    this._endCallback = promised.callback
    this._pulseQueue()
    return promised.result
  }

  get waitingCount () {
    return this._pendingQueue.length
  }

  get idleCount () {
    return this._idle.length
  }

  get totalCount () {
    return this._clients.length
  }
}
module.exports = Pool
<|endoftext|>