• Welcome to Overclockers Forums! Join us to reply in threads, receive reduced ads, and to customize your site experience!

F@H stats in your sig: not just for Linux anymore!

Overclockers is supported by our readers. When you click a link to make a purchase, we may earn a commission. Learn More.

Christoph

JAPH Senior
Joined
Oct 8, 2001
Location
Redmond, WA
Windows setup
Thanks to BeerCan for writing this section up.

Ok. Thanks to Christoph and his new perl script you can now update your signatures from a windows machine automatically.
There is one prerequisite. You need to download a win32 version of perl. You can find it here http://www.activestate.com/Products/Download/Download.plex?id=ActivePerl. I downloaded the msi version but your preference may vary. The AS Package doesn't provide any uninstall functionality, and ActiveState recommends it only if you can't use the MSI installer. Install using all of the defaults. It will create a directory c:\Perl and automatically install all necessary files there. It will also create your program groups and associate all perl extensions with perl.exe. The files we care about will end with the .pl extension. Next, we need a copy of Christoph's mksig script.

Create a directory on your c:\ drive called c:\mksig. Then, save the above linked file as c:\mksig\mksig.pl . Please make sure it has just the .pl extension and not the .pl.txt extension. If you renamed the file to mksig.pl and it still has the text icon, you need to disable hiding of known extenstions. If you do it right, the icon should turn from the notepad icon to an icon with a lizard on it. Next, execute mksig.pl. Either double click the icon or run it from a dos prompt. Both methods work. Answer all of the questions. It should create the following files in c:\mksig -- mksig.conf, sig, sig_gen.pl and sig.log. These are explaned later in this howto.

If all of those files are there, it installed correctly.
The next step is to make sure that any firewalls you're running don't block Perl.exe from connecting to the Internet. How this is accomplished will depend on your firewall, so check its documentation for more information. If you get an error like Please make sure that Perl can connect to the outside world. , you probably forgot to unblock Perl.exe.

If you want to keep your current forum sig, you should save it now, since mksig doesn't currently back up old sigs. Now when you run mksig.pl again it will update your sig :) Now we need to get it running as a task so it will update automatically.

Open the windows Scheduled Tasks manager. On windows XP it's start-->All Programs-->Accessories-->System Tools-->Scheduled Tasks on Win2K its Start-->Programs-->Accessories-->System Tools-->Scheduled Tasks.

Next click Add a Scheduled Task-->Next on the next screen you are going to hit Browse and browse to C:\mksig\mksig.pl and click open. Next you need to pick how often to run the task. I picked daily. Next, customize the start time to your liking and click next. On the next screen you need to enter the windows user that you would like to run the task under. This is what you use to login to windows and has nothing to do with your forum username. Make sure you enter a password or the task won't run properly. Click next. If you would like to run the task more often than daily, click on the open advanced properties checkbox and click finish. Now you can click the schedule tab and customize to your liking. It should be clear. Click ok and save and you are done.

Of course, if you want to change your sig you need to customize sig_gen.pl. That's covered in the last section of this howto.


Linux setup

Most distros today have Perl available, and installing it is usually a simple matter. For this script, you'll need Perl, LWP (which comes with the base Perl system), the Digest::MD5 module and the XML::Simple module if you're running Linux. If Digest::MD5 isn't installed on your system, just run the following command as root: perl -MCPAN -e "install Digest::MD5" or install from a distro-specific package. If you've never used CPAN before, you'll be asked a number of questions about your setup, and the overall setup can take several minutes. If you're running Gentoo, Debian or their offspring, you can install Digest-MD5 and XML-Simple or libdigest-md5-perl and libxml-simple-perl, respectively and avoid the hassle of CPAN. I don't know if similar packages are available for other distros.

Once you've got Digest::MD5 and XML::Simple installed, download mksig. To get it ready to run, do the following commands as root:
Code:
mv mksig.txt mksig
chmod 755 mksig
mv mksig /usr/bin

The previous instructions recommended changing the ownership to root:root. With versions .62 and later, having mksig owned by either root or non-root will work, although installing as root and running as non-root will prevent automatic updates form working. Since you should *never ever* run day-to-day stuff like this as root, I recommend leaving the default ownership.

Now run mksig as a normal user. Tell it your username and password when asked and use y or n to indicate if you want automatic updates. (If you enable this, mksig will check for a newer version of itself each time it runs, and if possible will download, install and run it. This feature has been tested in both windows and Linux.) Now you're ready to use the default sig. Note that mksig won't change your sig the first time it's run. This is to give you a chance to backup the old one and edit your sig generator (see next section). All user-specific information is stored in ~/.mksig and is covered in the next section.

To get mksig to run at regular intervals, you have a couple options.
The simplest is a backgrounded while loop. Pick and update interval and run (while let 1 do; mksig >/dev/null; sleep 30m; done) & and your sig will silently be updated every half-hour. If you need it to stop updating, simply run pkill sleep and it'll stop.
A similar method is to the first is while loop in the foreground. Simply run while let 1 do; mksig >/dev/null; cat ~/.mksig/sig; sleep 30m; done and your sig will be updated every 30 minutes, and the vbcode will be displayed in the terminal window.
The third method is to use a cron job. cron jobs are executed at regular intervals and are quite simple to set up. You can find Gentoo's instructions on three popular cron implementations here.


What the Files Do

There are four files: two config files and two logs. In mksig's directory, mksig.conf contains your username and password. sig_gen.pl is the Perl script (or any executable) whose output is submitted as your sig. Under Linux this file is called sig_gen because it's easier to type and Linux doesn't rely on filename extensions. sig contains the most recently submitted sig, and sig.log contains every sig mksig has submitted, along with a timestamp.


How to Get Your DC Stats in Your Sig

mksig determines what your sig will look by executing mksig.pl . Whatever it spits out will be your sig.
Below, I'll post a couple simple example sigs, two that demonstrate how to get stats from Stanford and Berkeley's pages, and the one I'm using now. If there's enough demand, I'll add code to get stats from other pages.
If you know Perl, you'll probably already have come up with some elaborate sig. Good for you. ;)
If you don't know Perl, however, feel free to use these examples as a starting point. While a Perl tutorial of decent length is beyond the scope of this howto, there are hundreds of Perl tutorials available via Google. Going over this one should help you figure out most of what these scripts do. If it looks intimidating, just look at a page of the tutorial and figure out how the examples use its concepts. When you understand it, go on to the next page, etc.
If you'd like a sig_gen with easy setup, excellent explanation and a good default look, make sure to go through JerMe's excellent guide here.
For something more basic, take a look at these scripts. In the first three, I've added links to the comments that explain what's happening on the next line. You're mostly on your own for the later ones.

