Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
You'll definitely want to move to a real framework eventually. I recommend Jifty, but I may be biased: I'm one of its developers. :) I haven't used Catalyst enough to draw a fair comparison, but what I do know is that Jifty (like Rails) is a full-stack framework. We give you a lot of what you'll need out of the box. Catalyst goes a different way, I guess they make it easy to plug in any modules you already have.

Adbot
ADBOT LOVES YOU

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

more falafel please posted:

I noticed this too, and my first thought was that, if any nonzero value of $| means autoflush, then maybe $|++ and $|-- are preferred to give stack semantics:
code:
$| = 1;
print_some_crap();
someone_elses_code();
print_some_crap();
$| = 0;

sub someone_elses_code
{
    $| = 1;
    print_some_crap();
    $| = 0;  # oh shi
}


Nope. $| is deeply magical. $|++ is equivalent to $| = 1. $|-- is equivalent to $| = 1 - $|.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

more falafel please posted:

Ok, then I have no idea, other than terseness. What's the reasoning for that semantic?

No idea. :)

Triple Tech posted:

What? I thought any non-zero value is funneled to 1 and all in/decrement operators work as expected (on either the numbers one or zero). I don't see any reason why the implementors would go out of their way to provide a different implementation to decrement.

code:
% re.pl
> $|
0
> $| = 100
1
> $| = -1
1
> $| = 0
0
> ++$|
1
> ++$|
1
> --$|
0
> --$|
1
> --$|
0

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

tef posted:

What other languages see as design choices, larry sees as developer choices:

Prototypes vs Class Based OO
Single vs Multiple Inheritance (and traits!)
Lazy vs Strict Evaluation
Static vs Dynamic Typing
And so on...

The problem here is that perl is becoming more of a series of dialects than a language itself. I often poked fun at people asking them if they coded basic in perl, c in perl or sh in perl - and it is becomming more true as more language paradigms are being embraced into perl 6.

To that I quote the recent State of the Onion:

Larry posted:

We don't see Perl 6 as a single language, but as the root for a family of related languages. As a family, there are shared cultural values that can be passed back and forth among sibling languages as well as to the descendants.

I think the idea is great. I do a lot of serious programming and Perl, and I'm very excited about being able to extend the language itself. Of course, maybe what I really want is a very very Perlish dialect of Lisp.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

heeen posted:

by the way, this also works:
code:
perl -e 'print "$_\n" foreach(<*.*> );'

Of course, a lot of that is redundant!

code:
perl -le 'print for <*.*>'

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

TiMBuS posted:

Hm, feels a bit hackish to do it like that, plus ill have to change the shebang once 5.10 is out from the repositories..

But hey, that's probably easier than making my own package.

You can built it from source in your home directory, then alias perl=/home/timbus/bin/perl5.10. This way you can run 5.8.8 with ./script and 5.10.0 with perl script. Also, your one-liners will be 5.10.0.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Triple Tech posted:

Anybody going to YAPC in Chicago this year? I think I'd like to convince my employer to let me go but I'm new here still...

Don't know yet. I'd like to go.

I will be speaking at Frozen Perl next month though!

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Triple Tech posted:

Oh yeah? A lightning talk probably... About what? Who are you really... Are you like a famous Perl guy? At least you've got balls to talk, that's gotta count for something.

I'm giving a twenty minute talk on Template:: Declare. It looks like this:

code:
template foo => page {
    div {
        ol {
            for (@bar) {
                li { $_ }
            }
        }
    }
}
Way way nicer than anything else I've used for generating HTML and XML.

edit: drat smilies.

another edit: Also, the only community I'm at all famous in is NetHack (where I go by the name Eidolos). I'm lucky enough to work on RT and Jifty, and I try to help with Moose when I can.

Filburt Shellbach fucked around with this message at 15:55 on Jan 16, 2008

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

leedo posted:

Whoa, I had never seen that syntax before (using a list of hash keys)... cool!

Yeah, hash slices are neat. Here are some more idioms:

code:
@to{@keys} = @from{@keys};
@to{keys %from} = values %from;  # much faster than %to = (%to, %from);
@exists{@items} = ();
delete @score{'bad', 'worse', 'worst'};

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Here's a good example of why I shouldn't be allowed near Perl's inner workings: autobox::Closure::Attributes

