Slide 1

Slide 1 text

HUBOT img me woman laughing alone with salad

Slide 2

Slide 2 text

developer and support

Slide 3

Slide 3 text

Hoyt @jonmagic http://theprogrammingbutler . com https://github . com/jonmagic

Slide 4

Slide 4 text

Internal Logic External Services Robot Butler

Slide 5

Slide 5 text

Robot Butler

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

hubot puggle bomb

Slide 8

Slide 8 text

hubot graph me -2d fs

Slide 9

Slide 9 text

git push

Slide 10

Slide 10 text

http://hubot-script-catalog.herokuapp.com hubot-script-catalog

Slide 11

Slide 11 text

hubot-scripts http://github.com/github/hubot-scripts/pulls

Slide 12

Slide 12 text

module.exports = (robot) -> robot.respond /good morning/i, (msg) -> msg.send "Good morning to you." jonmagic> hubot good morning hubot> Good morning to you. Respond & Send

Slide 13

Slide 13 text

Regular Expressions

Slide 14

Slide 14 text

module.exports = (robot) -> robot.hear /gasoline/i, (msg) -> msg.reply "Here we call it petrol." jonmagic> Jon, did you get gasoline yet? hubot> Hoyt: Here we call it petrol. Hear & Reply

Slide 15

Slide 15 text

Internal Logic

Slide 16

Slide 16 text

module.exports = (robot) -> robot.respond /good morning/i, (msg) -> msg.send "Good morning to you." common.js module specification

Slide 17

Slide 17 text

# Public: Loads a file in path # # path - A String path on the filesystem. # file - A String filename in path on the filesystem. # # Returns nothing. loadFile: (path, file) -> ext = Path.extname file full = Path.join path, Path.basename(file, ext) if ext is '.coffee' or ext is '.js' try require(full) @ @parseHelp "#{path}/#{file}" catch err @logger.error "#{err}" src/robot.coffee

Slide 18

Slide 18 text

Options = path: "." name: "Hubot" create: false adapter: "shell" alias: false enableHttpd: true ... robot = Hubot.loadBot options... ... robot.run ~/hubot-demo $ ./bin/hubot --name Jeeves ./bin/hubot

Slide 19

Slide 19 text

exports.loadBot = (adapterPath...) -> robot = require './src/robot' new robot adapterPath, adapterName... index.coffee

Slide 20

Slide 20 text

class Robot hear: (regex, callback) -> ... respond: (regex, callback) -> ... send: (user, strings...) -> ... reply: (user, strings...) -> ... http: (url) -> ... src/robot.coffee

Slide 21

Slide 21 text

hear: (regex, callback) -> @listeners.push new TextListener(@, regex, callback) class TextListener extends Listener constructor: (@robot, @regex, @callback) -> @matcher = (message) => if message instanceof Robot.TextMessage message.match @regex class Listener call: (message) -> if match = @matcher message @callback new @robot.Response(@robot, message, match) true else false src/robot.coffee

Slide 22

Slide 22 text

respond: (regex, callback) -> re = regex.toString().split("/") re.shift() # remove empty first item modifiers = re.pop() # pop off modifiers ... pattern = re.join("/") # combine the pattern back again if @alias alias = @alias.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") newRegex = new RegExp("^(?:#{alias}[:,]?|#{@name}[:,]?) ... ", mod...) else newRegex = new RegExp("^#{@name}[:,]?\\s*(?:#{pattern})", mod...) @logger.debug newRegex.toString() @listeners.push new TextListener(@, newRegex, callback) src/robot.coffee

Slide 23

Slide 23 text

send: (strings...) -> @robot.adapter.send @message.user, strings... send: (user, strings...) -> if strings.length > 0 @bot.Room(user.room).speak strings.shift(), (err, data) => @robot.logger.error "Campfire error: #{err}" if err? @send user, strings... src/robot.coffee src/adapters/campfire.coffee

Slide 24

Slide 24 text

