Quotegrabs.pm now uses quotegrabs_db API for interfacing with storage backend

Two quotegrabs_db backends are now availble:

  * Quotegrabs_Hashtable.pm: the original hashtable implementation
  * Quotegrabs_SQLite.pm: the new SQLite implementation

Quotegrabs_SQLite.pm is now the default quotegrabs_db backend.

This was done to reduce the memory footprint of the bot by not needing to
keep the entire quotegrabs table in memory any longer.

A similiar change will be coming soon to the Factoids table as well as the
MessageHistory table.
This commit is contained in:
Pragmatic Software 2014-05-06 05:15:27 +00:00
parent 2c2b2c2e4b
commit 239e3de8ea
9 changed files with 404 additions and 126 deletions

View File

@ -160,6 +160,7 @@ sub ack_die {
$self->{pbot}->factoids->save_factoids;
$self->{pbot}->ignorelist->save_ignores;
$self->{pbot}->antiflood->save_message_history;
$self->{pbot}->{quotegrabs}->{quotegrabs_db}->end();
$self->{pbot}->conn->privmsg($from, "Good-bye.") if defined $from;
$self->{pbot}->conn->quit("Departure requested.");
exit 0;

View File

@ -55,7 +55,7 @@ use PBot::Timer;
sub new {
if(ref($_[1]) eq 'HASH') {
Carp::croak("Options to Logger should be key/value pairs, not hash reference");
Carp::croak("Options to PBot should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_;
@ -159,9 +159,6 @@ sub initialize {
export_site => $export_quotegrabs_site,
);
$self->quotegrabs->add_quotegrab($self->{botnick}, "#pbot2", 0, "pragma_", "Who's a bot?");
$self->quotegrabs->load_quotegrabs() if defined $quotegrabs_file;
$self->timer->start();
}

View File

@ -16,6 +16,9 @@ use Time::Duration;
use Time::HiRes qw(gettimeofday);
use Getopt::Long qw(GetOptionsFromString);
use PBot::Quotegrabs_SQLite; # use SQLite backend for quotegrabs database
#use PBot::Quotegrabs_Hashtable; # use Perl hashtable backend for quotegrabs database
use POSIX qw(strftime);
sub new {
@ -37,7 +40,10 @@ sub initialize {
$self->{filename} = delete $conf{filename};
$self->{export_path} = delete $conf{export_path};
$self->{export_site} = delete $conf{export_site};
$self->{quotegrabs} = [];
$self->{quotegrabs_db} = PBot::Quotegrabs_SQLite->new(pbot => $self->{pbot}, filename => $self->{filename});
#$self->{quotegrabs_db} = PBot::Quotegrabs_Hashtable->new(pbot => $self->{pbot}, filename => $self->{filename});
$self->{quotegrabs_db}->begin();
#-------------------------------------------------------------------------------------
# The following could be in QuotegrabsCommands.pm, or they could be kept in here?
@ -51,66 +57,14 @@ sub initialize {
$self->{pbot}->commands->register(sub { $self->recall_message(@_) }, "recall", 0);
}
sub load_quotegrabs {
my $self = shift;
my $filename;
if(@_) { $filename = shift; } else { $filename = $self->{filename}; }
return if not defined $filename;
$self->{pbot}->logger->log("Loading quotegrabs from $filename ...\n");
open(FILE, "< $filename") or die "Couldn't open $filename: $!\n";
my @contents = <FILE>;
close(FILE);
my $i = 0;
foreach my $line (@contents) {
chomp $line;
$i++;
my ($nick, $channel, $timestamp, $grabbed_by, $text) = split(/\s+/, $line, 5);
if(not defined $nick || not defined $channel || not defined $timestamp
|| not defined $grabbed_by || not defined $text) {
die "Syntax error around line $i of $self->{quotegrabs}_file\n";
}
my $quotegrab = {};
$quotegrab->{nick} = $nick;
$quotegrab->{channel} = $channel;
$quotegrab->{timestamp} = $timestamp;
$quotegrab->{grabbed_by} = $grabbed_by;
$quotegrab->{text} = $text;
$quotegrab->{id} = $i + 1;
push @{ $self->{quotegrabs} }, $quotegrab;
}
$self->{pbot}->logger->log(" $i quotegrabs loaded.\n");
$self->{pbot}->logger->log("Done.\n");
}
sub save_quotegrabs {
my $self = shift;
my $filename;
if(@_) { $filename = shift; } else { $filename = $self->{filename}; }
return if not defined $filename;
open(FILE, "> $filename") or die "Couldn't open $filename: $!\n";
for(my $i = 0; $i <= $#{ $self->{quotegrabs} }; $i++) {
my $quotegrab = $self->{quotegrabs}[$i];
next if $quotegrab->{timestamp} == 0;
print FILE "$quotegrab->{nick} $quotegrab->{channel} $quotegrab->{timestamp} $quotegrab->{grabbed_by} $quotegrab->{text}\n";
}
close(FILE);
$self->export_quotegrabs();
}
sub uniq { my %seen; grep !$seen{$_}++, @_ }
sub export_quotegrabs() {
sub export_quotegrabs {
my $self = shift;
return "Not enabled" if not defined $self->{export_path};
my $quotegrabs = $self->{quotegrabs_db}->get_all_quotegrabs();
my $text;
my $table_id = 1;
my $had_table = 0;
@ -124,7 +78,7 @@ sub export_quotegrabs() {
my $i = 0;
my $last_channel = "";
foreach my $quotegrab (sort { $$a{channel} cmp $$b{channel} or $$a{nick} cmp $$b{nick} } @{ $self->{quotegrabs} }) {
foreach my $quotegrab (sort { $$a{channel} cmp $$b{channel} or $$a{nick} cmp $$b{nick} } @$quotegrabs) {
if(not $quotegrab->{channel} =~ /^$last_channel$/i) {
print FILE "<a href='#" . $quotegrab->{channel} . "'>" . encode_entities($quotegrab->{channel}) . "</a><br>\n";
$last_channel = $quotegrab->{channel};
@ -132,7 +86,7 @@ sub export_quotegrabs() {
}
$last_channel = "";
foreach my $quotegrab (sort { $$a{channel} cmp $$b{channel} or lc $$a{nick} cmp lc $$b{nick} } @{ $self->{quotegrabs} }) {
foreach my $quotegrab (sort { $$a{channel} cmp $$b{channel} or lc $$a{nick} cmp lc $$b{nick} } @$quotegrabs) {
if(not $quotegrab->{channel} =~ /^$last_channel$/i) {
print FILE "</tbody>\n</table>\n" if $had_table;
print FILE "<a name='" . $quotegrab->{channel} . "'></a>\n";
@ -211,7 +165,7 @@ sub grab_quotegrab {
}
if(not defined $arguments or not length $arguments) {
return "Usage: grab <nick> [history [channel]] -- where [history] is an optional argument that is either an integral number of recent messages or a regex (without whitespace) of the text within the message; e.g., to grab the 3rd most recent message for nick, use `grab nick 3` or to grab a message containing 'pizza', use `grab nick pizza`; and [channel] is an optional channel, so you can use it from /msg (you will need to also specify [history] in this case)";
return "Usage: grab <nick> [history [channel]] [+ <nick> [history [channel]] ...] -- where [history] is an optional argument that is a regex (without whitespace) of the text within the message; e.g., to grab a message containing 'pizza', use `grab nick pizza`; you can chain grabs with + to grab multiple messages";
}
$arguments = lc $arguments;
@ -323,56 +277,41 @@ sub grab_quotegrab {
$quotegrab->{timestamp} = gettimeofday;
$quotegrab->{grabbed_by} = "$nick!$user\@$host";
$quotegrab->{text} = $grab_text;
$quotegrab->{id} = $#{ $self->{quotegrabs} } + 2;
$quotegrab->{id} = undef;
push @{ $self->{quotegrabs} }, $quotegrab;
$self->save_quotegrabs();
$quotegrab->{id} = $self->{quotegrabs_db}->add_quotegrab($quotegrab);
if(not defined $quotegrab->{id}) {
return "Failed to grab quote.";
}
$self->export_quotegrabs();
my $text = $quotegrab->{text};
($grab_nick) = split /\+/, $grab_nicks, 2;
if($text =~ s/^\/me\s+//) {
return "Quote grabbed: " . ($#{ $self->{quotegrabs} } + 1) . ": * $grab_nick $text";
return "Quote grabbed: $quotegrab->{id}: * $grab_nick $text";
} else {
return "Quote grabbed: " . ($#{ $self->{quotegrabs} } + 1) . ": <$grab_nick> $text";
return "Quote grabbed: $quotegrab->{id}: <$grab_nick> $text";
}
}
sub add_quotegrab {
my ($self, $nick, $channel, $timestamp, $grabbed_by, $text) = @_;
my $quotegrab = {};
$quotegrab->{nick} = $nick;
$quotegrab->{channel} = $channel;
$quotegrab->{timestamp} = $timestamp;
$quotegrab->{grabbed_by} = $grabbed_by;
$quotegrab->{text} = $text;
$quotegrab->{id} = $#{ $self->{quotegrabs} } + 2;
push @{ $self->{quotegrabs} }, $quotegrab;
}
sub delete_quotegrab {
my ($self, $from, $nick, $user, $host, $arguments) = @_;
if($arguments < 1 || $arguments > $#{ $self->{quotegrabs} } + 1) {
return "/msg $nick Valid range for `getq` is 1 - " . ($#{ $self->{quotegrabs} } + 1);
}
my $quotegrab = $self->{quotegrabs_db}->get_quotegrab($arguments);
my $quotegrab = $self->{quotegrabs}[$arguments - 1];
if(not defined $quotegrab) {
return "/msg $nick No quotegrab matching id $arguments found.";
}
if(not $self->{pbot}->admins->loggedin($from, "$nick!$user\@$host") and $quotegrab->{grabbed_by} ne "$nick!$user\@$host") {
return "You are not the grabber of this quote.";
}
splice @{ $self->{quotegrabs} }, $arguments - 1, 1;
for(my $i = $arguments - 1; $i <= $#{ $self->{quotegrabs} }; $i++ ) {
$self->{quotegrabs}[$i]->{id}--;
}
$self->save_quotegrabs();
$self->{quotegrabs_db}->delete_quotegrab($arguments);
$self->export_quotegrabs();
my $text = $quotegrab->{text};
@ -388,11 +327,12 @@ sub delete_quotegrab {
sub show_quotegrab {
my ($self, $from, $nick, $user, $host, $arguments) = @_;
if($arguments < 1 || $arguments > $#{ $self->{quotegrabs} } + 1) {
return "/msg $nick Valid range for !getq is 1 - " . ($#{ $self->{quotegrabs} } + 1);
my $quotegrab = $self->{quotegrabs_db}->get_quotegrab($arguments);
if(not defined $quotegrab) {
return "/msg $nick No quotegrab matching id $arguments found.";
}
my $quotegrab = $self->{quotegrabs}[$arguments - 1];
my $timestamp = $quotegrab->{timestamp};
my $ago = ago(gettimeofday - $timestamp);
my $text = $quotegrab->{text};
@ -443,46 +383,34 @@ sub show_random_quotegrab {
if(not defined $channel_search) {
$channel_search = $from;
}
}
$nick_search = '.*' if not defined $nick_search;
$channel_search = '.*' if not defined $channel_search or $channel_search !~ /^#/;
$text_search = '.*' if not defined $text_search;
eval {
for(my $i = 0; $i <= $#{ $self->{quotegrabs} }; $i++) {
my $hash = $self->{quotegrabs}[$i];
if($hash->{channel} =~ /$channel_search/i && $hash->{nick} =~ /$nick_search/i && $hash->{text} =~ /$text_search/i) {
$hash->{id} = $i + 1;
push @quotes, $hash;
}
}
};
if($@) {
$self->{pbot}->logger->log("Error in show_random_quotegrab parameters: $@\n");
return "/msg $nick Error in search parameters: $@"
}
$channel_search = undef if defined $channel_search and $channel_search !~ /^#/;
print "nick: [" . (defined $nick_search ? $nick_search : "undef") . "]\n";
print "channel: [" . (defined $channel_search ? $channel_search : "undef") . "]\n";
print "text: [" . (defined $text_search ? $text_search : "undef") . "]\n";
my $quotegrab = $self->{quotegrabs_db}->get_random_quotegrab($nick_search, $channel_search, $text_search);
if($#quotes < 0) {
if(not defined $quotegrab) {
my $result = "No quotes grabbed ";
if($nick_search ne '.*') {
if(defined $nick_search) {
$result .= "for nick $nick_search ";
}
if($channel_search ne '.*') {
if(defined $channel_search) {
$result .= "in channel $channel_search ";
}
if($text_search ne '.*') {
if(defined $text_search) {
$result .= "matching text '$text_search' ";
}
return $result . "yet ($usage).";;
}
my $quotegrab = $quotes[int rand($#quotes + 1)];
my $text = $quotegrab->{text};
my ($first_nick) = split /\+/, $quotegrab->{nick}, 2;

View File

@ -0,0 +1,173 @@
# File: Quotegrabs_Hashtable.pm
# Author: pragma_
#
# Purpose: Hashtable backend for storing and retreiving quotegrabs
package PBot::Quotegrabs_Hashtable;
use warnings;
use strict;
use vars qw($VERSION);
$VERSION = $PBot::PBot::VERSION;
use HTML::Entities;
use Time::Duration;
use Time::HiRes qw(gettimeofday);
use Getopt::Long qw(GetOptionsFromString);
use POSIX qw(strftime);
sub new {
if(ref($_[1]) eq 'HASH') {
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_;
my $self = bless {}, $class;
$self->initialize(%conf);
return $self;
}
sub initialize {
my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference in " . __FILE__);
$self->{filename} = delete $conf{filename};
$self->{quotegrabs} = [];
}
sub begin {
my $self = shift;
$self->load_quotegrabs;
}
sub end {
}
sub load_quotegrabs {
my $self = shift;
my $filename;
if(@_) { $filename = shift; } else { $filename = $self->{filename}; }
return if not defined $filename;
$self->{pbot}->logger->log("Loading quotegrabs from $filename ...\n");
open(FILE, "< $filename") or die "Couldn't open $filename: $!\n";
my @contents = <FILE>;
close(FILE);
my $i = 0;
foreach my $line (@contents) {
chomp $line;
$i++;
my ($nick, $channel, $timestamp, $grabbed_by, $text) = split(/\s+/, $line, 5);
if(not defined $nick || not defined $channel || not defined $timestamp
|| not defined $grabbed_by || not defined $text) {
die "Syntax error around line $i of $filename\n";
}
my $quotegrab = {};
$quotegrab->{nick} = $nick;
$quotegrab->{channel} = $channel;
$quotegrab->{timestamp} = $timestamp;
$quotegrab->{grabbed_by} = $grabbed_by;
$quotegrab->{text} = $text;
$quotegrab->{id} = $i + 1;
push @{ $self->{quotegrabs} }, $quotegrab;
}
$self->{pbot}->logger->log(" $i quotegrabs loaded.\n");
$self->{pbot}->logger->log("Done.\n");
}
sub save_quotegrabs {
my $self = shift;
my $filename;
if(@_) { $filename = shift; } else { $filename = $self->{filename}; }
return if not defined $filename;
open(FILE, "> $filename") or die "Couldn't open $filename: $!\n";
for(my $i = 0; $i <= $#{ $self->{quotegrabs} }; $i++) {
my $quotegrab = $self->{quotegrabs}[$i];
next if $quotegrab->{timestamp} == 0;
print FILE "$quotegrab->{nick} $quotegrab->{channel} $quotegrab->{timestamp} $quotegrab->{grabbed_by} $quotegrab->{text}\n";
}
close(FILE);
}
sub add_quotegrab {
my ($self, $quotegrab) = @_;
push @{ $self->{quotegrabs} }, $quotegrab;
$self->save_quotegrabs();
return $#{ $self->{quotegrabs} } + 1;
}
sub delete_quotegrab {
my ($self, $id) = @_;
if($id < 1 || $id > $#{ $self->{quotegrabs} } + 1) {
return undef;
}
splice @{ $self->{quotegrabs} }, $id - 1, 1;
for(my $i = $id - 1; $i <= $#{ $self->{quotegrabs} }; $i++ ) {
$self->{quotegrabs}[$i]->{id}--;
}
$self->save_quotegrabs();
}
sub get_quotegrab {
my ($self, $id) = @_;
if($id < 1 || $id > $#{ $self->{quotegrabs} } + 1) {
return undef;
}
return $self->{quotegrabs}[$id - 1];
}
sub get_random_quotegrab {
my ($self, $nick, $channel, $text) = @_;
$nick = '.*' if not defined $nick;
$channel = '.*' if not defined $channel;
$text = '.*' if not defined $text;
my @quotes;
eval {
for(my $i = 0; $i <= $#{ $self->{quotegrabs} }; $i++) {
my $hash = $self->{quotegrabs}[$i];
if($hash->{channel} =~ /$channel/i && $hash->{nick} =~ /$nick/i && $hash->{text} =~ /$text/i) {
$hash->{id} = $i + 1;
push @quotes, $hash;
}
}
};
if($@) {
$self->{pbot}->logger->log("Error in show_random_quotegrab parameters: $@\n");
return undef;
}
if($#quotes < 0) {
return undef;
}
return $quotes[int rand($#quotes + 1)];
}
sub get_all_quotegrabs {
my $self = shift;
return $self->{quotegrabs};
}
1;

172
PBot/Quotegrabs_SQLite.pm Normal file
View File

@ -0,0 +1,172 @@
# File: Quotegrabs_SQLite.pm
# Author: pragma_
#
# Purpose: SQLite back-end for storing and retreiving quotegrabs
package PBot::Quotegrabs_SQLite;
use warnings;
use strict;
use vars qw($VERSION);
$VERSION = $PBot::PBot::VERSION;
use DBI;
use Carp qw(shortmess);
sub new {
if(ref($_[1]) eq 'HASH') {
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_;
my $self = bless {}, $class;
$self->initialize(%conf);
return $self;
}
sub initialize {
my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference in " . __FILE__);
$self->{filename} = delete $conf{filename};
}
sub begin {
my $self = shift;
$self->{pbot}->logger->log("Opening quotegrabs SQLite database: $self->{filename}\n");
$self->{dbh} = DBI->connect("dbi:SQLite:dbname=$self->{filename}", "", "", { RaiseError => 1, PrintError => 0 }) or die $DBI::errstr;
eval {
$self->{dbh}->do(<< 'SQL');
CREATE TABLE IF NOT EXISTS Quotegrabs (
id INTEGER PRIMARY KEY,
nick TEXT,
channel TEXT,
grabbed_by TEXT,
text TEXT,
timestamp NUMERIC
)
SQL
};
$self->{pbot}->logger->log($@) if $@;
}
sub end {
my $self = shift;
$self->{pbot}->logger->log("Closing quotegrabs SQLite database\n");
if(exists $self->{dbh} and defined $self->{dbh}) {
$self->{dbh}->disconnect();
}
}
sub add_quotegrab {
my ($self, $quotegrab) = @_;
my $id = eval {
my $sth = $self->{dbh}->prepare('INSERT INTO Quotegrabs VALUES (?, ?, ?, ?, ?, ?)');
$sth->bind_param(1, undef);
$sth->bind_param(2, $quotegrab->{nick});
$sth->bind_param(3, $quotegrab->{channel});
$sth->bind_param(4, $quotegrab->{grabbed_by});
$sth->bind_param(5, $quotegrab->{text});
$sth->bind_param(6, $quotegrab->{timestamp});
$sth->execute();
return $self->{dbh}->sqlite_last_insert_rowid();
};
$self->{pbot}->logger->log($@) if $@;
return $id;
}
sub get_quotegrab {
my ($self, $id) = @_;
my $quotegrab = eval {
my $sth = $self->{dbh}->prepare('SELECT * FROM Quotegrabs WHERE id == ?');
$sth->bind_param(1, $id);
$sth->execute();
return $sth->fetchrow_hashref();
};
$self->{pbot}->logger->log($@) if $@;
return $quotegrab;
}
sub get_random_quotegrab {
my ($self, $nick, $channel, $text) = @_;
$nick =~ s/\.?\*/%/g if defined $nick;
$channel =~ s/\.?\*/%/g if defined $channel;
$text =~ s/\.?\*/%/g if defined $text;
my $quotegrab = eval {
my $sql = 'SELECT * FROM Quotegrabs ';
my @params;
my $where = 'WHERE ';
my $and = '';
if(defined $nick) {
$sql .= $where . 'nick LIKE ? ';
push @params, "%$nick%";
$where = '';
$and = 'AND ';
}
if(defined $channel) {
$sql .= $where . $and . 'channel LIKE ? ';
push @params, $channel;
$where = '';
$and = 'AND ';
}
if(defined $text) {
$sql .= $where . $and . 'text LIKE ? ';
push @params, "%$text%";
}
$sql .= 'ORDER BY RANDOM() LIMIT 1';
print "sql: [$sql]\n";
my $sth = $self->{dbh}->prepare($sql);
$sth->execute(@params);
return $sth->fetchrow_hashref();
};
$self->{pbot}->logger->log($@) if $@;
return $quotegrab;
}
sub get_all_quotegrabs {
my $self = shift;
my $quotegrabs = eval {
my $sth = $self->{dbh}->prepare('SELECT * from Quotegrabs');
$sth->execute();
return $sth->fetchall_arrayref({});
};
$self->{pbot}->logger->log($@) if $@;
return $quotegrabs;
}
sub delete_quotegrab {
my ($self, $id) = @_;
eval {
my $sth = $self->{dbh}->prepare('DELETE FROM Quotegrabs WHERE id == ?');
$sth->bind_param(1, $id);
$sth->execute();
};
$self->{pbot}->logger->log($@) if $@;
}
1;

View File

@ -13,8 +13,8 @@ use warnings;
# These are set automatically by the build/commit script
use constant {
BUILD_NAME => "PBot",
BUILD_REVISION => 565,
BUILD_DATE => "2014-05-04",
BUILD_REVISION => 566,
BUILD_DATE => "2014-05-05",
};
1;

View File

@ -336,7 +336,6 @@ twkm ##c 1393837048.42629 dozn!~dozn@24-207-52-240.eastlink.ca you have limited
edk ##c 1393889567.48333 pragma-!~chaos@unaffiliated/pragmatic-chaos sometimes this channel makes me want to mash my brains into a cheese grater
Duzz+Chris ##c 1393933389.37563 dozn!~dozn@24-207-52-240.eastlink.ca What is the term for determining instruction rates from benchmark programs? <Chris> divining
Teckla ##c 1393949900.2454 aemquo!~UN@unaffiliated/aemquo And the LORD said, "Four spaces shall it be; neither more, nor less. Thine indentation shall not be tabs, as they are an abomination."
Zhivago ##c 1393985619.14992 CaZe!~caze@unaffiliated/caze That's what she said.
edk+zid`+zid` ##c 1394473406.13345 rob``!~rob@gtng-4db0408b.pool.mediaWays.net you could always read the fucking man page <zid`> don't google for man abs btw <zid`> you get a lot of half naked men
dozn+someHuman+rob`` ##c 1394520942.81382 dozn!~dozn@24-207-52-240.eastlink.ca someHuman, then learn C# <someHuman> What's the difference? <rob``> one semitone
CaZe ##c 1394525928.2901 rob``!~rob@gtng-4db0491e.pool.mediaWays.net Sorry I was watching electric eel videos.
@ -366,3 +365,11 @@ pragma-+jack_rabbit+pragma- ##c 1397262758.23935 jack_rabbit!~jack_rabb@c-98-253
Zhivago ##c 1397702764.01239 nitrix!~nitrix@unaffiliated/nitrix It's like training a dog, only less adorable.
pragma-+CaZe+pragma- ##c 1398135398.42557 pragma-!~chaos@unaffiliated/pragmatic-chaos some say that the white light you see when you die is actually the birth canal opening as you're born again <CaZe> goatse <pragma-> being born out of an anus would make for a pretty crappy life
nitrix+Chris ##c 1398481252.71708 fisted!~fisted@unaffiliated/fisted Thankfully, I'm more responsible than I'm retarded. <Chris> that's certainly a great deal of responsibility
fisted ##c-unregistered 1398813908.81641 pragma-!~chaos@unaffiliated/pragmatic-chaos can someone explain to me how the sizeof() function works?
pragma- ##c-unregistered 1398814181.04319 fisted!~fisted@unaffiliated/fisted I sux.
Seabasschan ##c-unregistered 1398815030.73377 pragma-!~chaos@unaffiliated/pragmatic-chaos The temptation to grab myself is becoming quite intense.
Chris+Chris ##c 1398905572.56347 pragma-!~chaos@unaffiliated/pragmatic-chaos just write some AI in candide to detect retards <Chris> you'll have to whitelist ops like nitrix
pragma- ##c 1399112839.26945 jack_rabbit!~jack_rabb@c-98-253-57-51.hsd1.il.comcast.net I think your view of humanity is weak and pathetic. You should probably be shot to rid your inferior ineffectual notions from the gene pool so that humanity can become stronger.
Snowleaksange ##c 1399234646.44097 kate`!~kate@unaffiliated/kate/x-0000001 complying with standard way more trouble than worth
BadCodSmell ##c 1399235309.39431 nitrix!~nib@unaffiliated/nitrix Portability is not built into C, that's why your standard exists.
Snowleaksange ##c 1399235839.80165 kate`!~kate@unaffiliated/kate/x-0000001 my advice is to ignore kate

BIN
data/quotegrabs.sqlite3 Normal file

Binary file not shown.

View File

@ -107,7 +107,7 @@ $config{ignorelist_file} = "$config{config_dir}/ignorelist";
$config{factoids_file} = "$config{data_dir}/factoids";
# Location of file containing channel user quotes
$config{quotegrabs_file} = "$config{data_dir}/quotegrabs";
$config{quotegrabs_file} = "$config{data_dir}/quotegrabs.sqlite3";
# Location of file containing message history
$config{message_history_file} = "$config{data_dir}/message_history";