Other than being a neat trick, it is a concise example of how to use really powerful tools you don't see every day:
  • autobox to let you add methods to ordinary scalars (in this case, coderefs)
  • PadWalker to inspect and change the variables captured by a closure
  • AUTOLOAD to catch all method calls
Are there any languages that have anything like this?

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

genericadmin posted:

code:
package main;
use strict;
my $a = sub { my $thing = 'blue'; };
sub test { print $_[0]() };
&test($a);
This will print 'blue', because $thing persists in the scope of the closure.

It's even more than that. To have a closure, the variable has to be defined outside of the function. In CSey words, it needs to be a "free variable" in the scope of the function.

code:
package main;
use strict;

my $a = do {
    my $thing = 'blue';
    sub { "I am colored $thing" };
};
sub test { print $_[0]() };
&test($a);
This will print "I am colored blue". The sub "captures" the variable $thing. What autobox-Closure-Attributes does is let you get and set $thing directly.

code:
use autobox::Closure::Attributes;

print $a->thing; # "blue"
$a->thing("green");
print $a->thing; # "green"

test($a); # I am colored green

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

genericadmin posted:

Interesting, I'd not realized a closure differed from an anonymous sub based on it encapsulating data from a higher scope.

Yep, that's what makes them so powerful. Take this example. Each instance of the function returned by create_counter gets its own $count.

code:
sub create_counter {
    my $count = shift;
    return sub {
        return ++$count;
    };
}

my $from_3 = create_counter(3);
my $from_9 = create_counter(9);

print $from_3->(); # 4
print $from_9->(); # 10
print $from_3->(); # 5
$from_3 and $from_9 are both references to functions, so you can pass them in anywhere that expects a function. Where would this be useful? Suppose you're using a module that expects you to provide a callback. You could see exactly how it's being called.

How about some imaginary function (delete_with_callback) that invokes your callback for a list of files, and you return true for files you want to delete, and false for files you want to keep.

However, the function returns the count of files that were deleted, but not the filenames. And you want to tell the user what you deleted. Here's how I'd do it:

code:
my @deleted;
my $callback = sub {
    my $file = shift;
    if ($file =~ m{\.py$}) {
        push @deleted, $file;
        return 1;
    }
    return 0;
};

delete_with_callback($callback);
print @files ? "Deleted @files" : "No files deleted";

genericadmin posted:

I'm curious why you chose to incur the overhead of AUTOLOAD and bring in PadWalker to accomplish this. Why not use a hash reference?

Oh, I totally wouldn't use this for regular objects. It's more a proof of concept than anything. However, on the very very small chance you need to get/set a closure's variables directly, this may be less painful than using PadWalker directly. For debugging, perhaps.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
See also Curses, if (any of) you are interested in a "full-screen" terminal application like vim or NetHack.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Perl rocks so much. I just used Bot::BasicBot and XML::Simple to get a bot announcing commits in a project's IRC channel.

Here's a complete and working (but less generalized) version of it.

code:
package Bot::BasicBot::Commit;
use strict;
use warnings;                                                                   
use XML::Simple;
use base 'Bot::BasicBot';

sub tick {
    my $self = shift;

    my $ever_checked = $self->{last_timestamp};

    my $xml = `darcs changes --repodir '$ENV{HOME}/www/code/TAEB' --xml --last 20`;
    my $changes = XMLin($xml, ForceArray => 1)->{patch};

    for my $change (reverse @$changes) {
        next if $change->{date} <= $self->{last_timestamp};
        $self->{last_timestamp} = $change->{date};

        # the first time around, we don't want to announce anything
        next if !$ever_checked;

        $self->say(channel => "#interhack", body =>
            sprintf '%s - %s',
                $change->{author},
                join ' ', @{ $change->{name} },
        );
    }

    return 20; # check again in 20 seconds
}

package main;
Bot::BasicBot::Commit->new(
    server => "irc.freenode.org",
    channels => ["#interhack"],
    nick => "NHBotCommit",
)->run;

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Narpas posted:

I'm trying to use PERL

Please call it Perl or perl. PERL reeks with everything wrong about the language.

Narpas posted:

