#!/usr/bin/perl -w
# comics.pl, a perl CGI script to collect web comics and display them on one page
# Copyright (C) 2005  Christian Wolff
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
# Or, download it from http://www.gnu.org/copyleft/gpl.html
#
# You can reach the author via email: sub-gpl <at> scara.com
#


# server path to a directory where pictures can be stored
my $picdir = '/comics';

my $wget = 'wget -t 3 -T 10';

# Adapt for your time zone, offset in hours to GMT
my $TZ_offs = -7;

# Comics database
my %titles = (
	# Ind.
	'di', 'Dilbert', 'uf', 'User Friendly', 'frly', 'Farley', 
	'csmb', 'Christian Science Monitor', 
	'tmt', "Tom Meyer's Take (SF Chronicle)", 
	'latmr', 'Michael Ramirez (LA Times)', 
	'guksb', 'Steve Bell', 'gukmr', 'Martin Rowson', 
	'tom', 'Tom Touch&eacute;', 'taz', 'Taz Karikatur', 
	'maeve', 'Madam & Eve', 'tav', 'T.A.Vision', 'dlz', 'Dolezal', 
	'si', 'Sutton Impact', 'pr', 'Perry Rhodan', 'drfun', 'Dr. Fun', 
	'bennet', 'Clay Bennet', 'gmg', 'Garfield Minus Garfield', 
	'xkcd', 'xkcd', 
	# King Features
	'zp', 'Zippy', 'hg', 'H&auml;gar', 'bz', 'Bizarro', 
	'kzjm', 'Katzenjammer Kids', 'shrm', "Sherman's Lagoon", 
	'pop', 'Popeye', 
	# UComics
	'db', 'Doonesbury', 'bo', 'The Boondocks', 'nq', 'Non Sequitur', 
	'ga', 'Garfield', 'tmsho', 'Shoe', 'ch', 'Calvin &amp; Hobbes', 
	'tmhel', 'Helen, Sweetheart of the Internet', 'ad', 'Adam@Home', 
	'tmpco', 'Paul Conrad', 'po', 'Pat Oliphant', 'la', 'Lalo Alcaraz', 
	'tmdlo', 'Dick Locher', 'tmssa', 'Steve Sack', 'tmate', 'Ann Telnaes', 
	'tt', 'Tom Toles', 'tmw', 'This Modern World', 'trall', 'Ted Rall', 
	'puni', 'Puni', 'trtw', 'Troubletown', 'tmmda', 'Matt Davies', 
	'jd', 'Jeff Danziger', 'sc', 'Stuart Carlson', 'tmdho', 'David Horsey', 
	'bs', 'Ben Sargent', 'tmdsh', 'Drew Sheneman', 
	'lc', 'La Cucaracha', 'yen', 'Yenny', 'cwkal', 'KAL by Kevin Kallaugher', 
	'cwjmo', 'Jim Morin', 'jp', 'Joel Pett', 'crsbe', 'Steve Benson', 
	'bad', 'Bad Reporter by Don Asmussen', 'biov', 'Biographic', 
	'ms', 'Minimum Security', 'slow', 'Slowpoke', 'myth', 'Myth Tickle');

my %kingshort = ('zp', 'zippy', 'hg', 'hagar', 
	'bz', 'bizarro', 'kzjm', 'katzkids', 'shrm', 'lagoon', 
	'pop', 'Popeye');
my %kinglong = ('zp', 'Zippy_the_Pinhead', 'hg', 'Hagar_The_Horrible', 
	'bz', 'Bizarro', 'kzjm', 'Katzenjammer_Kids', 'shrm', 'Shermans_Lagoon', 
	'pop', 'Popeye');
my %kingfn = ('zp', 632, 'hg', 1302, 
	'bz', 72, 'kzjm', 2182, 'shrm', 1442,  
	'pop', 232);
#"Apartment_3-G", "Apartment 3-G", 12
#"Baby_Blues", "Baby Blues", 22
#"Barney_Google", "Barney Google &amp; Snuffy Smith", 32
#"Beetle_Bailey", "Beetle Bailey", 42
#"Bizarro", "Bizarro", 72
#"Blondie", "Blondie", 82
#"Curtis", "Curtis", 132
#"Dennis_The_Menace", "Dennis the Menace", 1032
#"Hagar_The_Horrible", "Hagar the Horrible", 1302
#"Hi_and_Lois", "Hi and Lois", 242
#"Judge_Parker", "Judge Parker", 282
#"Lockhorns", "The Lockhorns", 292
#"Mark_Trail", "Mark Trail", 332
#"Marvin", "Marvin", 342
#"Mary_Worth", "Mary Worth", 352
#"Mutts", "Mutts", 1572
#"Fast_Track", "On the Fastrack", 1212
#"Phantom", "The Phantom", 1692
#"Piranha", "Piranha Club", 442
#"Rex_Morgan", "Rex Morgan, M.D.", 62
#"Sally_Forth", "Sally Forth", 482
#"Shermans_Lagoon", "Sherman's Lagoon", 1442
#"6Chix", "Six Chix", 1862
#"Slylock", "Slylock Fox &amp; Comics for Kids", 112
#"SFI", "Slylock Fox &amp; Comics for Kids Interactive", 112
#"Zippy_the_Pinhead", "Zippy the Pinhead", 632
#"Zits", "Zits", 642

# UComics to GoComics tag translation
my %ucomics_go = (
	'db', 'doonesbury', 'bo', 'boondocks', 'nq', 'nonsequitur', 
	'ga', 'garfield', 'tmsho', 'shoe', 'ch', 'calvinandhobbes', 
	'ad', 'adamathome', 'po', 'patoliphant', 'la', 'laloalcaraz', 
	'tt', 'tomtoles', 'trall', 'tedrall', 'tmmda', 'mattdavies', 
	'jd', 'jeffdanziger', 'sc', 'stuartcarlson', 'bs', 'bensargent', 
	'tmdsh', 'drewsheneman', 'lc', 'lacucaracha', 'yen', 'yenny-lopez', 
	'cwkal', 'kevinkallaugher', 'cwjmo', 'jimmorin', 'jp', 'joelpett', 
	'crsbe', 'stevebenson', 'bad', 'badreporter', 'biov', 'biographic', 
	'ms', 'minimumsecurity', 'myth', 'mythtickle');

my $default = 'zp/db/nq/bo/di/uf/trall/csmb/guksb/maeve/tom/ch';
if (open DEF, "comics_default.txt") {
	$default = <DEF>;
	chomp $default;
	close DEF;
}

my $useragent = 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)';

my @weekdays = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
my @months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');

my $now = time() + $TZ_offs * 3600;
my ($sec, $min, $hour, $day, $month, $year, $wday, $yday, $isdst) = localtime($now);
$year += 1900;
$month++;
my ($cyear, $cmonth, $cday) = ($year, $month, $day);

# get cookies
my @cookies = ();
@cookies = split(/[;,]\s*/,$ENV{'HTTP_COOKIE'}) if $ENV{'HTTP_COOKIE'};

