protolink 0.2.7 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +12 -0
  3. data/README.markdown +15 -4
  4. data/example/chatbot.rb +24 -0
  5. data/example/create_and_subscribe.rb +5 -1
  6. data/example/linkbot/base_plugins.rb +71 -0
  7. data/example/linkbot/plugins/awwwyeah.rb +11 -0
  8. data/example/linkbot/plugins/blowhard.rb +40 -0
  9. data/example/linkbot/plugins/comic.rb +40 -0
  10. data/example/linkbot/plugins/dumb.rb +11 -0
  11. data/example/linkbot/plugins/dupe.rb.inactive +64 -0
  12. data/example/linkbot/plugins/face.rb +11 -0
  13. data/example/linkbot/plugins/fuuu.rb +12 -0
  14. data/example/linkbot/plugins/help.rb +26 -0
  15. data/example/linkbot/plugins/image.rb +30 -0
  16. data/example/linkbot/plugins/imgur.rb +31 -0
  17. data/example/linkbot/plugins/jason.rb +73 -0
  18. data/example/linkbot/plugins/karma.rb.inactive +75 -0
  19. data/example/linkbot/plugins/last.rb +40 -0
  20. data/example/linkbot/plugins/links.rb.inactive +41 -0
  21. data/example/linkbot/plugins/log.rb +17 -0
  22. data/example/linkbot/plugins/okay.rb +11 -0
  23. data/example/linkbot/plugins/onion.rb +19 -0
  24. data/example/linkbot/plugins/popcorn.rb +32 -0
  25. data/example/linkbot/plugins/qwantz.rb +29 -0
  26. data/example/linkbot/plugins/search.rb +32 -0
  27. data/example/linkbot/plugins/shutup.rb +11 -0
  28. data/example/linkbot/plugins/slap.rb +15 -0
  29. data/example/linkbot/plugins/snap.rb +18 -0
  30. data/example/linkbot/plugins/stab.rb +12 -0
  31. data/example/linkbot/plugins/store.rb +71 -0
  32. data/example/linkbot/plugins/store_help.rb +22 -0
  33. data/example/linkbot/plugins/swanson.rb +41 -0
  34. data/example/linkbot/plugins/titles.rb +34 -0
  35. data/example/linkbot/plugins/translate.rb +21 -0
  36. data/example/linkbot/plugins/tsa.rb +22 -0
  37. data/example/linkbot/plugins/twss.rb +20 -0
  38. data/example/linkbot/plugins/urban.rb +27 -0
  39. data/example/linkbot/util.rb +28 -0
  40. data/lib/protolink.rb +4 -0
  41. data/lib/protolink/channel.rb +4 -0
  42. data/lib/protolink/flash_connection.rb +47 -0
  43. data/lib/protolink/proto_socket.rb +33 -0
  44. data/lib/protolink/protonet.rb +18 -3
  45. data/lib/protolink/version.rb +1 -1
  46. data/test/all_tests.rb +2 -2
  47. metadata +41 -4
