For posterity...

Flagg

The Most Electrifying Man in Sports Entertainment
I always get nervous about things like this getting lost, even though the server has redundant disks and regular backups. The script which auto-updates the comic is close to 400 lines of code now, and it would be a huge PITA to re-do.


So, just in case I need to cut-and-paste it from here later:

Code:
#!/usr/bin/perl

## Keychain of Creation Updater Script, by Flagg <flagg@patternspider.net>
##
## Created 20070815
## Updated 20070819 - added notify_email_list()
## Updated 20070820 - Fixed archive nav bug in generate_page()
## Updated 20070902 - Added image size calculation and added "news" to email notification
## Updated 20080104 - Added functionality for RSS feed - generate_rss_page()
## Updated 20080111 - Added code to 'ping' the feedburner RSS feed

use strict;
use Image::Size 'html_imgsize';
use HTML::Strip;
use LWP::Simple;

my $basepath = "/home/patternspider.net/www/keychain/";         # path to KOC
my $comicpath = "comics";                                       # path to comics
my $bufferpath = "buffer";                                      # path to buffer
my $archivepath = "archive";                                    # path to archives
my $templatepath = "script/template";                           # path to templates
my $newspath = "news";                                          # path to news & synopses
my $imagepath = "images";                                       # path to images
my $prefix = "koc";                                             # file name prefix
my $imgext = "png";                                             # image file extension
my $curr = get_current();                                       # current issue number
my $currstring = pad_number($curr);                             # padded current issue string
my $prevstring = pad_number($curr - 1);                         # padded previous issue
my $prevarchivestring = pad_number($curr - 2);                  # padded previous archive string

### begin program

chdir $basepath;

# if these files exist, continue
if ( check_files() ) {

       # move new comic out of buffer
       system ("/bin/mv $bufferpath/$prefix$currstring.$imgext $comicpath/$prefix$currstring.$imgext");

       # generate new archive page
       generate_page("$archivepath/$prefix$prevstring.html", "$templatepath/archiveheader.html", "", "$templatepath/archivefooter.html", ($curr - 1), 1);

       # re-generate old archive page
       generate_page("$archivepath/$prefix$prevarchivestring.html", "$templatepath/archiveheader.html", "", "$templatepath/archivefooter.html", ($curr - 2), 1);

       # generate new index file
       generate_page("$basepath/index.html", "$templatepath/mainheader.html", "$newspath/$prefix$currstring.news.txt", "$templatepath/mainfooter.html", $curr, 0);

       # update archives page
       update_archives_page();

       # update current file
       set_current();

       # update RSS feed
       update_rss_page("$newspath/$prefix$currstring.news.txt", "$newspath/$prefix$currstring.title.txt");

       print "\nKeychain of Creation #$curr has been updated successfully.\n\n";
       notify_email_list("$newspath/$prefix$currstring.news.txt");
}
else { print "\nKeychain of Creation has not been updated.\n\n" }

### end program

### subroutines

# update current file
sub set_current {
       my $currentfile = "$basepath/script/current.issue";

       open(CURRENT, ">$currentfile");
       print CURRENT $curr;
       close(CURRENT);
}


# read current file
sub get_current {
       my $currentfile = "$basepath/script/current.issue";
       my $r;

       open(CURRENT, "<$currentfile");
       $r = <CURRENT>;
       close(CURRENT);
       chomp($r);
       $r++;

       return $r;
}

