diff options
author | Trygve Laugstøl <trygvis@inamo.no> | 2012-06-01 19:29:08 +0200 |
---|---|---|
committer | Trygve Laugstøl <trygvis@inamo.no> | 2012-06-01 19:29:08 +0200 |
commit | a105b34ab53963ab651810f33caa2ee51869b1c7 (patch) | |
tree | be49b089e1d4a81d6b327c6370afcc14c60ac865 | |
download | dynobot-irc-a105b34ab53963ab651810f33caa2ee51869b1c7.tar.gz dynobot-irc-a105b34ab53963ab651810f33caa2ee51869b1c7.tar.bz2 dynobot-irc-a105b34ab53963ab651810f33caa2ee51869b1c7.tar.xz dynobot-irc-a105b34ab53963ab651810f33caa2ee51869b1c7.zip |
o Initial import.
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | lib/arktekk-bot.js | 165 | ||||
-rw-r--r-- | lib/irc.js | 12 | ||||
-rw-r--r-- | main.js | 75 | ||||
-rw-r--r-- | package.json | 36 | ||||
-rw-r--r-- | test/feed.xml | 297 | ||||
-rw-r--r-- | test/irc.test.js | 11 |
8 files changed, 604 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..eb73cae --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +PATH := $(PATH):node_modules/.bin +all: test + +test: + mocha test/*.test.js + +.PHONY: all test diff --git a/lib/arktekk-bot.js b/lib/arktekk-bot.js new file mode 100644 index 0000000..3a00c7f --- /dev/null +++ b/lib/arktekk-bot.js @@ -0,0 +1,165 @@ +/* + * Possible strategies for updating the topic: + * + * o Set the topic unconditionally when the feed changes. This makes + * it possible for users to change the topic and it won't be + * overridden until the feed changes. + * + * o Set the topic on any topic change (making the feed control the + * entire topic) + * + * o Support a delimiter so it can control only a part of the topic, + * like "<>". Example + * + * Next meeting, sat 1900 <> DATA FROM FEED. + * + * A regexp selecting the are to be updated might conver it. + * + * o If the bot changed the topic the last time, it's probably safe to + * just update it. + */ + +var node_irc = require('../node_modules/node-irc/IRC.js') + , cron = require('cron').CronJob + , parser = require('blindparser') + , events = require('events') + , _ = require('underscore'); + +var parserOptions = {}; + +var config; +var cronJobs = []; + +var state = { + channelTopic: undefined, + irc: undefined, + updatingFeed: false, + feeds: [], + newest: { + timestamp: 0, + text: undefined + } +}; +module.exports.state = state; + +var eventEmitter = new events.EventEmitter; + +function startIrc() { + irc = new node_irc.IRC(config.host, config.port); + irc.on('raw', function(data) { console.log(data) }); + irc.on('connected', function(server) { + console.log('Connected to ' + server); + irc.join(config.channel, function(error) { + irc.notice(config.channel, 'well hello yall'); + }); + }); + irc.topic = function(channel, topic) { + irc._socket.write('topic ' + channel + ' :' + topic + '\r\n'); + }; + + irc.on('topic', function(channel, topic) { + console.log("new topic: " + topic); + /* If we're not storing this, it is possible for people to set + * the topic after the bot has set it and it will persist (until + * next update from the feed). + topic = t; + */ + + state.channelTopic = topic; + }); +} + +function updateFeed(feedState) { + console.log("Fetching " + feedState.url); + if(feedState.updatingFeed) + console.log("Already working"); + feedState.updatingFeed = true; + + parser.parseURL(feedState.url, parserOptions, function(err, feed) { +// console.log("Fetched " + feedState.url + ", status=" + (err ? "failure" : "success")); + if(err) { + console.log(err); + return; + } + var newest = processFeed(feed); + if(typeof newest == "object") { + eventEmitter.emit("feedChanged", feedState.url, newest); + } + feedState.updatingFeed = false; + }); +} + +function processFeed(feed) { + // Extracts the username from the feed. + // TODO: Use something better than blindparser to parse atom so that + // each entry has an author too to get the full name. + if(typeof feed.items[0] == "undefined") { + console.log("feed does not contain any items", feed); + return undefined; + } + var match = /^http:\/\/twitter.com\/([a-zA-Z0-9_]+)\/.*$/.exec(feed.items[0].link) + if(match.length != 2) { + return undefined; + } + return { + text: feed.items[0].title, + author: match[1], + timestamp: feed.items[0].date + }; +} +module.exports.processFeed = processFeed; + +eventEmitter.on("feedChanged", function(url, newest) { + state.feeds[url] = newest; + + if(state.newest.timestamp >= newest.timestamp) { +// console.log("oold: " + newest.text); + return; + } + + var text = newest.author + ": " + newest.text; + console.log("New topic", newest.timestamp, url, text); + state.newest = newest; + if(config.connect && state.topic != text) { + irc.topic(config.channel, text); + } +}); + +eventEmitter.on("configUpdated", function(c) { + setup(); +}); + +function setup() { + console.log("Stopping " + cronJobs.length + " cron jobs"); + _.each(cronJobs, function(job) { job.stop(); }); + cronJobs = []; + _.each(config.feeds, function(feed) { + var state = { + url: feed, + updatingFeed: false, + last: undefined + }; + var job = new cron("*/10 * * * *", function() { + updateFeed(state); + }, function() {}, true); + cronJobs.push(job); + }); +} + +function start(c) { + config = c; + startIrc(); + setup(); + if(config.connect) { + console.log('Connecting to ' + config.host + ':' + config.port); + irc.connect(config.nick); + } else { + console.log('Not connecting to IRC'); + } +} + +module.exports.start = start; + +module.exports.emit = function(config) { + eventEmitter.emit("configUpdated", config); +} diff --git a/lib/irc.js b/lib/irc.js new file mode 100644 index 0000000..935d2b3 --- /dev/null +++ b/lib/irc.js @@ -0,0 +1,12 @@ +module.exports.nickGenerator = function(nick) { + var nickCount = 0; + var nickAdditions = [ '', '^', '-', '_', '\\', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; + + return function() { + if (nickCount == nickAdditions.length) { + nickCount = 0; + } + + return nick + nickAdditions[nickCount++]; + } +} @@ -0,0 +1,75 @@ +var cmdopt = require('cmdopt') + , os = require('os') + , repl = require('repl') + , _ = require('underscore'); + +var parser = new cmdopt.Parser(); +parser.option("-h, --help", "show help"); +parser.option("-c, --channel=CHANNEL", "IRC channel to join"); +parser.option("-n, --nick=NICK", "Nickname of the bot"); +parser.option("--connect=[yes,no]", "Should the bot connect to IRC").action(function(opts, val) { + opts.connect = val === "yes" +}); +parser.option("--feed=FEED", "A feed to watch").action(function(opts, val) { + if (!opts.feeds) + opts.feeds = []; + opts.feeds.push(val); +}); + +var args = process.argv.slice(2); +var defaults = { + channel: "#hoonk", + feeds: [ +// "http://search.twitter.com/search.atom?q=arktekk", +// "http://search.twitter.com/search.atom?q=from:AgileBorat" +// "http://search.twitter.com/search.atom?q=from:KongenDin" +// "http://search.twitter.com/search.atom?q=from:NestenSivJensen" + "http://search.twitter.com/search.atom?q=awesome", + "http://search.twitter.com/search.atom?q=eurovision", + ], + nick: os.hostname(), + host: "gibson.freenode.net", + port: 6667, + connect: true +}; + +var bots = [{ + name: 'arktekk', + js: './lib/arktekk-bot.js' +}]; + +try { + var config = parser.parse(args); + config = _.defaults(config, defaults); + if (config.help) { + console.log(parser.help()); + console.log("Config:"); + console.log(config); + return; + } + + _.each(bots, function(bot) { + var instance = require(bot.js) + instance.start(config); + bot.instance = instance; + }); + var r = repl.start('irc> '); + r.context.bots = bots; + r.context.config = JSON.parse(JSON.stringify(config)); + // TODO: Make the config per-plugin. + r.context.setConfig = function(c) { + // TODO: store configuration + console.log("Setting config"); +// console.log(c); + _.each(bots, function(bot) { bot.instance.emit("configUpdated", config); }); + config = c; + r.context.config = JSON.parse(JSON.stringify(c)); + return "Config updated"; + } +} catch (ex) { + if (ex instanceof cmdopt.ParseError) { + process.stderr.write(ex.message + "\n"); + process.exit(1); + } + throw ex; +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d45104d --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "author": { + "name": "Trygve Laugstøl", + "email": "trygvis@inamo.no", + "url": "https://github.com/trygvis" + }, + "name": "bitraf-irc-client", + "description": "Bitraf's IRC client", + "keywords": [ + "irc", + "chat" + ], + "version": "0.0.1", + "main": "main.js", + "engines": { + "node": ">=0.4.7" + }, + "dependencies": { + "blindparser": "0.0.13" + "cmdopt": "0.2.0", + "cron": "~0.3.2", + "date": "1.0.2", + "getit": "~0.1.7", + "mocha": "~1.0.3", + "node-irc": "https://github.com/einaros/node-irc/tarball/master", + "underscore": "1.3.3", + }, + "devDependencies": {}, + "optionalDependencies": {}, + "licenses": [ + { + "type": "Apache Software License, version 2", + "url": "http://apache.org/licenses/LICENSE-2.0" + } + ] +} diff --git a/test/feed.xml b/test/feed.xml new file mode 100644 index 0000000..113c438 --- /dev/null +++ b/test/feed.xml @@ -0,0 +1,297 @@ +<?xml version="1.0" encoding="UTF-8"?> +<feed xmlns:google="http://base.google.com/ns/1.0" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns="http://www.w3.org/2005/Atom" xmlns:twitter="http://api.twitter.com/" xmlns:georss="http://www.georss.org/georss" xml:lang="en-US"> + <id>tag:search.twitter.com,2005:search/from:AgileBorat OR from:KongenDin</id> + <link type="text/html" href="http://search.twitter.com/search?q=from%3AAgileBorat+OR+from%3AKongenDin" rel="alternate"/> + <link type="application/atom+xml" href="http://search.twitter.com/search.atom?q=from%3AAgileBorat+OR+from%3AKongenDin" rel="self"/> + <title>from:AgileBorat OR from:KongenDin - Twitter Search</title> + <link type="application/opensearchdescription+xml" href="http://twitter.com/opensearch.xml" rel="search"/> + <link type="application/atom+xml" href="http://search.twitter.com/search.atom?since_id=206355859759046656&q=from%3AAgileBorat%20OR%20from%3AKongenDin" rel="refresh"/> + <updated>2012-05-26T12:07:25Z</updated> + <openSearch:itemsPerPage>15</openSearch:itemsPerPage> + <link type="application/atom+xml" href="http://search.twitter.com/search.atom?page=2&max_id=206355859759046656&q=from%3AAgileBorat%20OR%20from%3AKongenDin" rel="next"/> + <entry> + <id>tag:search.twitter.com,2005:206355859759046656</id> + <published>2012-05-26T12:07:25Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/206355859759046656" rel="alternate"/> + <title>i dag skal jeg ikke kjøpe noe som det ikke står "tutti frutti" på</title> + <content type="html">i dag skal jeg ikke kjøpe noe som det ikke står "tutti frutti" på</content> + <updated>2012-05-26T12:07:25Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>no</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:206304970952278017</id> + <published>2012-05-26T08:45:12Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/206304970952278017" rel="alternate"/> + <title>klarer aldri å huske hvem som er knoll og hvem som er tott, men det er ikke akkurat noe stort problem</title> + <content type="html">klarer aldri å huske hvem som er knoll og hvem som er tott, men det er ikke akkurat noe stort problem</content> + <updated>2012-05-26T08:45:12Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>no</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:206274812157505537</id> + <published>2012-05-26T06:45:22Z</published> + <link type="text/html" href="http://twitter.com/AgileBorat/statuses/206274812157505537" rel="alternate"/> + <title>Svetlana is offer to explain term of "counter rucking". But Azamat is quite sure she is only hear wrong.</title> + <content type="html">Svetlana is offer to explain term of "counter rucking". But Azamat is quite sure she is only hear wrong.</content> + <updated>2012-05-26T06:45:22Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1327024640/borat_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a></twitter:source> + <twitter:lang>en</twitter:lang> + <author> + <name>AgileBorat (Agile Borat)</name> + <uri>http://twitter.com/AgileBorat</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:206273546287194112</id> + <published>2012-05-26T06:40:20Z</published> + <link type="text/html" href="http://twitter.com/AgileBorat/statuses/206273546287194112" rel="alternate"/> + <title>Vlad is introduce more of rugby term in Scrum team. But is not sure of how do proper "counter rucking".</title> + <content type="html">Vlad is introduce more of rugby term in Scrum team. But is not sure of how do proper "counter rucking".</content> + <updated>2012-05-26T06:40:20Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1327024640/borat_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a></twitter:source> + <twitter:lang>en</twitter:lang> + <author> + <name>AgileBorat (Agile Borat)</name> + <uri>http://twitter.com/AgileBorat</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:206050172109721600</id> + <published>2012-05-25T15:52:43Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/206050172109721600" rel="alternate"/> + <title>de spanske s-ene er så vriene at jeg sier bare Barfelona jeg</title> + <content type="html">de spanske s-ene er så vriene at jeg sier bare Barfelona jeg</content> + <updated>2012-05-25T15:52:43Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>da</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:206012501576523778</id> + <published>2012-05-25T13:23:02Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/206012501576523778" rel="alternate"/> + <title>kongen befaler at man kan ha pinseegg i pinsen. De ligner på påskeegg, men er større.</title> + <content type="html">kongen befaler at man kan ha pinseegg i pinsen. De ligner på påskeegg, men er større.</content> + <updated>2012-05-25T13:23:02Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>no</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:205652909323591682</id> + <published>2012-05-24T13:34:09Z</published> + <link type="text/html" href="http://twitter.com/AgileBorat/statuses/205652909323591682" rel="alternate"/> + <title>Vlad is introduce more of rugby term in Scrum team. When Azamat is do "dump tackle", database is stay dumped! Is nice.</title> + <content type="html">Vlad is introduce more of rugby term in Scrum team. When Azamat is do "dump tackle", database is stay dumped! Is nice.</content> + <updated>2012-05-24T13:34:09Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1327024640/borat_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a></twitter:source> + <twitter:lang>en</twitter:lang> + <author> + <name>AgileBorat (Agile Borat)</name> + <uri>http://twitter.com/AgileBorat</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:205627784033345536</id> + <published>2012-05-24T11:54:18Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/205627784033345536" rel="alternate"/> + <title>jeg har blitt rød i nakken!!! Har antagelig fått jentelus.</title> + <content type="html">jeg har blitt rød i nakken!!! Har antagelig fått jentelus.</content> + <updated>2012-05-24T11:54:18Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>no</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:205584907840393216</id> + <published>2012-05-24T09:03:56Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/205584907840393216" rel="alternate"/> + <title>hold båtisene deres unna badekaret. de kantrer veldig lett.</title> + <content type="html">hold båtisene deres unna badekaret. de kantrer veldig lett.</content> + <updated>2012-05-24T09:03:56Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>no</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:205397941488336896</id> + <published>2012-05-23T20:41:00Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/205397941488336896" rel="alternate"/> + <title>ett sted går grensen, og denne "Biber" er på feil side av den. HVis dere vil se 18-åringer spankulere kan dere nøye dere med garden!!</title> + <content type="html">ett sted går grensen, og denne "Biber" er på feil side av den. HVis dere vil se 18-åringer spankulere kan dere nøye dere med garden!!</content> + <updated>2012-05-23T20:41:00Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>no</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:205307417414742018</id> + <published>2012-05-23T14:41:17Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/205307417414742018" rel="alternate"/> + <title>ba slottsfrisøren om å klippe meg som Odd nerdrum, men endte opp som ODd einar dørum igjen :-((</title> + <content type="html">ba slottsfrisøren om å klippe meg som Odd nerdrum, men endte opp som ODd einar dørum igjen :-((</content> + <updated>2012-05-23T14:41:17Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>no</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:205295504064655360</id> + <published>2012-05-23T13:53:57Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/205295504064655360" rel="alternate"/> + <title>når jeg ser en dåp liker jeg å tenke at babyen er et glass med melk og at døpevannet er o'boy!!</title> + <content type="html">når jeg ser en dåp liker jeg å tenke at babyen er et glass med melk og at døpevannet er o'boy!!</content> + <updated>2012-05-23T13:53:57Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>no</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:204881566177050625</id> + <published>2012-05-22T10:29:06Z</published> + <link type="text/html" href="http://twitter.com/AgileBorat/statuses/204881566177050625" rel="alternate"/> + <title>I am wish I have one dollar for every smiling Scrum Master I am meet! Then I would have $0.50.</title> + <content type="html">I am wish I have one dollar for every smiling Scrum Master I am meet! Then I would have $0.50.</content> + <updated>2012-05-22T10:29:06Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1327024640/borat_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a></twitter:source> + <twitter:lang>en</twitter:lang> + <author> + <name>AgileBorat (Agile Borat)</name> + <uri>http://twitter.com/AgileBorat</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:204526346481840128</id> + <published>2012-05-21T10:57:35Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/204526346481840128" rel="alternate"/> + <title>Ari sier at det er ku og gris inni pølsene!!! ÆÆÆÆSJ!!</title> + <content type="html">Ari sier at det er ku og gris inni pølsene!!! ÆÆÆÆSJ!!</content> + <updated>2012-05-21T10:57:35Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/">web</a></twitter:source> + <twitter:lang>da</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> + <entry> + <id>tag:search.twitter.com,2005:204296372051132416</id> + <published>2012-05-20T19:43:45Z</published> + <link type="text/html" href="http://twitter.com/KongenDin/statuses/204296372051132416" rel="alternate"/> + <title>det er ikke vanskelig å dunke i basketball. Med utendørstrampoline</title> + <content type="html">det er ikke vanskelig å dunke i basketball. Med utendørstrampoline</content> + <updated>2012-05-20T19:43:45Z</updated> + <link type="image/png" href="http://a0.twimg.com/profile_images/1133995526/SEILING__kongen_tit_808754x_normal.jpg" rel="image"/> + <twitter:geo/> + <twitter:metadata> + <twitter:result_type>recent</twitter:result_type> + </twitter:metadata> + <twitter:source><a href="http://twitter.com/#!/download/iphone" rel="nofollow">Twitter for iPhone</a></twitter:source> + <twitter:lang>no</twitter:lang> + <author> + <name>KongenDin (Harald Rex)</name> + <uri>http://twitter.com/KongenDin</uri> + </author> + </entry> +</feed> diff --git a/test/irc.test.js b/test/irc.test.js new file mode 100644 index 0000000..af89a81 --- /dev/null +++ b/test/irc.test.js @@ -0,0 +1,11 @@ +var assert = require('assert'), + irc = require('../lib/irc.js'); + +describe('irc.js', function() { + it('work', function() { + var nick = irc.nickGenerator("foo"); + assert.equal("function", typeof nick); + assert.equal("foo", nick()); + assert.equal("foo^", nick()); + }); +}); |