<commit_before>/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# SETUP THE APP on HEROKU:
  Create a Slack app. Make sure to configure the bot user!
    -> https://api.slack.com/applications/new
    -> Add the Redirect URI: https://${APP_NAME}.herokuapp.com/oauth
  Deply and run your app on Heroku.
    -> Add Config Vars on the Heroku app setting page: clientId, clientSecret
    -> Deploy and run on Heroku.
  Set RequestURL on Slack.
    -> Add the RequesteURL of Interactive Message: https://${APP_NAME}.herokuapp.com/slack/receive
# USE THE APP
  Add the app to your Slack by visiting the login page:
    -> https://${APP_NAME}.herokuapp.com/login
  After you've added the app, try talking to your bot!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

var Botkit = require('botkit');
var MongoUrl = process.env.MONGODB_URI || 'mongodb://localhost:27017/zangyo-bot';

if (!process.env.clientId || !process.env.clientSecret || !process.env.port) {
  console.log('Error: Specify clientId clientSecret and port in environment');
  process.exit(1);
}

var controller = Botkit.slackbot({
  // interactive_replies: true, // tells botkit to send button clicks into conversations
  storage: require('botkit-storage-mongo')({mongoUri: MongoUrl})
}).configureSlackApp(
  {
    clientId: process.env.clientId,
    clientSecret: process.env.clientSecret,
    scopes: ['bot'],
  }
);

controller.setupWebserver(process.env.port,function(err,webserver) {
  controller.createWebhookEndpoints(controller.webserver);

  controller.createOauthEndpoints(controller.webserver,function(err,req,res) {
    if (err) {
      res.status(500).send('ERROR: ' + err);
    } else {
      res.send('Success!');
    }
  });
});

// just a simple way to make sure we don't
// connect to the RTM twice for the same team
var _bots = {};
function trackBot(bot) {
  _bots[bot.config.token] = bot;
}

controller.on('create_bot',function(bot,config) {

  if (_bots[bot.config.token]) {
    // already online! do nothing.
  } else {
    bot.startRTM(function(err) {

      if (!err) {
        trackBot(bot);
      }

      bot.startPrivateConversation({user: config.createdBy},function(err,convo) {
        if (err) {
          console.log(err);
        } else {
          convo.say('I am a bot that has just joined your team');
          convo.say('You must now /invite me to a channel so that I can be of use!');
        }
      });

    });
  }

});

// Handle events related to the websocket connection to Slack
controller.on('rtm_open',function(bot) {
  console.log('** The RTM api just connected!');
});

controller.on('rtm_close',function(bot) {
  console.log('** The RTM api just closed');
  // you may want to attempt to re-open
});

controller.hears('button', ['direct_message'],function(bot,message) {
  var reply = {
    "text": "ボタンのテストです。",
    "attachments": [{
      "text": "どれか押してください。",
      "fallback": "失敗しました。",
      "callback_id": "test_button",
      "color": "#808080",
      "actions": [
        {
          "type": "button",
          "name": "test_button1",
          "text": "テストボタン1"
        },
        {
          "type": "button",
          "name": "test_button2",
          "text": "テストボタン2"
        }
      ]
    }]
  };
  bot.reply(message, reply);
});

controller.hears('^.*残業.*申請.*',['direct_message'],function(bot,message) {
  bot.startConversation(message, askApprover);
});

askApprover = function(response, convo) {
  convo.ask("プロマネは誰？ [@xxx]", function(response, convo) {
    if (!response.text.match(/^<@[a-zA-Z0-9]*>$/)) {
      convo.say('@xxx の形式でユーザーを１人指定してね。');
      askApprover(response, convo);
      convo.next();
    } else {
      var zangyo = {}
      zangyo.id = uuid();
      zangyo.applicant = response.user;
      zangyo.approver = response.text.slice(2, -1);
      askEndTime(response, convo, zangyo);
      convo.next();
    }
  });
}
askEndTime = function(response, convo, zangyo) {
  convo.ask("何時に終わる？ [HH:MM]", function(response, convo) {
    if (!response.text.match(/^([0-2]?[0-9]):([0-5]?[0-9])$/)) {
      convo.say('HH:MM の形式で時間を指定してね。29:59まで指定できるよ。');
      askEndTime(response, convo, zangyo);
      convo.next();
    } else {
      zangyo.endTime = response.text;
      askReason(response, convo, zangyo);
      convo.next();
    }
  });
}
askReason = function(response, convo, zangyo) {
  convo.ask("残業する理由は？", function(response, convo) {
    zangyo.reason = response.text;
    var summary = {
      "text": "この内容で残業申請しますか？",
      "attachments": [
        {
          "text": "申請内容まとめ",
          "fallback": "申請内容のまとめ",
          "callback_id": "apply-" + response.user + '-' + zangyo.id,
          "color": "#36a64f",
          "fields": [
            {
              "title": "申請者",
              "value": "<@" + zangyo.applicant + ">",
              "short": false
            },
            {
              "title": "承認者",
              "value": "<@" + zangyo.approver + ">",
              "short": false
            },
            {
              "title": "終了時間",
              "value": zangyo.endTime,
              "short": false
            },
            {
              "title": "残業する理由",
              "value": zangyo.reason,
              "short": false
            }
          ],
          "actions": [
            {
              "type": "button",
              "name": "apply",
              "text": "申請"
            },
            {
              "type": "button",
              "name": "redo",
              "text": "やり直し"
            },
            {
              "type": "button",
              "name": "cancel",
              "text": "キャンセル"
            }
          ]
        }
      ]
    }
    controller.storage.users.get(response.user, function(err, user) {
        if (!user) {
          user = {
            id: response.user,
            zangyos: []
          }
        } else if (!user.zangyos) {
          user.zangyos = [];
        }

        user.zangyos.push(zangyo);
        controller.storage.users.save(user);
    });
    convo.say(summary);
    convo.next();
  });
}

controller.on('interactive_message_callback', function(bot, message) {
  var ids = message.callback_id.split(/\-/);
  var action = ids[0];
  var user_id = ids[1];
  var item_id = ids[2];

  if (action == 'apply') {
    var ans = message.actions[0].name;
    controller.storage.users.get(user_id, function(err, user) {
      for (var x = 0; x < user.zangyos.length; x++) {
        if (user.zangyos[x].id == item_id) {
          if (ans == 'apply') {
            var zangyo = user.zangyos[x];
            var summary = {
              "attachments": [
                {
                  "text": "申請内容まとめ",
                  "fallback": "申請内容のまとめ",
                  "color": "#36a64f",
                  "fields": [
                    {
                      "title": "申請者",
                      "value": "<@" + zangyo.applicant + ">",
                      "short": false
                    },
                    {
                      "title": "承認者",
                      "value": "<@" + zangyo.approver + ">",
                      "short": false
                    },
                    {
                      "title": "終了時間",
                      "value": zangyo.endTime,
                      "short": false
                    },
                    {
                      "title": "残業する理由",
                      "value": zangyo.reason,
                      "short": false
                    }
                  ]
                }
              ]
            }
            bot.replyInteractive(message, summary);
            bot.reply(message, "この内容で残業申請したよ。");
            bot.startPrivateConversation({user: zangyo.approver}, function(err,convo) {
              if (err) {
                console.log(err);
              } else {
                var application = {
                  "text": "残業申請があります。承認しますか？",
                  "attachments": [
                    {
                      "text": "申請内容まとめ",
                      "fallback": "申請内容のまとめ",
                      "callback_id": "approve-" + zangyo.applicant + '-' + zangyo.id,
                      "color": "#36a64f",
                      "fields": [
                        {
                          "title": "申請者",
                          "value": "<@" + zangyo.applicant + ">",
                          "short": false
                        },
                        {
                          "title": "承認者",
                          "value": "<@" + zangyo.approver + ">",
                          "short": false
                        },
                        {
                          "title": "終了時間",
                          "value": zangyo.endTime,
                          "short": false
                        },
                        {
                          "title": "残業する理由",
                          "value": zangyo.reason,
                          "short": false
                        }
                      ],
                      "actions": [
                        {
                          "type": "button",
                          "name": "approve",
                          "text": "承認"
                        },
                        {
                          "type": "button",
                          "name": "reject",
                          "text": "却下"
                        }
                      ]
                    }
                  ]
                }
                convo.say(application);
                convo.next();
              }
            });
          } else if (ans == 'redo') {
            user.zangyos.splice(x, 1);
            bot.replyInteractive(message, "最初からやり直し！");
            bot.startConversation(message, askApprover);
          } else {
            user.zangyos.splice(x, 1);
            bot.replyInteractive(message, "キャンセルしたよ。さっさと帰ろう！");
          }
          controller.storage.users.save(user);
          break;
        }
      }
    });
  } else if (message.callback_id == "test_button") {
    var users_answer = message.actions[0].name;
    bot.replyInteractive(message, "あなたは「" + users_answer + "」を押しました");
  }
});

controller.storage.teams.all(function(err,teams) {

  if (err) {
    throw new Error(err);
  }

  // connect all teams with bots up to slack!
  for (var t  in teams) {
    if (teams[t].bot) {
      controller.spawn(teams[t]).startRTM(function(err, bot) {
        if (err) {
          console.log('Error connecting bot to Slack:',err);
        } else {
          trackBot(bot);
        }
      });
    }
  }
});

function uuid() {
  var uuid = "", i, random;
  for (i = 0; i < 32; i++) {
    random = Math.random() * 16 | 0;
    uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16);
  }
  return uuid;
};
<commit_msg>approve approve approve<commit_after>/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# SETUP THE APP on HEROKU:
  Create a Slack app. Make sure to configure the bot user!
    -> https://api.slack.com/applications/new
    -> Add the Redirect URI: https://${APP_NAME}.herokuapp.com/oauth
  Deply and run your app on Heroku.
    -> Add Config Vars on the Heroku app setting page: clientId, clientSecret
    -> Deploy and run on Heroku.
  Set RequestURL on Slack.
    -> Add the RequesteURL of Interactive Message: https://${APP_NAME}.herokuapp.com/slack/receive
# USE THE APP
  Add the app to your Slack by visiting the login page:
    -> https://${APP_NAME}.herokuapp.com/login
  After you've added the app, try talking to your bot!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

var Botkit = require('botkit');
var MongoUrl = process.env.MONGODB_URI || 'mongodb://localhost:27017/zangyo-bot';

if (!process.env.clientId || !process.env.clientSecret || !process.env.port) {
  console.log('Error: Specify clientId clientSecret and port in environment');
  process.exit(1);
}

var controller = Botkit.slackbot({
  // interactive_replies: true, // tells botkit to send button clicks into conversations
  storage: require('botkit-storage-mongo')({mongoUri: MongoUrl})
}).configureSlackApp(
  {
    clientId: process.env.clientId,
    clientSecret: process.env.clientSecret,
    scopes: ['bot'],
  }
);