# update archive spage
sub update_archives_page {

       my $outfile = "$basepath/archives.html";
       my $headerfile = "$templatepath/mainheader.html";
       my @header;
       my $footerfile = "$templatepath/mainfooter.html";
       my @footer;
       my $titlefile = "$newspath/$prefix$currstring.title.txt";
       my $title;
       my $prevtitlefile = "$newspath/$prefix$prevstring.title.txt";
       my $prevtitle;
       my $archivefile = "$templatepath/archives.html";
       my @archivesin;
       my @archivesout;
       my $prevnumber = int($prevstring);

       open(HEADER, $headerfile);
       @header = <HEADER>;
       close(HEADER);

       open(FOOTER, $footerfile);
       @footer = <FOOTER>;
       close(FOOTER);

       open(TITLE, $titlefile);
       $title = <TITLE>;
       close(TITLE);
       chomp($title);

       open(PREVTITLE, $prevtitlefile);
       $prevtitle = <PREVTITLE>;
       close(PREVTITLE);
       chomp($prevtitle);


       open(ARCHIVES, "<$archivefile");
       @archivesin = <ARCHIVES>;
       close(ARCHIVES);
       for (my $x = 0; $x < (@archivesin - 1); $x++) {
               $archivesout[$x] = $archivesin[$x];
               next;
       }
       open(ARCHIVES, ">$archivefile");
       print ARCHIVES @archivesout;
       print ARCHIVES "\n            <a href=\"$archivepath/$prefix$prevstring.html\">Comic $prevnumber</a> - $prevtitle<br />";
       print ARCHIVES "\n            <a href=\"index.html\">Comic $curr</a> - $title<br />";
       close(ARCHIVES);
       open(ARCHIVES, "<$archivefile");
       @archivesout = <ARCHIVES>;
       close(ARCHIVES);


       open(OUTFILE, ">$outfile");
       print OUTFILE @header;
       print OUTFILE @archivesout;
       print OUTFILE "</p>\n";
       print OUTFILE @footer;
       close(OUTFILE);
}

# generate output page
sub generate_page {
       my $outfile = $_[0];                                            # output file
       my $headerfile = $_[1];                                         # page header file
       my @header;                                                     # page header code
       my $newsfile = "$_[2]";                                         # news file
       my @news;                                                       # news file code
       my $footerfile = $_[3];                                         # page footer file
       my @footer;                                                     # page footer code
       my $current = pad_number($_[4]);                                # issue number to create
       my $previous = pad_number($_[4] - 1);                           # previous issue
       my $next = pad_number($_[4] + 1);                               # next issue
       my $intcurrent = $_[4];                                         # current issue in int format
       my $isarchive = $_[5];                                          # boolean check to see page is archive
       my $pathtocomics;
       my $pathtonav;
       my $pathtomenu;
       my $pathtoimages;
       my $imgsize = html_imgsize("$comicpath/$prefix$current.$imgext"); # returns preformatting width/height tags

       if ($isarchive){
               $pathtocomics = "../$comicpath";
               $pathtonav = ".";
               $pathtomenu = "..";
               $pathtoimages = "../$imagepath";
       }
       else {
               $pathtocomics = "$comicpath";
               $pathtonav = "archive";
               $pathtomenu = ".";
               $pathtoimages = "$imagepath";
       }


       # open templates and read in data
       open(HEADER, $headerfile);
       @header = <HEADER>;
       close(HEADER);

       open(FOOTER, $footerfile);
       @footer = <FOOTER>;
       close(FOOTER);

       open(NEWS, $newsfile);
       @news = <NEWS>;
       close(NEWS);

       open(OUTFILE, ">$outfile");

       print OUTFILE "@header";

       # print CURRENT comic
       print OUTFILE "<img src=\"$pathtocomics/$prefix$current.$imgext\" alt=\"Comic $intcurrent\" $imgsize />";
       print OUTFILE "  <br />\n<br />";

       # print FIRST nav button
       print OUTFILE "  <td><a href=\"$pathtonav/koc0001.html\"><img src=\"$pathtoimages/first.gif\" alt=\"first\" width=\"144\" height=\"100\" border=\"0\" /></a>";

       # print BACK nav button
       print OUTFILE "<a href=\"$pathtonav/$prefix$previous.html\"><img src=\"$pathtoimages/back.gif\" alt=\"back\" width=\"134\" height=\"95\" border=\"0\" align=\"bottom\" /></a>\n";

       # if page is in archive
       if ( $isarchive ) {
               # if not newest archive page, print FORWARD and LATEST nav buttons
               if ( int($current) == ($curr - 2) ) {
                       print OUTFILE "<a href=\"$pathtonav/$prefix$next.html\"><img src=\"$pathtoimages/forward.gif\" alt=\"forward\" width=\"123\" height=\"100\" border=\"0\" /></a>";
                       print OUTFILE "<a href=\"$pathtomenu/index.html\"><img src=\"$pathtoimages/latest.gif\" alt=\"latest\" width=\"118\" height=\"96\" border=\"0\" /></a>";
               }
               # if newest archive page, print FORWARD nav button
               else {
                       print OUTFILE "<a href=\"$pathtomenu/index.html\"><img src=\"$pathtoimages/forward.gif\" alt=\"forward\" width=\"123\" height=\"100\" border=\"0\" /></a>";
               }
       }
       # if not in archive, print NEWS
       else {
               print OUTFILE "  <hr size=\"1\" width=\"500\"/>\n<img src=\"$pathtoimages/newsheader.gif\" alt=\"news\" width=\"111\" height=\"36\" />\n<br /><br />\n";
               print OUTFILE "  <table width=\"500\" border=\"0\" align=\"center\" cellpadding=\"2\" cellspacing=\"2\">\n  <tr>\n      <td valign=\"top\"><div align=\"justify\" class=\"style3\">\n";
               print OUTFILE "@news";
       }

       print OUTFILE "@footer";

       close(OUTFILE);
}