$err = '';
# get selection from cookie
my @selection = ();
my $selvalid = 0;
for (@cookies) {
#$err .= "co: $_<br>\n";
	if (/^comicselection=(.*)$/) {
		@selection = split(/\//, $1);
#$err .= "sel from cookie: $1<br>\n";
		$selvalid = 1;
	} elsif (/^selection=(.*)$/) {
		@selection = split(/\//, $1) unless ($selvalid);
		$selvalid = 1;
	}
}
@selection = split(/\//, $default) unless ($selvalid);
$selvalid = 0;

my $pick = '';
my $sortmode = 0;
my $fullyear = 0;
my $currentday = 1;

# get CGI parameter: 8 digit date, new selection
my %query = ();
my $query = $ENV{'QUERY_STRING'};
chomp $query;

my $redirect = "https://comics.scara.com/cgi-bin/comics";
if ($redirect) {
	# print HTTP header
	my $location = $redirect;
	my $tag = '?';
	if ($ENV{'QUERY_STRING'}) {
		$location = $location . $tag . $ENV{'QUERY_STRING'};
		$tag = '&';
	}
	if ($ENV{'HTTP_COOKIE'}) {
		my $cookie = $ENV{'HTTP_COOKIE'};
		$cookie =~s/comicselection/selection/;
		$location = $location . $tag . $cookie;
	}
	print "MIME-Version: 1.0\nLocation: $location\n\n";
	
	exit;
}

for (split (/&/, $query)) {
	if (/=/) {
		my ($param,$content) = split(/=/, $_, 2);
		$content =~ tr/+/ /;
		$content =~ s/%([0-9a-fA-F]{2})/pack('c',hex($1))/ge;
		$query{$param} = $content;
	} elsif ($_) {
		$query{'date'} = $_;
	}
}

# use specified date instead of today's
if ($query{'date'}) {
	$year = substr($query{'date'}, 0, 4);
	$month = substr($query{'date'}, 4, 2);
	$day = substr($query{'date'}, 6, 2);
	$currentday = 0;
}

# use specified selection instead of default or the one from cookie
if ($query{'selection'}) {
	@selection = split /\//, $query{'selection'};
	my @newcook = ();
	for (@cookies) {
		push @newcook, $_ unless (/^comicsel.?=/ || /^comicselection=/ || /^selection=/);
#		push @newcook, $_ unless (/^comicsel.?=/);
#$err .= "don't" if (/^comicsel=/);
#$err .= "add cookie: $_<br>\n";
	}
	@cookies = ();
	push @cookies, "comicselection=" . join '/', @selection;
	push @cookies, @newcook;
	$selvalid = 1;
}

if ($query{'pick'}) {
	$pick = $query{'pick'};
}

if ($query{'sort'}) {
	$sortmode = 1;
}

if ($query{'fullyear'}) {
	$fullyear = 1;
}

my $force = $query{'force'};

`mkdir -p $ENV{'DOCUMENT_ROOT'}${picdir}`;

# print HTTP header
print "MIME-Version: 1.0\nContent-Type: text/html\n";
if ($selvalid) {
	print "Set-Cookie: ";
	for (@cookies) {
		print "$_; ";
#$err .= "cookie: $_<br>\n";
	}
	my ($esec, $emin, $ehour, $eday, $emonth, $eyear, $ewday, $eyday, $eisdst) = gmtime(time() + 360 * 24 * 60 * 60);
	my $expire = sprintf("%s, %02d-%s-%02d %02d:%02d:%02d GMT", 
		$weekdays[$ewday], $eday, $months[$emonth], $eyear % 100, $ehour, $emin, $esec);
	print "expires=${expire}; path=/; domain=.scarabaeus.org\n";
}
print "\n";

# prepare calendar and date links
my $start = $wday - 6;  # start last monday
my $weekspast = 0;
my $nowvec = $day + $month * 64 + $year * 1024;
my ($isec, $imin, $ihour, $iday, $imonth, $iyear, $iwday, $iyday, $iisdst) = localtime($now + $start * 86400);
$iyear += 1900; $imonth++;
my $firstvec = $iday + $imonth * 64 + $iyear * 1024;
while ($nowvec <= $firstvec) {
	$weekspast++;
	$start -= 7;
	($isec, $imin, $ihour, $iday, $imonth, $iyear, $iwday, $iyday, $iisdst) = localtime($now + $start * 86400);
	$iyear += 1900; $imonth++;
	$firstvec = $iday + $imonth * 64 + $iyear * 1024;
}
$start = (($weekspast + (($weekspast > 2) ? 2 : 4)) * -7) - $wday + 1;  # start on a monday
my ($yesterday, $tomorrow, $lastsun, $nextsun, $today, $twday, $yyear, $ymonth, $yyday) = ('', '', '', '', 0, 0, 0, 0, 0);
my ($i, $toffs);
($isec, $imin, $ihour, $iday, $imonth, $iyear, $iwday, $iyday, $iisdst) = localtime($now + $start * 86400);
$iyear += 1900; $imonth++;
my $rows = 0;
($isec, $imin, $ihour, $iday, $imonth, $iyear, $iwday, $iyday, $iisdst) = localtime($now + ($start - 1) * 86400);
$iyear += 1900; $imonth++;
$lastsun = sprintf("%04d%02d%02d", $iyear, $imonth, $iday);
for ($i = $start; $i <= 0; $i++) {
	($isec, $imin, $ihour, $iday, $imonth, $iyear, $iwday, $iyday, $iisdst) = localtime($now + $i * 86400);
	$iyear += 1900; $imonth++;
	my $link = sprintf("%04d%02d%02d", $iyear, $imonth, $iday);
	$tomorrow = $link if ($today && (! $tomorrow));
	$nextsun = $link if ($today && (! $nextsun) && ($iwday == 0));
	if (($year == $iyear) && ($month == $imonth) && ($day == $iday)) {
		$today = $link;
		$twday = $iwday;
		$toffs = $i;
		$start -= 7 if ! $rows;
	}
	if (! $today) {
		$yesterday = $link;
		$yyear = $iyear;
		$ymonth = $imonth;
		$yyday = $iday;
	}
	$lastsun = $link if ((! $today) && ($iwday == 0));
	$rows++ if ($iwday == 0);
}
my $title = sprintf "Comics for %s%s, %04d-%02d-%02d", 
	$pick ? "the week ending on " : '', 
	$weekdays[$twday], $year, $month, $day;

# print HTML header
#	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
print <<END;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "https://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
	<meta http-equiv="content-type" content="text/html; charset=utf-8">
	<title>${title}</title>
</head>
<body>

$err
END

sub calendar {
	#print calendar
	print <<END;
<table border=1 cellspacing=0 cellpadding=2>
	<tr>
		<th width=42>Mon</th>
		<th width=42>Tue</th>
		<th width=42>Wed</th>
		<th width=42>Thu</th>
		<th width=42>Fri</th>
		<th width=42>Sat</th>
		<th width=42>Sun</th>
	</tr>
	<tr>
END
	my $row = 0;
	for ($i = $start; $i <= 0; $i++) {
		($isec, $imin, $ihour, $iday, $imonth, $iyear, $iwday, $iyday, $iisdst) = localtime($now + $i * 86400);
		if (($row < 4) || ($row + 3 >= $rows)) {
			$iyear += 1900; $imonth++;
			my $link = sprintf("%04d%02d%02d", $iyear, $imonth, $iday);
			$link = "date=${link}&pick=${pick}" if ($pick);
			print "\t\t\<td><a href=\"$ENV{SCRIPT_NAME}?${link}\">${imonth}/${iday}</a></td>\n";
			print "\t</tr>\n\t\t<tr>\n" if (($iwday == 0) && $i);
		} elsif (($row == 4) && ($iwday == 1)) {
			print "\t\t\<td colspan=7 align=center>. . .</td>\n";
			print "\t</tr>\n\t\t<tr>\n";
		}
		$row ++ if ($iwday == 0);
	}
	if ($wday) {
		for ($i = $wday; $i < 7; $i++) {
			print "\t\t\<td>&nbsp;</td>\n";
		}
	}
	print "\t</tr>\n</table>\n\n";
}

calendar();

print "<H3>${title}</H3>\n\n";

#print "${hour}:${min}:${sec}<br>\n";

my $yestlink = $yesterday;
my $todaylink = $today;
my $tomolink = $tomorrow;
if ($pick) {
	$yestlink = "date=${lastsun}&pick=${pick}" if $lastsun;
	$todaylink = "date=${today}&pick=${pick}";
	$tomolink = "date=${nextsun}&pick=${pick}" if $nextsun;
}
print "<table width=600><tr><td width=200 align=left>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${yestlink}\"><img src=\"/img/left.gif\" width=10 height=10 border=0 alt=\"&lt;&lt;&lt;\"></a>\n" if $yestlink;
print "</td><td width=200 align=center>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${todaylink}\"><img src=\"/img/cross.gif\" width=10 height=10 border=0 alt=\"O\"></a>\n" if ($todaylink && $sortmode);
print "</td><td width=200 align=right>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${tomolink}\"><img src=\"/img/right.gif\" width=10 height=10 border=0 alt=\"&gt;&gt;&gt;\"></a>\n" if $tomolink;
print "</td></tr></table><br>\n\n";

sub img_chk {
	my $url = shift;
	if ($url) {
		return 0 if system("$wget --spider '${url}' 2>/tmp/piclog.txt");
		return 0 if system("grep -q '\\[image\\/' /tmp/piclog.txt");
		return 1;
	} else {
		return 0;
	}
}

sub img {
	my ($url, $tag, $year, $month, $day, $force, $found) = @_;
	my $today = sprintf("%04d%02d%02d", $year, $month, $day);
	my $link = $pick ? $today : "date=${today}&pick=${tag}";
	if ($force ? $found : img_chk($url)) {
		print "<a href=\"$ENV{SCRIPT_NAME}?${link}\"><img src=\"${url}\" border=0></a></br>\n";
		return 1;
	} else {
		print "No cartoon image found!<br>\n";
		print "<a href=\"${url}\">[$titles{$tag}]</a></br>\n" if $force;
		return 0;
	}
}

# cache and display comic from kingfeatures.com (old, stopped working 2013-02-08)
sub king0 {
	my ($tag, $year, $month, $day, $wday) = @_;
	if ($tag eq 'kzjm') {
		if ($wday != 0) {
			print "Sundays only!\n" unless $pick;
			return;
		}
	}
	my $name = $kingshort{$tag} . sprintf("_%04d%02d%02d.gif", $year, $month, $day);
	#my $archive = "http://www.kingfeatures.com/features/comics/$kingshort{$tag}/about.htm";
	#my $archive = sprintf("http://www.kingfeatures.com/features/comics/$kingshort{$tag}/aboutMaina.php?date=%04d%02d%02d&view_comic=Get+Comic", 
	#my $archive = sprintf("http://dailyink.com/features/$kinglong{$tag}/aboutMaina.php?date=%04d%02d%02d&view_comic=Get+Comic", 
	my $archive = sprintf("https://www.kingfeatures.com/features/comics/$kinglong{$tag}/aboutMaina.php?date=%04d%02d%02d&view_comic=Get+Comic", 
		$year, $month, $day);
	my $url = sprintf("https://est.rbma.com/content/$kinglong{$tag}?date=%04d%02d%02d",
		$year, $month, $day);
	my $found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}";
	unless ($found) {
		`${wget} -q --referer='${archive}' -O '$ENV{'DOCUMENT_ROOT'}${picdir}/${name}' '${url}' 2>/dev/null`;
		$found = -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}";
	}
	return img($found ? "${picdir}/${name}" : $archive, $tag, $year, $month, $day, 1, $found);
}

# (new version, still good after 2013-02-08)
# 2017-11-04: local dir from <picdir>/ to <picdir>/<tag>/<tag>_<year>/
sub king {
	my ($tag, $year, $month, $day, $wday) = @_;
	if ($tag eq 'kzjm') {
		if ($wday != 0) {
			print "Sundays only!\n" unless $pick;
			return;
		}
	}
	my $dir = sprintf("${picdir}/$kingshort{$tag}/$kingshort{$tag}_%04d", $year);
	`mkdir -p $ENV{'DOCUMENT_ROOT'}${dir}`;
	my $name = $kingshort{$tag} . sprintf("_%04d%02d%02d.gif", $year, $month, $day);
	my $fn = $kingfn{$tag}; # Need to know the feature number!
#	my $url = sprintf("http://safr.kingfeatures.com/idn/zone/js/index.php?cn=92&zn=182&fn=%d&fd=%04d%02d%02d&wt=1&fs=0&null=0", 
#		$fn, $year, $month, $day);
#	my $referer = "http://www.washingtonpost.com/wp-srv/artsandliving/comics/king.html";
	my $url = sprintf("https://safr.kingfeatures.com/idn/ck3/zone/js/index.php?cn=32&zn=332&fn=%d&fd=%04d%02d%02d&wt=0&fs=0&null=0", 
		$fn, $year, $month, $day);
	my $referer = "https://v4.comicskingdom.net/safr/getSafr";
#	my $referer = "http://v4.comicskingdom.net/widgets/176/init/1443184957.js";
#	my $referer = "http://www.seattlepi.com/comics-and-games/fun/$kinglong{$tag}/";
	my $found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
	unless ($found) {
		$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}";
		$dir = $picdir if $found;
	}
	unless ($found) {
		if (open PAGE, "${wget} -q --referer='${referer}' -U '${useragent}' -O - '${url}' 2>/dev/null |") {
			while (<PAGE>) {
				if (/img src='(.*)' alt/) {
					`${wget} -q --referer='${url}' -U '${useragent}' -O '$ENV{'DOCUMENT_ROOT'}${dir}/${name}' '${1}' 2>/dev/null`;
					$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
				}
			}
			$url = "${dir}/${name}" if $found;
		}
		close PAGE;
	}
	unless ($found) {
		`${wget} -q --referer='${archive}' -O '$ENV{'DOCUMENT_ROOT'}${dir}/${name}' '${url}' 2>/dev/null`;
		$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
	}
	return img($found ? "${dir}/${name}" : $archive, $tag, $year, $month, $day, 1, $found);
}