controller.setupWebserver(process.env.port,function(err,webserver) {
  controller.createWebhookEndpoints(controller.webserver);

  controller.createOauthEndpoints(controller.webserver,function(err,req,res) {
    if (err) {
      res.status(500).send('ERROR: ' + err);
    } else {
      res.send('Success!');
    }
  });
});

// just a simple way to make sure we don't
// connect to the RTM twice for the same team
var _bots = {};
function trackBot(bot) {
  _bots[bot.config.token] = bot;
}

controller.on('create_bot',function(bot,config) {

  if (_bots[bot.config.token]) {
    // already online! do nothing.
  } else {
    bot.startRTM(function(err) {

      if (!err) {
        trackBot(bot);
      }

      bot.startPrivateConversation({user: config.createdBy},function(err,convo) {
        if (err) {
          console.log(err);
        } else {
          convo.say('I am a bot that has just joined your team');
          convo.say('You must now /invite me to a channel so that I can be of use!');
        }
      });

    });
  }

});

// Handle events related to the websocket connection to Slack
controller.on('rtm_open',function(bot) {
  console.log('** The RTM api just connected!');
});

controller.on('rtm_close',function(bot) {
  console.log('** The RTM api just closed');
  // you may want to attempt to re-open
});

controller.hears('button', ['direct_message'],function(bot,message) {
  var reply = {
    "text": "ボタンのテストです。",
    "attachments": [{
      "text": "どれか押してください。",
      "fallback": "失敗しました。",
      "callback_id": "test_button",
      "color": "#808080",
      "actions": [
        {
          "type": "button",
          "name": "test_button1",
          "text": "テストボタン1"
        },
        {
          "type": "button",
          "name": "test_button2",
          "text": "テストボタン2"
        }
      ]
    }]
  };
  bot.reply(message, reply);
});

controller.hears('^.*残業.*申請.*',['direct_message'],function(bot,message) {
  bot.startConversation(message, askApprover);
});

askApprover = function(response, convo) {
  convo.ask("プロマネは誰？ [@xxx]", function(response, convo) {
    if (!response.text.match(/^<@[a-zA-Z0-9]*>$/)) {
      convo.say('@xxx の形式でユーザーを１人指定してね。');
      askApprover(response, convo);
      convo.next();
    } else {
      var zangyo = {}
      zangyo.id = uuid();
      zangyo.applicant = response.user;
      zangyo.approver = response.text.slice(2, -1);
      askEndTime(response, convo, zangyo);
      convo.next();
    }
  });
}
askEndTime = function(response, convo, zangyo) {
  convo.ask("何時に終わる？ [HH:MM]", function(response, convo) {
    if (!response.text.match(/^([0-2]?[0-9]):([0-5]?[0-9])$/)) {
      convo.say('HH:MM の形式で時間を指定してね。29:59まで指定できるよ。');
      askEndTime(response, convo, zangyo);
      convo.next();
    } else {
      zangyo.endTime = response.text;
      askReason(response, convo, zangyo);
      convo.next();
    }
  });
}
askReason = function(response, convo, zangyo) {
  convo.ask("残業する理由は？", function(response, convo) {
    zangyo.reason = response.text;
    var summary = {
      "text": "この内容で残業申請しますか？",
      "attachments": [
        {
          "text": "申請内容まとめ",
          "fallback": "申請内容のまとめ",
          "callback_id": "apply-" + response.user + '-' + zangyo.id,
          "color": "#36a64f",
          "fields": [
            {
              "title": "申請者",
              "value": "<@" + zangyo.applicant + ">",
              "short": false
            },
            {
              "title": "承認者",
              "value": "<@" + zangyo.approver + ">",
              "short": false
            },
            {
              "title": "終了時間",
              "value": zangyo.endTime,
              "short": false
            },
            {
              "title": "残業する理由",
              "value": zangyo.reason,
              "short": false
            }
          ],
          "actions": [
            {
              "type": "button",
              "name": "apply",
              "text": "申請"
            },
            {
              "type": "button",
              "name": "redo",
              "text": "やり直し"
            },
            {
              "type": "button",
              "name": "cancel",
              "text": "キャンセル"
            }
          ]
        }
      ]
    }
    controller.storage.users.get(response.user, function(err, user) {
        if (!user) {
          user = {
            id: response.user,
            zangyos: []
          }
        } else if (!user.zangyos) {
          user.zangyos = [];
        }

        user.zangyos.push(zangyo);
        controller.storage.users.save(user);
    });
    convo.say(summary);
    convo.next();
  });
}

controller.on('interactive_message_callback', function(bot, message) {
  var ids = message.callback_id.split(/\-/);
  var action = ids[0];
  var user_id = ids[1];
  var item_id = ids[2];

  if (action == 'apply') {
    var ans = message.actions[0].name;
    controller.storage.users.get(user_id, function(err, user) {
      for (var x = 0; x < user.zangyos.length; x++) {
        if (user.zangyos[x].id == item_id) {
          if (ans == 'apply') {
            var zangyo = user.zangyos[x];
            var summary = {
              "attachments": [
                {
                  "text": "申請内容まとめ",
                  "fallback": "申請内容のまとめ",
                  "color": "#36a64f",
                  "fields": [
                    {
                      "title": "申請者",
                      "value": "<@" + zangyo.applicant + ">",
                      "short": false
                    },
                    {
                      "title": "承認者",
                      "value": "<@" + zangyo.approver + ">",
                      "short": false
                    },
                    {
                      "title": "終了時間",
                      "value": zangyo.endTime,
                      "short": false
                    },
                    {
                      "title": "残業する理由",
                      "value": zangyo.reason,
                      "short": false
                    }
                  ]
                }
              ]
            }
            bot.replyInteractive(message, summary);
            bot.reply(message, "この内容で残業申請したよ。");
            bot.startPrivateConversation({user: zangyo.approver}, function(err,convo) {
              if (err) {
                console.log(err);
              } else {
                var application = {
                  "text": "残業申請があります。承認しますか？",
                  "attachments": [
                    {
                      "text": "申請内容まとめ",
                      "fallback": "申請内容のまとめ",
                      "callback_id": "approve-" + zangyo.applicant + '-' + zangyo.id,
                      "color": "#36a64f",
                      "fields": [
                        {
                          "title": "申請者",
                          "value": "<@" + zangyo.applicant + ">",
                          "short": false
                        },
                        {
                          "title": "承認者",
                          "value": "<@" + zangyo.approver + ">",
                          "short": false
                        },
                        {
                          "title": "終了時間",
                          "value": zangyo.endTime,
                          "short": false
                        },
                        {
                          "title": "残業する理由",
                          "value": zangyo.reason,
                          "short": false
                        }
                      ],
                      "actions": [
                        {
                          "type": "button",
                          "name": "approve",
                          "text": "承認"
                        },
                        {
                          "type": "button",
                          "name": "reject",
                          "text": "却下"
                        }
                      ]
                    }
                  ]
                }
                convo.say(application);
                convo.next();
              }
            });
          } else if (ans == 'redo') {
            user.zangyos.splice(x, 1);
            bot.replyInteractive(message, "最初からやり直し！");
            bot.startConversation(message, askApprover);
          } else {
            user.zangyos.splice(x, 1);
            bot.replyInteractive(message, "キャンセルしたよ。さっさと帰ろう！");
          }
          controller.storage.users.save(user);
          break;
        }
      }
    });
  } else if (action == 'approve') {
    var ans = message.actions[0].name;
    controller.storage.users.get(user_id, function(err, user) {
      for (var x = 0; x < user.zangyos.length; x++) {
        if (user.zangyos[x].id == item_id) {
          var zangyo = user.zangyos[x];
          var summary = {
            "attachments": [
              {
                "text": "申請内容まとめ",
                "fallback": "申請内容のまとめ",
                "color": "#36a64f",
                "fields": [
                  {
                    "title": "申請者",
                    "value": "<@" + zangyo.applicant + ">",
                    "short": false
                  },
                  {
                    "title": "承認者",
                    "value": "<@" + zangyo.approver + ">",
                    "short": false
                  },
                  {
                    "title": "終了時間",
                    "value": zangyo.endTime,
                    "short": false
                  },
                  {
                    "title": "残業する理由",
                    "value": zangyo.reason,
                    "short": false
                  }
                ]
              }
            ]
          }
          bot.replyInteractive(message, summary);
          if (ans == 'approve') {
            user.zangyos[x].approved = true;
            bot.reply(message, "この申請を承認したよ。");
            bot.startPrivateConversation({user: zangyo.applicant}, function(err,convo) {
              if (err) {
                console.log(err);
              } else {
                convo.say(summary);
                convo.say("この申請が承認されました。");
                convo.next();
              }
            });
          } else if (ans == 'reject') {
            user.zangyos[x].approved = false;
            bot.reply(message, "この申請を却下したよ。");
            bot.startPrivateConversation({user: zangyo.applicant}, function(err,convo) {
              if (err) {
                console.log(err);
              } else {
                convo.say(summary);
                convo.say("この申請が却下されました。");
                convo.next();
              }
            });
          }
          controller.storage.users.save(user);
          break;
        }
      }
    });
  } else if (message.callback_id == "test_button") {
    var users_answer = message.actions[0].name;
    bot.replyInteractive(message, "あなたは「" + users_answer + "」を押しました");
  }
});

controller.storage.teams.all(function(err,teams) {

  if (err) {
    throw new Error(err);
  }

  // connect all teams with bots up to slack!
  for (var t  in teams) {
    if (teams[t].bot) {
      controller.spawn(teams[t]).startRTM(function(err, bot) {
        if (err) {
          console.log('Error connecting bot to Slack:',err);
        } else {
          trackBot(bot);
        }
      });
    }
  }
});

function uuid() {
  var uuid = "", i, random;
  for (i = 0; i < 32; i++) {
    random = Math.random() * 16 | 0;
    uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16);
  }
  return uuid;
};
<|endoftext|>


<commit_before>'use strict';
var execFile = require('child_process').execFile;
var spawn = require('child_process').spawn;
var path = require('path');
var multiTypeof = require('multi-typeof');