The problem is that the line $size = -s "$file"; returns "" for $size. Is there a different way to get the file size, or should I just pass a function to bash?

-s $file returning the empty string means it couldn't find the file. Are you sure you're in the right directory and that $file is there?

If you're building up @files through readdir, they won't have the directory name prepended - you have to manually do that.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Narpas posted:

Well, I knew, academically, about making a hash table, but I didn't realize they were implemented simply - I've always figured that they were needlessly complex for small scale tasks.

Hash tables are very very useful for tasks small and large. Perl can probably be blamed for most modern languages having hash tables built into the language (or at least in a standard library).

Narpas posted:

Also, Sartak - I loved your LP Nethack, assuming that's, in fact, you.

Yeah, that's me :clint:

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Triple Tech posted:

Maybe you should try word boundaries.
code:
if ($text =~ /\bsize\b/) { do_it }

But that matches "Install-Size: 34234" which he doesn't want to be matched. I'd say a combination:
code:
if ($text =~ /(^|\s)size\b/i)

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

TiMBuS posted:

Need halp picking a MVC framework.

I want to keep it lightweight, because it's just a modpanel. This means catalyst is out the window because I installed it about half an hour ago and that poo poo is HUGE.

I thought Catalyst was small, and that the functionality is in its plugins..

quote:

Think I should just bang out my own custom framework?

God no!

quote:

Also, Sorta Off-Topic: Has anyone had a look at the Continuity module on CPAN?

I've been playing with it the last few days. It's really interesting.


I'm a Jifty developer but if you want something small I'd recommend Catalyst. Jifty comes with everything you need, so the install is much larger than Catalyst's.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Triple Tech posted:

The fastest method to date (from my informal testing) looks like this:
code:
my $first_col  = substr $_, 0, 10;
my $second_col = substr $_, 10, 2;
my $third_col  = substr $_, 12, 6;
# and so on

I'd really be surprised if this wasn't the fastest method:

code:
my @cols = unpack 'a10a2a6...', $_;

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

LightI3ulb posted:

I'm having a hell of a time trying to figure out why when I try to open a file, it sets the filehandle to the name of the file and not the lines inside of the file.