@@ -0,0 +1,73 @@
1
+ require 'active_support'
2
+
3
+ class Jason < Linkbot::Plugin
4
+ Linkbot::Plugin.register('jason', self,
5
+ {
6
+ :message => {:regex => Regexp.new('(?:!randomlink|!jason)(?: (\d+))?'), :handler => :on_message, :help => :help},
7
+ :"direct-message" => {:regex => Regexp.new('(?:!randomlink|!jason)(?: (\d+))?'), :handler => :on_message, :help => :help}
8
+ }
9
+ )
10
+
11
+ def self.on_message(message, matches)
12
+ times = matches[0]
13
+ reddits = {
14
+ "/r/pics/" => 10,
15
+ "/r/comics/" => 10,
16
+ "/r/wallpaper/" => 10,
17
+ "/r/gonewild/" => 2,
18
+ "/r/funny/" => 10,
19
+ "/r/fffffffuuuuuuuuuuuu/" => 10,
20
+ "/r/reddit.com/" => 10,
21
+ "/r/WTF/" => 10,
22
+ "/r/bestof/" => 10,
23
+ "/r/videos/" => 10,
24
+ "/r/aww" => 10,
25
+ }
26
+
27
+ # Build out a weighted range
28
+ total_value = reddits.values.reduce(:+)
29
+ last_end = 0.0
30
+
31
+ reddits.each do |k,v|
32
+ reddits[k] = [last_end, last_end + (v.to_f / total_value)*100]
33
+ last_end += (v.to_f / total_value) * 100
34
+ end
35
+
36
+ times = times ? times.to_i : 1
37
+ times = times <= 5 ? times : 5
38
+
39
+ messages = []
40
+
41
+ 1.upto(times) do
42
+
43
+ # Brute force this mother
44
+ subreddit = nil
45
+ val = rand(100000)/1000.0
46
+ reddits.each {|k,v|
47
+ if val >= v[0] && val <= v[1]
48
+ subreddit = "http://reddit.com#{k}.json"
49
+ break
50
+ end
51
+ }
52
+
53
+ puts subreddit
54
+ doc = ActiveSupport::JSON.decode(open(subreddit, "Cookie" => "reddit_session=8390507%2C2011-03-22T07%3A06%3A44%2C2516dcc69a22ad297b9900cbde147b365203bbbb").read)
55
+
56
+ url = doc["data"]["children"][rand(doc["data"]["children"].length)]["data"]["url"]
57
+
58
+ # Check if it's an imgur link without an image extension
59
+ if url =~ /http:\/\/(www\.)?imgur\.com/ && !['jpg','png','gif'].include?(url.split('.').last)
60
+ # Fetch the imgur page and pull out the image
61
+ doc = Hpricot(open(url).read)
62
+ url = doc.search("img")[1]['src']
63
+ end
64
+
65
+ messages << url
66
+ end
67
+ return messages.join("\n")
68
+ end
69
+
70
+ def self.help
71
+ "!randomlink - return a random link"
72
+ end
73
+ end
@@ -0,0 +1,75 @@
1
+ class Karma < Linkbot::Plugin
2
+ Linkbot::Plugin.register('karma', self,
3
+ {
4
+ :star => {:handler => :on_starred},
5
+ :unstar => {:handler => :on_unstarred}
6
+ }
7
+ )
8
+
9
+ #TODO
10
+ #def self.on_starred(message, matches)
11
+ # starred_user = msg['star']['message']['user']
12
+ # starred_message = msg['star']['message']['message']
13
+ # karma = self.get_karma(starred_user)
14
+ # msg = ""
15
+ # if user['id'] == starred_user['id']
16
+ # Linkbot.db.execute("update karma set karma = #{karma - 5} where user_id = '#{starred_user['id']}'")
17
+ # msg = "You can't vote for yourself. Lose 5 karma."
18
+ # else
19
+ # Linkbot.db.execute("update karma set karma = #{karma + 5} where user_id = '#{starred_user['id']}'")
20
+ # starred_username = Linkbot.db.execute("select username from users where user_id = '#{starred_user['id']}'")[0][0]
21
+ # username = Linkbot.db.execute("select username from users where user_id = '#{user['id']}'")[0][0]
22
+ # end
23
+ # msg
24
+ #end
25
+
26
+ #TODO
27
+ #def self.on_unstarred(text, matches)
28
+ # starred_user = msg['star']['message']['user']
29
+ # starred_message = msg['star']['message']['message']
30
+ # karma = self.get_karma(starred_user)
31
+ # msg = ""
32
+ # if user['id'] == starred_user['id']
33
+ # Linkbot.db.execute("update karma set karma = #{karma - 20} where user_id = '#{starred_user['id']}'")
34
+ # msg = "That was incredibly stupid. Lose 20 karma."
35
+ # else
36
+ # Linkbot.db.execute("update karma set karma = #{karma - 5} where user_id = '#{starred_user['id']}'")
37
+ # starred_username = Linkbot.db.execute("select username from users where user_id = '#{starred_user['id']}'")[0][0]
38
+ # username = Linkbot.db.execute("select username from users where user_id = '#{user['id']}'")[0][0]
39
+ # end
40
+ # msg
41
+ #end
42
+
43
+ def self.on_newlink(message, url)
44
+ karma = self.get_karma(message.user_id)
45
+ Linkbot.db.execute("update karma set karma = #{karma + 1} where user_id = '#{message.user_id}'")
46
+ end
47
+
48
+ def self.on_dupe(message, url, duped_user, duped_timestamp)
49
+ karma = self.get_karma(message.user_id)
50
+ Linkbot.db.execute("update karma set karma = #{karma - 5} where user_id = '#{message.user_id}'")
51
+ "Removed 5 karma"
52
+ end
53
+
54
+ def self.get_karma(user_id)
55
+ karma = 0
56
+ # Create the user's info, if it does not exist
57
+ rows = Linkbot.db.execute("select * from users where user_id = '#{user_id}'")
58
+ if rows.empty?
59
+ #linkbot should ensure creating a user... bail out here if it hasn't
60
+ raise "could not find user #{user_id}"
61
+ end
62
+
63
+ rows = Linkbot.db.execute("select user_id,karma from karma where user_id = '#{user_id}'")
64
+ if rows.empty?
65
+ Linkbot.db.execute("insert into karma (user_id,karma) values ('#{user_id}', 0)")
66
+ else
67
+ karma = rows[0][1]
68
+ end
69
+ return karma
70
+ end
71
+
72
+ if Linkbot.db.table_info('karma').empty?
73
+ Linkbot.db.execute('CREATE TABLE karma (user_id INTEGER, karma INTEGER)');
74
+ end
75
+ end
@@ -0,0 +1,40 @@
1
+ class Last < Linkbot::Plugin
2
+ def self.on_message(message, match)
3
+ count = match[0] || 5
4
+ rows = nil
5
+ mess = ""
6
+ if match[1]
7
+ rows = Linkbot.db.execute("select l.url,l.dt from links l, users u where u.username='#{match[1]}' and u.user_id = l.user_id order by l.dt desc limit #{count}")
8
+ i = 1
9
+ if rows.length > 0
10
+ rows.each {|row| mess = mess + "#{i}. #{row[0]} (#{::Util.ago_in_words(Time.now, Time.at(row[1]))})\n"; i = i + 1}
11
+ else
12
+ mess = "No links from user '#{match[1]}'"
13
+ end
14
+ else
15
+ rows = Linkbot.db.execute("select l.url,l.dt,u.username,u.showname from links l, users u where l.user_id = u.user_id order by l.dt desc limit #{count}")
16
+ i = 1
17
+ if rows.length > 0
18
+ rows.each {|row|
19
+ username = (row[3].nil? || row[3] == '') ? row[2] : row[3]
20
+ mess = mess + "#{i}. #{row[0]} (#{username} #{::Linkbot::Util.ago_in_words(Time.now, Time.at(row[1]))})\n"; i = i + 1
21
+ }
22
+ else
23
+ mess = "No links"
24
+ end
25
+ end
26
+ mess
27
+
28
+ end
29
+
30
+ def self.help
31
+ "!last (num) (nick) - Displays the last links provided by users. (num) is optional and defaults to 5; (nick) is optional and returns only links from the specified user."
32
+ end
33
+
34
+ Linkbot::Plugin.register('last', self,
35
+ {
36
+ :message => {:regex => /!last(?: (\d+))?(?: (.*))?/, :handler => :on_message, :help => :help},
37
+ :"direct-message" => {:regex => /!last(?: (\d+))?(?: (.*))?/, :handler => :on_message, :help => :help}
38
+ }
39
+ )
40
+ end
@@ -0,0 +1,41 @@
1
+ class Linkbot
2
+ class Dupe
3
+ Linkbot::Plugin.register('links', self,
4
+ {
5
+ :message => {:regex => Regexp.new('(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))'),
6
+ :handler => :on_message}
7
+ }
8
+ )
9
+
10
+ def self.on_message(message, matches)
11
+ url = matches[0]
12
+
13
+ messages = []
14
+ rows = Linkbot.db.execute("select username, dt from links, users where links.user_id=users.user_id and url = '#{url}'")
15
+ if rows.empty?
16
+ Linkbot::Plugin.plugins.each {|k,v|
17
+ messages << v[:ptr].on_newlink(message, url).join("\n") if(v[:ptr].respond_to?(:on_newlink))
18
+ }
19
+ # Add the link to the dupe table
20
+ Linkbot.db.execute("insert into links (user_id, dt, url) VALUES ('#{message.user_id}', '#{Time.now}', '#{url}')")
21
+ else
22
+ Linkbot::Plugin.plugins.each {|k,v|
23
+ messages << v[:ptr].on_dupe(message, url, rows[0][0], rows[0][1]) if(v[:ptr].respond_to?(:on_dupe))
24
+ }
25
+ end
26
+ messages.join("\n")
27
+ end
28
+
29
+ if Linkbot.db.table_info('users').empty?
30
+ Linkbot.db.execute('CREATE TABLE users (user_id INTEGER, username TEXT, showname TEXT)')
31
+ end
32
+ if Linkbot.db.table_info('links').empty?
33
+ Linkbot.db.execute('CREATE TABLE links (user_id INTEGER, dt DATETIME, url TEXT)');
34
+ end
35
+
36
+ if Linkbot.db.table_info('trans').empty?
37
+ Linkbot.db.execute('CREATE TABLE trans (user_id INTEGER, karma INTEGER, trans TEXT)');
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ class MessageLog < Linkbot::Plugin
2
+ Linkbot::Plugin.register('log', self,
3
+ {
4
+ :message => {:handler => :on_message}
5
+ }
6
+ )
7
+
8
+ def self.on_message(message, matches)
9
+ # Pop off a message if we've reached our max
10
+ if @@message_log.length >= 100
11
+ @@message_log.pop
12
+ end
13
+
14
+ @@message_log.unshift(message)
15
+ ""
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ class Okay < Linkbot::Plugin
2
+ def self.on_message(message, matches)
3
+ "http://i.imgur.com/p7uaa.jpg"
4
+ end
5
+
6
+ Linkbot::Plugin.register('okay', self,
7
+ {
8
+ :message => {:regex => /okay\./i, :handler => :on_message}
9
+ }
10
+ )
11
+ end
@@ -0,0 +1,19 @@
1
+ require 'active_support'
2
+
3
+ class Onion < Linkbot::Plugin
4
+ Linkbot::Plugin.register('onion', self,
5
+ {
6
+ :message => {:regex => Regexp.new('!onion'), :handler => :on_message, :help => :help},
7
+ :"direct-message" => {:regex => Regexp.new('!onion'), :handler => :on_message, :help => :help}
8
+ }
9
+ )
10
+
11
+ def self.on_message(message, matches)
12
+ links = Hpricot(open('http://feeds.theonion.com/theonion/daily')).search('feedburner:origlink').collect{|l| l.html}
13
+ links[rand(links.length)]
14
+ end
15
+
16
+ def self.help
17
+ "!onion - return an onion link from the RSS feed"
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ class Popcorn < Linkbot::Plugin
2
+ def self.on_message(message, matches)
3
+ quotes = ['http://i.imgur.com/qlRu3.gif',
4
+ 'http://i.imgur.com/DDMBW.gif',
5
+ 'http://i.imgur.com/SbyLU.gif',
6
+ 'http://i.imgur.com/y8F8s.gif',
7
+ 'http://i.imgur.com/lozGr.gif',
8
+ 'http://i.imgur.com/YG6vv.gif',
9
+ 'http://i.imgur.com/IUoJx.gif',
10
+ 'http://i.imgur.com/lae9h.gif',
11
+ 'http://www.strangecosmos.com/images/content/167278.gif',
12
+ 'http://i.imgur.com/enRL0.gif',
13
+ 'http://i.imgur.com/QfkRE.gif',
14
+ 'http://i.imgur.com/kXfy9.gif',
15
+ 'http://i.imgur.com/ZDdhJ.gif',
16
+ 'http://www.threadbombing.com/data/media/2/scarjo_popcorn.gif'
17
+ ]
18
+ quotes[rand(quotes.length)]
19
+ end
20
+
21
+ def self.help
22
+ "!popcorn - Everyone loves popcorn"
23
+ end
24
+
25
+
26
+ Linkbot::Plugin.register('popcorn', self,
27
+ {
28
+ :message => {:regex => /!popcorn/, :handler => :on_message, :help => :help},
29
+ :"direct-message" => {:regex => /!popcorn/, :handler => :on_message, :help => :help}
30
+ }
31
+ )
32
+ end
@@ -0,0 +1,29 @@
1
+ class Qwantz < Linkbot::Plugin
2
+ Linkbot::Plugin.register('qwantz', self,
3
+ {
4
+ :message => {:regex => /!qwantz/, :handler => :on_message, :help => :help},
5
+ :"direct-message" => {:regex => /!qwantz/, :handler => :on_message, :help => :help}
6
+ }
7
+ )
8
+
9
+ def self.on_message(message, matches)
10
+ doc = Hpricot(open('http://qwantz.com/index.php'))
11
+ link = doc.search("div.randomquote a")[1]
12
+ doc = Hpricot(open(link['href']))
13
+ img = doc.search('img.comic')
14
+ "#{link.inner_html.strip}\n#{img.first['src']}"
15
+ end
16
+
17
+ def self.help
18
+ helpers = [
19
+ "HILARIOUS OUTTAKES COMICS",
20
+ "PHILOSOPHY COMICS",
21
+ "UNINFORMED OPINIONS ABOUT ARCHAEOLOGY COMICS",
22
+ "COMICS WITH NON-TWIST ENDINGS",
23
+ "COMICS FROM THE FUTURE",
24
+ "ENTHUSIASTIC USE OF OUTDATED CATCH-PHRASES COMICS",
25
+ "BAD DECISIONS COMICS"
26
+ ]
27
+ "!qwantz - #{helpers[rand(helpers.length)]}"
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ class Search < Linkbot::Plugin
2
+ Linkbot::Plugin.register('search', self,
3
+ {
4
+ :message => {:regex => Regexp.new('!search (.*)'), :handler => :on_message, :help => :help}
5
+ }
6
+ )
7
+
8
+ def self.on_message(message, matches)
9
+ search = matches[0]
10
+ rows = nil
11
+ mess = ""
12
+ rows = Linkbot.db.execute('select l.url,u.username,l.dt,u.showname from links l, users u where l.url like ? and l.user_id = u.user_id order by l.dt desc limit 10', "%#{search}%")
13
+ i = 1
14
+ if rows.length > 0
15
+ rows.each {|row|
16
+ username = (row[3].nil? || row[3] == '') ? row[1] : row[3]
17
+ mess = mess + "#{i}. #{row[0]} (#{username} #{::Util.ago_in_words(Time.now, Time.at(row[2]))})\n"; i = i + 1
18
+ }
19
+ else
20
+ mess = "No links"
21
+ end
22
+
23
+ # Take the karma hit
24
+ karma = Linkbot.db.execute("select karma from karma where user_id=#{user['id']}")[0][0] - 1
25
+ Linkbot.db.execute("update karma set karma=#{karma} where user_id=#{user['id']}")
26
+ mess
27
+ end
28
+
29
+ def self.help
30
+ "!search query - search for links that you think should be dupes"
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ class Shutup < Linkbot::Plugin
2
+ def self.on_message(message, matches)
3
+ "No, YOU #{matches[0]}"
4
+ end
5
+
6
+ Linkbot::Plugin.register('shutup', self,
7
+ {
8
+ :message => {:regex => /(.*), linkbot/, :handler => :on_message}
9
+ }
10
+ )
11
+ end
@@ -0,0 +1,15 @@
1
+ class Slap < Linkbot::Plugin
2
+ Linkbot::Plugin.register('slapper', self,
3
+ {
4
+ :message => {:regex => /\/slap(?: (@[\w\s]+))?/, :handler => :on_message, :help => :help}
5
+ }
6
+ )
7
+
8
+ def self.on_message(message, matches)
9
+ "#{message.user_name} slaps #{matches[0]} around a bit with a large trout"
10
+ end
11
+
12
+ def self.help
13
+ "/slap [username] - Flashback to the halcyon days of the 1990s when hammer pants were all the rage"
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ class Snap < Linkbot::Plugin
2
+ def self.on_message(message, matches)
3
+ snaps = [ "http://i52.tinypic.com/302melk.gif",
4
+ "http://www.youtube.com/watch?v=qL3TWooBGrI",
5
+ "http://i51.tinypic.com/2roj8k0.jpg",
6
+ "http://i3.photobucket.com/albums/y79/IJG/oh_snap.gif",
7
+ "http://webimages.stephen-wright.net/house-ohsnap.gif",
8
+ "http://www.gifsoup.com/webroot/animatedgifs/108696_o.gif"
9
+ ]
10
+ snaps[rand(snaps.length)]
11
+ end
12
+
13
+ Linkbot::Plugin.register('snap', self,
14
+ {
15
+ :message => {:regex => /SNAP\!/, :handler => :on_message}
16
+ }
17
+ )
18
+ end
@@ -0,0 +1,12 @@
1
+ class Stab < Linkbot::Plugin
2
+ Linkbot::Plugin.register('stab', self,
3
+ {
4
+ :message => {:regex => /\/stab(?: ([\w\s]+))?/, :handler => :on_message}
5
+ }
6
+ )
7
+
8
+ def self.on_message(message, matches)
9
+ name = matches[0] || "everyone in the face"
10
+ "#{message.user_name} stabs #{name}"
11
+ end
12
+ end
@@ -0,0 +1,71 @@
1
+ class Store < Linkbot::Plugin
2
+ def self.on_message(message, matches)
3
+ mymsg = nil
4
+
5
+ if matches[0] && matches[0].length > 0
6
+ args = matches[0].split(" ")
7
+ command = args.shift
8
+
9
+ Linkbot::Plugin.plugins.each {|k,v|
10
+ if v[:handlers][:"linkbot-store"] && v[:handlers][:"linkbot-store"][:regex] && v[:handlers][:"linkbot-store"][:regex].match(command)
11
+ cost = v[:ptr].respond_to?(:cost) ? v[:ptr].send(:cost).to_i : 0
12
+ if check_karma(user, cost)
13
+ begin
14
+ mymsg = v[:ptr].send(v[:handlers][:"linkbot-store"][:handler], user, args).join("\n")
15
+ deduct_karma(user, cost)
16
+ rescue StoreError
17
+ mymsg = $!.message
18
+ end
19
+ else
20
+ mymsg = "Not enough karma"
21
+ end
22
+ end
23
+ }
24
+ end
25
+
26
+
27
+ if mymsg.nil?
28
+ # Build out the menu
29
+ mymsg = [
30
+ "Karma Store",
31
+ "-----------",
32
+ "Buy some stuff with karma. To buy, just use the !store command, followed by the appropriate stuff.",
33
+ ""
34
+ ]
35
+
36
+ num = 1
37
+ Linkbot::Plugin.plugins.each {|k,v|
38
+ if v[:handlers][:"linkbot-store"] && v[:ptr].respond_to?(:cost) && v[:ptr].respond_to?(:advertisement)
39
+ mymsg << "#{num}. [COST #{v[:ptr].send(:cost)}] #{v[:ptr].send(:advertisement)}"
40
+ num += 1
41
+ end
42
+ }
43
+
44
+ mymsg = mymsg.join("\n")
45
+ end
46
+ mymsg
47
+ end
48
+
49
+ def self.check_karma(user, cost)
50
+ karma = Linkbot.db.execute("select karma from karma where user_id=#{user['id']}")[0][0]
51
+ karma > cost
52
+ end
53
+
54
+ def self.deduct_karma(user, cost)
55
+ karma = Linkbot.db.execute("select karma from karma where user_id=#{user['id']}")[0][0] - cost
56
+ Linkbot.db.execute("update karma set karma=#{karma} where user_id=#{user['id']}")
57
+ end
58
+
59
+ def self.help
60
+ "!store - Buy some shit"
61
+ end
62
+
63
+ Linkbot::Plugin.register('store', self,
64
+ {
65
+ :"direct-message" => {:regex => /!store(.*)/, :handler => :on_message, :help => :help},
66
+ }
67
+ )
68
+ end
69
+
70
+ class StoreError < StandardError
71
+ end