function checkInput(input) {
	if (!multiTypeof(input, ['string', 'array'])) {
		throw new TypeError('Expected a string or an array as input');
	}

	if (!Array.isArray(input)) {
		var reg = new RegExp(/[^\s"']+|"([^"]*)"|'([^']*)'/g);
		input = input.match(reg);

		input.forEach(function (el) {
			input[input.indexOf(el)] = el.replace(/"/g, '');
		});
	}

	return input;
}

module.exports = function (input, cb) {
	if (process.platform !== 'win32') {
		throw new Error('Only Windows systems are supported');
	}

	execFile(path.join(__dirname, 'nircmd.exe'), checkInput(input), function (err, res) {
		if (err) {
			cb(err);
			return;
		}

		cb(null, res);
	});
};

module.exports.spawn = function (input, opts) {
	opts = opts || {};

	if (process.platform !== 'win32') {
		throw new Error('Only Windows systems are supported');
	}

	return spawn(path.join(__dirname, 'nircmd.exe'), checkInput(input), opts);
};
<commit_msg>Expose options in default method<commit_after>'use strict';
var execFile = require('child_process').execFile;
var spawn = require('child_process').spawn;
var path = require('path');
var multiTypeof = require('multi-typeof');

function checkInput(input) {
	if (!multiTypeof(input, ['string', 'array'])) {
		throw new TypeError('Expected a string or an array as input');
	}

	if (!Array.isArray(input)) {
		var reg = new RegExp(/[^\s"']+|"([^"]*)"|'([^']*)'/g);
		input = input.match(reg);

		input.forEach(function (el) {
			input[input.indexOf(el)] = el.replace(/"/g, '');
		});
	}

	return input;
}

module.exports = function (input, opts, cb) {
	opts = opts || {};

	if (process.platform !== 'win32') {
		throw new Error('Only Windows systems are supported');
	}

	if (typeof opts === 'function') {
		cb = opts;
		opts = {};
	}

	execFile(path.join(__dirname, 'nircmd.exe'), checkInput(input), opts, function (err, res) {
		if (err) {
			cb(err);
			return;
		}

		cb(null, res);
	});
};

module.exports.spawn = function (input, opts) {
	opts = opts || {};

	if (process.platform !== 'win32') {
		throw new Error('Only Windows systems are supported');
	}

	return spawn(path.join(__dirname, 'nircmd.exe'), checkInput(input), opts);
};
<|endoftext|>


<commit_before>"use strict";

var request = require('request');

module.exports = function herokuSelfPing(url, options) {
  if(!options) {
    options = {};
  }

  options.interval = options.interval || 45 * 1000 * 60;
  options.logger = options.logger || console.log;
  options.verbose = options.verbose || false;

  var isHeroku = require("is-heroku");

  if(!url) {
    options.verbose && options.logger("heroku-self-ping: no url provided. Exiting.");
    return false;
  }
  if(!isHeroku) {
    options.verbose && options.logger("heroku-self-ping: heroku not detected. Exiting.");

    return false;
  }

  options.verbose && options.logger("heroku-self-ping: Setting up hearbeat to " + url + " every " + options.interval + "ms.");

  return setInterval(function() {
    options.logger("heroku-self-ping: Sending hearbeat to " + url);
    request(url, function () {});
  }, options.interval);
};
<commit_msg>Set defaut interval to 20 minutes<commit_after>"use strict";

var request = require('request');

module.exports = function herokuSelfPing(url, options) {
  if(!options) {
    options = {};
  }

  options.interval = options.interval || 20 * 1000 * 60;
  options.logger = options.logger || console.log;
  options.verbose = options.verbose || false;

  var isHeroku = require("is-heroku");

  if(!url) {
    options.verbose && options.logger("heroku-self-ping: no url provided. Exiting.");
    return false;
  }
  if(!isHeroku) {
    options.verbose && options.logger("heroku-self-ping: heroku not detected. Exiting.");

    return false;
  }

  options.verbose && options.logger("heroku-self-ping: Setting up hearbeat to " + url + " every " + options.interval + "ms.");

  return setInterval(function() {
    options.logger("heroku-self-ping: Sending hearbeat to " + url);
    request(url, function () {});
  }, options.interval);
};
<|endoftext|>


<commit_before>#! /usr/bin/env node
var fs   = require('fs')
var path = require('path')
var pull = require('pull-stream')
var pfs  = require('pull-fs')
var paramap = require('pull-paramap')
var clean = require('./clean')
var cont = require('continuable')
var para = require('continuable-para')

function filter () {
  return pull(pull.filter(),
    pull.map(function (pkg) {
      return {
        name   : pkg.name,
        version: pkg.version,
        path   : pkg.path
      }
    })
  )
}

function first (cb) {
  var f
  return pull.drain(
    function (data) { f = data; return false },
    function (err) { cb(err === true ? null : err, f) }
  )
}

var readJson = cont.to(function (file, cb) {
  fs.readFile(file, 'utf8', function (err, data) {
    if(err) return cb(err)
    var json
    try { json = JSON.parse(data) }
    catch (err) { return cb(err) }
    json.path = path.dirname(file)
    cb(null, json)
  })
})

var exists = cont.to(function (file, cb) {
  fs.stat(file, function (err, stat) {
    cb(null, stat)
  })
})

function readPackage (dir, cb) {
  var pkg
  para([
    readJson(path.resolve(dir, 'package.json')),
    exists(path.resolve(dir, 'bindings.gyp'))
  ]) (function (err, data) {
    if(!err) {
      pkg = data[0]
      if(!!data[1])
        pkg.gypfile = true
      pkg.path = dir
    }
    cb(err, pkg)
  })
}

function maybe(test) {
  return function (arg, cb) {
    test(arg, function (err, value) {
      cb(null, value)
    })
  }
}

function findPackage (dir, cb) {
  if(!cb) cb = dir, dir = null
  dir = dir || process.cwd()

  pull(
    pfs.ancestors(dir),
    pfs.resolve('package.json'),
    pfs.isFile(),
    pull.asyncMap(maybe(readJson)),
    pull.filter(),
    first(cb)
  )
}

//retrive the current files,
function ls (dir, cb) {
  if(!cb) cb = dir, dir = null

  dir = dir || process.cwd()

  pull(
    pfs.ancestors(dir),
    pfs.resolve('node_modules'),
    pfs.star(),
    pull.filter(Boolean),
    paramap(maybe(readPackage)),
    filter(),
    pull.unique('name'),
    pull.reduce(function (obj, val) {
      if(!obj[val.name])
        obj[val.name] = val
      return obj
    }, {}, function (err, obj) {
      cb(err, obj)
    })
  )
}

//creates the same datastructure as resolve,
//selecting all dependencies...

function tree (dir, opts, cb) {
  var i = 0
  findPackage(dir, function (err, pkg) {
    pull(
      pull.depthFirst(pkg, function (pkg) {
        pkg.tree = {}
        return pull(
          pfs.readdir(path.resolve(pkg.path, 'node_modules')),
          paramap(maybe(readPackage)),
          pull.filter(function (_pkg) {
            if(!_pkg) return
            _pkg.parent = pkg

            pkg.tree[_pkg.name] = _pkg
            return pkg
          })
        )
      }),
      opts.post ? paramap(function (data, cb) {
        //run a post install-style hook.
        opts.post(data, !(i++), cb)
      }) : pull.through(),
      pull.drain(null, function (err) {
        cb(err === true ? null : err, clean(pkg))
      })
    )
  })
}

exports.tree = tree
exports.findPackage = findPackage
exports.ls = ls

if(!module.parent) {
  var opts = require('optimist').argv
  var exec = require('child_process').exec
  if(opts.ls)
    ls(process.cwd(), function (err, data) {
      if(err) throw err
      console.log(JSON.stringify(data, null, 2))
    })
  else if(opts.pkg)
    findPackage(process.cwd(), function (err, data) {
      if(err) throw err
      console.log(JSON.stringify(data, null, 2))
    })
  else
  tree(process.cwd(), {post: function (data, first, cb) {
      if(!opts.c) return cb(null, data)
      var cp =
        exec(opts.c, {cwd: data.path}, function (err, stdout) {
          cb(err, data)
        })
      cp.stdout.pipe(process.stdout)
      cp.stderr.pipe(process.stderr)
    }}, function (err, tree) {
    if(err) throw err
    if(!opts.quiet)
      console.log(JSON.stringify(tree, null, 2))
  })
}

<commit_msg>don't give the root any special treatment<commit_after>#! /usr/bin/env node
var fs   = require('fs')
var path = require('path')
var pull = require('pull-stream')
var pfs  = require('pull-fs')
var paramap = require('pull-paramap')
var clean = require('./clean')
var cont = require('continuable')
var para = require('continuable-para')

function filter () {
  return pull(pull.filter(),
    pull.map(function (pkg) {
      return {
        name   : pkg.name,
        version: pkg.version,
        path   : pkg.path
      }
    })
  )
}

function first (cb) {
  var f
  return pull.drain(
    function (data) { f = data; return false },
    function (err) { cb(err === true ? null : err, f) }
  )
}

var readJson = cont.to(function (file, cb) {
  fs.readFile(file, 'utf8', function (err, data) {
    if(err) return cb(err)
    var json
    try { json = JSON.parse(data) }
    catch (err) { return cb(err) }
    json.path = path.dirname(file)
    cb(null, json)
  })
})

var exists = cont.to(function (file, cb) {
  fs.stat(file, function (err, stat) {
    cb(null, stat)
  })
})

function readPackage (dir, cb) {
  var pkg
  para([
    readJson(path.resolve(dir, 'package.json')),
    exists(path.resolve(dir, 'bindings.gyp'))
  ]) (function (err, data) {
    if(!err) {
      pkg = data[0]
      if(!!data[1])
        pkg.gypfile = true
      pkg.path = dir
    }
    cb(err, pkg)
  })
}

function maybe(test) {
  return function (arg, cb) {
    test(arg, function (err, value) {
      cb(null, value)
    })
  }
}

function findPackage (dir, cb) {
  if(!cb) cb = dir, dir = null
  dir = dir || process.cwd()

  pull(
    pfs.ancestors(dir),
    pfs.resolve('package.json'),
    pfs.isFile(),
    pull.asyncMap(maybe(readJson)),
    pull.filter(),
    first(cb)
  )
}

//retrive the current files,
function ls (dir, cb) {
  if(!cb) cb = dir, dir = null

  dir = dir || process.cwd()

  pull(
    pfs.ancestors(dir),
    pfs.resolve('node_modules'),
    pfs.star(),
    pull.filter(Boolean),
    paramap(maybe(readPackage)),
    filter(),
    pull.unique('name'),
    pull.reduce(function (obj, val) {
      if(!obj[val.name])
        obj[val.name] = val
      return obj
    }, {}, function (err, obj) {
      cb(err, obj)
    })
  )
}

//creates the same datastructure as resolve,
//selecting all dependencies...

function tree (dir, opts, cb) {
  var i = 0
  findPackage(dir, function (err, pkg) {
    pull(
      pull.depthFirst(pkg, function (pkg) {
        pkg.tree = {}
        return pull(
          pfs.readdir(path.resolve(pkg.path, 'node_modules')),
          paramap(maybe(readPackage)),
          pull.filter(function (_pkg) {
            if(!_pkg) return
            _pkg.parent = pkg

            pkg.tree[_pkg.name] = _pkg
            return pkg
          })
        )
      }),
      opts.post ? paramap(function (data, cb) {
        //run a post install-style hook.
        opts.post(data, cb)
      }) : pull.through(),
      pull.drain(null, function (err) {
        cb(err === true ? null : err, clean(pkg))
      })
    )
  })
}

exports.tree = tree
exports.findPackage = findPackage
exports.ls = ls

if(!module.parent) {
  var opts = require('optimist').argv
  var exec = require('child_process').exec
  if(opts.ls)
    ls(process.cwd(), function (err, data) {
      if(err) throw err
      console.log(JSON.stringify(data, null, 2))
    })
  else if(opts.pkg)
    findPackage(process.cwd(), function (err, data) {
      if(err) throw err
      console.log(JSON.stringify(data, null, 2))
    })
  else
  tree(process.cwd(), {post: function (data, cb) {
      if(!opts.c) return cb(null, data)
      var cp =
        exec(opts.c, {cwd: data.path}, function (err, stdout) {
          cb(err, data)
        })
      cp.stdout.pipe(process.stdout)
      cp.stderr.pipe(process.stderr)
    }}, function (err, tree) {
    if(err) throw err
    if(!opts.quiet)
      console.log(JSON.stringify(tree, null, 2))
  })
}

<|endoftext|>


<commit_before>'use strict';
var through = require('through2'),
	PluginError = require('gulp-util/lib/PluginError'),
	pluginName = 'mini-selectors';

var expressions = {
	selectorMatch: /(\.|#)(-?[_a-zA-Z]+[_\w-]*)\s*;*}*/g,
	selectorNameMatch: /(-?[_a-zA-Z]+[_\w-]*)/g,
	selectorAttributeMatch: /(class|id|for)\s*=\s*["'](-?[_a-zA-Z]+[_\w-\s]*)["']/g,
	selectorStringMatch: function(selector) {
		return new RegExp('"' + selector + '"|' + "'" + selector + "'", 'g');
	}
};

module.exports = function() {

	var classLibrary = {},
		shortClassLibrary = [],
		idLibrary = {},
		shortIdLibrary = [];

	/**
	 * Main task for uglify classes. Processes files based on type.
	 *
	 * @param file Stream from through2
	 * @param encoding
	 * @param callback for through2
	 */
	function miniSelectors(file, encoding, callback) {
		var extensions = file.path.split('.'),
			extension = extensions[extensions.length - 1],
			fileString = String(file.contents),
			reducedFile;

		switch (extension) {
			case 'css':
			case 'scss':
			case 'sass':
			case 'less':
				reducedFile = replaceCssSelectors(fileString);
				break;
			case 'html':
				reducedFile = replaceHtmlSelectors(fileString);
				break;
			case 'js':
				reducedFile = file;
				break;
			default:
				return callback(
					new PluginError(pluginName, 'Filetype not supported: ' + extension, {
						fileName: file.path,
						showStack: false
					}));
		}

		file.contents = new Buffer(reducedFile);
		this.push(file);
		callback();
	}

	/**
	 * Replaces all class names with shortnames. Also builds a library of shortnames which can be
	 * used to reduce other file types.
	 *
	 * @param file String
	 * @returns {reducedFile String}
	 */
	function replaceCssSelectors(file) {
		var className,
			classNameMatch = expressions.selectorMatch,
			nameMatch = expressions.selectorNameMatch;

		return file.replace(classNameMatch, function(match) {
			//exclude property values (matches ending in ';')
			if (match[match.length - 1] === ';' || match[match.length - 1] === '}') {
				return match;
			}

			//get the selector type and name
			var selectorType = match.substr(0, 1);

			return match.replace(nameMatch, function(selector) {
				switch (selectorType) {
					case '.':
						return getShortname(selector, classLibrary, shortClassLibrary);
					case '#':
						return getShortname(selector, idLibrary, shortIdLibrary);
					default:
						//probably don't touch something we don't understand
						console.log(selector);
						return selector;
				}
			});
		});
	}

	/**
	 * Replaces all class and id attributes found in the library. Only tested on *.html files with
	 * classes declared in *class= attributes.
	 *
	 * @param file String
	 * @returns {reducedFile String}
	 */
	function replaceHtmlSelectors(file) {
		return file.replace(expressions.selectorAttributeMatch, function(attributes) {
			var attribute = attributes.split('=');
			return attribute[0] + '=' + attribute[1]
				.replace(expressions.selectorNameMatch, function(selectorName) {
					switch (attribute[0]) {
						case 'class':
							return getShortname(selectorName, classLibrary, shortClassLibrary);
						case 'id':
						case 'for':
							return getShortname(selectorName, idLibrary, shortIdLibrary);
						default:

					}
				});
		});
	}

	/**
	 * Will replace all exact occurrences of all class names from the library which are present as
	 * strings.
	 * e.g. "className" and 'className' will be matched but "className anotherClass" will not
	 *
	 * @param file String
	 * @returns {reducedFile String}
	 */
	function replaceJsSelectors(file) {
		for (var className in classLibrary) {
			var matcher = expressions.selectorStringMatch(className);
			file = file.replace(matcher, function(match) {
				return match[0] + classLibrary[className].shortName + match[match.length - 1];
			});
		}
		return file;
	}

	return through.obj(miniSelectors);
};

/**
 * Helper function for getting a shortname. Generates a new shortname if it does not exist.
 *
 * @param selector String representing the name of the item to get a shortname for
 * @param fullLibrary Object {selector: {shortName: shortName}, ...}
 * @param shortLibrary Array [shortName, ...]
 * @returns {shortName String} From library or from generator
 */
function getShortname(selector, fullLibrary, shortLibrary) {
	var shortName;

	if (!fullLibrary[selector]) {
		//check if the shortname is in the library
		shortName = generateShortname(shortLibrary.length);
		fullLibrary[selector] = {
			shortName: shortName
		}
		shortLibrary.push(shortName);
	} else {
		//grab the shortname that already exists
		shortName = fullLibrary[selector].shortName;
	}

	return shortName;
}

/**
 * Helper function for generating shortnames based on an alphabetic library.
 *
 * @param seed Integer
 * @returns {string Shortname}
 */
function generateShortname(seed) {
	var library = 'abcdefghijklmnopqrstuvwxyz',
		libraryLength = library.length,
		prefix = '';
	//break the seed down if it is larger than the library
	if (seed >= libraryLength) {
		prefix = generateShortname(Math.floor(seed / libraryLength) - 1);
	}
	//return the prefixed shortname
	return prefix + library[seed % libraryLength];
}<commit_msg>removing bad JavaScript logic<commit_after>'use strict';
var through = require('through2'),
	PluginError = require('gulp-util/lib/PluginError'),
	pluginName = 'mini-selectors';

var expressions = {
	selectorMatch: /(\.|#)(-?[_a-zA-Z]+[_\w-]*)\s*;*}*/g,
	selectorNameMatch: /(-?[_a-zA-Z]+[_\w-]*)/g,
	selectorAttributeMatch: /(class|id|for)\s*=\s*["'](-?[_a-zA-Z]+[_\w-\s]*)["']/g
};

module.exports = function() {

	var classLibrary = {},
		shortClassLibrary = [],
		idLibrary = {},
		shortIdLibrary = [];

	/**
	 * Main task for uglify classes. Processes files based on type.
	 *
	 * @param file Stream from through2
	 * @param encoding
	 * @param callback for through2
	 */
	function miniSelectors(file, encoding, callback) {
		var extensions = file.path.split('.'),
			extension = extensions[extensions.length - 1],
			fileString = String(file.contents),
			reducedFile;

		switch (extension) {
			case 'css':
			case 'scss':
			case 'sass':
			case 'less':
				reducedFile = replaceCssSelectors(fileString);
				break;
			case 'html':
				reducedFile = replaceHtmlSelectors(fileString);
				break;
			case 'js':
				reducedFile = file;
				break;
			default:
				return callback(
					new PluginError(pluginName, 'Filetype not supported: ' + extension, {
						fileName: file.path,
						showStack: false
					}));
		}

		file.contents = new Buffer(reducedFile);
		this.push(file);
		callback();
	}

	/**
	 * Replaces all class names with shortnames. Also builds a library of shortnames which can be
	 * used to reduce other file types.
	 *
	 * @param file String
	 * @returns {reducedFile String}
	 */
	function replaceCssSelectors(file) {
		var classNameMatch = expressions.selectorMatch,
			nameMatch = expressions.selectorNameMatch;

		return file.replace(classNameMatch, function(match) {
			//exclude property values (matches ending in ';')
			if (match[match.length - 1] === ';' || match[match.length - 1] === '}') {
				return match;
			}

			//get the selector type and name
			var selectorType = match.substr(0, 1);

			return match.replace(nameMatch, function(selector) {
				switch (selectorType) {
					case '.':
						return getShortname(selector, classLibrary, shortClassLibrary);
					case '#':
						return getShortname(selector, idLibrary, shortIdLibrary);
					default:
						//probably don't touch something we don't understand
						console.log(selector);
						return selector;
				}
			});
		});
	}

	/**
	 * Replaces all class and id attributes found in the library. Only tested on *.html files with
	 * classes declared in *class= attributes.
	 *
	 * @param file String
	 * @returns {reducedFile String}
	 */
	function replaceHtmlSelectors(file) {
		return file.replace(expressions.selectorAttributeMatch, function(attributes) {
			var attribute = attributes.split('=');
			return attribute[0] + '=' + attribute[1]
				.replace(expressions.selectorNameMatch, function(selectorName) {
					switch (attribute[0]) {
						case 'class':
							return getShortname(selectorName, classLibrary, shortClassLibrary);
						case 'id':
						case 'for':
							return getShortname(selectorName, idLibrary, shortIdLibrary);
						default:

					}
				});
		});
	}

	return through.obj(miniSelectors);
};

/**
 * Helper function for getting a shortname. Generates a new shortname if it does not exist.
 *
 * @param selector String representing the name of the item to get a shortname for
 * @param fullLibrary Object {selector: {shortName: shortName}, ...}
 * @param shortLibrary Array [shortName, ...]
 * @returns {shortName String} From library or from generator
 */
function getShortname(selector, fullLibrary, shortLibrary) {
	var shortName;

	if (!fullLibrary[selector]) {
		//check if the shortname is in the library
		shortName = generateShortname(shortLibrary.length);
		fullLibrary[selector] = {
			shortName: shortName
		}
		shortLibrary.push(shortName);
	} else {
		//grab the shortname that already exists
		shortName = fullLibrary[selector].shortName;
	}

	return shortName;
}

/**
 * Helper function for generating shortnames based on an alphabetic library.
 *
 * @param seed Integer
 * @returns {string Shortname}
 */
function generateShortname(seed) {
	var library = 'abcdefghijklmnopqrstuvwxyz',
		libraryLength = library.length,
		prefix = '';
	//break the seed down if it is larger than the library
	if (seed >= libraryLength) {
		prefix = generateShortname(Math.floor(seed / libraryLength) - 1);
	}
	//return the prefixed shortname
	return prefix + library[seed % libraryLength];
}<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var argv = require('yargs').alias('v', 'verbose').argv;

var parser   = require('./lib/parser');
var printer  = require('./lib/printer');
var TaskList = require('./lib/models').TaskList;

module.exports = inheritGulp();

/**
 * Define a task
 * @param {string} name The name of the task.
 * @param {Array} [dep] Task dependencies
 * @param {Function} fn The function that performs the task's operations
 * @return {Stream|Promise}
 */
module.exports.task = function task(name, dep, fn) {
  this.taskList.push(parser.makeTaskInfo(name));
  return gulp.task.apply(gulp, arguments);
};

/**
 * Factory that creates gulp task function
 * @param {Object}   [options]
 * @param {Object}   options.parser
 * @param {Function} options.print
 * @returns {Function}
 */
module.exports.help = function help(options) {
  options = options || {};
  var list = module.exports.taskList;
  var print = options.print || printer;

  return function() {
    list.forEach(function(task) {
      parser.parseComments(task, options.parser);
    });
    console.log(print(list, argv.verbose));
  };
};

/**
 * Alternative way of the library usage, apply monkey-patching to gulp.task
 * @param {Gulp} [gulpInst]
 */
module.exports.patchGulp = function patchGulp(gulpInst) {
  gulpInst = gulpInst || gulp;

  var originalTasks = gulpInst.task;
  gulpInst.task = function task(name, dep, fn) {
    module.exports.taskList.push(parser.makeTaskInfo(name));
    return originalTasks.apply(gulpInst, arguments);
  };

  return this;
};

/**
 * Return a new instance that is inherited from Gulp
 * @returns {TaskDoc}
 */
function inheritGulp() {
  function TaskDoc() {
    this.taskList = new TaskList();
    gulp.Gulp.call(this);
  }
  TaskDoc.prototype = gulp;
  return new TaskDoc();
}<commit_msg>Fix jsdoc<commit_after>'use strict';

var gulp = require('gulp');
var argv = require('yargs').alias('v', 'verbose').argv;

var parser   = require('./lib/parser');
var printer  = require('./lib/printer');
var TaskList = require('./lib/models').TaskList;

module.exports = inheritGulp();

/**
 * Define a task
 * @param {string}   name  The name of the task.
 * @param {Array}    [dep] Task dependencies
 * @param {Function} [fn]  The function that performs the task's operations
 * @return {Stream|Promise}
 */
module.exports.task = function task(name, dep, fn) {
  this.taskList.push(parser.makeTaskInfo(name));
  return gulp.task.apply(gulp, arguments);
};

/**
 * Factory that creates gulp task function
 * @param {Object}   [options]
 * @param {Object}   options.parser
 * @param {Function} options.print
 * @returns {Function}
 */
module.exports.help = function help(options) {
  options = options || {};
  var list = module.exports.taskList;
  var print = options.print || printer;

  return function() {
    list.forEach(function(task) {
      parser.parseComments(task, options.parser);
    });
    console.log(print(list, argv.verbose));
  };
};

/**
 * Alternative way of the library usage, apply monkey-patching to gulp.task
 * @param {Gulp} [gulpInst]
 */
module.exports.patchGulp = function patchGulp(gulpInst) {
  gulpInst = gulpInst || gulp;

  var originalTasks = gulpInst.task;
  gulpInst.task = function task(name, dep, fn) {
    module.exports.taskList.push(parser.makeTaskInfo(name));
    return originalTasks.apply(gulpInst, arguments);
  };

  return this;
};

/**
 * Return a new instance that is inherited from Gulp
 * @returns {TaskDoc}
 */
function inheritGulp() {
  function TaskDoc() {
    this.taskList = new TaskList();
    gulp.Gulp.call(this);
  }
  TaskDoc.prototype = gulp;
  return new TaskDoc();
}<|endoftext|>


<commit_before>'use strict';
module.exports = function (str, opts) {
  if (typeof str !== 'string') {
    throw new TypeError('Expected a string');
  }

  opts = opts || {};

  return str + ' & ' + (opts.postfix || 'rainbows');
};
<commit_msg>feat(android): add android?<commit_after>// https://developer.mozilla.org/en-US/Add-ons/Firefox_for_Android/Code_snippets#Supporting_both_desktop_and_mobile
const { Cc, Ci } = require('chrome');

module.exports = () =>
Cc['@mozilla.org/xre/app-info;1']
  .getService(Ci.nsIXULRuntime)
  .widgetToolkit.toLowerCase() === 'android';
<|endoftext|>


<commit_before>'use strict';

var path = require('path'),
    chalk = require('chalk'),
    childProcess = require('child_process'),
    phantomjs = require('phantomjs'),
    binPath = phantomjs.path,
    phantomjsRunnerDir = path.dirname(require.resolve('qunit-phantomjs-runner'));

module.exports = function (filepath, options, callback) {
    var opt = options || {},
        cb = callback || function () {},
        runner = path.join(phantomjsRunnerDir, 'runner-json.js');

    if (opt.verbose) {
        runner = path.join(phantomjsRunnerDir, 'runner-list.js');
    } else if (opt.customRunner) {
        // A custom phantomjs runner can be used to have more control
        // over phantomjs configuration or to customize phantomjs hooks.
        runner = opt.customRunner;
    }

    var absolutePath = path.resolve(filepath),
        isAbsolutePath = absolutePath.indexOf(filepath) >= 0,
        childArgs = [];

    if (opt['phantomjs-options'] && opt['phantomjs-options'].length) {
        childArgs.push( opt['phantomjs-options'] );
    }

    childArgs.push(
        runner,
        (isAbsolutePath ? 'file:///' + absolutePath.replace(/\\/g, '/') : filepath)
    );

    if ( opt.timeout ) {
        childArgs.push( opt.timeout );
    }

    var proc = childProcess.execFile(binPath, childArgs, function (err, stdout, stderr) {
        console.log('Testing ' + chalk.blue( path.relative(__dirname, filepath) ));

        if (stdout) {
            try {
                var out,
                    result,
                    message,
                    output;

                stdout.trim().split('\n').forEach(function(line) {
                    try{
                        out = JSON.parse(line.trim());
                        result = out.result;

                        message = 'Took ' + result.runtime + ' ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.';

                        output = result.failed > 0 ? chalk.red(message) : chalk.green(message);

                        console.log(output);

                        if(out.exceptions) {
                            for(var test in out.exceptions) {
                                console.log('\n' + chalk.red('Test failed') + ': ' + chalk.red(test) + ': \n' + out.exceptions[test].join('\n  '));
                            }
                        }
                    } catch(e) {
                        line = line.trim(); // Trim trailing cr-lf
                        console.log(line);
                    }
                });
            } catch (e) {
                this.emit('error', new Error(e));
            }
        }

        if (stderr) {
            console.log(stderr);
        }

        if (err) {
            console.log(err);
        }
    }.bind(this));

    proc.on('close', function (code) {
        return cb(code);
    });
};
<commit_msg>Update phantomjs package name.<commit_after>'use strict';

var path = require('path'),
    chalk = require('chalk'),
    childProcess = require('child_process'),
    phantomjs = require('phantomjs-prebuilt'),
    binPath = phantomjs.path,
    phantomjsRunnerDir = path.dirname(require.resolve('qunit-phantomjs-runner'));

module.exports = function (filepath, options, callback) {
    var opt = options || {},
        cb = callback || function () {},
        runner = path.join(phantomjsRunnerDir, 'runner-json.js');

    if (opt.verbose) {
        runner = path.join(phantomjsRunnerDir, 'runner-list.js');
    } else if (opt.customRunner) {
        // A custom phantomjs runner can be used to have more control
        // over phantomjs configuration or to customize phantomjs hooks.
        runner = opt.customRunner;
    }

    var absolutePath = path.resolve(filepath),
        isAbsolutePath = absolutePath.indexOf(filepath) >= 0,
        childArgs = [];

    if (opt['phantomjs-options'] && opt['phantomjs-options'].length) {
        childArgs.push( opt['phantomjs-options'] );
    }

    childArgs.push(
        runner,
        (isAbsolutePath ? 'file:///' + absolutePath.replace(/\\/g, '/') : filepath)
    );

    if ( opt.timeout ) {
        childArgs.push( opt.timeout );
    }

    var proc = childProcess.execFile(binPath, childArgs, function (err, stdout, stderr) {
        console.log('Testing ' + chalk.blue( path.relative(__dirname, filepath) ));

        if (stdout) {
            try {
                var out,
                    result,
                    message,
                    output;

                stdout.trim().split('\n').forEach(function(line) {
                    try{
                        out = JSON.parse(line.trim());
                        result = out.result;

                        message = 'Took ' + result.runtime + ' ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.';

                        output = result.failed > 0 ? chalk.red(message) : chalk.green(message);

                        console.log(output);

                        if(out.exceptions) {
                            for(var test in out.exceptions) {
                                console.log('\n' + chalk.red('Test failed') + ': ' + chalk.red(test) + ': \n' + out.exceptions[test].join('\n  '));
                            }
                        }
                    } catch(e) {
                        line = line.trim(); // Trim trailing cr-lf
                        console.log(line);
                    }
                });
            } catch (e) {
                this.emit('error', new Error(e));
            }
        }

        if (stderr) {
            console.log(stderr);
        }

        if (err) {
            console.log(err);
        }
    }.bind(this));

    proc.on('close', function (code) {
        return cb(code);
    });
};
<|endoftext|>


<commit_before>var util = require('./lib/util')
	, mkdirp = require('mkdirp')
	, _ = require('underscore')
	, path = require('path');

/** Function: defaultPathBuilder
 * This function builds paths for a screenshot file. It is appended to the
 * constructors base directory and gets prependend with `.png` or `.json` when
 * storing a screenshot or JSON meta data file.
 *
 * Parameters:
 *     (Object) spec - The spec currently reported
 *     (Array) descriptions - The specs and their parent suites descriptions
 *     (Object) result - The result object of the current test spec.
 *     (Object) capabilities - WebDrivers capabilities object containing
 *                             in-depth information about the Selenium node
 *                             which executed the test case.
 *
 * Returns:
 *     (String) containing the built path
 */
function defaultPathBuilder(spec, descriptions, results, capabilities) {
	return util.generateGuid();
}

/** Function: defaultMetaDataBuilder
 * Uses passed information to generate a meta data object which can be saved
 * along with a screenshot.
 * You do not have to add the screenshots file path since this will be appended
 * automatially.
 *
 * Parameters:
 *     (Object) spec - The spec currently reported
 *     (Array) descriptions - The specs and their parent suites descriptions
 *     (Object) result - The result object of the current test spec.
 *     (Object) capabilities - WebDrivers capabilities object containing
 *                             in-depth information about the Selenium node
 *                             which executed the test case.
 *
 * Returns:
 *     (Object) containig meta data to store along with a screenshot
 */
function defaultMetaDataBuilder(spec, descriptions, results, capabilities) {
	var metaData = {
			description: descriptions.join(' ')
			, passed: results.passed()
			, os: capabilities.caps_.platform
			, browser: {
				name: capabilities.caps_.browserName
				, version: capabilities.caps_.version
			}
		};
	console.dir(results.items_);
	if(results.items_.length > 0) {
		var result = results.items_[0];
		if(!results.passed()){
			var failedItem = _.where(results.items_,{passed_: false})[0];
			if(failedItem){
				metaData.message = failedItem.message || 'Failed';
				metaData.trace = failedItem.trace? (failedItem.trace.stack || 'No Stack trace information') : 'No Stack trace information';
			}

		}else{
			metaData.message = result.message || 'Passed';
			metaData.trace = result.trace.stack;
		}

	}

	return metaData;
}

/** Class: ScreenshotReporter
 * Creates a new screenshot reporter using the given `options` object.
 *
 * For more information, please look at the README.md file.
 *
 * Parameters:
 *     (Object) options - Object with options as described below.
 *
 * Possible options:
 *     (String) baseDirectory - The path to the directory where screenshots are
 *                              stored. If not existing, it gets created.
 *                              Mandatory.
 *     (Function) pathBuilder - A function which returns a path for a screenshot
 *                              to be stored. Optional.
 *     (Function) metaDataBuilder - Function which returns an object literal
 *                                  containing meta data to store along with
 *                                  the screenshot. Optional.
 *     (Boolean) takeScreenShotsForSkippedSpecs - Do you want to capture a
 *                                                screenshot for a skipped spec?
 *                                                Optional (default: false).
 */
function ScreenshotReporter(options) {
	options = options || {};
	if(!options.baseDirectory || options.baseDirectory.length === 0) {
		throw new Error('Please pass a valid base directory to store the ' +
			'screenshots into.');
	} else {
		this.baseDirectory = options.baseDirectory;
	}

	this.pathBuilder = options.pathBuilder || defaultPathBuilder;
	this.metaDataBuilder = options.metaDataBuilder || defaultMetaDataBuilder;
	this.takeScreenShotsForSkippedSpecs =
		options.takeScreenShotsForSkippedSpecs || false;
		this.takeScreenShotsOnlyForFailedSpecs =
 		options.takeScreenShotsOnlyForFailedSpecs || false;
 	this.finalOptions = {
 		takeScreenShotsOnlyForFailedSpecs: this.takeScreenShotsOnlyForFailedSpecs,
 		takeScreenShotsForSkippedSpecs: this.takeScreenShotsForSkippedSpecs,
 		metaDataBuilder: this.metaDataBuilder,
 		pathBuilder: this.pathBuilder,
 		baseDirectory: this.baseDirectory
 	};
}

/** Function: reportSpecResults
 * Called by Jasmine when reporteing results for a test spec. It triggers the
 * whole screenshot capture process and stores any relevant information.
 *
 * Parameters:
 *     (Object) spec - The test spec to report.
 */
ScreenshotReporter.prototype.reportSpecResults =
function reportSpecResults(spec) {
	/* global browser */
	var self = this
		, results = spec.results()

	if(!self.takeScreenShotsForSkippedSpecs && results.skipped) {
		return;
	}

	browser.takeScreenshot().then(function (png) {
		browser.getCapabilities().then(function (capabilities) {
			var descriptions = util.gatherDescriptions(
					spec.suite
					, [spec.description]
				)

				, baseName = self.pathBuilder(
					spec
					, descriptions
					, results
					, capabilities
				)
				, metaData = self.metaDataBuilder(
					spec
					, descriptions
					, results
					, capabilities
				)

				, screenShotFile = baseName + '.png'
				, metaFile = baseName + '.json'
				, screenShotPath = path.join(self.baseDirectory, screenShotFile)
				, metaDataPath = path.join(self.baseDirectory, metaFile)

				// pathBuilder can return a subfoldered path too. So extract the
				// directory path without the baseName
				, directory = path.dirname(screenShotPath);

			metaData.screenShotFile = screenShotFile;
			mkdirp(directory, function(err) {
				if(err) {
					throw new Error('Could not create directory ' + directory);
				} else {
					util.addMetaData(metaData, metaDataPath, descriptions, self.finalOptions);
					if(!(self.takeScreenShotsOnlyForFailedSpecs && results.passed())) {
						util.storeScreenShot(png, screenShotPath);
					}
					util.storeMetaData(metaData, metaDataPath);
				}
			});
		});
	});

};

module.exports = ScreenshotReporter;<commit_msg>removing the console<commit_after>var util = require('./lib/util')
	, mkdirp = require('mkdirp')
	, _ = require('underscore')
	, path = require('path');

/** Function: defaultPathBuilder
 * This function builds paths for a screenshot file. It is appended to the
 * constructors base directory and gets prependend with `.png` or `.json` when
 * storing a screenshot or JSON meta data file.
 *
 * Parameters:
 *     (Object) spec - The spec currently reported
 *     (Array) descriptions - The specs and their parent suites descriptions
 *     (Object) result - The result object of the current test spec.
 *     (Object) capabilities - WebDrivers capabilities object containing
 *                             in-depth information about the Selenium node
 *                             which executed the test case.
 *
 * Returns:
 *     (String) containing the built path
 */
function defaultPathBuilder(spec, descriptions, results, capabilities) {
	return util.generateGuid();
}

/** Function: defaultMetaDataBuilder
 * Uses passed information to generate a meta data object which can be saved
 * along with a screenshot.
 * You do not have to add the screenshots file path since this will be appended
 * automatially.
 *
 * Parameters:
 *     (Object) spec - The spec currently reported
 *     (Array) descriptions - The specs and their parent suites descriptions
 *     (Object) result - The result object of the current test spec.
 *     (Object) capabilities - WebDrivers capabilities object containing
 *                             in-depth information about the Selenium node
 *                             which executed the test case.
 *
 * Returns:
 *     (Object) containig meta data to store along with a screenshot
 */
function defaultMetaDataBuilder(spec, descriptions, results, capabilities) {
	var metaData = {
			description: descriptions.join(' ')
			, passed: results.passed()
			, os: capabilities.caps_.platform
			, browser: {
				name: capabilities.caps_.browserName
				, version: capabilities.caps_.version
			}
		};
	if(results.items_.length > 0) {
		var result = results.items_[0];
		if(!results.passed()){
			var failedItem = _.where(results.items_,{passed_: false})[0];
			if(failedItem){
				metaData.message = failedItem.message || 'Failed';
				metaData.trace = failedItem.trace? (failedItem.trace.stack || 'No Stack trace information') : 'No Stack trace information';
			}

		}else{
			metaData.message = result.message || 'Passed';
			metaData.trace = result.trace.stack;
		}

	}

	return metaData;
}

/** Class: ScreenshotReporter
 * Creates a new screenshot reporter using the given `options` object.
 *
 * For more information, please look at the README.md file.
 *
 * Parameters:
 *     (Object) options - Object with options as described below.
 *
 * Possible options:
 *     (String) baseDirectory - The path to the directory where screenshots are
 *                              stored. If not existing, it gets created.
 *                              Mandatory.
 *     (Function) pathBuilder - A function which returns a path for a screenshot
 *                              to be stored. Optional.
 *     (Function) metaDataBuilder - Function which returns an object literal
 *                                  containing meta data to store along with
 *                                  the screenshot. Optional.
 *     (Boolean) takeScreenShotsForSkippedSpecs - Do you want to capture a
 *                                                screenshot for a skipped spec?
 *                                                Optional (default: false).
 */
function ScreenshotReporter(options) {
	options = options || {};
	if(!options.baseDirectory || options.baseDirectory.length === 0) {
		throw new Error('Please pass a valid base directory to store the ' +
			'screenshots into.');
	} else {
		this.baseDirectory = options.baseDirectory;
	}

	this.pathBuilder = options.pathBuilder || defaultPathBuilder;
	this.metaDataBuilder = options.metaDataBuilder || defaultMetaDataBuilder;
	this.takeScreenShotsForSkippedSpecs =
		options.takeScreenShotsForSkippedSpecs || false;
		this.takeScreenShotsOnlyForFailedSpecs =
 		options.takeScreenShotsOnlyForFailedSpecs || false;
 	this.finalOptions = {
 		takeScreenShotsOnlyForFailedSpecs: this.takeScreenShotsOnlyForFailedSpecs,
 		takeScreenShotsForSkippedSpecs: this.takeScreenShotsForSkippedSpecs,
 		metaDataBuilder: this.metaDataBuilder,
 		pathBuilder: this.pathBuilder,
 		baseDirectory: this.baseDirectory
 	};
}

/** Function: reportSpecResults
 * Called by Jasmine when reporteing results for a test spec. It triggers the
 * whole screenshot capture process and stores any relevant information.
 *
 * Parameters:
 *     (Object) spec - The test spec to report.
 */
ScreenshotReporter.prototype.reportSpecResults =
function reportSpecResults(spec) {
	/* global browser */
	var self = this
		, results = spec.results()

	if(!self.takeScreenShotsForSkippedSpecs && results.skipped) {
		return;
	}

	browser.takeScreenshot().then(function (png) {
		browser.getCapabilities().then(function (capabilities) {
			var descriptions = util.gatherDescriptions(
					spec.suite
					, [spec.description]
				)

				, baseName = self.pathBuilder(
					spec
					, descriptions
					, results
					, capabilities
				)
				, metaData = self.metaDataBuilder(
					spec
					, descriptions
					, results
					, capabilities
				)

				, screenShotFile = baseName + '.png'
				, metaFile = baseName + '.json'
				, screenShotPath = path.join(self.baseDirectory, screenShotFile)
				, metaDataPath = path.join(self.baseDirectory, metaFile)

				// pathBuilder can return a subfoldered path too. So extract the
				// directory path without the baseName
				, directory = path.dirname(screenShotPath);

			metaData.screenShotFile = screenShotFile;
			mkdirp(directory, function(err) {
				if(err) {
					throw new Error('Could not create directory ' + directory);
				} else {
					util.addMetaData(metaData, metaDataPath, descriptions, self.finalOptions);
					if(!(self.takeScreenShotsOnlyForFailedSpecs && results.passed())) {
						util.storeScreenShot(png, screenShotPath);
					}
					util.storeMetaData(metaData, metaDataPath);
				}
			});
		});
	});

};

module.exports = ScreenshotReporter;<|endoftext|>


<commit_before>var Botkit = require('botkit')
var http = require('http')

// Expect a SLACK_TOKEN environment variable

//
firebaseStorage = require('botkit-storage-firebase')({firebase_uri: 'https://demobot.firebaseIO.com'})
var controller = Botkit.slackbot({
    storage: firebaseStorage
});

//var controller = Botkit.slackbot()
var con = require('beepboop-botkit').start(controller)
//var kv = require('beepboop-persist')()

controller.hears(['hello', 'hi', 'hola'], ['direct_message'], function (bot, message) {
    bot.reply(message, 'Hello :wave:. ')
})

var persona = {id:"default", persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};

var morgan = require('morgan')

controller.setupWebserver(process.env.PORT,function(err,webserver) {
    controller.createWebhookEndpoints(webserver);
});

controller.on('slash_command', function (bot, message) {
    console.log('Here is the actual slash command used: ', message.command);
    var team_id  = message.team_id;
    loadPersonality(team_id, function () {

        if(message.command == '/learn'){
            var learn = message.text
            var man_say = learn.substr(0, learn.indexOf("\n")-1);
            var bot_say = learn.substr(learn.indexOf("\n")+1);
            man_say = man_say.toLowerCase().trim();
            bot_say = bot_say.trim();
            var  attachments = null;
            if(bot_say.indexOf('"attachments')>0){
                p_data = JSON.parse(bot_say);
                attachments = p_data["attachments"];
                bot_say  = "";
            }
            saving  = persona.id+'_voc/_'+man_say;
            console.log('Saving key, value: ', "["+saving+"],["+bot_say+"}", attachments );
            if(attachments != null){
                var learning = {id: saving, botsay: bot_say, attachments: attachments};
                controller.storage.teams.save(learning);
                bot.replyPrivate(message, 'When you say: '+man_say+' \n I will say: '+p_data)
            }else{
                var learning = {id: saving, botsay: bot_say};
                controller.storage.teams.save(learning);
                bot.replyPrivate(message, 'When you say: '+man_say+' \n I will say: '+bot_say)
            }

        }else if(message.command == '/new-persona'){

            var new_persona_id = message.text.toLowerCase().trim();
            controller.storage.teams.get(new_persona_id , function(err, val) {
                if(val != null){
                    bot.replyPrivate(message, 'I already have this persona');
                }else{
                    save_id = team_id+"_"+new_persona_id
                    new_persona = {id:save_id, persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};
                    controller.storage.teams.save(new_persona);

                    var current_persona = {id: team_id+"_"+'current_persona', data: new_persona};
                    controller.storage.teams.save(current_persona);

                    bot.replyPrivate(message, 'Created new persona - '+new_persona_id);
                }
            });

        }else if (message.command == '/load-persona'){
            var new_persona_id = message.text.toLowerCase().trim();
            load_id = team_id+"_"+new_persona_id
            controller.storage.teams.get(load_id , function(err, val) {
                if(val != null){
                    //console.log('loaded value, new_persona_id -', val, new_persona_id);
                    var current_persona = {id: team_id+"_"+'current_persona', data: val};
                    controller.storage.teams.save(current_persona);

                    bot.replyPrivate(message, 'Loaded new persona - '+val.id);
                }else{

                    // persona not found
                    bot.replyPrivate(message, 'I need my meds! could not find - '+new_persona_id);
                }
            });

        }else if (message.command == '/set-persona-name'){
            var new_persona_name = message.text.trim();
            controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
                if(val != null){
                    persona = val.data
                    val.data.persona_name = new_persona_name;
                    controller.storage.teams.save(val);
                    persona_id = val.data.id;
                    controller.storage.teams.get(persona_id, function(err, val1) {
                        if(val1 != null){
                            val1.persona_name = new_persona_name;
                            controller.storage.teams.save(val1);
                            bot.replyPrivate(message, 'From now on I shall be called Sir '+new_persona_name);

                        }
                    });
                }
            });

        }else if (message.command == '/set-persona-icon-url'){
            var new_persona_icon_url = message.text.trim();
            controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
                if(val != null){
                    persona = val.data
                    val.data.persona_icon = new_persona_icon_url;
                    controller.storage.teams.save(val);
                    persona_id = val.data.id;
                    controller.storage.teams.get(persona_id, function(err, val1) {
                        if(val1 != null){
                            val1.persona_icon = new_persona_icon_url;
                            controller.storage.teams.save(val1);
                            bot.replyPrivate(message, 'From now on I shall use a new icon - '+new_persona_icon_url);

                        }
                    });
                }
            });

        }else if (message.command == '/demo-setting'){
            var setting = message.text.trim();
            var key = setting.substring(0, setting.indexOf(" ")).trim();
            var value = setting.substring(setting.indexOf(" ")).trim();
            console.log('Saving key, value: ', "["+key+"],["+value+"]" );
            save_id = team_id+"_setting/"+key;
            new_persona = {id:save_id, value:value};
            controller.storage.teams.save(new_persona);
            bot.replyPublic(message, "");

        }else if (message.command == '/persona-set-notification'){

            var setting = message.text.trim();
            var key = setting.substring(0, setting.indexOf(" ")).trim();
            var interval = setting.substring(setting.indexOf(" "),setting.indexOf("\n")).trim();
            var bot_say = learn.substr(setting.indexOf("\n")+1);
            console.log('Saving notification key, interval, bot_say - ', "["+key+"],["+interval+"],["+bot_say+"]" );
            //save_id = team_id+"_notification/"+key;
            //new_persona = {id:save_id, value:value};
            //controller.storage.teams.save(new_persona);

            bot.replyPublic(message, "");

        }else{
            bot.replyPublic(message, "");

        }
    });

});

/*
beepboop.on('botkit.rtm.started', function (bot, resource, meta) {
    var slackUserId = resource.SlackUserID

    if (meta.isNew && slackUserId) {
        bot.api.im.open({ user: slackUserId }, function (err, response) {
            if (err) {
                return console.log(err)
            }
            var dmChannel = response.channel.id
            bot.say({channel: dmChannel, text: 'Thanks for adding me to your team!'})
            bot.say({channel: dmChannel, text: 'You can now /invite me to a channel, so that I can be of use to the team, or DM/@wordsbot me anytime!'})
        })
    }
})
*/

controller.on('bot_channel_join', function (bot, message) {
    bot.reply(message, "Hello team :wave: I am your WordsBot - give me a word and I will provide you with Definition and Synonyms. \n I support direct mentions and DMs, I will not read what is in this channel,  you will need to `@wordsbot: word-you-are-looking-for` me.")
})

controller.hears(['hello', 'hi'], ['direct_mention'], function (bot, message) {
    bot.reply(message, ':wave:')
})

controller.hears('meta-help', ['direct_message', 'direct_mention'], function (bot, message) {
    var help = 'I will respond to the following messages: \n' +
        '`DM` me with a word.\n' +
        '`@wordsbot:` with a word.\n' +
        '`/define` with a word (this way only you see the results).\n' +
        '`bot help` to see this again.'
    bot.reply(message, help)
})

controller.hears('.*', ['direct_message', 'direct_mention', 'ambient'], function (bot, message) {
    console.log('msg - ', message);
    var team_id = message.team;
    loadPersonality(team_id, function () {
        man_say = message.text.toLowerCase().trim();
        loading  = persona.id+'_voc/_'+man_say;
        console.log('Loading key: ', "["+loading+"]");

        controller.storage.teams.get(loading, function(err, val) {
            console.log("got value" , val)
            if(val == undefined){
                console.log('what should I say when you say "'+man_say+'"');
                if(message.event != "ambient"){
                    bot.reply(message, compose('what should I say when you say "'+man_say+'"? not sure... \n Please use /learn to teach me new tricks!', [] ));
                }
            }else{
                resp = val["botsay"].toString();
                var attach = val["attachments"];
                if(attach == undefined || attach == null){
                    attach = []
                }
                bot.reply(message, compose(resp, attach) )
            }
        });

    });

})

function compose(text, attachments){
    console.log('compose for persona ', persona);
    var reply_with_attachments = {
        'username': persona.persona_name ,
        'text': text,
        'attachments': attachments,
        'icon_url': persona.persona_icon
    }
    return reply_with_attachments;

}

function loadPersonality(team_id, callback) {
    console.log('loadPersonality ');
    controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
        if(val != null){
            persona = val.data
            console.log('calling callback', val.data);
            callback();
        }else{
            save_id = team_id+"_default"
            new_persona = {id:save_id, persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};
            controller.storage.teams.save(new_persona);
            var current_persona = {id: team_id+"_"+'current_persona', data: new_persona};
            controller.storage.teams.save(current_persona);
            persona = current_persona.data;
            callback();
        }
    });
}

function getRandomColor() {
    var letters = '0123456789ABCDEF'.split('');
    var color = '#';
    for (var i = 0; i < 6; i++ ) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}<commit_msg>small<commit_after>var Botkit = require('botkit')
var http = require('http')

// Expect a SLACK_TOKEN environment variable

//
firebaseStorage = require('botkit-storage-firebase')({firebase_uri: 'https://demobot.firebaseIO.com'})
var controller = Botkit.slackbot({
    storage: firebaseStorage
});

//var controller = Botkit.slackbot()
var con = require('beepboop-botkit').start(controller)
//var kv = require('beepboop-persist')()

controller.hears(['hello', 'hi', 'hola'], ['direct_message'], function (bot, message) {
    bot.reply(message, 'Hello :wave:. ')
})

var persona = {id:"default", persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};

var morgan = require('morgan')

controller.setupWebserver(process.env.PORT,function(err,webserver) {
    controller.createWebhookEndpoints(webserver);
});

controller.on('slash_command', function (bot, message) {
    console.log('Here is the actual slash command used: ', message.command);
    var team_id  = message.team_id;
    loadPersonality(team_id, function () {

        if(message.command == '/learn'){
            var learn = message.text
            var man_say = learn.substr(0, learn.indexOf("\n")-1);
            var bot_say = learn.substr(learn.indexOf("\n")+1);
            man_say = man_say.toLowerCase().trim();
            bot_say = bot_say.trim();
            var  attachments = null;
            if(bot_say.indexOf('"attachments')>0){
                p_data = JSON.parse(bot_say);
                attachments = p_data["attachments"];
                bot_say  = "";
            }
            saving  = persona.id+'_voc/_'+man_say;
            console.log('Saving key, value: ', "["+saving+"],["+bot_say+"}", attachments );
            if(attachments != null){
                var learning = {id: saving, botsay: bot_say, attachments: attachments};
                controller.storage.teams.save(learning);
                bot.replyPrivate(message, 'When you say: '+man_say+' \n I will say: '+p_data)
            }else{
                var learning = {id: saving, botsay: bot_say};
                controller.storage.teams.save(learning);
                bot.replyPrivate(message, 'When you say: '+man_say+' \n I will say: '+bot_say)
            }

        }else if(message.command == '/new-persona'){

            var new_persona_id = message.text.toLowerCase().trim();
            controller.storage.teams.get(new_persona_id , function(err, val) {
                if(val != null){
                    bot.replyPrivate(message, 'I already have this persona');
                }else{
                    save_id = team_id+"_"+new_persona_id
                    new_persona = {id:save_id, persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};
                    controller.storage.teams.save(new_persona);

                    var current_persona = {id: team_id+"_"+'current_persona', data: new_persona};
                    controller.storage.teams.save(current_persona);

                    bot.replyPrivate(message, 'Created new persona - '+new_persona_id);
                }
            });

        }else if (message.command == '/load-persona'){
            var new_persona_id = message.text.toLowerCase().trim();
            load_id = team_id+"_"+new_persona_id
            controller.storage.teams.get(load_id , function(err, val) {
                if(val != null){
                    //console.log('loaded value, new_persona_id -', val, new_persona_id);
                    var current_persona = {id: team_id+"_"+'current_persona', data: val};
                    controller.storage.teams.save(current_persona);

                    bot.replyPrivate(message, 'Loaded new persona - '+val.id);
                }else{

                    // persona not found
                    bot.replyPrivate(message, 'I need my meds! could not find - '+new_persona_id);
                }
            });

        }else if (message.command == '/set-persona-name'){
            var new_persona_name = message.text.trim();
            controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
                if(val != null){
                    persona = val.data
                    val.data.persona_name = new_persona_name;
                    controller.storage.teams.save(val);
                    persona_id = val.data.id;
                    controller.storage.teams.get(persona_id, function(err, val1) {
                        if(val1 != null){
                            val1.persona_name = new_persona_name;
                            controller.storage.teams.save(val1);
                            bot.replyPrivate(message, 'From now on I shall be called Sir '+new_persona_name);

                        }
                    });
                }
            });

        }else if (message.command == '/set-persona-icon-url'){
            var new_persona_icon_url = message.text.trim();
            controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
                if(val != null){
                    persona = val.data
                    val.data.persona_icon = new_persona_icon_url;
                    controller.storage.teams.save(val);
                    persona_id = val.data.id;
                    controller.storage.teams.get(persona_id, function(err, val1) {
                        if(val1 != null){
                            val1.persona_icon = new_persona_icon_url;
                            controller.storage.teams.save(val1);
                            bot.replyPrivate(message, 'From now on I shall use a new icon - '+new_persona_icon_url);

                        }
                    });
                }
            });

        }else if (message.command == '/demo-setting'){
            var setting = message.text.trim();
            var key = setting.substring(0, setting.indexOf(" ")).trim();
            var value = setting.substring(setting.indexOf(" ")).trim();
            console.log('Saving key, value: ', "["+key+"],["+value+"]" );
            save_id = team_id+"_setting/"+key;
            new_persona = {id:save_id, value:value};
            controller.storage.teams.save(new_persona);
            bot.replyPublic(message, "");

        }else if (message.command == '/persona-set-notification'){

            var setting = message.text.trim();
            var key = setting.substring(0, setting.indexOf(" ")).trim();
            var interval = setting.substring(setting.indexOf(" "),setting.indexOf("\n")).trim();
            var bot_say = learn.substr(setting.indexOf("\n")+1);
            console.log('Saving notification key, interval, bot_say - ', "["+key+"],["+interval+"],["+bot_say+"]" );
            //save_id = team_id+"_notification/"+key;
            //new_persona = {id:save_id, value:value};
            //controller.storage.teams.save(new_persona);

            bot.replyPublic(message, "");

        }else{
            bot.replyPublic(message, "");

        }
    });

});