Example 1:
Code:
#!/usr/bin/perl -w
print "Hello!\n";
print "I am a sig.\n";

output from example 1:
Code:
Hello!
I am a sig.



Example 2:
Code:
#!/usr/bin/perl -w
#[url]http://www.perldoc.com/perl5.6/pod/func/localtime.html[/url]
@time = localtime;
$time[5] += 1900;
$time[4]++;
#[url]http://www.perldoc.com/perl5.6/pod/perlfunc.html#Alphabetical-Listing-of-Perl-Functions[/url]
$time_str = sprintf("%02d/%02d/%04d at %02d:%02d.\n",$time[4],$time[3],$time[5],$time[2],$time[1]);

print "Christoph's automatic sig generator v.8\n";
print "This sig was generated on $time_str";

possible output from example 2:
Code:
Christoph's automatic sig generator v.8
This sig was generated on 01/26/2005 at 23:49.



Example 3 (default sig_gen):
Code:
#!/usr/bin/perl
use LWP::UserAgent;

#Get fortune from a website because windows isn't cool enough
#to have it installed natively.
#[url]http://www.perldoc.com/perl5.6/lib/LWP/UserAgent.html[/url]
$ua= LWP::UserAgent->new();
$res=$ua->get("http://www.update.uu.se/user-cgi/bjorn/cookie.cgi?1+5");
$f_state=0;

$fortune="";

for $line (split /^/, $res->content) {
  if ($line =~ m#<HR># && $f_state == 0) {
    $f_state=1;
  } elsif ($f_state==1) {
    if ($line =~ m#</pre>#) {
      $f_state=0;
    } else {
      $line =~ s/<[^>]*>//g;
      $fortune .= $line;
    }
  }
}

@time = localtime;
$time[5] += 1900;
$time[4]++;
$time_str = sprintf("%02d/%02d/%04d at %02d:%02d.\n",$time[4],$time[3],$time[5],$time[2],$time[1]);

print "Christoph's automatic sig generator v.8\\n";
print "your fortune:[ font=monospace][ b]\\n";
print "$fortune";
print "\\n";
print "[/font][/b]This sig was generated on ";
print "$time_str";

possible output from example 3:
Code:
Christoph's automatic sig generator v.8
your fortune:[font=monospace][b]
You are not Morg.  You are not Eymorg.
                         -- Kara the Eymorg, "Spock's Brain," stardate 5432.3
 
[/font][/b]This sig was generated on[b][font=monospace]1/27/2005 at 0:1:59[/b][/font].

S@H stat example code
This will make a simple sig and demonstrate how to adapt it to your tastes. It's not pretty, but it's really more of a starting point than an end. A rewrite's on my todo list, but getting something that works is more important than getting something that's pretty and works.
Note that this has a lot of unnecessary code. Feel free to nuke all the code having to do with any pages you don't use stats from.

Code:
#!/usr/bin/perl 

use XML::Simple;
use LWP::Simple;
use LWP::UserAgent;
  
$boinc_id=841;

#I don't know how to find out this email for any given user.
#I assume that you have to give Berkeley your email addy when you signed up.
$berk_email = "lmester\@access.k12.wv.us";

#This is where your seti client lives.  If you're in windows, make sure
#to separate directories with "\\" instead of "\".
$seti_home = "/home/ideamagnate/OCFAQ/foldsig/seti/boincdir";
#$seti_home = "c:\\something\\something";

$wu      = "$seti_home/slots/0/work_unit.sah";
$state   = "$seti_home/slots/0/state.sah";
$c_state = "$seti_home/client_state.xml";

#0 means disable, 1 means enable
$use_boincstats   = 1;
$use_localboinc   = 1;
$use_classicstats = 0;
#Local classic client monitoring isn't implemented yet.
#I'll get to it.  Bug me about it if not.
$use_localclassic = 0;

#windows-specific stuff
if ($^O =~ /win/i) {
  #change "/" into "\" on windows machines
  $wu      =~ s/\//\\\\/g;
  $state   =~ s/\//\\\\/g;
  $c_state =~ s/\//\\\\/g;
}

#read client's state into $boinc_progress
open BOINC_STATE, "$state";
while (<BOINC_STATE>) {
  if (/<prog>[[b][u][/b][/u]\d\.]*<\/prog>/) {
    s/<prog>([[b][u][/b][/u]\d\.]*)<\/prog>/$1/;
    chomp;
    $boinc_progress = $_;
  }
}
close BOINC_STATE;

#get current wu's name from appropriate place
open BOINC_WU, "$wu";
while (<BOINC_WU>) {
  s/<soft_link>\.\.\\\.\.\\projects\\setiathome\.berkeley\.edu\\//;
  s/<\/soft_link>//;
  chomp;
  $wu_name = $_;
}
close BOINC_WU;

#parse and extract info from xml file
$cs_xml = XMLin($c_state);
$total_credit = $cs_xml->{project}->{host_total_credit};

###########################
#get BOINC stats from web##
###########################