reply: (strings...) -> @robot.adapter.reply @message.user, strings... reply: (user, strings...) -> @send user, strings.map((str) -> "#{user.name}: #{str}")... src/robot.coffee src/adapters/campfire.coffee

Slide 25

Slide 25 text

http: (url) -> @httpClient.create(url) class ScopedClient constructor: (url, options) -> @options = @buildOptions url, options exports.create = (url, options) -> new ScopedClient url, options src/robot.coffee node-scoped-http-client https://github.com/technoweenie/node-scoped-http-client

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

Image Search

Slide 28

Slide 28 text

Maps & Geo

Slide 29

Slide 29 text

Definitions

Slide 30

Slide 30 text

Messaging

Slide 31

Slide 31 text

Meme Generators

Slide 32

Slide 32 text

dnsimple.com

Slide 33

Slide 33 text

GitHub Issues

Slide 34

Slide 34 text

module.exports = (robot) -> robot.respond /(image|img)( me)? (.*)/i, (msg) -> imageMe msg, msg.match[3], (url) -> msg.send url imageMe = (msg, query, cb) -> msg.http('http://ajax.googleapis.com/ajax/...') .query(v: "1.0", rsz: '8', q: query) .get() (err, res, body) -> images = JSON.parse(body) images = images.responseData.results if images.length > 0 image = msg.random images cb "#{image.unescapedUrl}#.png" google-images.coffee

Slide 35

Slide 35 text

module.exports = (robot) -> robot.hear /check domain (.*)/i, (msg) -> domain = escape(msg.match[1]) user = process.env.DNSIMPLE_USERNAME pass = process.env.DNSIMPLE_PASSWORD auth = 'Basic ' + new Buffer(user + ':' + pass).toString('base64'); msg.http("https://dnsimple.com/domains/#{domain}/check") .headers(Authorization: auth, Accept: 'application/json') .get() (err, res, body) -> switch res.statusCode when 200 msg.send "Sorry, #{domain} is not available." when 404 msg.send "Cybersquat that shit!" when 401 msg.send "You need to authenticate by ..." dnsimple.coffee

Slide 36

Slide 36 text

module.exports = (robot) -> robot.respond /salesforce query (.*)$/i, (msg) -> query = msg.match[1] msg.http(auth_url).post() (err, res, body) -> oath_token = JSON.parse(body).access_token query = encodeURIComponent(query) msg.http(query_url + query) .headers(Authorization: "OAuth #{oath_token}") .get() (err, res, body) -> if err msg.send "Salesforce says: #{err}" return salesforce.coffee

Slide 37

Slide 37 text

Takeout (take-away)

Slide 38

Slide 38 text

Note: http://www.kayak.com/terms-of-use Airfares?

Slide 39

Slide 39 text

http://github.com/jonmagic/fareme Middleware

Slide 40

Slide 40 text

https://gist.github.com/215b0989b23e3b01fe6f Finally the Script

Slide 41

Slide 41 text

hubot fare me ord to den may 15 to may 20

Slide 42

Slide 42 text

No API? Build one.

Slide 43

Slide 43 text

BeagleBone

Slide 44

Slide 44 text

sys = require('sys') exec = require('child_process').exec; express = require 'express' app = module.exports = express.createServer() app.get "/door", (req, res) -> # unlock the door exec "echo 38 > /sys/class/gpio/export" exec "echo out > /sys/class/gpio/gpio38/direction" exec "echo 1 > /sys/class/gpio/gpio38/value" sleep 2000 # lock the door and cleanup exec "echo 1 > /sys/class/gpio/gpio38/value" exec "echo 38 > /sys/class/gpio/unexport" res.send "Unlocked the door for you :)" Unlocking a door becomes easy

Slide 45

Slide 45 text

Robot Butler - do our bidding Internal Logic - easy to grok External Services - change the world Other Resources - http://hubot-factory.herokuapp.com - https://github.com/tombell/learnhubotthehardway

Slide 46

Slide 46 text

@jonmagic http://theprogrammingbutler . com https://github . com/jonmagic HUBOT img me woman laughing alone with salad