/*
beepboop.on('botkit.rtm.started', function (bot, resource, meta) {
    var slackUserId = resource.SlackUserID

    if (meta.isNew && slackUserId) {
        bot.api.im.open({ user: slackUserId }, function (err, response) {
            if (err) {
                return console.log(err)
            }
            var dmChannel = response.channel.id
            bot.say({channel: dmChannel, text: 'Thanks for adding me to your team!'})
            bot.say({channel: dmChannel, text: 'You can now /invite me to a channel, so that I can be of use to the team, or DM/@wordsbot me anytime!'})
        })
    }
})
*/

controller.on('bot_channel_join', function (bot, message) {
    bot.reply(message, "Hello team :wave: I am your WordsBot - give me a word and I will provide you with Definition and Synonyms. \n I support direct mentions and DMs, I will not read what is in this channel,  you will need to `@wordsbot: word-you-are-looking-for` me.")
})

controller.hears(['hello', 'hi'], ['direct_mention'], function (bot, message) {
    bot.reply(message, ':wave:')
})

controller.hears('meta-help', ['direct_message', 'direct_mention'], function (bot, message) {
    var help = 'I will respond to the following messages: \n' +
        '`DM` me with a word.\n' +
        '`@wordsbot:` with a word.\n' +
        '`/define` with a word (this way only you see the results).\n' +
        '`bot help` to see this again.'
    bot.reply(message, help)
})