if ($use_boincstats) {
 
  #[url]http://www.boincstats.com/stats/user_graph.php?pr=sah&id=841[/url]
  
  $boinc_page = "http://www.boincstats.com/stats/user_graph.php?pr=sah&id=$boinc_id";
  $local_boinc_cache = "boinc.html";

  getstore($boinc_page, $local_boinc_cache);

  if (! -e $local_boinc_cache) {
    print "get the file, stupid\n";
    exit;
  }
  
  #extract stats from boinc page
  open BC, "$local_boinc_cache";
  while(<BC>){

    if (/Detailed statistics for<br>/) {
      $_ =~ s/"([[b][u][/b][/u]a-zA-Z][[b][u][/b][/u]\w\s]*)/$1/;
      $boinc_user = $1;
        
    } elsif (/>User ID</) {
      <BC>;
      $boinc_id = <BC>;
      chomp($boinc_id);
      $boinc_id =~ s/\s*(\d*).*/$1/;
    
    } elsif (/<td>Total Credit</) {
      <BC>;
      $boinc_total_credit = <BC>;
      chomp($boinc_total_credit);
      $boinc_total_credit =~ s/\s*([[b][u][/b][/u]\d\.\,]*)<.*/$1/;
  
    } elsif (/Number of hosts/) { 
      <BC>;
      $boinc_hostcount = <BC>;
      chomp($boinc_hostcount);
      $boinc_hostcount =~ s/\s*([[b][u][/b][/u]\d,]*).*/$1/;
  
    } elsif (/World Position/) {
      <BC>;
      $boinc_overall_rank = <BC>;
      chomp($boinc_overall_rank);
      $boinc_overall_rank =~ s/\s*([[b][u][/b][/u]\d,]*).*/$1/;
  
    } elsif (/than % of all users/) {
      $boinc_percentile = <BC>;
      chomp($boinc_percentile);
      $boinc_percentile =~ s/<td>(\d*.\d*)%.*/$1/;
  
    } elsif (/Position in Team/) {
      <BC>;
      $boinc_team_rank = <BC>;
      chomp($boinc_team_rank);
      $boinc_team_rank =~ s/\s*([[b][u][/b][/u]\d,]*).*/$1/;
    }
  }
  close BC;
}


##########################
#get stats from Berkeley##
##########################

if ($use_classicstats) {
  
  $berk_url = "http://setiathome2.ssl.berkeley.edu/fcgi-bin/fcgi";
  $berk_url = "http://setiathome2.ssl.berkeley.edu/fcgi-bin/fcgi?email=";
  $berk_url .= "$berk_email&cmd=user_xml";
  $berk_url =~ s/@/%40/;

  #[url]http://setiathome2.ssl.berkeley.edu/fcgi-bin/fcgi?email=lmester%40access.k12.wv.us+&cmd=user_xml[/url]

  $ua = LWP::UserAgent->new();
  $berk_xml = $ua->get( "$berk_url");

  #$berk_xml = $ua->get( "$berk_url",
  #                    [[b][u][/b][/u] "cmd"   => "user_xml",
  #		      "email" => $berk_email]);

  #extract info from Berkeley's not-quite XML 
  foreach $line (split /^/, $berk_xml->content) {
  
    if ($line =~ /<name>/) {
      for ($cl_name = $line) {
        chomp;
	s/<[[b][u][/b][/u]^>]*>//g;
	s/\s*//;
      }
    } elsif ($line =~ /numresults/) {
      for ($cl_num_results = $line) {
        chomp;
        s/\s*<[[b][u][/b][/u]a-z_]*>([[b][u][/b][/u]^<]*).*/$1/;
      }
    } elsif ($line =~ /cputime/) {
      for ($cl_user_time = $line) {
        chomp;
        s/\s*<[[b][u][/b][/u]a-z_]*>([[b][u][/b][/u]^<]*).*/$1/;
      }
    } elsif ($line =~ /resultsperday/) {
      for ($cl_daily_results = $line) {
        chomp;
        s/\s*<[[b][u][/b][/u]a-z_]*>([[b][u][/b][/u]^<]*).*/$1/;
      }
    } elsif ($line =~ /<rank>/) {
      for ($cl_rank = $line) {
        chomp;
        s/\s*<[[b][u][/b][/u]a-z_]*>([[b][u][/b][/u]^<]*).*/$1/;
      }
    }
  }
}  

#These are boring examples of how to print out stuff.
#Hopefully, you'll come up with something more interesting. ;)

#print "LOCAL BOINC INFO:\n";
#print "progress is $boinc_progress\n";
#print "total credits is $total_credit\n";
#print "wu name is $wu_name\n";

#if ($use_boincstats) {
#  print "BOINC INFO:\n";
#  print "username = $boinc_user\n";
#  print "ID = $boinc_id\n";
#  print "total credit = $boinc_total_credit\n";
#  print "hosts = $boinc_hostcount\n";
#  print "overall rank = $boinc_overall_rank\n";
#  print "percentile = $boinc_percentile\n";
#  print "team rank = $boinc_team_rank\n";
#}


#if ($use_classicstats) { 
#  print "CLASSIC INFO:\n";
#  print "username is $cl_name\n";
#  print "number of results is $cl_num_results\n";
#  print "total cpu time donated is $cl_user_time\n";
#  print "results per day is $cl_daily_results\n";
#  print "overall rank is $cl_rank\n";
#}

#make a pretty progress bar

#length of progress bar
$prog_len = 25;

#starting and ending colors for progress bar
$prog_start = "ff0000";
$prog_end   = "0000ff";

#colors for the percent indicator
$pct_begin  = "ff0000";
$pct_end    = "00ff00";

#You can't see me.
$invisible  = "333333";

$filled_bars = sprintf("%.0f",($boinc_progress)*$prog_len);
$pct_prog = sprintf("%.0f",$boinc_progress*100);

$empty_bars = $prog_len - $filled_bars;
#print "$pct_prog% progress, $filled_bars chars, $empty_bars unfilled\n";
                                                                                                                                         

$prog_bar = "{";
                                                                                                                                                
for($i=0; $i < $filled_bars; $i++) {
  $progress_char = "~";
  $color=color_grad($[b][u][/b][/u]prog_start,$prog_end,$prog_len,$i);
  $prog_bar .= "\[[b][u][/b][/u]color=#$color\]$progress_char\[[b][u][/b][/u]/color\]";
}
$prog_bar .= "\[[b][u][/b][/u]color=#$invisible\]";
$prog_bar .=  "_" x $empty_bars;
$prog_bar .= "\[[b][u][/b][/u]/color\]";
$prog_bar .= "}";
                                                                                                                                                
#now $prog_bar looks like "{****___}" but with color tags
                                                                                                                                                