# display comic from ucomics.com and gocomics.com
# 2017-11-04: local dir from <picdir>/ucomics/<tag>/ to <picdir>/ucomics/<tag>/<tag>_<year>/
sub ucomics {
	my ($tag, $year, $month, $day) = @_;
	my $ext = 'gif';
	if (($tag eq 'tmhel') && (($year > 2005) || (($year == 2005) && (($month > 12) || (($month == 12) && ($day > 25)))))) {
		print "Discontinued as of 2005-12-25!\n";
		return;
	}
	my ($found, $img, $url, $dir) = (0, '', '', '');
	# Calvin & Hobbes: loop through old ones, modulo 10 years
	if ($tag eq 'ch') {
		if ($year > 1996) {
			$year = 1986 + (($year + 4) % 10);
		}
		$img = sprintf("%02d/%02d/%02d.${ext}", $year % 100, $month, $day);
		$dir = "${picdir}/${tag}";
		$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
	}
	# Check if GIF already cached (old location, flat dir)
	unless ($found) {
		$dir = "${picdir}/ucomics/${tag}";
		`mkdir -p $ENV{'DOCUMENT_ROOT'}${dir}`;
		$img = sprintf("%s%02d%02d%02d.${ext}",
			$tag, $year % 100, $month, $day);
		$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
	}
	# Check if GIF already cached (new location, yearly dirs)
	unless ($found) {
		$dir = "${picdir}/ucomics/${tag}/${tag}_" . sprintf("%04d", $year);
		`mkdir -p $ENV{'DOCUMENT_ROOT'}${dir}`;
		$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
	}
	# New: get from gocomics (GIF or JPG, dummy .gif extension)
	unless ($found) {
		if ($ucomics_go{$tag}) {
			my $today_go = sprintf("$ucomics_go{$tag}/%04d/%02d/%02d", $year, $month, $day);
			my $today_match = 0;
			$url = "http://www.gocomics.com/${today_go}";
			if (open PAGE, "${wget} -q -U '${useragent}' -O - '${url}' 2>/dev/null |") {
				while (<PAGE>) {
					$today_match = 1 if (/${today_go}/);
					# Look for the "zoom" link first, then try without insisting on zoom
					if (($today_match) && (/zoom_link.*class="strip" src="(.*?)"/)) {
						$img = sprintf("%s%02d%02d%02d.${ext}",
							$tag, $year % 100, $month, $day);
						`${wget} -q --referer='${url}' -U '${useragent}' -O '$ENV{'DOCUMENT_ROOT'}${dir}/${img}' '${1}' 2>/dev/null`;
						`rm "$ENV{'DOCUMENT_ROOT'}${dir}/${img}"` if -z "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
						$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
						last if $found;
					}
					elsif (($today_match) && (/class="strip" src="(.*?)"/)) {
						$img = sprintf("%s%02d%02d%02d.${ext}",
							$tag, $year % 100, $month, $day);
						`${wget} -q --referer='${url}' -U '${useragent}' -O '$ENV{'DOCUMENT_ROOT'}${dir}/${img}' '${1}' 2>/dev/null`;
						`rm "$ENV{'DOCUMENT_ROOT'}${dir}/${img}"` if -z "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
						$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
						last if $found;
					}
				}
				close PAGE;
			}
		}
	}
	# Old: get GIF from ucomics
	unless ($found) {
		$url = sprintf("http://images.ucomics.com/comics/%s/%4d/%s", 
			$tag, $year, $img);
		`${wget} -q -O '$ENV{'DOCUMENT_ROOT'}${dir}/${img}' '${url}' 2>/dev/null`;
		`rm "$ENV{'DOCUMENT_ROOT'}${dir}/${img}"` if -z "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
		$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
	}
	# No GIF, try JPG from cache
	unless ($found) {
		$ext = 'jpg';
		$img = sprintf("%s%02d%02d%02d.${ext}",
			$tag, $year % 100, $month, $day);
		$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
	}
	# Get JPG from ucomics
	unless ($found) {
		$url = sprintf("http://images.ucomics.com/comics/%s/%4d/%s", 
			$tag, $year, $img);
		`${wget} -q -O '$ENV{'DOCUMENT_ROOT'}${dir}/${img}' '${url}' 2>/dev/null`;
		`rm "$ENV{'DOCUMENT_ROOT'}${dir}/${img}"` if -z "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
		$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
	}
	$url = "${dir}/${img}" if $found;
	return img($url, $tag, $year, $month, $day, $found, $found);
}