controller.hears('.*', ['direct_message', 'direct_mention', 'ambient'], function (bot, message) {
    console.log('msg - ', message);
    var team_id = message.team;
    loadPersonality(team_id, function () {
        man_say = message.text.toLowerCase().trim();
        loading  = persona.id+'_voc/_'+man_say;
        console.log('Loading key: ', "["+loading+"]");

        controller.storage.teams.get(loading, function(err, val) {
            console.log("got value" , val)
            if(val == undefined){
                console.log('what should I say when you say "'+man_say+'"');
                if(message.event != "ambient"){
                    bot.reply(message, compose('what should I say when you say "'+man_say+'"? not sure... \n Please use /learn to teach me new tricks!', [] ));
                }
            }else{
                resp = val["botsay"].toString();
                var attach = val["attachments"];
                if(attach == undefined || attach == null){
                    attach = []
                }
                bot.reply(message, compose(resp, attach) )
            }
        });

    });

})

function compose(text, attachments){
    console.log('compose for persona ', persona);
    var reply_with_attachments = {
        'username': persona.persona_name ,
        'text': text,
        'attachments': attachments,
        'icon_url': persona.persona_icon
    }
    return reply_with_attachments;

}

function loadPersonality(team_id, callback) {
    console.log('loadPersonality ');
    controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
        if(val != null){
            persona = val.data
            console.log('calling callback', val.data);
            callback();
        }else{
            save_id = team_id+"_default"
            new_persona = {id:save_id, persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};
            controller.storage.teams.save(new_persona);
            var current_persona = {id: team_id+"_"+'current_persona', data: new_persona};
            controller.storage.teams.save(current_persona);
            persona = current_persona.data;
            callback();
        }
    });
}