$pct_len = length $pct_prog;
$spc_len = 4 - $pct_len;
$spc = "_" x $spc_len;
$prog_bar =~ s/$/\[[b][u][/b][/u]color=#$invisible\]$spc\[[b][u][/b][/u]\/color\]/;
#print "$prog_bar\n";
                                                                                                                                                
$pct_color = color_grad($pct_begin,$pct_end,100,$pct_prog);
$prog_bar =~ s/$/\[[b][u][/b][/u]color=#$pct_color\]$pct_prog\%\[[b][u][/b][/u]\/color\]/;

#progress bar is done!
#It should look like "{~~~~~~_____} 34%" but will COLOR.

$crunch_start = "ff00ff";
$crunch_end   = "00ff00";

$crunch_str = color_string($crunch_start,$crunch_end,"Crunching for Overclockers.com!");

#99% means you're in the top 1%, so put that in $top_pct
$top_pct = sprintf("%.2f",100.0 - $boinc_percentile);
$rank = $boinc_overall_rank;
$boinc_total_credit =~ s/,//g;
$credits = sprintf("%.0f",$boinc_total_credit);


##################################
#This is where stuff is printed.##
##################################

print "[[b][u][/b][/u]b]$crunch_str\[[b][u][/b][/u]\/b]\n";
print "ranked #$rank in the top $top_pct% with $credits credits\n";
print "current wu: $prog_bar completed\n";


#Given a starting color, an ending color, a total number of steps, the
#current step and an optional error, return the color that corresponds
#to that step in a gradient.
sub color_grad
{
  $start_rgb = shift; #"ff00ff"
  $end_rgb   = shift; #"00ff00"
  $last_step = shift; #"36"
  $curr_step = shift; #"12"
  #error is random variation, in decimal shades
  $error     = shift;
  $periods   = shift;
  $fun       = shift;

  return color_grad_fun($start_rgb,$end_rgb,$curr_step/$last_step,$error,$periods,$fun);
}


sub color_grad_fun
{
  my $start_rgb = shift; #"ff00ff"
  my $end_rgb   = shift; #"00ff00"
  my $curr_step = shift; #floating pt number, modded between 0 and 1. inclusive
  
  #OPTIONAL ARG: error is random variation, in decimal shades
  my $error     = shift;
  $error = 0 if (! defined $error);
  
  #OPTIONAL ARG: how many times to cycle through the above function
  my $periods   = shift;
  $periods = 1 if (! defined $periods);
  
  #OPTIONAL ARG: function with a period of 1 and a range 0-1 to determine color distribution
  my $fun       = shift; 
  #This function has the same behavior as the previous implementation.
  $fun = sub {my $x = shift; return ((255*$x % 255)/255);} if (!defined $fun);
  
  $error /= 255;
  
  for $curr (0,1,2) {
  
    $min   = hex(substr($start_rgb,$curr*2,2)) / 255;
    $max   = hex(substr($end_rgb,$curr*2,2)) / 255;
    $range = $max - $min;
    $funval = &$fun($curr_step*$periods);
  
    #print "max is $max, min is $min, range is $range, step is $curr_step,";
    $color[[b][u][/b][/u]$curr] = ($min + $range*$funval);
    
    if ($error == 0) {
      $my_error = 0;
    } else {
      $my_error = (rand 2*$error) - $error;
    }
    
    while (($color[[b][u][/b][/u]$curr]+$my_error) < 0 || ($color[[b][u][/b][/u]$curr]+$my_error) > 1) {
      $my_error = ((rand 2*$error) - $error);
    }
    #print "using error of $my_error, max is $error\n";
    #$norml = $color[[b][u][/b][/u]$curr]*255;
    #print "normal color is $norml, ";
    $color[[b][u][/b][/u]$curr] += $my_error;
    $color[[b][u][/b][/u]$curr] *= 255;
    #$color[[b][u][/b][/u]$curr] = sprintf("%.0f",)
    #print "color is $color[[b][u][/b][/u]$curr]\n";
  
  }
  return sprintf("%02x%02x%02x",$color[[b][u][/b][/u]0],$color[[b][u][/b][/u]1],$color[[b][u][/b][/u]2]);
}

#Make a string shift from start_rgb to end_rgb, with an optional random error
sub color_string
{
  $start_rgb = shift;
  $end_rgb = shift;
  $string = shift;
  #optional args below
  $error = shift;
  $error = 0 if (! defined $error);
  
  $periods = shift;
  $periods = 1 if (! defined $periods);
  
  $fun = shift;
  $fun = sub {my $x = shift; return ((255*$x % 256)/255);} if (!defined $fun);

  #ugly bug if this isn't declared my
  my $color_str;
  my $str_len = length $string;
  my $prev_color = "gggggg";
  my $prev_char = "?";
  $i=0;
  
  foreach $char (split //, $string) {
    
    $fstr_color=color_grad($start_rgb,$end_rgb,$s[b][u][/b][/u]tr_len,$i++,$error,$periods,$fun);
    
    #vb3 seems to treat individually colored spaces an non-printable
    if ($char eq " ") {
      
      #if this is the same char we just printed, we can use less bbcode
      if ($prev_char eq " " && $color_str =~ /\[[b][u][/b][/u]\/color\]$/) {
        $color_str =~ s/.$/\.\.\[[b][u][/b][/u]\/color\]/;
	
      
      #we only need an invisible char if there's more than one in a row	
      } elsif ($prev_char eq " ") {
        $color_str =~ s/.$/\[[b][u][/b][/u]color=\#$invisible\]\.\.\[[b][u][/b][/u]\/color\]/;
      
      #else we've got a single space
      } else {
        #$color_str .= "\[[b][u][/b][/u]color\=\#$invisible\].\[[b][u][/b][/u]/color\]";
        $color_str .= " ";
      }
      
      $fstr_color = $invisible;
    
    } else {
    
      #if this is the same color we just used, we can reuse tag
      if ($prev_color eq $fstr_color) {
        $color_str =~ s/(.)\[[b][u][/b][/u]\/color\]$/$1$char\[[b][u][/b][/u]\/color\]/;
      } else {
        $color_str .= "\[[b][u][/b][/u]color\=\#$fstr_color\]$char\[[b][u][/b][/u]/color\]";
      }
    }
    
    $prev_char = $char;
    $prev_color = $fstr_color;
  }
  #print "COLOR STRING: returning $color_str\n";
  return $color_str;
}


Possible output from example s@h script:
Code:
[b][color=#ff00ff]C[/color][color=#f708f7]r[/color][color=#ef10ef]u[/color][color=#e718e7]n[/color][color=#df20df]c[/color][color=#d629d6]h[/color][color=#ce31ce]i[/color][color=#c639c6]n[/color][color=#be41be]g[/color] [color=#ad52ad]f[/color][color=#a45aa4]o[/color][color=#9d629d]r[/color] [color=#8c738c]O[/color][color=#837b83]v[/color][color=#7c837c]e[/color][color=#748b74]r[/color][color=#6a946a]c[/color][color=#629c62]l[/color][color=#5aa45a]o[/color][color=#52ac52]c[/color][color=#4ab44a]k[/color][color=#41bd41]e[/color][color=#39c539]r[/color][color=#31cd31]s[/color][color=#29d529].[/color][color=#20de20]c[/color][color=#18e618]o[/color][color=#10ee10]m[/color][color=#08f608]![/color][/b]
ranked #1 in the top 0.11% with 495535 credits
current wu: {[color=#ff0000]~[/color][color=#f5000a]~[/color][color=#eb0014]~[/color][color=#e1001e]~[/color][color=#d70028]~[/color][color=#cc0033]~[/color][color=#c2003d]~[/color][color=#b80047]~[/color][color=#ae0051]~[/color][color=#a3005b]~[/color][color=#990066]~[/color][color=#8f0070]~[/color][color=#84007a]~[/color][color=#7a0084]~[/color][color=#333333]___________[/color]}[color=#333333]__[/color][color=#718e00]56%[/color] completed


F@H stat example code
This is something of a hack. While writing it, I downloaded the page so that each test run of the script wouldn't require re-downloading it again. While using the downloaded page, I accidentally wrote it so it depended on having a downloaded page. It isn't exactly good style, but it's all my brain will allow me to do at 1:22 in the morning.

Code:
#!/usr/bin/perl -w
use LWP::UserAgent;
                                                                                                                                                
#Stanford's stats
$stfd_username="PMSFishy";
$team_num=32;
$stfd_url="http://vspx27.stanford.edu/cgi-bin/main.py?qtype=userpage&username=$stfd_username&teamnum=$team_num";
                                                                                                                                                
$ua = LWP::UserAgent->new();
$page = $ua->get($stfd_url);
open STFD_PAGE,">stfd.html";
print STFD_PAGE $page->content;
close STFD_PAGE;
                                                                                                                                                
                                                                                                                                                
open STFD_PAGE, "stfd.html";
while (<STFD_PAGE>){
                                                                                                                                                
  chop;
                                                                                                                                                
  if (/updated/) {
    s/.*updated://;
    s/ //;
    $stfd_last_update=$_;
  }
                                                                                                                                                
  if (/last work unit/) {
    $_ = <STFD_PAGE>;
    s/<[^>]*>//g;
    s/[^\d]*//;
    s/(\d\d:\d\d:\d\d)[^\d]*/$1/;
    $stfd_last_wu=$_;
  }
                                                                                                                                                
  if (/Total score/) {
    $_ = <STFD_PAGE>;
    s/<[^>]*>//g;
    s/[^\d]*//g;
    $stfd_total_score=$_;
  }
                                                                                                                                                
  if (/Overall rank/) {
    $_ = <STFD_PAGE>;
    s/.*\d> //;
    s/([\d]* of [\d]*)[^\d]*/$1/;
    $stfd_overall_rank=$_;
  }
                                                                                                                                                
  if (/50 days/) {
    $_ = <STFD_PAGE>;
    s/.*\d> //;
    /([\d]*)/;
    $stfd_cpus_50days=$1;
  }
                                                                                                                                                
  if (/7 days/) {
    $_ = <STFD_PAGE>;
    s/.*\d> //;
    /([\d]*)/;
    $stfd_cpus_7days=$1;
  }
                                                                                                                                                
  if (/> WU/) {
    $_ = <STFD_PAGE>;
    $_ = <STFD_PAGE>;
    s/[^\d]*//;
    s/([\d]*)//;
    $stfd_wu_total=$1;
  }
                                                                                                                                                
}
                                                                                                                                                
print "date of last WU: $stfd_last_wu\n";
print "total score: $stfd_total_score\n";
print "overall rank: $stfd_overall_rank\n";
print "active cpus (50d): $stfd_cpus_50days\n";
print "active cpus (7d): $stfd_cpus_7days\n";
print "WU total: $stfd_wu_total\n";
print "stats last updated: $stfd_last_update\n";

possible output from F@H example code:
Code:
date of last WU: 2005-01-27 16:16:34
total score: 698940
overall rank: 166 of 419739
active cpus (50d): 28
active cpus (7d): 10
WU total: 16330
stats last updated: Fri Jan 28 00:29:16 PST 2005



This is what my current sig_gen looks like. I don't claim any great wisdom, but this is definitely not good code for a beginner to learn from. I release it into the public domain. Feel free to do with it whatever you like, although I appreciate giving credit where it's due.

Notes:
A little of the code specific to my computer. I run 3 instances of the F@H client on my SMP rig, which live in ~/f1 , ~/f2 and ~/f3 . Having similar names means that I can use 1 loop to do all the progress bar processing. The dirs where the F@H clients live is refered to by the line that reads open FH, "$home/f$n/unitinfo.txt" or die "error opening file: $!"; .
The load average is Linux-specific. To take it out, delete from open LOAD_AVG, ... to the next } .
The gradient functions look the easiest to rip off. Basically, the color_string takes a starting color, an ending color and a string and returns a string that evenly shifts from the beginning color to the ending one.
Since I wrote this, I have no idea how understandable it will be for others, and while I may have the time to help people out playing with it, be prepared to accept “no” or “later” for an answer.
In order to get this code to shop up semi-correctly, I had to put a space in all opening vbcode tags. When you see something like [ color=#333333], just delete the space.

Code:
#!/usr/bin/perl -w
use LWP::UserAgent;

#might be cool:
# * have the color of the "45%" change as they approach 100
# * Use.  More.  Colors.
# * use a funky character helix for the progress bar
# * find random quotes from the forums, maybe threads you've posted in
# * make everything invisible except for colored letters spelling out "FOLD!"
# * get gradient randomization working properly

#string to use for progress indicator
$progress_char="o";

#how many of the above char to use at 100%
$prog_len = 10;

#starting/ending color for progress indicator
$prog_start = "333333";
$prog_end   = "ffd700";
#$prog_start = "ff00ff";
#$prog_end   = "ffff00";

$fstr_start = "ff00ff";
$fstr_end   = "ffff00";

$ldavg_begin = "00ff00";
$ldavg_end   = "ff0000";
    
$pct_begin   = "8f9aff";
$pct_end     = "ff0000"; 

#how many times to cycle through the progress indicator gradient
$prog_cycles = 1;

#a place to hang your hat
$home = glob "~/";

#you can't see me
$invisible="333333";

@time = localtime;
$time[[b][u][/b][/u]5] += 1900;
$time[[b][u][/b][/u]4]++;

#get local info about current WUs

$stfd_cache = "stfd.html";
#$invisible_char = "\[[b][u][/b][/u]color\=\#$invisible\].\[[b][u][/b][/u]/color\]";

$min_pct = 100;

for $n (1, 2, 3) {
  $f_name = "";
  $f_prog = "";
  open FH, "$home/f$n/unitinfo.txt" or die "error opening file: $!";
  while(<FH>){
    chomp;
    $f_name .= $_;
  }
  close FH;
  $f_prog = $f_name;
  
  $f_name =~ s/.*Name://;
  $f_name =~ s/Download.*//;
  $f_name = color_string("ffff00","ff0000",$f_name,50);

  for ($f_prog) {
    s/.*Progress: //;
    s/\%.*//;
    $pct_prog = $_;
    #$pct_prog = 100;
    #this is a *recommended* way of rounding
    $filled_bars = sprintf("%.0f",($pct_prog/100)*$prog_len);
    $empty_bars = $prog_len - $filled_bars;
    #print "$pct_prog% progress, $filled_bars chars, $empty_bars unfilled\n";

    $f_prog = "{";
    
    for($i=0; $i < $filled_bars; $i++) {
      $color=color_grad($prog_start,$prog_end,$prog_len/$prog_cycles,$i);
      $f_prog .= "\[[b][u][/b][/u]color=#$color\]$progress_char\[[b][u][/b][/u]/color\]";
    }
    $f_prog .= "[[b][u][/b][/u]color=#$invisible]";
    $f_prog .=  "_" x $empty_bars;
    $f_prog .= "[[b][u][/b][/u]/color]";
    $f_prog .= "}";

    # now looks like "{****___}" but with color tags
    
    $f_prog .= "$pct_prog%";
    
    if ($pct_prog > 99) {
      s/(\d\d\d%)/[[b][u][/b][/u]color=#$invisible]_[[b][u][/b][/u]\/color]$1/;
    } elsif ($pct_prog >9) {
      s/(\d\d%)/[[b][u][/b][/u]color=#$invisible]__[[b][u][/b][/u]\/color]$1/;
    } else {
      s/(\d%)/[[b][u][/b][/u]color=#$invisible]___[[b][u][/b][/u]\/color]$1/;
    }
    #print "$f_prog\n";

    $pct_color = color_grad($pct_begin,$pct_end,100,$pct_prog);
    s/(\d*%)/\[[b][u][/b][/u]color=#$pct_color\]$1\[[b][u][/b][/u]\/color\]/;
    
    $min_pct = $pct_prog if ($pct_prog < $min_pct);
    
  }

  $f_name[[b][u][/b][/u]$n-1] = $f_name;
  $f_prog[[b][u][/b][/u]$n-1] = $f_prog;
}


#get stats from Intarw3b

$user="IdeaMagnate";
$team=32;

#only download stanford's page every hour ( = 60*60 seconds)
#(stat(file))[[b][u][/b][/u]9] is the time since file was last modified, in seconds
if ((! -e $stfd_cache) || (time+(60*60) > (stat($stfd_cache))[[b][u][/b][/u]9])) {

  $ua = LWP::UserAgent->new();
  $stfd_page = $ua->get("http://vspx27.stanford.edu/cgi-bin/main.py?qtype=userpage&teamnum=$team&username=$user");
  
  if (! $stfd_page->is_success) {
    die "Couldn't download Stanford's page.";
  }

  open STFD_CACHE, ">$stfd_cache";
  print STFD_CACHE $stfd_page->content;
  close STFD_CACHE;

  $s_content = $stfd_page->content;

} else {

  open STFD_CACHE, "$stfd_cache";
  while(<STFD_CACHE>) {
    $s_content .= $_;
  }
  close STFD_CACHE;

}

$pts = $s_content;
$wus = $s_content;
$cpu = $s_content;

for ($pts) {
  s/[[b][u][/b][/u]\n\r]//g;
  s/.*Total score//g;
  s/[[b][u][/b][/u]^\d]*//;
  s/4> (\d*).*/$1/;
}

for ($wus) {
  s/[[b][u][/b][/u]\n\r]//g;
  s/.*WU</</g;
  s/<[[b][u][/b][/u]^>]*>//g;
  s/\w*(\d\d\d\d).*/$1/;
  s/ //g;
  s/\t//g;
}

for ($cpu) {
  s/[[b][u][/b][/u]\n\r]//g;
  s/.*Active processors//;
  s/<[[b][u][/b][/u]^>]*>//g;
  s/[[b][u][/b][/u] \t]//g;
  s/\([[b][u][/b][/u]^\)]*\)//g;
  s/(\d*).*/$1/g;
}

open LOAD_AVG, "uptime |";
$load_avg = <LOAD_AVG>;
close LOAD_AVG;

for ($load_avg) {
  s/.*load average/\[[b][u][/b][/u]u\]Load Avg\[[b][u][/b][/u]\/u\]/;
  s/,//g;
  /(\d\d*\.\d\d*) *(\d\d*\.\d\d*) *(\d\d*\.\d\d*)/;
  $c1 = color_grad($ldavg_begin,$ldavg_end,450,$1*100);
  $c2 = color_grad($ldavg_begin,$ldavg_end,450,$2*100);
  $c3 = color_grad($ldavg_begin,$ldavg_end,450,$3*100);
  s/(\d\d*\.\d\d*) *(\d\d*\.\d\d*) *(\d\d*\.\d\d*)/\[[b][u][/b][/u]color=#$c1\]$1\[[b][u][/b][/u]\/color] [[b][u][/b][/u]color=#$c2\]$2\[[b][u][/b][/u]\/color] [[b][u][/b][/u]color=#$c3\]$3\[[b][u][/b][/u]\/color]/;
  chomp;
}

$pts_len=7;
$wus_len=9;
$cpu_len=5;

$spcr1= "[[b][u][/b][/u]color=#$invisible]" . "_" x 4 . "[[b][u][/b][/u]/color]";
$spcr2= "[[b][u][/b][/u]color=#$invisible]" . "_" x 4 . "[[b][u][/b][/u]/color]";
$spcr3= "[[b][u][/b][/u]color=#$invisible]" . "_" x 8 . "[[b][u][/b][/u]/color]";


$pts_pad = $pts_len - (length $pts);
$wus_pad = $wus_len - (length $wus);
$cpu_pad = $cpu_len - (length $cpu);

$pts = "[[b][u][/b][/u]color=#$invisible]" . "_" x $pts_pad . "[[b][u][/b][/u]/color]" . $pts . $spcr1;
$wus = "[[b][u][/b][/u]color=#$invisible]" . "_" x $wus_pad . "[[b][u][/b][/u]/color]" . $wus . $spcr1;
$cpu = "[[b][u][/b][/u]color=#$invisible]" . "_" x $cpu_pad . "[[b][u][/b][/u]/color]" . $cpu . $spcr1;

$folding_str = color_string($fstr_start,$fstr_end,"Folding for team 32!");

$time_str = sprintf("%02d/%02d/%04d at %02d:%02d.\n",$time[[b][u][/b][/u]4],$time[[b][u][/b][/u]3],$time[[b][u][/b][/u]5],$time[[b][u][/b][/u]2],$time[[b][u][/b][/u]1]);

print "[[b][u][/b][/u]font=monospace][[b][u][/b][/u]size=1][[b][u][/b][/u]b][[b][u][/b][/u]url=http://www.ocforums.com/forumdisplay.php?f=25]Alt OS Lead Senior[[b][u][/b][/u]/url] | [[b][u][/b][/u]url=http://del.icio.us/ideamagnate]del.icio.us[[b][u][/b][/u]/url] | [[b][u][/b][/u]url=http://heatware.com/eval.php?id=1958]Heatware[[b][u][/b][/u]/url] | [[b][u][/b][/u]url=http://www.ocforums.com/showthread.php?t=328963]FAQ 2.0[[b][u][/b][/u]/url] | [[b][u][/b][/u]url=http://gladstone.uoregon.edu/~cotto1/ochosting/jellyfish.txt]Jellyfish[[b][u][/b][/u]/url][[b][u][/b][/u]/font][[b][u][/b][/u]/b]\n";
print "[[b][u][/b][/u]b][[b][u][/b][/u]color=#CCCC00]Did someone go out of his way to help you?  Show your appreciation [[b][u][/b][/u]url=http://www.ocforums.com/showthread.php?t=345204]here[[b][u][/b][/u]/url].[[b][u][/b][/u]/color][[b][u][/b][/u]/b][[b][u][/b][/u]/size]\n\n";
print "[[b][u][/b][/u]font=monospace][[b][u][/b][/u]b]$folding_str\n";
print "[[b][u][/b][/u]u]My stats[[b][u][/b][/u]/u]:".$spcr3. "[[b][u][/b][/u]u]My current WUs[[b][u][/b][/u]/u]:$spcr2$load_avg\n";
print "score:$pts".              "$f_prog[[b][u][/b][/u]0] :$f_name[[b][u][/b][/u]0]\n";
print "WUs:$wus".                "$f_prog[[b][u][/b][/u]1] :$f_name[[b][u][/b][/u]1]\n";
print "clients:$cpu".            "$f_prog[[b][u][/b][/u]2] :$f_name[[b][u][/b][/u]2]\n";
#      stat:    03030            {******    } 61% : p1139_p1133_L939_K12M_355K
print "[[b][u][/b][/u]/font][[b][u][/b][/u]/b]This sig was generated on $time_str";

sub color_grad
{
  $start_rgb = shift; #"ff00ff"
  $end_rgb   = shift; #"00ff00"
  $last_step = shift; #"36"
  $curr_step = shift; #"12"
  #error is random variation, in decimal shades
  $error     = shift;

  $error = 0 if (! defined $error);

  $curr_step %= $last_step;

  for $curr (0,1,2) {
    
    $error[[b][u][/b][/u]$curr] = (rand 2*$error) - $error;
    $start[[b][u][/b][/u]$curr] = hex(substr($start_rgb,$curr*2,2));
    $end[[b][u][/b][/u]$curr]   = hex(substr($end_rgb,$curr*2,2));
    $step[[b][u][/b][/u]$curr]  = ($end[[b][u][/b][/u]$curr] - $start[[b][u][/b][/u]$curr]) / $last_step;
    $color[[b][u][/b][/u]$curr] = $start[[b][u][/b][/u]$curr] + $step[[b][u][/b][/u]$curr]*$curr_step + $error[[b][u][/b][/u]$curr];
    #ensure that the color is within the possible range
    while ((0 > $color[[b][u][/b][/u]$curr]) || ($color[[b][u][/b][/u]$curr] > 255)) {
      $error[[b][u][/b][/u]$curr] = (rand 2)*$error - $error;
      $color[[b][u][/b][/u]$curr] = $start[[b][u][/b][/u]$curr]+ $step[[b][u][/b][/u]$curr]*$curr_step + $error[[b][u][/b][/u]$curr];
    }
    #print "start is $start[[b][u][/b][/u]$curr], end is $end[[b][u][/b][/u]$curr], step is $step[[b][u][/b][/u]$curr], color is $color[[b][u][/b][/u]$curr]\n";
  }

  return sprintf("%02x%02x%02x",$color[[b][u][/b][/u]0],$color[[b][u][/b][/u]1],$color[[b][u][/b][/u]2]);
}


sub color_string
{
  $start_rgb = shift;
  $end_rgb = shift;
  $string = shift;
  $error = shift;
  #print "COLOR STRING: passed $string\n";
  $error = 0 if (! defined $error);
  
  #ugly bug if this isn't declared my
  my $color_string;
  $str_len = length $string;
  $i=0;
  
  foreach $char (split //, $string) {
     $fstr_color=color_grad($start_rgb,$end_rgb,$st[b][/b]r_len,$i++,$error);
     #vb3 seems to treat individually colored spaces an non-printable
     if ($char eq " ") {
       $color_string .= "\[[b][u][/b][/u]color\=\#$invisible\].\[[b][u][/b][/u]/color\]";
     } else {
       $color_string .= "\[[b][u][/b][/u]color\=\#$fstr_color\]$char\[[b][u][/b][/u]/color\]";
     }
  }
  #print "COLOR STRING: returning $color_string\n";
  return $color_string;
}

License
All code in this post, including the linked mksig.pl script, is released into the public domain, meaning that you are free to do absolutely anything you like with it. I ask, but do not require, credit where it is due.
Enjoy!
 
Last edited:
This is going to be fun. :D
If you downloaded mksig.txt before this post, it will store its files in c:/Program Files/mksig instead of c:/mksig like I specified. The version up now is in sync with my instructions.
 
Also, please download the version that's up now if you plan on using the default sig_gen. I've noticed that the old one will occasionally make excessively long sigs, and I don't want to get nasty PMs from people about it.
To upgrade, just download the current version (.54) and nuke your current sig_gen. Next time your run mksig, a new one will be put in place that ensures that sigs will be the proper length.
You can grab it here, as always.
 
Very nice, I am going to link to this thread (and the previous Linux thread also) on the downloads section of the team page, they seem to have all the info, unless you have a website set up for these tools. Let me know.
 
Go ahead. If I find the time to put up a separate page about this, I'll make sure to post a link in this thread.

To everyone, you're welcome. :D
 
Alright, I'm smart.
If you're using the default sig_gen, please download again and nuke the old sig_gen. The fortune site I use, while very easy to parse, occasionally comes up with some fortunes that violate forum rules. I looked at several while writing the default sig_gen, but apparently I didn't look at the right ones. The sig_gen that the current version (.55) of mksig creates will filter out fortunes with certain unacceptable words. The version number is stored near the top of mksig.pl.
I'm pretty sure the changes will catch all the offensive fortunes that slip through, but I still *highly* recommend checking your sig.log to make sure nothing bad has slipped through. If it has, rerunning mksig.pl will take care of it.

Later today, I plan on adding some code to automatically check for updates so people won't have to worry about constantly re-downloading a new version of the script.

Note that if you're using your own sig_gen, you don't need any of these updates.
 
When I try to use your sig script (the one at the bottom of your first post), I can't seem to get it to work...... I deleted the lines that you mentioned, but what I think is getting me is the directory to point to for the unitinfo.txt.

Instead of $home\F$n\unitinfo.txt .... what should I put in there if the directory is:

D:\Program Files\FAH\FAH1\unitinfo.txt

I'm not familiar with Perl, I've just used C++ so it's a little hard to figure out where to point to.

Here's the screen I get when I try to run mksig.pl
untitled1.jpg


Thanks
 
Line 35 of the mksig.pl script reads $sig_gen="$dir/sig_gen"; you need to add the .pl so it reads $sig_gen="$dir/sig_gen.pl"; That will fix your error dealing with the unrecognized command
 
Okay, thanks :)

I'll give that a try

[edit]

Nope, didn't work.... well it did, it created a new sig_gen.pl, but I'm getting the same string of errors.

I'll dig around some more to see if there's something I should delete or change.

[double edit]

Well, I redownloaded and edited everything and it worked this time, so I'll go about editing the sig_gen now... thanks for your help. :)
 

Attachments

  • untitled1.JPG
    untitled1.JPG
    21.7 KB · Views: 2,780
Last edited:
For this part specifically
Code:
for $n (1, 2, 3) {
  $f_name = "";
  $f_prog = "";
  open FH, "$home/f$n/unitinfo.txt" or die "error opening file: $!";
  while(<FH>){
    chomp;
    $f_name .= $_;


How would I go about directing it to D:\Program Files\FAH\FAH1\unitinfo.txt
?

It seems that I only get the errors when I download Christolf's script for his sig...... the little guy booby trapped it!!! :D
 
Ok, beercan and I discovered that the last sig_gen and code example listed is cristoph's script for *nix. It errors because it is trying to do *nix related commands. What you need to do is just d/l the default 0.55 mksig.pl and copy and paste the first FAH stats code example into notepad and save it as sig_gen.pl. That will get your stats into your sig looking like mine. The second script listed under FAH stats, once again, is for *NIX only and needs to be ported to windows.
 
mtb856 said:
How would I go about directing it to D:\Program Files\FAH\FAH1\unitinfo.txt
?



The simplest way is simply to change the $home/f$n stuff, as below. You have to use two slashes because Perl interperts one as an escape, and gives the character after it a special meaning. Also note that if you're not running 3 (or more) instances of the client, it will die. This part of the code is easy to chage for an arbitrary number of local clients (just change (1,2,3) to (1) or (1,2), etc) but the bottom part of the sig depends on there being three clients running. The script will still work since Perl doesn't complain when you use variables that haven't been defined, but the formatting will be broken.


Code:
for $n (1, 2, 3) {
  $f_name = "";
  $f_prog = "";
  open FH, "D:\\Program Files\\FAH\\FAH$n\\unitinfo.txt" or die "error opening file: $!";
  while(<FH>){
    chomp;
    $f_name .= $_;

In case you missed my edit in the first post, you'll also need to delete the stuff referring to $load_avg, since that's Linux-specific. The code you want to delete is all in one chunk:

Code:
open LOAD_AVG, "uptime |";
$load_avg = <LOAD_AVG>;
close LOAD_AVG;
                                                                                                                                               
for ($load_avg) {
  s/.*load average/\[u\]Load Avg\[\/u\]/;
  s/,//g;
  chomp;
}

mtb856 said:
It seems that I only get the errors when I download Christolf's script for his sig...... the little guy booby trapped it!!! :D

BTW, I now have access to your checking accont. I'd like to thank your for the major hardware upgrade you just bought me. ;)
 
Cristoph, I deleted the load_avg calls, changed the dir to mine and used the double \'s, and it is still giving me errors. It gives me: "building sig...error opening file: No such file or directory at C:\mksig\sig_gen.pl line 47.
Use of uninitialized value in string at C:\mksig\mksig.pl line 178.
OK
logging in...OK
submitting new sig...Use of uninitialized value in string at C:\mksig\mksig.pl line 228.
OK
logging out...OK"

Any ideas?
 
Back