# pad issue number with zeroes
sub pad_number {
       my $input = $_[0];      # input value
       my $r;                  # return value

       if ($input < 10)        { $r = "000$input" }
       elsif ($input < 100)    { $r = "00$input" }
       elsif ($input < 1000)   { $r = "0$input" }
       return $r;
}

# check that all critical files exist before proceeding
sub check_files {
       my $filesexist = 1;                             # boolean check for existence of necessary files

       # check to see if the new current.issue file exists
       if ( !( open(CHECK, "<script/current.issue") ) ) {
               print "!! ERROR: File $templatepath/current.issue does not exist!\n";
               $filesexist = 0;
       }
       else { close(CHECK) }

       # check to see if the main header file exists
       if ( !( open(CHECK, "<$templatepath/mainheader.html") ) ) {
               print "!! ERROR: File $templatepath/mainheader.html does not exist!\n";
               $filesexist = 0;
       }
       else { close(CHECK) }

       # check to see if the main footer file exists
       if ( !( open(CHECK, "<$templatepath/mainfooter.html") ) ) {
               print "!! ERROR: File $templatepath/mainfooter.html does not exist!\n";
               $filesexist = 0;
       }
       else { close(CHECK) }

       # check to see if the archive header file exists
       if ( !( open(CHECK, "<$templatepath/archiveheader.html") ) ) {
               print "!! ERROR: File $templatepath/archiveheader.html does not exist!\n";
               $filesexist = 0;
       }
       else { close(CHECK) }

       # check to see if the archive footer file exists
       if ( !( open(CHECK, "<$templatepath/archivefooter.html") ) ) {
               print "!! ERROR: File $templatepath/archivefooter.html does not exist!\n";
               $filesexist = 0;
       }
       else { close(CHECK) }

       # check to see if the new comic exists in the buffer
       if ( !( open(CHECK, "<$bufferpath/$prefix$currstring.$imgext") ) ) {
               print "!! ERROR: File $bufferpath/$prefix$currstring.$imgext does not exist!\n";
               $filesexist = 0;
       }
       else { close(CHECK) }

       # check to see if the previous comic exists in the archive
       if ( !( open(CHECK, "<$archivepath/$prefix$prevarchivestring.html") ) ) {
               print "!! ERROR: File $archivepath/$prefix$prevarchivestring.html does not exist!\n";
               $filesexist = 0;
       }
       else { close(CHECK) }

       return $filesexist;
}

# Send email to distribution list
sub notify_email_list {

       my $newsfile = $_[0];
       my @news;
       my $dest = "To: keychain-of-creation\@googlegroups.com\n";
       my $subject = "Subject: Issue #$curr has been released!\n";
       my $reply_to = "Reply-to: jukashi\@patternspider.net\n";
       my $sendmail = "/usr/sbin/sendmail -t";
       my $message;

       open(NEWS, $newsfile);
       @news = <NEWS>;
       close(NEWS);

       $message = "<a href=\"http://keychain.patternspider.net\">Keychain of Creation</a><br><br>NEWS:<br>@news<br>";

       open (SENDMAIL, "|$sendmail");
       print SENDMAIL $dest;
       print SENDMAIL $reply_to;
       print SENDMAIL $subject;
       print SENDMAIL "Content-type: text/html; charset=iso-8859-1\n\n";
       print SENDMAIL $message;
       close (SENDMAIL);
}