function getRandomColor() {
    var letters = '0123456789ABCDEF'.split('');
    var color = '#';
    for (var i = 0; i < 6; i++ ) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}<|endoftext|>


<commit_before>#! /usr/bin/env node

"use strict";

const express = require('express'),
      bodyParser = require('body-parser'),
      Bolt = require('misfit-bolt'),
      debug = require('debug')(require('./package').name),
      argv = require('minimist')(process.argv.slice(2)),
      util = require('./lib/util'),
      ucfirst = util.ucfirst,
      assert = util.assert,
      errorHandler = util.errorHandler,
      responseHandler = util.responseHandler,
      errors = require('./lib/errors'),
      NotFound = errors.NotFound,
      BadRequest = errors.BadRequest,
      ServerError = errors.ServerError;

const app = express(),
      port = parseInt(argv.p, 10) || 3000,
      actions = ['state', 'hue', 'saturation', 'brightness'];

app.use(bodyParser.json());
app.listen(port, () => { console.log(`listening on port ${port}`); });

app.get('/', (req, res) => {
  const bolts = Bolt.bolts.map((bolt) => {
    return {
      id: bolt.id,
      connected: bolt.connected
    };
  });
  res.send({bolts});
});

actions.forEach((name) => {

  app.get(`/:id/${name}`, (req, res) => {

    try {
      const method = `get${ucfirst(name)}`,
          id = req.params.id,
          bolt = Bolt.get(id);
      assert(bolt, NotFound, `cannot find Bolt with id ${id}`);

      debug(`${method} called for ${id}`);
      bolt.connect(() => {
        bolt[method]((err, value) => {
          debug(`${method} returned value: ${value}`);
          responseHandler(res, name, value);
        });
      });
    } catch (err) {
      debug(`error ${err}`);
      errorHandler(err, res);
    }

  });

  app.put(`/:id/${name}`, (req, res) => {

    try {
      const method = `set${ucfirst(name)}`,
            id = req.params.id,
            bolt = Bolt.get(id);
      assert(bolt, NotFound, `cannot find Bolt with id ${id}`);
      assert(req.body && req.body[name], BadRequest, `missing value for ${name}`);

      const value = req.body[name];
      debug(`${method} called for ${id} with ${value}`);
      bolt.connect(() => {
        bolt[method](value, (err) => {
          responseHandler(res, name, value);
        });
      });
    } catch (err) {
      debug(`error ${err.status}, ${err.message}`);
      errorHandler(err, res);
    }

  });

});

