comboy-autumn 3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +1192 -0
- data/autumn.gemspec +25 -0
- data/bin/autumn +27 -0
- data/lib/autumn.rb +2 -0
- data/lib/autumn/authentication.rb +290 -0
- data/lib/autumn/channel_leaf.rb +107 -0
- data/lib/autumn/coder.rb +166 -0
- data/lib/autumn/console_boot.rb +9 -0
- data/lib/autumn/ctcp.rb +250 -0
- data/lib/autumn/daemon.rb +207 -0
- data/lib/autumn/datamapper_hacks.rb +290 -0
- data/lib/autumn/foliater.rb +231 -0
- data/lib/autumn/formatting.rb +236 -0
- data/lib/autumn/generator.rb +231 -0
- data/lib/autumn/genesis.rb +191 -0
- data/lib/autumn/inheritable_attributes.rb +162 -0
- data/lib/autumn/leaf.rb +738 -0
- data/lib/autumn/log_facade.rb +49 -0
- data/lib/autumn/misc.rb +87 -0
- data/lib/autumn/script.rb +74 -0
- data/lib/autumn/speciator.rb +165 -0
- data/lib/autumn/stem.rb +919 -0
- data/lib/autumn/stem_facade.rb +176 -0
- data/resources/daemons/Anothernet.yml +3 -0
- data/resources/daemons/AustHex.yml +29 -0
- data/resources/daemons/Bahamut.yml +67 -0
- data/resources/daemons/Dancer.yml +3 -0
- data/resources/daemons/GameSurge.yml +3 -0
- data/resources/daemons/IRCnet.yml +3 -0
- data/resources/daemons/Ithildin.yml +7 -0
- data/resources/daemons/KineIRCd.yml +56 -0
- data/resources/daemons/PTlink.yml +6 -0
- data/resources/daemons/QuakeNet.yml +20 -0
- data/resources/daemons/RFC1459.yml +158 -0
- data/resources/daemons/RFC2811.yml +16 -0
- data/resources/daemons/RFC2812.yml +36 -0
- data/resources/daemons/RatBox.yml +25 -0
- data/resources/daemons/Ultimate.yml +24 -0
- data/resources/daemons/Undernet.yml +6 -0
- data/resources/daemons/Unreal.yml +110 -0
- data/resources/daemons/_Other.yml +7 -0
- data/resources/daemons/aircd.yml +33 -0
- data/resources/daemons/bdq-ircd.yml +3 -0
- data/resources/daemons/hybrid.yml +38 -0
- data/resources/daemons/ircu.yml +67 -0
- data/resources/daemons/tr-ircd.yml +8 -0
- data/skel/Rakefile +135 -0
- data/skel/config/global.yml +2 -0
- data/skel/config/seasons/testing/database.yml +7 -0
- data/skel/config/seasons/testing/leaves.yml +7 -0
- data/skel/config/seasons/testing/season.yml +2 -0
- data/skel/config/seasons/testing/stems.yml +9 -0
- data/skel/leaves/administrator/README +20 -0
- data/skel/leaves/administrator/controller.rb +67 -0
- data/skel/leaves/administrator/views/autumn.txt.erb +1 -0
- data/skel/leaves/administrator/views/reload.txt.erb +11 -0
- data/skel/leaves/insulter/README +17 -0
- data/skel/leaves/insulter/controller.rb +65 -0
- data/skel/leaves/insulter/views/about.txt.erb +1 -0
- data/skel/leaves/insulter/views/help.txt.erb +1 -0
- data/skel/leaves/insulter/views/insult.txt.erb +1 -0
- data/skel/leaves/scorekeeper/README +34 -0
- data/skel/leaves/scorekeeper/config.yml +2 -0
- data/skel/leaves/scorekeeper/controller.rb +104 -0
- data/skel/leaves/scorekeeper/helpers/general.rb +64 -0
- data/skel/leaves/scorekeeper/models/channel.rb +12 -0
- data/skel/leaves/scorekeeper/models/person.rb +14 -0
- data/skel/leaves/scorekeeper/models/pseudonym.rb +11 -0
- data/skel/leaves/scorekeeper/models/score.rb +14 -0
- data/skel/leaves/scorekeeper/tasks/stats.rake +17 -0
- data/skel/leaves/scorekeeper/views/about.txt.erb +1 -0
- data/skel/leaves/scorekeeper/views/change.txt.erb +5 -0
- data/skel/leaves/scorekeeper/views/history.txt.erb +11 -0
- data/skel/leaves/scorekeeper/views/points.txt.erb +5 -0
- data/skel/leaves/scorekeeper/views/usage.txt.erb +1 -0
- data/skel/script/console +34 -0
- data/skel/script/daemon +29 -0
- data/skel/script/destroy +48 -0
- data/skel/script/generate +48 -0
- data/skel/script/server +15 -0
- metadata +170 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
= Administrator: An Autumn Leaf
|
2
|
+
|
3
|
+
<b>Version 1.0 (Jul 8, 2008)</b>
|
4
|
+
|
5
|
+
Author:: Tim Morgan (mailto:riscfuture@gmail.com)
|
6
|
+
Copyright:: Copyright (c)2008 Tim Morgan
|
7
|
+
License:: Distributed under the same terms as Ruby.
|
8
|
+
|
9
|
+
This leaf allows the owner of the IRC bot to perform administrative commands on
|
10
|
+
the bot, such as quitting or reloading it. In order to protect such commands
|
11
|
+
from abuse, this bot uses the Authenticator module. The Authenticator method
|
12
|
+
that is used is specified by the +authentication+ option. For more information,
|
13
|
+
see the *Authentication* section of the README.
|
14
|
+
|
15
|
+
== Usage
|
16
|
+
|
17
|
+
!autumn:: Displays information about the version of Autumn that is running this
|
18
|
+
leaf (unprotected command).
|
19
|
+
!quit:: Terminates the stem on which the message was received.
|
20
|
+
!reload:: Reloads all source files of all leaves, and all their view files.
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Controller for the Administrator leaf.
|
2
|
+
|
3
|
+
class Controller < Autumn::Leaf
|
4
|
+
|
5
|
+
# Typing this command reloads all source code for all leaves and support
|
6
|
+
# files, allowing you to make "on-the-fly" changes without restarting the
|
7
|
+
# process. It does this by reloading the source files defining the classes.
|
8
|
+
#
|
9
|
+
# If you supply the configuration name of a leaf, only that leaf is reloaded.
|
10
|
+
#
|
11
|
+
# This command does not reload the YAML configuration files, only the source
|
12
|
+
# code.
|
13
|
+
|
14
|
+
def reload_command(stem, sender, reply_to, msg)
|
15
|
+
var :leaves => Hash.new
|
16
|
+
if msg then
|
17
|
+
if Foliater.instance.leaves.include?(msg) then
|
18
|
+
begin
|
19
|
+
Foliater.instance.hot_reload Foliater.instance.leaves[msg]
|
20
|
+
rescue
|
21
|
+
logger.error "Error when reloading #{msg}:"
|
22
|
+
logger.error $!
|
23
|
+
var(:leaves)[msg] = $!.to_s
|
24
|
+
else
|
25
|
+
var(:leaves)[msg] = false
|
26
|
+
end
|
27
|
+
logger.info "#{msg}: Reloaded"
|
28
|
+
else
|
29
|
+
var :not_found => msg
|
30
|
+
end
|
31
|
+
else
|
32
|
+
Foliater.instance.leaves.each do |name, leaf|
|
33
|
+
begin
|
34
|
+
Foliater.instance.hot_reload leaf
|
35
|
+
rescue
|
36
|
+
logger.error "Error when reloading #{name}:"
|
37
|
+
logger.error $!
|
38
|
+
var(:leaves)[name] = $!.to_s
|
39
|
+
else
|
40
|
+
var(:leaves)[name] = false
|
41
|
+
end
|
42
|
+
logger.info "#{name}: Reloaded"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
ann :reload_command, :protected => true
|
47
|
+
|
48
|
+
# Typing this command will cause the Stem to exit.
|
49
|
+
|
50
|
+
def quit_command(stem, sender, reply_to, msg)
|
51
|
+
stem.quit
|
52
|
+
end
|
53
|
+
ann :quit_command, :protected => true
|
54
|
+
|
55
|
+
# Typing this command will display information about the version of Autumn
|
56
|
+
# that is running this leaf.
|
57
|
+
|
58
|
+
def autumn_command(stem, sender, reply_to, msg)
|
59
|
+
var :version => AUTUMN_VERSION
|
60
|
+
end
|
61
|
+
|
62
|
+
# Suppress the !commands command; don't want to publicize the administrative
|
63
|
+
# features.
|
64
|
+
|
65
|
+
def commands_command(stem, sender, reply_to, msg)
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Autumn version <%= var :version %>, an IRC bot framework for Ruby (http://github.com/RISCfuture/autumn).
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% if var(:not_found) %>
|
2
|
+
There is no leaf named <%= var :not_found %>.
|
3
|
+
<% else %>
|
4
|
+
<% var(:leaves).each do |leaf, error| %>
|
5
|
+
<% if error %>
|
6
|
+
<%= leaf %> couldn't be reloaded: <%= error %>
|
7
|
+
<% else %>
|
8
|
+
<%= leaf %> was reloaded successfully.
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
= Insulter: An Autumn Leaf
|
2
|
+
|
3
|
+
<b>Version 1.0 (Jul 4, 2008)</b>
|
4
|
+
|
5
|
+
Author:: Tim Morgan (mailto:riscfuture@gmail.com)
|
6
|
+
Copyright:: Copyright (c)2008 Tim Morgan
|
7
|
+
License:: Distributed under the same terms as Ruby. Portions of this content
|
8
|
+
are copyright (c)1996 Main Strike Telecommunications, Inc.
|
9
|
+
|
10
|
+
A simple Autumn Leaf that generates faux-Shakespearean insults. This leaf
|
11
|
+
required no database and no additional gems beyond that of a normal Autumn
|
12
|
+
install.
|
13
|
+
|
14
|
+
== Usage
|
15
|
+
|
16
|
+
!insult [name]:: The bot lets fly a barbarous insult against [name], whose very
|
17
|
+
spirit will thenceforth be crushed into a negligible pulp.
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Controller and model for the Insulter leaf; maintains the list of insult
|
2
|
+
# substrings and chooses from them randomly.
|
3
|
+
|
4
|
+
class Controller < Autumn::Leaf
|
5
|
+
|
6
|
+
# Insults the unfortunate argument of this command.
|
7
|
+
|
8
|
+
def insult_command(stem, sender, reply_to, msg)
|
9
|
+
if msg.nil? then render :help
|
10
|
+
else insult msg.capitalize end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Displays information about the leaf.
|
14
|
+
|
15
|
+
def about_command(stem, sender, reply_to, msg)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
ADJECTIVES = [
|
21
|
+
'an artless', 'a bawdy', 'a beslubbering', 'a bootless', 'a churlish',
|
22
|
+
'a clouted', 'a cockered', 'a craven', 'a currish', 'a dankish',
|
23
|
+
'a dissembling', 'a droning', 'an errant', 'a fawning', 'a fobbing',
|
24
|
+
'a frothy', 'a froward', 'a gleeking', 'a goatish', 'a gorbellied',
|
25
|
+
'an impertinent', 'an infectious', 'a jarring', 'a loggerheaded',
|
26
|
+
'a lumpish', 'a mammering', 'a mangled', 'a mewling', 'a paunchy',
|
27
|
+
'a pribbling', 'a puking', 'a puny', 'a qualling', 'a rank', 'a reeky',
|
28
|
+
'a roguish', 'a ruttish', 'a saucy', 'a spleeny', 'a spongy', 'a surly',
|
29
|
+
'a tottering', 'an unmuzzled', 'a vain', 'a venomed', 'a villainous',
|
30
|
+
'a warped', 'a wayward', 'a weedy', 'a yeasty'
|
31
|
+
]
|
32
|
+
|
33
|
+
PARTICIPLES = [
|
34
|
+
'base-court', 'bat-fowling', 'beef-witted', 'beetle-headed', 'boil-brained',
|
35
|
+
'clapper-clawed', 'clay-brained', 'common-kissing', 'crook-pated',
|
36
|
+
'dismal-dreaming', 'dizzy-eyed', 'doghearted', 'dread-bolted',
|
37
|
+
'earth-vexing', 'elf-skinned', 'fat-kidneyed', 'fen-sucked', 'flap-mouthed',
|
38
|
+
'fly-bitten', 'folly-fallen', 'fool-born', 'full-gorged', 'guts-griping',
|
39
|
+
'half-faced', 'hasty-witted', 'hedge-born', 'hell-hated', 'idle-headed',
|
40
|
+
'ill-breeding', 'ill-nurtured', 'knotty-pated', 'milk-livered',
|
41
|
+
'motley-minded', 'onion-eyed', 'plume-plucked', 'pottle-deep', 'pox-marked',
|
42
|
+
'reeling-ripe', 'rough-hewn', 'rude-growing', 'rump-fed', 'shard-borne',
|
43
|
+
'sheep-biting', 'spur-galled', 'swag-bellied', 'tardy-gaited',
|
44
|
+
'tickle-brained', 'toad-spotted', 'urchin-snouted', 'weather-bitten'
|
45
|
+
]
|
46
|
+
|
47
|
+
NOUNS = [
|
48
|
+
'apple-john', 'baggage', 'barnacle', 'bladder', 'boar-pig', 'bugbear',
|
49
|
+
'bum-bailey', 'canker-blossom', 'clack-dish', 'clotpole', 'codpiece',
|
50
|
+
'coxcomb', 'death-token', 'dewberry', 'flap-dragon', 'flax-wench',
|
51
|
+
'flirt-gill', 'foot-licker', 'fustilarian', 'giglet', 'gudgeon', 'haggard',
|
52
|
+
'harpy', 'hedge-pig', 'horn-beast', 'hugger-mugger', 'joithead', 'lewdster',
|
53
|
+
'lout', 'maggot-pie', 'malt-worm', 'mammet', 'measle', 'minnow',
|
54
|
+
'miscreant', 'moldwarp', 'mumble-news', 'nut-hook', 'pigeon-egg', 'pignut',
|
55
|
+
'pumpion', 'puttock', 'ratsbane', 'scut', 'skainsmate', 'strumpet',
|
56
|
+
'varlet', 'vassal', 'wagtail', 'whey-face'
|
57
|
+
]
|
58
|
+
|
59
|
+
def insult(victim)
|
60
|
+
var :adjective => ADJECTIVES.pick
|
61
|
+
var :participle => PARTICIPLES.pick
|
62
|
+
var :noun => NOUNS.pick
|
63
|
+
var :victim => victim
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Insulter version 1.0 (7-4-08) by Tim Morgan: An Autumn Leaf. Insults copyright (c)1996 Main Strike Telecommunications, Inc.
|
@@ -0,0 +1 @@
|
|
1
|
+
Type "!insult Ted" to crush Ted's spirit with a devastating insult.
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= var :victim %>, thou art <%= var :adjective %> <%= var :participle %> <%= var :noun %>!
|
@@ -0,0 +1,34 @@
|
|
1
|
+
= Scorekeeper: An Autumn Leaf
|
2
|
+
|
3
|
+
<b>Version 3.0 (Jul 4, 2008)</b>
|
4
|
+
|
5
|
+
Author:: Tim Morgan (mailto:riscfuture@gmail.com)
|
6
|
+
Copyright:: Copyright (c)2007-2008 Tim Morgan
|
7
|
+
License:: Distributed under the same terms as Ruby.
|
8
|
+
|
9
|
+
An Autumn Leaf used for an in-channel scorekeeping system. This can operate both
|
10
|
+
as an open or closed score system. (In the former, new members are automatically
|
11
|
+
added when they receive points; in the latter, only authorized members can give
|
12
|
+
and receive points.)
|
13
|
+
|
14
|
+
Scorekeeper is a database-backed leaf. It requires the DataMapper gem
|
15
|
+
(http://www.datamapper.org) in order to run. The database stores channels and
|
16
|
+
their members, and each member's point history.
|
17
|
+
|
18
|
+
Scorekeeper supports pseudonyms. Entries in the +pseudonyms+ table can be used
|
19
|
+
to help ensure that the correct person's points are changed even when the sender
|
20
|
+
uses a nickname or abbreviation.
|
21
|
+
|
22
|
+
Scorekeeper takes one custom configuration option, +scoring+, which can be
|
23
|
+
either "open" or "closed". A closed system only allows a specified set of users
|
24
|
+
to receive and give points. An open system allows anyone to award points to
|
25
|
+
anyone.
|
26
|
+
|
27
|
+
== Usage
|
28
|
+
|
29
|
+
!points [name]:: Get a person's score
|
30
|
+
!points [name] [+|-][number] [reason]:: Change a person's score (you must have a
|
31
|
+
"+" or a "-"). A reason is optional.
|
32
|
+
!points [name] history:: Return some recent history of that person's score.
|
33
|
+
!points [name] history [time period]:: Selects history from a time period.
|
34
|
+
!points [name] history [sender]:: Selects point changes from a sender.
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'dm-ar-finders'
|
2
|
+
|
3
|
+
begin
|
4
|
+
gem 'chronic'
|
5
|
+
require 'chronic'
|
6
|
+
rescue Gem::LoadError
|
7
|
+
# Install the "chronic" gem for more robust date parsing
|
8
|
+
end
|
9
|
+
|
10
|
+
# Controller for the Scorekeeper leaf. This class contains only the methods
|
11
|
+
# directly relating to IRC. Other methods are stored in the helper and model
|
12
|
+
# classes.
|
13
|
+
|
14
|
+
class Controller < Autumn::Leaf
|
15
|
+
|
16
|
+
# Displays an about message.
|
17
|
+
|
18
|
+
def about_command(stem, sender, reply_to, msg)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Displays the current point totals, or modifies someone's score, depending on
|
22
|
+
# the message provided with the command.
|
23
|
+
|
24
|
+
def points_command(stem, sender, reply_to, msg)
|
25
|
+
if msg.nil? or msg.empty? then
|
26
|
+
var :totals => totals(stem, reply_to)
|
27
|
+
elsif msg =~ /^(\w+)\s+history\s*(.*)$/ then
|
28
|
+
parse_history stem, reply_to, $1, $2
|
29
|
+
render :history
|
30
|
+
elsif msg =~ /^(\w+)\s+([\+\-]\d+)\s*(.*)$/ then
|
31
|
+
parse_change stem, reply_to, sender, $1, $2.to_i, $3
|
32
|
+
render :change
|
33
|
+
else
|
34
|
+
render :usage
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def points(stem, channel)
|
41
|
+
chan = Channel.find_or_create :server => server_identifier(stem), :name => channel
|
42
|
+
scores = chan.scores.all
|
43
|
+
scores.inject(Hash.new(0)) { |hsh, score| hsh[score.receiver.name] += score.change; hsh }
|
44
|
+
end
|
45
|
+
|
46
|
+
def totals(stem, channel)
|
47
|
+
points(stem, channel).sort { |a,b| b.last <=> a.last }
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_change(stem, channel, sender, victim, delta, note)
|
51
|
+
giver = find_person(stem, sender[:nick])
|
52
|
+
receiver = find_person(stem, victim)
|
53
|
+
if giver.nil? and options[:scoring] == 'open' then
|
54
|
+
giver ||= Person.create :server => server_identifier(stem), :name => sender[:nick]
|
55
|
+
end
|
56
|
+
if receiver.nil? and options[:scoring] == 'open' then
|
57
|
+
receiver ||= Person.create :server => server_identifier(stem), :name => find_in_channel(stem, channel, victim)
|
58
|
+
end
|
59
|
+
unless authorized?(giver, receiver)
|
60
|
+
var :unauthorized => true
|
61
|
+
var :receiver => receiver.nil? ? victim : receiver.name
|
62
|
+
return
|
63
|
+
end
|
64
|
+
change_points stem, channel, giver, receiver, delta, note
|
65
|
+
var :giver => giver
|
66
|
+
var :receiver => receiver
|
67
|
+
var :delta => delta
|
68
|
+
end
|
69
|
+
|
70
|
+
def parse_history(stem, channel, subject, argument)
|
71
|
+
date = argument.empty? ? nil : parse_date(argument)
|
72
|
+
scores = Array.new
|
73
|
+
|
74
|
+
chan = Channel.first(:name => channel)
|
75
|
+
person = find_person(stem, subject)
|
76
|
+
if person.nil? then
|
77
|
+
var :person => subject
|
78
|
+
var :no_history => true
|
79
|
+
return
|
80
|
+
end
|
81
|
+
|
82
|
+
if date then
|
83
|
+
start, stop = find_range(date)
|
84
|
+
scores = chan.scores.all(:conditions => [ "receiver_id = ? AND created_at >= ? AND created_at < ?", person.id, start, stop ], :order => [ :created_at.desc ], :limit => 5)
|
85
|
+
#TODO is there a way to scope by both channel and receiver?
|
86
|
+
elsif argument.empty? then
|
87
|
+
scores = chan.scores.all(:conditions => [ "receiver_id = ?", person.id ], :order => [ :created_at.desc ], :limit => 5)
|
88
|
+
#TODO is there a way to scope by both channel and receiver?
|
89
|
+
else
|
90
|
+
giver = find_person(stem, argument)
|
91
|
+
if giver.nil? then
|
92
|
+
var :giver => argument
|
93
|
+
var :receiver => person
|
94
|
+
var :no_giver_history => true
|
95
|
+
return
|
96
|
+
end
|
97
|
+
scores = chan.scores.all(:conditions => [ "receiver_id = ? AND giver_id = ?", person.id, giver.id ], :order => [ :created_at.desc ], :limit => 5)
|
98
|
+
#TODO is there a way to scope by channel, receiver, and giver?
|
99
|
+
end
|
100
|
+
var :receiver => person
|
101
|
+
var :giver => giver
|
102
|
+
var :scores => scores
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Utility methods used by Scorekeeper.
|
2
|
+
|
3
|
+
module GeneralHelper
|
4
|
+
def parse_date(str)
|
5
|
+
date = nil
|
6
|
+
begin
|
7
|
+
date = Chronic.parse(str, :context => :past, :guess => false)
|
8
|
+
rescue NameError
|
9
|
+
begin
|
10
|
+
date = Date.parse(str)
|
11
|
+
rescue ArgumentError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
return date
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_range(date)
|
18
|
+
start = nil
|
19
|
+
stop = nil
|
20
|
+
if date.kind_of? Range then
|
21
|
+
start = date.first
|
22
|
+
stop = date.last
|
23
|
+
elsif date.kind_of? Time then
|
24
|
+
start = date.to_date
|
25
|
+
stop = date.to_date + 1
|
26
|
+
else
|
27
|
+
start = date
|
28
|
+
stop = date + 1
|
29
|
+
end
|
30
|
+
return start, stop
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_person(stem, nick)
|
34
|
+
Person.all(:server => server_identifier(stem)).each do |person|
|
35
|
+
return person if person.name.downcase == normalize(nick) or person.pseudonyms.collect { |pn| pn.name.downcase }.include? normalize(nick)
|
36
|
+
end
|
37
|
+
return nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def find_in_channel(stem, channel, victim)
|
41
|
+
stem.channel_members[channel].each do |name, privilege|
|
42
|
+
return normalize(name, false) if normalize(name) == normalize(victim)
|
43
|
+
end
|
44
|
+
return victim
|
45
|
+
end
|
46
|
+
|
47
|
+
def normalize(nick, dc=true)
|
48
|
+
dc ? nick.downcase.split(/\|/)[0] : nick.split(/\|/)[0]
|
49
|
+
end
|
50
|
+
|
51
|
+
def authorized?(giver, receiver)
|
52
|
+
giver and receiver and giver.authorized? and giver.name != receiver.name
|
53
|
+
end
|
54
|
+
|
55
|
+
def change_points(stem, channel, giver, receiver, delta, note=nil)
|
56
|
+
return if delta.zero?
|
57
|
+
chan = Channel.find_or_create :server => server_identifier(stem), :name => channel
|
58
|
+
chan.scores.create :giver => giver, :receiver => receiver, :change => delta, :note => note
|
59
|
+
end
|
60
|
+
|
61
|
+
def server_identifier(stem)
|
62
|
+
"#{stem.server}:#{stem.port}"
|
63
|
+
end
|
64
|
+
end
|