sub update_rss_page {

       my $htmlstrip = HTML::Strip->new();
       my $outfile = "$basepath/rss.xml";
       my $headerfile = "$templatepath/rssheader.xml";
       my @header;
       my $footerfile = "$templatepath/rssfooter.xml";
       my @footer;
       my $titlefile = $_[1];
       my $title;
       my $rssfile = "$templatepath/rssbody.xml";
       my @rssin;
       my @rssout;
       my $newsfile = $_[0];
       my @news;
       my @htmlnews;
       my $pingurl = "http://www.feedburner.com/fb/a/pingSubmit?bloglink=http://keychain.patternspider.net";

       open(NEWS, $newsfile);
       @htmlnews = <NEWS>;
       close(NEWS);
       my @news = $htmlstrip->parse( @htmlnews );
       $htmlstrip->eof;

       open(HEADER, $headerfile);
       @header = <HEADER>;
       close(HEADER);

       open(FOOTER, $footerfile);
       @footer = <FOOTER>;
       close(FOOTER);

       open(TITLE, $titlefile);
       $title = <TITLE>;
       close(TITLE);
       chomp($title);

       open(RSS, "<$rssfile");
       @rssin = <RSS>;
       close(RSS);
       for (my $x = 0; $x < 14; $x++) {
               $rssout[$x] = $rssin[$x];
               next;
       }
       open(RSS, ">$rssfile");
       print RSS "<item><title>Comic $curr - $title</title><description><img src=http://keychain.patternspider.net/comics/$prefix$currstring.$imgext /> <br/> <br/> @news</description><link>http://keychain.patternspider.net</link></item>\n";
       print RSS @rssout;
       close(RSS);
       open(RSS, "<$rssfile");
       @rssout = <RSS>;
       close(RSS);


       open(OUTFILE, ">$outfile");
       print OUTFILE @header;
       print OUTFILE @rssout;
       print OUTFILE @footer;
       close(OUTFILE);

       # ping feedburner feed
       get $pingurl;
}
 
I may need to learn that although I am not sure what school I will be going to in about a year or so for Comp. Sci.
 
