package Acme::PerlMonkify; use 5.008; use strict; use warnings; our $strict; our $warnings; our $VERSION = '0.01'; use LWP::Simple; use Cache::FileCache (); use B::Deobfuscate '0.10'; use constant DEBUG => 0; our ( $start_url, $USERNAME, $START ); BEGIN { $start_url = "http://tinymicros.com/pm/index.php?goto=MonkStats&start=1"; $USERNAME = "usernames"; $START = "start"; } BEGIN { my $old = \ &B::Deparse::declare_hints; no warnings 'redefine'; *B::Deparse::declare_hints = sub { my $r = $old->( @_ ); no strict 'refs'; ${__PACKAGE__ . "::$1"} = 1 if $r =~ /^use (warnings|strict)/; ${__PACKAGE__ . "::warnings"} = 1 if $^W or ${^WARNING_BITS}; return $r; } } sub cached_get { my $cache = shift; my $start = shift; my $url; ($url = $start_url) =~ s/(?<=start=)\d+/$start/; my $html = $cache->get( $url ); return $html if $html; $html = get( $url ); $cache->set( $url, $html ); return $html; } sub usernames { my $cache = Cache::FileCache->new( { namespace => __PACKAGE__ } ); my $users = $cache->get( $USERNAME ) || {}; my $start = $cache->get( $START ) || 0; # Get the next cached page my $page = cached_get( $cache, $start ); # Update the start parameter so we'll search farther next time. DEBUG and print "$START: $start\n"; my $new_start = $start + 50; $cache->set( $START, $new_start ); # Update the users list my @urls = $page =~ m{(?>(?!]+)>(.+)}ig; for (my $i = 0; $i < @urls; $i += 2) { unless ($urls[$i] =~ m{http://(?:www\.)+perlmonks\.org}) { $urls[$i + 1] = undef; } $urls[$i] = undef; } my @new_users = grep defined, @urls; for (@new_users) { s((?:\s*]+>)*\s*$)()mi; s/\W/_/g; } @$users{@new_users} = () x @new_users; DEBUG and print "\@new_users: " . @new_users . "\n"; $cache->set( $USERNAME, $users ); DEBUG and print( "%users: ".(0+keys %$users), "\n" ); return join "\n", keys %$users; } sub import { shift; return if @_; my $deparse = B::Deparse->new(qw(-p))->coderef2text( \&B::Deparse::begin_is_use ); $deparse =~ s{^\s*if\s*\(\s*\(\s*\(\s*\(\s*\(\s*(\$\w+)\s+eq\s*'strict' \s*\)\s*or\s*\(\s*\$\w+\s+eq\s*'integer'\s*\)\s*\)\s*or\s*\(\s*\$\w+\s+eq \s*'bytes'\s*\)\s*\)\s*or\s*\(\s*\$\w+\s+eq\s*'warnings'\s*\)\s*\)\s*\) \s*{\s*return\s*\(\s*''\s*\)\s*;\s*}\s*^}{ \$Acme::PerlMonkify::strict = 1 if $1 eq 'strict'; \$Acme::PerlMonkify::warnings = 1 if $1 eq 'warnings'; }mx; { no warnings; *B::Deparse::begin_is_use = eval "sub $deparse" or die $@; } open *B::Deobfuscate::DATA, "<", \ usernames(); require O; tie *STDOUT, __PACKAGE__ || die $!; O->import( 'Deobfuscate', "-m/${\qr[\A(?=\w*[[:lower:]]\w*)\w+\z]}/" ); } sub TIEHANDLE { bless \my $stick, shift } sub PRINT { my $src = $_[1]; local *OUT; open OUT, ">", $0 or die "Cannot monkify '$0'"; select OUT; $| = 1; open STDIN, $0; my $octothorpebang = ; print OUT $octothorpebang if $octothorpebang and $octothorpebang =~ /^\Q#!/; print OUT +(not ($strict or $warnings)) ? qq[warn "So you didn't use strict? And no warnings? - Expect the Inquisitors\n";] : not($strict) ? qq[warn "No strict?! Who do you think you are, [TheDamian]?\n";] : not($warnings) ? qq[use strict;\nwarn "I didn't see you use warnings so I turned them on for you and made them fatal errors";\nuse warnings FATAL => 'all'; \# Bwuahaha!\n] : "\# Sit! What a good monk you are! Good boy!\nuse strict;\nuse warnings;\n"; $src =~ s/\A(?:^sub Cache::[\w:]+;\s*)+//gm; print OUT $src; close STDERR; } 1; __END__