code:
opendir(DIRENT, "/var/local/translog/do_not_market");
my @entries = readdir(DIRENT);
foreach $name (@entries){
	if (($name ne ".") && ($name ne "..")){
		open(LOG, '<', \$name);

That looks wrong. You're passing in the name of the file by reference.. why? Also, readdir returns the filenames relative to the directory from which you're reading. So you have to prepend the directory's path to each file. You actually want something like:

code:
open(LOG, '<', "/var/local/translog/do_not_market/$name");

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Triple Tech posted:

Are scalar file handles superior to traditional ones in every way?

I'd say so. Another big benefit is that they automatically close when the scalar is freed. Globals are freed (and thus, the filehandle automatically closed) only when the interpreter shuts down.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Triple Tech posted:

Actually, there is a difference... And it's a terrible one. And I never use it. But in this particular scenario and use, you are correct.

In case anyone was curious: using & means the function call ignores the function's prototype, and passes in a plain list. As Triple Tech mentioned, it's pretty terrible.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

LightI3ulb posted:

Fixed. Still clueless.

What errors are you getting?

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Fenderbender posted:

Among a bunch of other things, you should concatenate with a period (.) not a comma (,) so the first I'm going to say is to replace:

open $out, ">", "$log_dir$csvfile";

with: open $out, ">" . "$log_dir$csvfile";

if not: open $out, ">$log_dir$csvfile";

or even better: open($out, '>' . $log_dir . $csvfile);

I'd suggest the very opposite! The way he already has it is perfect. Separating the mode from the filename is a really good idea. What if his filename started with a >? Or any other character the mode parser looks for. Concatenation versus interpolation is really a preference thing - Perl transforms interpolation to concatenation in the compile phase.



The error is here:

foreach (my $csvfile (@csvfiles)){

The correct syntax is:

foreach my $csvfile (@csvfiles) {

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
YAPC::Asia is streaming their talks at http://live.yapcasia.org/. Right now I'm listening to Ingy talk about pQuery. The schedule of talks will also be useful.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Is anyone else going to be at YAPC::NA in Chicago next month?

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Triple Tech posted:

For some reason I'm feeling a little ehh about it... Is YAPC really that fun/worth it?

It'll be my first YAPC, so I can't say for sure. But I am very excited about it. There are so many talks I want to see and people I want to meet. You should definitely come by. It's only $100. I think you'll get your money's worth.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

6174 posted:

Scalar::Util is somehow screwed up and the answer is to reinstall the module in CPAN

I'll expand on this, because it's a lovely problem that's worth knowing about.

Some vendors (notably, RedHat, though maybe they've since fixed this) ship a broken Scalar::Util. In particular, weaken just does not work. This sucks because weaken is absolutely necessary for working with circular data structures.

Module authors: depend on Task::Weaken. It will test weaken support explicitly and do whatever it can to help the situation, including letting the user that his Scalar::Util is broken.

Thankfully it's not as big a deal nowadays as Scalar::Util is in the core distribution as of 5.8.

Filburt Shellbach fucked around with this message at 01:22 on Jun 12, 2008

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
It's quite common to use regular methods for this. I use this pattern all the time. For example:

code:
package My::Widget;

sub type { croak "You must defined a type in " . blessed($_[0]) }

sub render {
    my $self = shift;
    my $type = $self->type;
    print qq{<input type="$type" />};
}

package My::Widget::Text;
use parent 'My::Widget';

sub type { 'text' }

package My::Widget::Submit;
use parent 'My::Widget';

sub type { 'submit' }


My::Widget::Text->render;
My::Widget::Submit->render;

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Triple Tech posted:

Is there anything inherently good/bad/better/wrong with passing things by reference and modifying them?

It doesn't really matter. I err on the side of returning values in a functional style. Modifying a reference can cause unexpected changes elsewhere in the program.

Sometimes you need references though, when you need to modify or return multiple values, or you have to return some other value.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

genericadmin posted:


Triple Tech posted:

code:
{
  open my($fh), 'foo.txt' or die;
  process($fh);
}

That's a bit useless because $fh only exists within the open() call and would go out of scope by the time process() was called.

That's not true. Function arguments don't create a new lexical scope, so the scope of $fh is the open call to the close brace. Basically, anywhere you can have a value, you can my a variable on the spot and you're probably good to go.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
I've got one more for you!

genericadmin posted:

open implies the '<' mode if none is specified. It won't ever clobber existing files unless specifically instructed to do so.

If the user has enough control over the filename, then they can do some damage. This is because two-arg open looks at the first few characters of the filename to figure out what mode to open the file in. Three-arg open is not susceptible to any of these:

code:
my $filename = ">credit-cards.sqlite";
open(HANDLE, $filename);
That opens your credit card database for writing, which first clears its contents!

It gets even better, because Perl supports opening handles to other programs in open, the user can run arbitrary programs as you:

code:
my $filename = "|echo MWA HA HA"; # or better yet, "|rm *"..
open(HANDLE, $filename);
I play it safe and always use three-arg open, which in the above examples will try to read from the files named >credit-cards.sqlite and |echo MWA HA HA. These are still annoying, but they can't really hurt you.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Why are you using my $hash{key}? Just remove the mys.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

GroovinPickle posted:

I've got files named foo1.jpg, foo2.jpg, ... foo521.jpg

No, they're not porn. I just want to rename them with the integer part of the filename padded with zeros (foo001.jpg, foo002.jpg, ...).

First, you suck for posting this in the Perl thread.

If you have the rename perl script:

rename 's/\d+/sprintf "%03d", $&/' foo*.jpg

Otherwise,

perl -e 'for (@ARGV) { my $old = $_; s/\d+/sprintf "%03d", $&/; rename $old => $_ }' foo*.jpg

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Ah. Good catch. Sorry. :)

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
PadWalker is an excellent piece of software. My only complaint is that you can't add new variables to a pad with it, you can only read or update.

Oh the evil I could do..

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Any Moose users in the crowd? Just curious! (disclosure: I'm on the devteam)

In case you haven't heard of it: it's a really nice way to do OO. Moose itself is very declarative. For example:

code:
package Forum::User;
use Moose; # also turns on strict and warnings for you

# "has" creates a new attribute
has post_count => (
    # the attribute is read/write, so we get a r/w accessor:
    # $self->post_count and $self->post_count($new_count)
    is => 'rw',

    # isa sets up a type constraint. post_count must be an integer
    isa => 'Int',

    # every user starts with 0 posts
    # (though we could create a user who starts with more)
    default => 0,
);

has regtime => (
    # read-only, so $self->regtime($today) throws an error
    # (SA's 9-11 regdate upgrade could still work, just not through this accessor)
    is => 'ro',

    # classes are type constraints too
    isa => 'DateTime',

    # default values can be arbitrarily complex
    default => sub { DateTime->now },

    # delegation: make a regdate method that calls $self->regtime->ymd
    handles => {
       regdate => 'ymd',
    },
);

# "post" method is up to your imagination
sub post { ... }

# "after" method modifiers are run after the original method is done
after post => sub {
    my $self = shift;

    # this could be written more concisely with MooseX::AttributeHelpers
    $self->post_count($self->post_count + 1);
};
Give it a try! I bet you'll like it, especially if you're using something like Class::Accessor already.

I'll of course answer any Moose questions you guys have (and if I can't, I'll forward them to the guy who started the project).

Want to see more code? Should I explain a MooseX module? I could rewrite a CPAN module using Moose to see just how much less code is required.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Moose's major performance hit is in startup speed. Moose has to instantiate objects for all of your classes, attributes, methods, etc. We're always working on improving that; it is much better than it used to be. There's also a MooseX-Compile project that aims to perform this compilation only once, and after that load your classes from a Storable blob on disk. I should probably lend a hand to this project. I'd really like to see it get off the ground.

There's also a runtime cost. Using "make_immutable" (described in the docs for Moose.pm) will eliminate a lot of the cost. make_immutable memoizes some meta-level methods and inlines others.

I don't know about memory usage, because I've never cared about that. (I should)

I personally think Moose is worth all of these costs.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

SpeedFrog posted:

what useful stuff in Moose/MooseX:: wouldn't be immediately obvious from the docs/CPAN?

Check out MooseX::AttributeHelpers.

You have an array attribute. But if you want to push elements onto it, you have to write something like this:

code:
sub add_rules {
    my $self = shift;
    my @rules = @_;

    push @{ $self->rules }, @rules;
}
But then @rules won't be type checked. MooseX::AttributeHelpers lets you write the following, which will have new rules be type-checked. It provides a bunch of helper methods for Perl's builtin types.

code:
has rules => (
    [b]metaclass => 'Collection::Array',[/b]
    is => 'ro',
    isa => 'ArrayRef[MyRule]',
    default => sub { [] },
    [b]provides => {
        push => 'add_rules',
    },[/b]
);

Triple Tech posted:

It's not "just regular Perl". It's trying to make has look like a regular keyword. I'm not even sure how it does that. :psyduck: (I wanted to say prototypes but on a shallow glance I can't seem to find where it implements it)

Here's what has looks like:
code:
sub has {
    my $name = shift;
    my %args = @_;
    ...
}
There's no magic or prototype. The parentheses are not required and => is a "fat" comma that quotes the word to its left. You can use this syntax anywhere.

edit: It's implemented in Moose.pm. The first instance of the word has is defining the keyword. It's only a little more complicated than what I've got, because you can pass in an array reference of names to define a bunch of attributes with the same options at once. We have a prototype, but it's only so passing in an odd number of arguments will explode sooner rather than later.

quote:

Regular Perl would a constructor named new that returns a blessed hash and has a bunch of subroutines attached to it.

Like Moose, you mean? :) Moose does use blessed hashrefs. Your class inherits "new" from Moose::Object. You still define methods as subroutines in a package.

Filburt Shellbach fucked around with this message at 16:49 on Aug 4, 2008

Adbot
ADBOT LOVES YOU

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Subotai posted:

Where are you getting this??

I assume Perl Best Practices:

PBP p 13 posted:

Don't use unnecessary parentheses for builtins and "honorary" builtins.

In my opinion it doesn't really matter. But there are some cases where you need use parentheses (to avoid indirect method call syntax :argh: ), though probably not for builtins.

Filburt Shellbach fucked around with this message at 18:09 on Aug 4, 2008

  • Locked thread