sub chronicle {
	my ($tag, $long, $year, $month, $day) = @_;
	$url = sprintf("https://www.sfgate.com/cgi-bin/article.cgi?file=/chronicle/archive/%04d/%02d/%02d/%s.DTL", 
		$year, $month, $day, $long);
	$found = 0;
	if (open PAGE, "${wget} -q -O - '${url}' 2>/dev/null |") {
		while (<PAGE>) {
			if (/(https:\/\/www\.sfgate\.com\/chronicle\/pictures\/.*?-\w+\.gif)/) {
				$url = $1;
				$found = 1;
				last;
			}
		}
		close PAGE;
	}
	img($url, $tag, $year, $month, $day, 1, $found);
}

# 2017-11-04: local dir from <picdir>/ to <picdir>/<tag>/<tag>_<year>/
sub taz {
	my ($tag, $long, $year, $month, $day, $wday) = @_;
	if ($wday == 0) {
		print "Not on Sundays!\n";
		return;
	}
	my $url = 'https://www.taz.de';
# http://www.taz.de/index.php?id=archiv&dig=2007/06/25/a0184
# http://www.taz.de/digitaz/.1/tomdestages
# http://www.taz.de/digitaz/.1/gif.t,tom.d,1182973790 2007-06-27 wed
# http://www.taz.de/digitaz/.1/gif.t,tom.d,1183206524 2007-06-30 sat
# http://www.taz.de/digitaz/.1/gif.t,tom.d,1183391474 2007-07-02 mon
# http://www.taz.de/digitaz/.1/tomtgif shuffle
# http://www.taz.de/fileadmin/seite1/kari.gif
# http://www.taz.de/digitaz/.tom/tomdestages?day=2009/05/20
#wget --referer='http://www.taz.de/digitaz/.1/tomdestages.php?day=2007/09/15' 'http://www.taz.de/dx/.1/gif.t,tom.d,1189807200
# wget -t 3 -T 10 --referer='http://www.taz.de/digitaz/.1/tomdestages' http://www.taz.de/digitaz/.1/gif.t,tom.d,1182973790
# 0 11 * * * /usr/bin/sudo -u nobody /usr/bin/wget -q -t 3 -T 10 > /dev/null 2>&1 --referer='http://www.taz.de/digitaz/.1/tomdestages' http://www.taz.de//usr/bin/wget -t 3 -T 10 -q http://www.taz.de/digitaz/.1/tomdestages -O - | /usr/bin/grep 'gif.t,tom.d' | /usr/bin/sed 's/^.*src="//' | /usr/bin/sed 's/" alt.*$//' -O /www/scarabaeus.org/htdocs/comics/tom_ate '+%Y%m%d'.gif
	my $dir = sprintf("${picdir}/${tag}/${tag}_%04d", $year);
	`mkdir -p $ENV{'DOCUMENT_ROOT'}${dir}`;
	my $name = $tag . sprintf("_%04d%02d%02d.gif", $year, $month, $day);
#	my $link = sprintf('/digitaz/.1/' . (($tag eq 'tom') ? 'tomdestages' : 'kari') . '.php?day=%04d/%02d/%02d', 
#		$year, $month, $day);
	my $link = sprintf('/digitaz/%04d/%02d/%02d.1/' . (($tag eq 'tom') ? 'tomcartoon' : 'kari'), 
		$year, $month, $day);
	if ($tag eq 'tom') {
		# $link = sprintf('/digitaz/.tom/tomdestages?day=%04d/%02d/%02d', $year, $month, $day);
#		my $sec = `date +%s -d ${year}-${month}-${day}` - 7200;
#		my $sec = `date +%s -d ${year}-${month}-${day}` + 62000;
		my $sec = `date +%s -d ${year}-${month}-${day}` + 9 * 3600;
#		my $sec = `date +%s -d ${year}-${month}-${day}` + 22 * 3600;
		$link = sprintf('/scripts/tom/gif.php?t=tom&d=%d', $sec);
# http://www.taz.de/scripts/tom/gif.php?t=tom&d=1507070028 1506988800
	}
#	my $link = sprintf('/pt/%04d/%02d/%02d.nf/%s',
#		$year, $month, $day, $long);
	my $pic = '';
#	my $found = -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}";
	my $found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
	unless ($found) {
		$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}";
		$dir = $picdir if $found;
	}
	if ((! $found) && ($tag eq 'tom')) {
		$pic = "${link}";
	} 
	elsif ((! $found) && open PAGE, "${wget} -q -O - '${url}${link}' 2>/dev/null |") {
		while (<PAGE>) {
			if (/(\/digitaz\/\.1\/gif\.t\,\w+\.d\,\d+)/) {
				$pic = $1;
				last;
			} elsif (/(\/dx\/\.1\/gif\.t\,\w+\.d\,\d+)/) {
				$pic = $1;
				last;
			} elsif (/(\/pt\/\.1\/gif\.t\,\w+\.d\,\d+)/) {
				$pic = $1;
				last;
			}
		}
		close PAGE;
		print "No cartoon image found on server!<br>\n" unless ($pic);
	}
	if ($pic) {
		`${wget} -q --referer='${url}${link}' -O '$ENV{'DOCUMENT_ROOT'}${dir}/${name}' '${url}${pic}' 2>/dev/null`;
		$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
	}
#	if ((! $found) && open PAGE, "${wget} -q -O - '${url}${link}' 2>/dev/null |") {
#		while (<PAGE>) {
#			if (/(\/pt\/\.nf\/gif\.t\,\w+\.d\,\d+)/) {
#				$pic = $1;
#				last;
#			} elsif (/(\/dx\/\.nf\/gif\.t\,\w+\.d\,\d+)/) {
#				$pic = $1;
#				last;
#			}
#		}
#		close PAGE;
#		if (! $pic) {
#			$link = sprintf('/dx/%04d/%02d/%02d.1/%s',
#				$year, $month, $day, $long);
#			if (open PAGE, "${wget} -q -O - '${url}${link}' 2>/dev/null |") {
#				while (<PAGE>) {
#					if (/(\/dx\/\.1\/gif\.t\,\w+\.d\,\d+)/) {
#						$pic = $1;
#						last;
#					}
#				}
#				close PAGE;
#			}
#		}
#		if (! $pic) {
#			$link = sprintf('/dx/%04d/%02d/%02d.1/%scartoon',
#				$year, $month, $day, $tag);
#			if (open PAGE, "${wget} -q -O - '${url}${link}' 2>/dev/null |") {
#				while (<PAGE>) {
#					if (/(\/dx\/\.1\/gif\.t\,\w+\.d\,\d+)/) {
#						$pic = $1;
#						last;
#					}
#				}
#				close PAGE;
#			}
#		}
#		print "No cartoon image found on server!<br>\n" unless ($pic);
#	}
#	if ($pic) {
#		`${wget} -q --referer='${url}${link}' -O '$ENV{'DOCUMENT_ROOT'}${picdir}/${name}' '${url}${pic}' 2>/dev/null`;
#		$found = -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}";
#	}
	img($found ? "${dir}/${name}" : "${url}${link}", $tag, $year, $month, $day, 1, $found);