Bolt.discover();
<commit_msg>Do not treat false property as bad request.<commit_after>#! /usr/bin/env node

"use strict";

const express = require('express'),
      bodyParser = require('body-parser'),
      Bolt = require('misfit-bolt'),
      debug = require('debug')(require('./package').name),
      argv = require('minimist')(process.argv.slice(2)),
      util = require('./lib/util'),
      ucfirst = util.ucfirst,
      assert = util.assert,
      errorHandler = util.errorHandler,
      responseHandler = util.responseHandler,
      errors = require('./lib/errors'),
      NotFound = errors.NotFound,
      BadRequest = errors.BadRequest,
      ServerError = errors.ServerError;

const app = express(),
      port = parseInt(argv.p, 10) || 3000,
      actions = ['state', 'hue', 'saturation', 'brightness'];

app.use(bodyParser.json());
app.listen(port, () => { console.log(`listening on port ${port}`); });

app.get('/', (req, res) => {
  const bolts = Bolt.bolts.map((bolt) => {
    return {
      id: bolt.id,
      connected: bolt.connected
    };
  });
  res.send({bolts});
});

actions.forEach((name) => {

  app.get(`/:id/${name}`, (req, res) => {

    try {
      const method = `get${ucfirst(name)}`,
          id = req.params.id,
          bolt = Bolt.get(id);
      assert(bolt, NotFound, `cannot find Bolt with id ${id}`);

      debug(`${method} called for ${id}`);
      bolt.connect(() => {
        bolt[method]((err, value) => {
          debug(`${method} returned value: ${value}`);
          responseHandler(res, name, value);
        });
      });
    } catch (err) {
      debug(`error ${err}`);
      errorHandler(err, res);
    }

  });

  app.put(`/:id/${name}`, (req, res) => {

    try {
      const method = `set${ucfirst(name)}`,
            id = req.params.id,
            bolt = Bolt.get(id);
      assert(bolt, NotFound, `cannot find Bolt with id ${id}`);
      assert(req.body && req.body[name] !== undefined, BadRequest, `missing value for ${name}`);

      const value = req.body[name];
      debug(`${method} called for ${id} with ${value}`);
      bolt.connect(() => {
        bolt[method](value, (err) => {
          responseHandler(res, name, value);
        });
      });
    } catch (err) {
      debug(`error ${err.status}, ${err.message}`);
      errorHandler(err, res);
    }

  });

});

Bolt.discover();
<|endoftext|>