I found perl really easy to pick up (at least for the humble uses I've put it towards). Compared to, say, C, it's incredibly fast and loose.
 
I have never really messed with programming and I think the reason I never did was because I never knew what the hell I would use it for.
 
I actually do want to learn more about computers, but it is mainly to be more competitive to earn a package that will earn me a commision as an Officer in the Air Force. Otherwise I was originally majoring in Psychology.


I know a bit more than the average computer operator, but nothing as a programmer, more focus on HTML, etc.
 
Also, remember Computer Science isn't really about programming, its more about how computers work and the study about programming than anything else. Things like circuits, how to make compilers, etc. Programming was just a little bit of it. I'm working on Masters in IT right now, and *that* is about programming. And databases.


But, Perl is a great language for doing fast code. I've done parsing projects with it for years, hell my boss has part of her business based on it. Though, I used PHP for my comic striip instead of Perl. Best tool for the job. :)
 
I have to disagree with Moonfire here. While it is true that Computer Science isn't really about programming (more like meta-programming), neither is IT. Both make use of programming, but training in either doesn't actually do much to train you for a real programming job. Any monkey can be taught to code, which is why so much of it sucks. Real programming ability (the kind that would get you hired in the companies I've been in) requires knowledge and practice in software engineering, and very few schools teach this. Unfortunately, you have to see a number of projects collapse under their own weight from the anti-patterns that built them before you really get how to build software correctly and efficiently.


To my mind, there are really four species of people who write code (as seen through the eyes of someone looking to hire one):

  • Scripters use things like HTML, JavaScript, maybe PHP or Perl (or, God forbid, VisualBasic) to build web sites or single-purpose utilities or "Frankenstein" applications. These are usually self-trained and are typically found as web consultants, QA or IT people. Pros: cheap, easily replaceable, often available as short-term contractors, often trainable, sometimes faster time to market. Cons: code quality low to non-existent, short attention span (meaning they jump to new jobs at the drop of a hat), results not usually capable of supporting further development for very long.
  • Programmers use "real" languages, including object-orientation, to write real programs. These have usually had schooling in CS or are advanced hobbyists, and form the bulk of the programming jobs, as well as the more advanced IT jobs. Pros: great for use in teams, likely trainable, usually flexible in the types of projects they can handle, usually able to swiftly integrate new tech, generally priced reasonably at time of hire. Cons: more expensive to keep, higher than average bug counts, code-quality highly dependent on the individual and not usually predictable in interview.
  • Hackers use code to solve problems extremely rapidly, and often very cleverly. Usually extremely smart people, sometimes lacking social skills. Often found in start-ups or anywhere else time to market is a factor. Pros: very rapid results, often can solve "impossible" problems", often very innovative, often willing to work long hours on projects that interest them. Cons: code almost always inscrutable (even to original coder) and not maintainable, very short attention span, expensive to hire, sometimes have ego or other social issues.
  • Software Engineers write code intended to be understood and maintained by other people. They can code, but are better used to design, not only knowing techniques, but also when and why to apply them to best effect. If they have any social skill at all, they are usually found as team leaders. Pros: high quality maintainable code, results usually much longer-lasting and adaptable, can usually train others, usually have lower than average bug counts. Cons: expensive, results often slower to market, sometimes ego is factor.
 
Heh, I've been guilty of all of those. :)


Going through the CS program at U of Iowa and the IT program at Capella, I'd do say that the IT program focuses more on the software engineer while the CS program focused on meta-programming or the science of computers more. But, I completely agree, neither is enough to really get employed by itself. Like every other degree, there is so much more than just a piece of paper. They do teach you a lot of useful things though. Glad I did (am doing) both.


Your pros and cons are actually pretty spot on, at least from my experiences.


Too bad you aren't probably hiring for Iowa. I'm starting the process of looking for a new job. :)
 
Wordman, having been involved in hiring 'coders' myself that is a pretty good summary of the usual types of coders you run into.  


Personally, I'd say I somewhere between a scripter and a programmer and have become more and more of a software engineer though I lack familiarity some of the 'lingo' and 'processes' one would hopefully have been exposed to having been formally educated for that type of work.
 
Wow, that was a pretty impressive description Wordman.


I don't have the ego to worry about. I have social skills, but am still a hermit for the most part. And I am all about learning more whenever I get the chance.


I am not worried about securing a job because I can get a contractor job after I retire courtesy of my clearance and my military experience. This degree is mainly to get a good shot at earning a commision, a chance at a different career field, and to learn some skills to expand my knowledge and improve.


I want to learn how to fix computers, build them myself, etc. Truthfully I am still learning of what is out there, but I have always been fascinated with computers. There is so much out there I just didn't really know where to start.
 
Coyotekin said:
Wow, that was a pretty impressive description Wordman.
I don't have the ego to worry about. I have social skills, but am still a hermit for the most part. And I am all about learning more whenever I get the chance.


I am not worried about securing a job because I can get a contractor job after I retire courtesy of my clearance and my military experience. This degree is mainly to get a good shot at earning a commision, a chance at a different career field, and to learn some skills to expand my knowledge and improve.


I want to learn how to fix computers, build them myself, etc. Truthfully I am still learning of what is out there, but I have always been fascinated with computers. There is so much out there I just didn't really know where to start.
Just promise me you won't do what my dad does and try to fix everything yourself.  Geez, the man can be such a moron and he assumes too much.  Example: He thinks that my computer (which my mom had been using IE on) got a trojan because of me using firefox.
 
What's wrong with fixing everything yourself, presupposing that you're competent?
 
I'm alla bout fixing everything that I can, but I am not so stubborn to think I can fix everything. I am the kind of guy that asks for directions when I am lost. I value my time and getting things done more than my pride.
 

Users who are viewing this thread

Back
Top