#	img("${picdir}/${name}", $tag, $year, $month, $day, 1, $found);
}

sub xkcd {
	my ($tag, $year, $month, $day) = @_;
	my $url = 'https://xkcd.com/archive/';
	my $date = sprintf("%04d-%d-%d", $year, $month, $day);
	my $found = 0;
	if (open ARCHIVE, "${wget} -q -U '${useragent}' -O - '${url}' 2>/dev/null |") {
		while (<ARCHIVE>) {
			if (/<a href="\/(\d+)\/" title="${date}">(.*)</) {
				$url = "https://xkcd.com/${1}/";
				if (open PAGE, "${wget} -q -U '${useragent}' -O - '${url}' 2>/dev/null |") {
					while (<PAGE>) {
						if (/<img src="(https:)?(\/\/imgs.xkcd.com\/comics\/.*\.png)" title="(.*?)" alt="(.*?)"/) {
							$found = 1;
							print "<a href=\"${url}\"><H4>${4}</H4></a>\n";
							$url = ($1) ? "${1}${2}" : "https:${2}";
							img($url, $tag, $year, $month, $day, 1, $found);
							print "<p>${3}</p>\n";
						}
					}
					close PAGE;
				}
			}
		}
		close ARCHIVE;
	}
	if (0 && (! $found) && $currentday) {
		$url = "https://xkcd.com/";
		if (open PAGE, "${wget} -q -U '${useragent}' -O - '${url}' 2>/dev/null |") {
			while (<PAGE>) {
				if (/<img src="(https:\/\/imgs.xkcd.com\/comics\/.*\.png)" title="(.*)" alt="(.*?)"/) {
					$found = 1;
					print "<a href=\"${url}\"><H4>${3}</H4></a>\n";
					$url = "${1}";
					img($url, $tag, $year, $month, $day, 1, $found);
					print "<p>${2}</p>\n";
				}
			}
			close PAGE;
		}
	}
	img($url, $tag, $year, $month, $day, 1, $found) unless $found;
}

sub keenspace {
	my ($tag, $year, $month, $day) = @_;
	my $url = sprintf('https://%s.keenspace.com/d/%04d%02d%02d.html', $tag, $year, $month, $day);
	my $found = 0;
	if (open PAGE, "${wget} -q -U '${useragent}' -O - '${url}' 2>/dev/null |") {
		while (<PAGE>) {
			while (s/(http\:\/\/${tag}\.keenspace\.com\/comics\/)(${tag}\d+.?\.jpg)//) {
				$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${2}";
				unless ($found) {
					`${wget} -q --referer='${url}' -U '${useragent}' -O '$ENV{'DOCUMENT_ROOT'}${picdir}/${2}' '${1}${2}' 2>/dev/null`;
					$found = -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${2}";
				}
				$url = "${picdir}/${2}" if $found;
			}
		}
		close PAGE;
	}
	img($url, $tag, $year, $month, $day, 1, $found);
}

sub comicgenesis {
	my ($tag, $year, $month, $day) = @_;
	my $url = sprintf('https://%s.comicgenesis.com/d/%04d%02d%02d.html', $tag, $year, $month, $day);
	my $found = 0;
	if (open PAGE, "${wget} -q -U '${useragent}' -O - '${url}' 2>/dev/null |") {
		while (<PAGE>) {
			while (s/(http\:\/\/${tag}\.comicgenesis\.com\/comics\/)(${tag}\d+.?\.jpg)//) {
				$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${2}";
				unless ($found) {
#print "${wget} -q --referer='${url}' -U '${useragent}' -O '$ENV{'DOCUMENT_ROOT'}${picdir}/${2}' '${1}${2}'<br>\n";
					`${wget} -q --referer='${url}' -U '${useragent}' -O '$ENV{'DOCUMENT_ROOT'}${picdir}/${tag}/${2}' '${1}${2}' 2>/dev/null`;
					$found = -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${tag}/${2}";
				}
				img("${picdir}/${tag}/${2}", $tag, $year, $month, $day, 1, $found) if $found;
			}
		}
		close PAGE;
	}
	img($url, $tag, $year, $month, $day, 1, $found) unless $found;
}

sub garfieldminusgarfield {
	my ($tag, $year, $month, $day) = @_;
	my $url = sprintf('https://garfieldminusgarfield.net/day/%04d/%02d/%02d/', $year, $month, $day);
	my $found = 0;
	if (open PAGE, "${wget} -q -U '${useragent}' -O - '${url}' 2>/dev/null |") {
		my $n = 1;
		while (<PAGE>) {
			if (/garfieldminusgarfield\.net\/post.*\<img src="(http\:\/\/.*\.(png|gif|jpg))/) {
				my $localpic = sprintf('garfieldminusgarfield/%04d-%02d-%02d_%d.png', $year, $month, $day, $n);
				$n ++;
				$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${localpic}";
				unless ($found) {
					`${wget} -q --referer='${url}' -U '${useragent}' -O '$ENV{'DOCUMENT_ROOT'}${picdir}/${localpic}' '${1}' 2>/dev/null`;
					$found = -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${localpic}";
				}
				img("${picdir}/${localpic}", $tag, $year, $month, $day, 1, $found) if $found;
			}
		}
		close PAGE;
	}
#	img($url, $tag, $year, $month, $day, 1, $found) unless $found;
}

my ($url, $found, $tag);

@selection = ($pick) if $pick;
foreach $tag (@selection) {
	#next if ($pick && ($pick ne $tag));
	# create links for comic maintenance
	unless ($pick) {
		my @subsel = (); for (@selection) { push @subsel, $_ unless ($_ eq $tag); };
		my @upsel = (); my $last = ''; for (@selection) { if ($last && ($_ eq $tag)) { push @upsel, $tag; } else {push @upsel, $last if ($last); $last = $_; } } push @upsel, $last;
		my @downsel = (); my $next = ''; for (@selection) { push @downsel, $_ if ($next eq $tag); push @downsel, $next if ($next); $next = ($next eq $tag) ? '' : $_; } push @downsel, $next;
		my $sublink = $ENV{'SCRIPT_NAME'} . sprintf("?date=%04d%02d%02d&sort=1&selection=%s", $year, $month, $day, join '/', @subsel);
		my $uplink = $ENV{'SCRIPT_NAME'} . sprintf("?date=%04d%02d%02d&sort=1&selection=%s", $year, $month, $day, join '/', @upsel);
		my $downlink = $ENV{'SCRIPT_NAME'} . sprintf("?date=%04d%02d%02d&sort=1&selection=%s", $year, $month, $day, join '/', @downsel);
		print "<a href=\"${uplink}\"><img src=\"/img/up.gif\" width=10 height=10 border=0 alt=\"[up]\"></a>\n";
		print "<a href=\"${sublink}\"><img src=\"/img/cross.gif\" width=10 height=10 border=0 alt=\"[remove]\"></a>\n";
		print "<a href=\"${downlink}\"><img src=\"/img/down.gif\" width=10 height=10 border=0 alt=\"[down]\"></a>\n";
	}
	print "<b>" . ($titles{$tag} ? $titles{$tag} : $tag) . "</b>\n";
	if ($sortmode) {
		print "<br>";
		next;
	}
	my $pluslink = $ENV{'SCRIPT_NAME'} . sprintf("?date=%04d%02d%02d", $year, $month, $day);
	$pluslink .= "&pick=${tag}" unless $pick;
	print "<a href=\"${pluslink}\"><img src=\"/img/plus.gif\" width=10 height=10 border=0 alt=\"[more]\"></a><br>\n";
	
	my $loopdays = $fullyear ? 365 : $pick ? ($twday ? $twday : 7) : 1;
	my $loopstart = 1 - $loopdays;
	my $loopday;
	for ($loopday = $loopstart; $loopday < $loopstart + $loopdays; $loopday++) {
		my ($lsec, $lmin, $lhour, $lday, $lmonth, $lyear, $lwday, $lyday, $lisdst) = localtime($now + ($toffs + $loopday) * 86400);
		$lyear += 1900; $lmonth++;
		printf ("<br>$weekdays[$lwday] %04d-%02d-%02d<br>\n", $lyear, $lmonth, $lday) if $pick;
		
		# Dilbert
		if ($tag eq 'di') {
			my $dilbert = "http://www.dilbert.com";
#			$url = sprintf("/comics/dilbert/archive/dilbert-%04d%02d%02d.html", $lyear, $lmonth, $lday);
#			$found = 0;
#			if (open PAGE, "${wget} -q -O - '${dilbert}${url}' 2>/dev/null |") {
#				$url = '';
#				while (<PAGE>) {
#					if (/(\/comics\/dilbert\/archive\/images\/dilbert\d+\.\w{3})/) {
#						$url = $1;
#						$found = 1;
#						last;
#					}
#				}
#				close PAGE;
#			}
			
#			$url = 'http://www.dilbert.com/strips/?CharIDs=&Order=s.DateStrip+DESC&PerPage=10&x=14&y=11&CharFilter=Any&Before=06%2F24%2F2008&After=06%2F24%2F2008';
			
#			http://www.dilbert.com/strip/2015-01-13
#			$url = sprintf("/strips/comic/%04d-%02d-%02d/", $lyear, $lmonth, $lday);
			$url = sprintf("/strips/%04d-%02d-%02d/", $lyear, $lmonth, $lday);
			$found = 0;
			if (open PAGE, "${wget} -q -O - '${dilbert}${url}' 2>/dev/null |") {
				$url = '';
				while (<PAGE>) {
#					if (/\"(\/dyn\/str_strip\/.*\.strip\.print\.\w{3})\"/) {
#					if (/src=\"(http\:\/\/assets\.amuniversal\.com\/.*)\"/) {
					if (/content=\"(http\:\/\/assets\.amuniversal\.com\/.*)\"/) {
						$url = $1;
						$url =~s/http/https/;
						$found = 1;
						last;
					}
				}
				close PAGE;
			} else {
				printf("Failed to load ${dilbert}${url}<br>\n");
			}
			
#			img("${dilbert}${url}", $tag, $lyear, $lmonth, $lday, 1, $found);
			img("${url}", $tag, $lyear, $lmonth, $lday, 1, $found);
		}
		
		# User Friendly
		elsif ($tag eq 'uf') {
			$url = sprintf("http://ars.userfriendly.org/cartoons/?id=%04d%02d%02d", $lyear, $lmonth, $lday);
			$found = 0;
			if (open PAGE, "${wget} -q -O - '${url}' 2>/dev/null |") {
				while (<PAGE>) {
					if (/(http\:\/\/www\.userfriendly\.org\/cartoons\/archives\/\d{2}\w{3}\/)(ufn?g?\d{6}\.gif)/) {
						my $name = $2;
						my $dir = "${picdir}/userfriendly";
						$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
						unless ($found) {
							$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}";
							$dir = $picdir;
						}
						unless ($found) {
							`${wget} -q --referer='${url}' -O '$ENV{'DOCUMENT_ROOT'}${dir}/${name}' '${1}${2}' 2>/dev/null`;
							$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
						}
						$url = "${dir}/${name}" if $found;
						last;
					}
				}
				close PAGE;
			}
			img($url, $tag, $lyear, $lmonth, $lday, 1, $found);
		}
		
		# Farley
		elsif ($tag eq 'frly') {
			if (($lyear > 2007) || (($lyear == 2007) && (($lmonth > 9) || (($lmonth == 9) && ($lday > 5))))) {
				print "Retired on 2007-09-06\n";
			} else {
				chronicle($tag, 'BAFARLEY', $lyear, $lmonth, $lday);
			}
		}
		
		# Tom Meyer's Take
		elsif ($tag eq 'tmt') {
			chronicle($tag, 'EDMEYER', $lyear, $lmonth, $lday);
		}
		
		# Perry Rhodan
		elsif ($tag eq 'pr') {
			if ($lwday != 5) {
				print "Friday only!\n" unless $pick;
			} else {
				$url = sprintf('https://www.perry-rhodan.net/pics/cartoons/%04d%02d%02d01.jpg', 
					$lyear, $lmonth, $lday);
				img($url, $tag, $lyear, $lmonth, $lday);
			}
		}
		
		# Dr. Fun
		elsif ($tag eq 'drfun') {
			if (($lwday == 0) || ($lwday == 6)) {
				print "Weekdays only!\n" unless $pick;
			} elsif (($lyear > 2006) || (($lyear == 2006) && (($lmonth > 6) || (($lmonth == 6) && ($lday > 9))))) {
				print "Discontinued as of 2006-06-09!\n";
			} else {
				$url = sprintf('https://www.ibiblio.org/Dave/Dr-Fun/df%04d%02d/df%04d%02d%02d.jpg', 
					$lyear, $lmonth, $lyear, $lmonth, $lday);
				img($url, $tag, $lyear, $lmonth, $lday);
			}
		}
		
		# Tom Tomorrow's This Modern World
		elsif ($tag eq 'tmw') {
#			if ($lwday != 2) {
#				print "Tuesday only!\n" unless $pick;
#			} else { # http://images.salon.com/comics/tomo/2009/04/28/tomo/story.jpg
				$url = sprintf('https://images.salon.com/comics/tomo/%04d/%02d/%02d/tomo/story.jpg', 
					$lyear, $lmonth, $lday);
#			if ($lwday != 3) {
#				print "Wednesday only!\n" unless $pick;
#			} else {
#				$url = sprintf('http://workingforchange.speedera.net/www.workingforchange.com/webgraphics/wfc/TMW%02d-%02d-%02d.jpg', 
#					$lmonth, $lday, $lyear % 100);
#				$url = sprintf('http://workingforchange.speedera.net/www.workingforchange.com/webgraphics/wfc/TMW%02d-%02d-%02d.jpg', 
#					$lmonth, $lday + 1, $lyear % 100) if (($lmonth == 12) && ($lday == 14) && ($lyear == 2005));
#				$url = sprintf('http://workingforchange.speedera.net/www.workingforchange.com/webgraphics/wfc/TMW%02d-%02d-%02d.jpg', 
#					$lmonth, $lday - 1, $lyear % 100) if (($lmonth == 8) && ($lday == 9) && ($lyear == 2006));
#				$url = sprintf('http://www.workingforchange.com/webgraphics/WFC/TMW%02d%02d%02d.jpg', 
#					$lmonth, $lday, $lyear % 100) if (($lmonth == 11) && 
#						(($lday == 22) || ($lday == 29)) && 
#						($lyear == 2006));
				img($url, $tag, $lyear, $lmonth, $lday);
#			}
		}
		
		# Slowpoke
		elsif ($tag eq 'slow') {
			$url = sprintf('https://www.workingforchange.com/webgraphics/WFC/js%02d%02d%02d.gif', $lmonth, $lday, $lyear % 100);
			$url = sprintf('https://www.workingforchange.com/webgraphics/WFC/sp%02d%02d%02d.gif', $lmonth, $lday, $lyear % 100) unless (img_chk($url));
			img($url, $tag, $lyear, $lmonth, $lday);
		}
		
		# Puni by Dan Siegler
		elsif ($tag eq 'puni') {
			if ($lwday != 3) {
				print "Wednesday only!\n" unless $pick;
			} elsif (($lyear > 2006) || (($lyear == 2006) && (($lmonth > 3) || (($lmonth == 3) && ($lday > 15))))) {
				print "Discontinued as of 2006-03-15!\n";
			} else {
				#$url = sprintf('http://sfweekly.com/comics/puni_views/strips/%04d-%02d-%02d.gif', 
				#	$lyear, $lmonth, $lday);
				$url = sprintf('https://sfweekly.com/php/comics/art/puni/%04d-%02d-%02d.jpg', 
					$lyear, $lmonth, $lday);
				img($url, $tag, $lyear, $lmonth, $lday);
			}
		}
		
		# Troubletown
		elsif ($tag eq 'trtw') {
			if ($lwday != 3) {
				print "Wednesday only!\n" unless $pick;
			} else {
				my $tt = 'https://www.troubletown.com/';
				if (open PAGE, "${wget} -q -O - '${tt}' 2>/dev/null |") {
					my $num = 0;
					while (<PAGE>) {
						if (/\/ttown([0-9]*?)\.jpg/) {
							$num = $1;
							last;
						}
					}
					close PAGE; # http://troubletown.com/uploaded_images/ttown958.jpg
					$url = $tt . sprintf('uploaded_images/ttown%03d.jpg', $num - $weekspast);
					img($url, $tag, $lyear, $lmonth, $lday);
				} else {
					print "[<a href=\"${tt}\">$titles{$tag}</a>]<br>\n";
				}
			}
		}
		
		# Clay Bennet (Chattanooga Times Free Press)
		elsif ($tag eq 'bennet') {
			$url = sprintf('https://editorialcartoonists.com/cartoons/BenneC/%04d/BenneC%04d%02d%02d_low.jpg', 
				$lyear, $lyear, $lmonth, $lday);
			my $img = sprintf("%s%04d%02d%02d.jpg",
				$tag, $lyear, $lmonth, $lday);
			my $dir = "${picdir}/${tag}";
			`mkdir -p $ENV{'DOCUMENT_ROOT'}${dir}`;
			my $found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
			unless ($found) {
				`${wget} -q -O '$ENV{'DOCUMENT_ROOT'}${dir}/${img}' '${url}' 2>/dev/null`;
				$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${img}";
				if ($found && (`grep 'Page Not Found' $ENV{'DOCUMENT_ROOT'}${dir}/${img}`)) {
					`rm $ENV{'DOCUMENT_ROOT'}${dir}/${img}`;
					$found = 0;
				}
			}
			$url = "${dir}/${img}" if $found;
			img($url, $tag, $lyear, $lmonth, $lday, $found, $found);
		}
		
		# Christian Science Monitor
		elsif ($tag eq 'csmb') {
			if (($lwday == 0) || ($lwday == 6)) {
				print "Weekdays only!\n" unless $pick;
			} else {
				$url = sprintf("https://www.csmonitor.com/%04d/%02d%02d/csmimg/cartoon.jpg", 
					$lyear, $lmonth, $lday);
				img($url, $tag, $lyear, $lmonth, $lday);
			}
		}
		
		# Michael Ramirez
		elsif ($tag eq 'latmr') {
			$url = sprintf("https://www.latimes.com/includes/ramirez/today_ramirez_%04d%02d%02d.gif", 
				$lyear, $lmonth, $lday);
			img($url, $tag, $lyear, $lmonth, $lday);
		}
		
		# Steve Bell
		elsif (($tag eq 'guksb') || ($tag eq 'gukmr')) {
			my $artist;
			if ($tag eq 'guksb') {
				$artist = 'stevebell';
			} elsif ($tag eq 'gukmr') {
				$artist = 'martinrowson';
			}
			$url = 'https://www.guardian.co.uk/';
			my $link = '';
			$found = 0;
			if (open PAGE, "${wget} -q -O - '${url}' 2>/dev/null |") {
				while (<PAGE>) {
					if (/(cartoons\/[0-9,]*?\.html)/) {
						$found = 1;
						$link = $1;
						last;
					}
				}
				close PAGE;
				print "No link to Cartoons on ${url}!<br>\n" unless ($found);
			}
			if ($found && open PAGE, "${wget} -q -O - '${url}${link}' 2>/dev/null |") {
				while (<PAGE>) {
					if (/(cartoons\/${artist}\/archive\/[0-9,]*?\.html)/) {
						$found = 1;
						$link = $1;
						last;
					}
				}
				close PAGE;
				print "No link to $titles{$tag} on ${url}!<br>\n" unless ($found);
			}
			if ($found && open PAGE, "${wget} -q -O - '${url}${link}' 2>/dev/null |") {
				$found = 0;
				my $search = sprintf('(cartoons\/' . $artist . '\/[0-9,]*?\.html)\"\>%02d\.%02d\.%02d', 
					$lday, $lmonth, $lyear % 100);
				while (<PAGE>) {
					if (/${search}/) {
						$found = 1;
						$link = $1;
						last;
					}
				}
				close PAGE;
			}
			if ($found && open PAGE, "${wget} -q -O - '${url}${link}' 2>/dev/null |") {
				#my $search = sprintf('http:\/\/image\.guardian\.co\.uk\/sys-images\/Guardian\/Pix\/pictures\/%04d\/%02d\/%02d\/.*?\.jpg', 
				#	$lyear, $lmonth, $lday);
				my $search = 'https:\/\/image\.guardian\.co\.uk\/sys-images\/Guardian\/Pix\/.*?\/\d{4}\/\d{2}\/\d{2}\/.*?\.(jpg|gif)';
				while (<PAGE>) {
					if (/(${search})/ && !/site_furniture/) {
						$found = 1;
						$url = $1;
						$link = '';
						last;
					}
				}
				close PAGE;
			}
			img("${url}${link}", $tag, $lyear, $lmonth, $lday, 1, $found);
		}
		
		# Taz Tom
		elsif ($tag eq 'tom') {
			taz($tag, 'tomnf', $lyear, $lmonth, $lday, $lwday);
		}
		
		# Taz Karikatur
		elsif ($tag eq 'taz') {
			taz($tag, 'kari', $lyear, $lmonth, $lday, $lwday);
		}
		
		# xkcd
		elsif ($tag eq 'xkcd') {
			xkcd($tag, $lyear, $lmonth, $lday);
		}
		
		elsif ($tag eq 'dlz') {
			if ($lwday != 3) {
				print "Wednesday only!\n" unless $pick;
			} elsif (($lyear > 2006) || (($lyear == 2006) && (($lmonth > 2) || (($lmonth == 2) && ($lday > 8))))) {
				print "Discontinued as of 2006-02-08!\n";
			} else {
				my ($sfbgyear, $sfbgissue) = ($lyear - 1966, $lyday / 7 + 14);
				if ($sfbgissue >= 52) {
					$sfbgyear++;
					$sfbgissue -= 52;
				}
				$url = sprintf('https://www.sfbg.com/%02d/%02d/dolezal.jpg', $sfbgyear, $sfbgissue);
				$url = sprintf('https://www.sfbg.com/%02d/%02d/dolezal.gif', $sfbgyear, $sfbgissue) unless (img_chk($url));
#print "$url<br>\n";
				img($url, $tag, $lyear, $lmonth, $lday);
			}
		}
		
		elsif ($tag eq 'tmsho') {
			if (($lyear < 2005) || (($lyear == 2005) && ($lmonth == 1) && ($lday <= 23))) {
				ucomics($tag, $lyear, $lmonth, $lday);
			} elsif (($lyear < 2008) || (($lyear == 2008) && (($lmonth < 7) || (($lmonth == 7) && ($lday <= 26))))) {
				$url = sprintf('https://www.tmsfeatures.com/tmsfeatures/servlet/com.featureserv.util.Download?file=%04d%02d%02dcssho-%s-p.jpg&code=cssho', 
					$lyear, $lmonth, $lday, ($lwday == 0) ? 's' : 'a');
				$url = sprintf('https://www.tmsfeatures.com/tmsfeatures/servlet/com.featureserv.util.Download?file=%04d%02d%02dcssho-%s-p.jpg&code=cssho', 
					$lyear, $lmonth, $lday, ($lwday == 0) ? 's' : 'x') unless (img_chk($url));
				img($url, $tag, $lyear, $lmonth, $lday);
			} elsif ($lyear < 2012) {
				$url = sprintf('https://picayune.uclick.com/comics/tmsho/%04d/tmsho%02d%02d%02d.gif', 
					$lyear, $lyear % 100, $lmonth, $lday);
				img($url, $tag, $lyear, $lmonth, $lday);
			} else {
				$url = sprintf('https://www.shoecomics.com/archives/shoe_daily/shoe_daily%02d%02d%02d.jpg', 
					$lmonth, $lday, $lyear % 100);
				img($url, $tag, $lyear, $lmonth, $lday);
			}
		}
		
		elsif ($tag eq 'maeve') {
			$url = 'http://www.madameve.co.za/';
			my $link = sprintf('archive.php?self_day=%d&self_month=%d&self_year=%d&selt_day=%d&selt_month=%d&selt_year=%d&do_search=1&search=sundae', 
				$lday, $lmonth, $lyear, $lday, $lmonth, $lyear);
			$found = 0;
			if (open PAGE, "${wget} -q -O - '${url}${link}' 2>/dev/null |") {
				while (<PAGE>) {
					while (s/(cartoons\/me\d{6}\.\w+)\'/\'/) {
						$found = 1;
						img("${url}${1}", $tag, $lyear, $lmonth, $lday, 1, $found)
					}
				}
				close PAGE;
			}
			img("${url}${link}", $tag, $lyear, $lmonth, $lday, 1, $found) unless $found;
		}
		
		elsif ($tag eq 'tav') {
			if (($lwday == 0) || ($lwday == 3)) {
				comicgenesis($tag, $lyear, $lmonth, $lday);
			} else {
				print "Sundays/Wednesdays only!<br>\n" unless $pick;
			}
		}
		
		elsif ($tag eq 'gmg') {
			garfieldminusgarfield($tag, $lyear, $lmonth, $lday);
		}
		
		elsif ($tag eq 'si') {
			if ($lwday != 3) {
				print "Wednesday only!\n" unless $pick;
			} elsif (($lyear > 2007) || (($lyear == 2007) && (($lmonth > 4) || (($lmonth == 4) && ($lday > 18))))) {
				print "Retired as of 2007-04-18!\n";
			} else {
				my $vvissue = sprintf "%02d%02d", $lyear % 100, $lyday / 7 + 1;
#print "Issue $vvissue<br>\n";
				my $name = "suttonimpact${vvissue}";
				my $dir = "${picdir}/suttonimpact";
				$found = 0;
				my $link = '';
				my $ls;
				for ($ls = 0; $ls < 100; $ls += 25) {
					$url = "https://www.villagevoice.com/home/index.php?page=columnpage&column=Sutton%20Impact&start=${ls}&total=100";
					if (open PAGE, "${wget} -q -O - '${url}' 2>/dev/null |") {
						while (<PAGE>) {
							if (/(\/news\/${vvissue},sutton,\d+,9.html)/) {
								$found = 1;
								$link = $1;
								last;
							} elsif (/(\/news\/${vvissue},cartoons,\d+,9.html)/) {
								$found = 1;
								$link = $1;
								last;
							} elsif (/(\/news\/${vvissue},suttnewo,\d+,9.html)/) {
								$found = 1;
								$link = $1;
								last;
							} elsif (/(\/people\/${vvissue},sutton,\d+,\d+.html)/) {
								$found = 1;
								$link = $1;
								last;
							}
						}
						close PAGE;
						last if $found;
					}
				}
				print "No link to Sutton Impact on ${url}!<br>\n" unless ($found);
				$url = "https://www.villagevoice.com";
				$found = 0;
				if ($link) {
					if (open PAGE, "${wget} -q -O - '${url}${link}' 2>/dev/null |") {
#print "SI: $url $link <br>\n";
						while (<PAGE>) {
#s/</&lt;/g;
#s/>/&gt;/g;
#print if (/(http:\/\/images\.villagevoice\.com\/issues\/${vvissue}\/sutton)(.*?)\"/);
#print if (/(http:\/\/images\.villagevoice\.com\/issues\/${vvissue}\/SI5_04WK1\.ElitistCLR)(.*?)\"/);
							if (
								(/(https:\/\/images\.villagevoice\.com\/issues\/${vvissue}\/\d*sutt?on)(.*?)\"/) || 
								(/(https:\/\/images\.villagevoice\.com\/issues\/\d{4}\/SI.*?CLR)(.*?)\"/)
							) {
								$found = 1;
								$pic = $1 . $2;
								`${wget} -q --referer='${url}${link}' -O '$ENV{'DOCUMENT_ROOT'}${dir}/${name}${2}' '${pic}' 2>/dev/null`;
								img("${dir}/${name}${2}", $tag, $year, $month, $day, 1, 1);
							}
						}
						close PAGE;
					}
				}
			}
		}
		
		elsif (($tag eq 'ch') && ($lyear < 1996)) {
			#$url = sprintf('http://www.transmogrifier.org/ch/comics/%02d/%02d/%02d.gif', 
			$url = sprintf('https://www.scarabaeus.org/comics/ch/%02d/%02d/%02d.gif', 
				$lyear % 100, $lmonth, $lday);
			img($url, $tag, $year, $month, $day);
		}
		
		# Zippy the Pinhead
#		elsif ($tag eq 'zp') {
#			#http://zippythepinhead.com/Merchant2/graphics/00000001/sundays/images/021013.jpg
#			#http://zippythepinhead.com/Merchant2/graphics/00000001/2013/images/021213.gif
#			if ($lwday == 0) {
#				$url = sprintf("http://zippythepinhead.com/Merchant2/graphics/00000001/sundays/images/%02d%02d%02d.jpg", 
#					$lmonth, $lday, $lyear % 100);
#			} else {
#				$url = sprintf("http://zippythepinhead.com/Merchant2/graphics/00000001/%04d/images/%02d%02d%02d.gif", 
#					$lyear, $lmonth, $lday, $lyear % 100);
#			}
#			img($url, $tag, $lyear, $lmonth, $lday);
#		}
		
		# Sunday Zippy
		elsif (($tag eq 'zp') && ($lwday == 0)) {
			my $dir = sprintf("${picdir}/$kingshort{$tag}/$kingshort{$tag}_%04d", $year);
			`mkdir -p $ENV{'DOCUMENT_ROOT'}${dir}`;
			my $name = $kingshort{$tag} . sprintf("_%04d%02d%02d.gif", $lyear, $lmonth, $lday);
			$url = sprintf("http://zippythepinhead.com/Merchant2/graphics/00000001/sundays/images/%02d%02d%02d.jpg", 
				$lmonth, $lday, $lyear % 100);
			my $found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
			unless ($found) {
				$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}";
				$dir = $picdir if $found;
			}
			unless ($found) {
				`${wget} -q -O '$ENV{'DOCUMENT_ROOT'}${dir}/${name}' '${url}' 2>/dev/null`;
				$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
			}
			img($found ? "${dir}/${name}" : $url, $tag, $lyear, $lmonth, $lday, 1, $found);
		}
		
		# UComics / King Features
		else {
			$found = 0;
			for (keys %kingshort) {
				if ($tag eq $_) {
					$found = 1;
					king($tag, $lyear, $lmonth, $lday, $lwday);
				}
			}
			if (! $found) {
				$found = ucomics($tag, $lyear, $lmonth, $lday);
				#if (! $found && ! $pick) {
				#	print("Yesterday's cartoon:<br>\n");
				#	$found = ucomics($tag, $yyear, $ymonth, $yyday);
				#}
			}
		}
	}
	
	print "<hr width=600 align=left></br>\n\n" unless $pick;
}

# offer missing comics
unless ($pick) {
	my $tit;
	foreach $tit (keys %titles) {
		my $found = 0;
		foreach $tag (@selection) {
			$found = 1 if ($tag eq $tit);
		}
		unless ($found) {
			my @addsel = @selection; push @addsel, $tit;
			my $addlink = $ENV{'SCRIPT_NAME'} . sprintf("?date=%04d%02d%02d&sort=1&selection=%s", $year, $month, $day, join '/', @addsel);
			print "<a href=\"${addlink}\"><img src=\"/img/plus.gif\" width=10 height=10 border=0 alt=\"[add]\"></a> <b>$titles{$tit}</b><br>\n";
		}
	}
}

print "<table width=600><tr><td width=200 align=left>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${yestlink}\"><img src=\"/img/left.gif\" width=10 height=10 border=0 alt=\"&lt;&lt;&lt;\"></a>\n" if $yestlink;
print "</td><td width=200 align=center>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${todaylink}\"><img src=\"/img/cross.gif\" width=10 height=10 border=0 alt=\"O\"></a>\n" if ($todaylink && $sortmode);
print "</td><td width=200 align=right>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${tomolink}\"><img src=\"/img/right.gif\" width=10 height=10 border=0 alt=\"&gt;&gt;&gt;\"></a>\n" if $tomolink;
print "</td></tr></table><br>\n\n";

#print calendar again
calendar();
print "<br>\n";

print "<a href=\"$ENV{'SCRIPT_NAME'}?selection=". (join '/', @selection) ."\">[clone]</a> configuration (use this link in a different browser to duplicate your cookie)<br>\n" unless $pick;

print "</body>\n";

