#!/usr/bin/perl -w

#
# comics.pl, a perl CGI script to collect web comics and display them on one page
# 
# Rev. 2024-11-05
# 
# Copyright 2005 Christian Wolff
# 
# Redistribution and use in source and binary forms, with or without 
# modification, are permitted provided that the following conditions 
# are met:
# 
# 1. Redistributions of source code must retain the above copyright 
# notice, this list of conditions and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright 
# notice, this list of conditions and the following disclaimer in the 
# documentation and/or other materials provided with the distribution.
# 
# 3. Neither the name of the copyright holder nor the names of its 
# contributors may be used to endorse or promote products derived 
# from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
# “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# 
# https://opensource.org/license/bsd-3-clause
# 
# The author can be reached at dev-comics<at>scara.com; 
# the project's page is at http://git.scara.com/comics/
#


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

my $wget = 'wget -t 3 -T 10';
my $wget_short = 'wget -t 1 -T 5';

# Default time zone, offset in hours to GMT (change w/ 'tz=<x>' URL parameter)
my $TZ_offs = -7;
my $tz_valid = 0;

# 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 (King)", 
	'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', 
	'sl', "Sherman's Lagoon");

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);
my %kingurl = ('zp', 'zippy-the-pinhead', 'hg', 'hagar-the-horrible', 
	'bz', 'bizarro', 'kzjm', 'katzenjammer-kids', 
	'pop', 'popeye');
#"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', 'ted-rall', 'tmmda', 'mattdavies', 
	'jd', 'jeffdanziger', 'sc', 'stuartcarlson', 'bs', 'bensargent', 
	'tmdsh', 'drewsheneman', 'lc', 'lacucaracha', 'yen', 'yenny-lopez', 
	'cwkal', 'kal', 'cwjmo', 'jimmorin', 'jp', 'joelpett', 
	'crsbe', 'stevebenson', 'bad', 'badreporter', 'biov', 'biographic', 
	'ms', 'minimumsecurity', 'myth', 'mythtickle', 'sl', 'shermanslagoon');

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)';

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

my $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;
	}
	if (/^tz=(.*)$/) {
		$TZ_offs = $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;

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'} = $_;
	}
}

if ($query{'tz'}) {
	$TZ_offs = $query{'tz'};
	$tz_valid = 1;
}

my @weekdays = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
my @months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
my @lmonths = ('January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');

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);

# 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 = 0;
if ($query{'force'}) {
	$force = 1;
}

`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";
	}
	# Cookie expiration 360 days from now
	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);
	my $domain = $ENV{'SERVER_NAME'};
	print "expires=${expire}; path=/; domain=${domain}\n";
}
if ($tz_valid) {
	print "Set-Cookie: ";
	print "tz=${TZ_offs}; ";
	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);
	my $domain = $ENV{'SERVER_NAME'};
	print "expires=${expire}; path=/; domain=${domain}\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, $lastyear, $nextyear, $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("date=%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("date=%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;
		$lastyear = sprintf("date=%04d%02d%02d", $iyear - 1, $imonth, $iday);
		$nextyear = sprintf("date=%04d%02d%02d", $iyear + 1, $imonth, $iday);
		$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 " . ($fullyear ? "year" : "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>
	<style>
		body {
			color: #000000; 
			background: #FFFFFF; 
			font-family: Helvetica, "Trebuchet MS", Verdana, Arial, sans-serif;
		}
		a:link {color: #0000EE; text-decoration: none; }
		a:visited {color: #551A8B; text-decoration: none; }
		a:hover {text-decoration: none; }
		a:active {color: #EE0000; text-decoration: none; }
		\@media (prefers-color-scheme: dark) {
			body {color: #FBFBFE; background: #1C1B22; }
			body a:link {color: #8C8CFF; }
			body a:visited {color: #FFADFF; }
			body a:active {color: #FF6666; }
		}
	</style>
</head>
<body>

${err}
END

# print "ENV{SERVER_NAME} = '". $ENV{'SERVER_NAME'} . "'<br>\n";

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 ($fullyear) {
	$lastsun = $lastyear;
	$nextsun = $nextyear;
}
if ($pick) {
	$yestlink = $lastsun if $lastsun;
	$tomolink = $nextsun if $nextsun;
	$yestlink .= "&pick=${pick}";
	$todaylink .= "&pick=${pick}";
	$tomolink .= "&pick=${pick}";
}
if ($fullyear) {
	$yestlink .= "&fullyear=1";
	$todaylink .= "&fullyear=1";
	$tomolink .= "&fullyear=1";
}
# UTF8 entities - left: &#x25C0;&#xFE0E;  cross: &#x2716;&#xFE0E;  right: &#x25B6;&#xFE0E;  
#print "<table width=600 cellspacing=0 cellpadding=0><tr><td width=200 align=left>\n";
#print "<a href=\"$ENV{SCRIPT_NAME}?${yestlink}\">&#x25C0;&#xFE0E;</a>\n" if $yestlink;
#print "</td><td width=200 align=center>\n";
#print "<a href=\"$ENV{SCRIPT_NAME}?${todaylink}\">&#x2716;&#xFE0E;</a>\n" if ($todaylink && $sortmode);
#print "</td><td width=200 align=right>\n";
#print "<a href=\"$ENV{SCRIPT_NAME}?${tomolink}\">&#x25B6;&#xFE0E;</a>\n" if $tomolink;
#print "</td></tr></table><br>\n\n";
print "<div><div align=left>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${yestlink}\">&#x25C0;&#xFE0E;</a>\n" if $yestlink;
print "</div><div align=center>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${todaylink}\">&#x2716;&#xFE0E;</a>\n" if ($todaylink && $sortmode);
print "</div><div align=right>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${tomolink}\">&#x25B6;&#xFE0E;</a>\n" if $tomolink;
print "</div><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;
	}
}

sub imgw {
	my ($url, $width, $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}\" width=\"${width}\" 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>/
# 2024-11-04: results in repeats of 11/02 strip
# Now as event click to open lightbox with complete image
#   https://comicskingdom.net/hagar-the-horrible/2024-11-05
#   https://comicskingdom.net/_next/image?url=https%3A%2F%2Fwp.comicskingdom.com%2Fcomicskingdom-redesign-uploads-production%2F2024%2F11%2FY2tIYWdhciBUaGUgSG9ycmlibGUtRU5HLTQ1MDE3MjM.jpg&w=3840&q=75
sub king {
	my ($tag, $year, $month, $day, $wday) = @_;
	if ($tag eq 'kzjm') {
		if ($wday != 0) {
			print "Sundays only!\n" unless $pick;
			return;
		}
	}
	if (($tag eq 'shrm') && (($year > 2022) || (($year == 2022) && (($month > 6) || (($month == 6) && ($day > 20)))))) {
		print "Discontinued at King Features as of 2022-06-21! Please add other Sherman's Lagoon from Go Comics (sl).<br>\n";
		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 $name = $kingshort{$tag} . sprintf("_%04d%02d%02d.jpg", $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 $url = sprintf("https://comicskingdom.net/$kingurl{$tag}/%04d-%02d-%02d",
                $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) {
		# print "Looking for KING at '${url}'<br>\n";
		if (open PAGE, "${wget} -q --referer='${referer}' -U '${useragent}' -O - '${url}' 2>/dev/null |") {
			while (<PAGE>) {
				#if (/img src='(.*)' alt/) {
				if (/\<meta property="og:image" content="(https:.*?)"\/>/) {
					# print "Found KING at '${1}'<br>\n";
					`${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 imgw($found ? "${dir}/${name}" : $archive, ((($tag eq 'bz') && ($wday != 0)) ? 360 : 900), $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, $wday) = @_;
	my $ext = 'gif';
	if (($tag eq 'tmhel') && (($year > 2005) || (($year == 2005) && (($month > 12) || (($month == 12) && ($day > 25)))))) {
		print "Discontinued as of 2005-12-25!<br>\n";
		return;
	}
	if (($tag eq 'tt') && (($year > 2020) || (($year == 2020) && (($month > 11) || (($month == 11) && ($day > 01)))))) {
		print "Discontinued as of 2020-11-01!<br>\n";
		return;
	}
	if (($tag eq 'bad') && (($year > 2020) || (($year == 2021) && ($month >= 5)))) {
		print "Discontinued as of 2021-04-30. Don Asmussen passsed away 2021-12-09 (cancer, 59).<br>\n";
		return;
	}
	if (($tag eq 'crsbe') && ($year > 2023)) {
		print "Discontinued as of 2023-12-30. Steve Benson passsed away 2025-07-08 (71).<br>\n";
		return;
	}
	if (($tag eq 'cwjmo') && (($year > 2020) || (($year == 2020) && (($month > 1) || (($month == 1) && ($day > 1)))))) {
		print "Discontinued after 2020-01-01!<br>\n";
		return;
	}
	if (($tag eq 'sl') && (($year < 2022) || (($year == 2022) && ($month < 5)))) {
		return king('shrm', $year, $month, $day, $wday);
	}
	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 (my $gtag = $ucomics_go{$tag}) {
			my $today_go = sprintf("${gtag}/%04d/%02d/%02d", $year, $month, $day);
			#my $today_match = 0;
			my $pubdate = sprintf("%s %d, %04d", $lmonths[$month - 1], $day, $year);
			$url = "https://www.gocomics.com/${today_go}";
			if (open PAGE, "${wget} -q -U '${useragent}' -O - '${url}' 2>/dev/null |") {
				while (<PAGE>) {
					# Look for the Facebook Open Graph Tag (as of 2025-03-21)
					#   <meta property="og:image" content="https://featureassets.gocomics.com/assets/9341a28001b9013e9c4c005056a9545d"/>
					#   <meta property="og:image" content="https://featureassets.amuniversal.com/assets/1e9e5730e63b013d96d1005056a9545d" />
					#   <meta property="og:image" content="https://gocomicscmsassets.gocomics.com/staging-assets/assets/GC_Social_FB_Non_Sequitur_1b37ef4309.jpg"/>
					#if (/meta property\=\"og:image"\s+content\=\"(https\:\/\/.*?)\"/) {
					#	$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;
					#}
					# Look for the JSON "@context" tag of "@type":"ImageObject" that also has /assets/ in the path
					#    ,"url":"https://featureassets.gocomics.com/assets/e1bbdf70ebb4013d9825005056a9545d",
					# {
					#	"@context":"https://schema.org",
					#	"@type":"ImageObject",
					#	"name":"Doonesbury - April 2, 2025",
					#	"description":"Dive into Doonesbury, a comic strip by creator Garry Trudeau. Learn more about Doonesbury, explore the archive, read extra content, and more! ",
					#	"url":"https://featureassets.gocomics.com/assets/c06f2200ebb4013d9825005056a9545d",
					#	"author":{"@type":"Person","name":"Garry Trudeau"},
					#	"contentUrl":"https://featureassets.gocomics.com/assets/c06f2200ebb4013d9825005056a9545d",
					#	"creator":{"@type":"Organization","name":"GoComics","url":"https://www.gocomics.com/"},
					#	"datePublished":"April 2, 2025",
					#	"representativeOfPage":true
					# }
					#if (/\,\"url\"\:\"(https\:\/\/featureassets\.gocomics\.com\/assets\/.*?)\"\,/) {
#					if (/<section class="ShowComicViewer(.*?"url":")(https:\/\/.*?)",(.*)/) {
#						my $inb = $1;
#						my $pic_url = $2;
#						my $rest = $3;
#$inb=~s/</&lt;/g;
#$inb=~s/>/&gt;/g;
#print "GoComics inbetween: '$inb'<br>\n";
#print "GoComics URL: '$url',<br>Picture: '$pic_url'<br>\n";
#						if (($inb=~/class="UpsellSectionBreak/) || ($inb=~/class="ShowFiveFavorites/)) {
#							if ($rest=~/"url":"(https:\/\/featureassets.gocomics.com\/assets\/.*?)",/) {
#								$pic_url = $1;
#$rest=~s/</&lt;/g;
#$rest=~s/>/&gt;/g;
#print "GoComics Updated Picture: '$pic_url'<br>From '$rest'<br>\n";
#							}
#						}
					if (/"url":"(https:\/\/featureassets\.gocomics\.com\/assets\/[0-9a-f]+)"[^>]*"datePublished":"${pubdate}"/) {
						my $pic_url = $1;
						$img = sprintf("%s%02d%02d%02d.${ext}",
							$tag, $year % 100, $month, $day);
						`${wget} -q --referer='${url}' -U '${useragent}' -O '$ENV{'DOCUMENT_ROOT'}${dir}/${img}' '${pic_url}' 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;
					}
					# Look for the 'data-image' tag in the comic container class <div> (as of 2019-07-14)
					#if (/data\-image\=\"(https\:\/\/.*assets\.amuniversal\.com\/.*)\"/) {
					#	$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;
					#}
					#$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
		$link = sprintf('/tomkariseite1/%04d-%02d-%02d/tom.gif', $year, $month, $day);
	}
#	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);
		# UTF8 entities - up: &#x25B2;  cross: &#x2716;&#xFE0E;  down: &#x25BC;  
		print "<a href=\"${uplink}\">&#x25B2;</a>\n";
		print "<a href=\"${sublink}\">&#x2716;&#xFE0E;</a>\n";
		print "<a href=\"${downlink}\">&#x25BC;</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;
	# UTF8 entities - plus: &#x271A;
	print "<a href=\"${pluslink}\">&#x271A;</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') {
			if (($lyear > 2023) || (($lyear == 2023) && (($lmonth > 3) || (($lmonth == 3) && ($lday > 12))))) {
				print "Cancelled as of 2023-03-13\n";
			} else {
#			my $dilbert = "https://www.dilbert.com";
#			my $dilbert = "https://dilbert.com";
			my $dilbert = "https://web.archive.org/web/submit?type=replay&url=https://dilbert.com";
			my $title ='';
#			$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
			#https://dilbert.com/strip/2022-11-14/
#			$url = sprintf("/strips/comic/%04d-%02d-%02d/", $lyear, $lmonth, $lday);
#			$url = $dilbert . sprintf("/strips/%04d-%02d-%02d/", $lyear, $lmonth, $lday);
			$url = $dilbert . sprintf("/strip/%04d-%02d-%02d/", $lyear, $lmonth, $lday);
			$found = 0;
			if (open PAGE, "${wget} -q -O - '${url}' 2>/dev/null |") {
#				$url = '';
				while (<PAGE>) {
					if (/data-title\=\"(.*?)\"/) {
						$title = $1;
					}
#					if (/\<meta property\=\"og\:title\" content\=\"(.*)\"\/\>/) {
#						$title = $1;
#					}
#					if (/\"(\/dyn\/str_strip\/.*\.strip\.print\.\w{3})\"/) {
#					if (/src=\"(http\:\/\/assets\.amuniversal\.com\/.*)\"/) {
					# data-image="https://assets.amuniversal.com/a64cd7403dda013bce11005056a9545d"
					if (/data-image\=\"(https\:\/\/assets\.amuniversal\.com\/.*)\"/) {
						$url = $1;
						$found = 1;
#						last;
					}
#					if (/content=\"(https\:\/\/assets\.amuniversal\.com\/.*)\"/) {
#						$url = $1;
#						$found = 1;
#						last;
#					}
				}
				close PAGE;
			} else {
				printf("Failed to load ${url}<br>\n");
			}
			
			print "<p>${title}</p>\n" if ($title);
#			img("${dilbert}${url}", $tag, $lyear, $lmonth, $lday, 1, $found);
			img("${url}", $tag, $lyear, $lmonth, $lday, 1, $found);
		}}
		
		# User Friendly
		elsif ($tag eq 'uf') {
			my $dir = "${picdir}/userfriendly";
			my $datename = '';
			if (($lyear > 2022) || (($lyear == 2022) && ($lmonth > 2))) { # userfriendly.org shut down as of 2022-03-01, my archive goes back to 1997-11-17
				$datename = sprintf("uf_%04d-%02d-%02d.gif", 1998 + ($lyear - 1998) % 24, $lmonth, $lday); # wrap back, starting at 1998-03-01
				$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${datename}";
			} else {
				$datename = sprintf("uf_%04d-%02d-%02d.gif", $lyear, $lmonth, $lday);
				$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${datename}";
				$url = sprintf("http://ars.userfriendly.org/cartoons/?id=%04d%02d%02d", $lyear, $lmonth, $lday);
				if (1 && (! $found) && open PAGE, "${wget_short} -q -O - '${url}' 2>/dev/null |") {
					while (<PAGE>) {
						if (/(http\:\/\/www\.userfriendly\.org\/cartoons\/archives\/\d{2}\w{3}\/)(x?u?f?n?g?\d+.*?\.gif)/) {
							my $name = $2;
							`mv -b "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}" "$ENV{'DOCUMENT_ROOT'}${dir}/${name}"` if (-s "$ENV{'DOCUMENT_ROOT'}${picdir}/${name}");
							$found = $force ? 0 : -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
							unless ($found) {
								`${wget_short} -q --referer='${url}' -O '$ENV{'DOCUMENT_ROOT'}${dir}/${name}' '${1}${2}' 2>/dev/null`;
								$found = -s "$ENV{'DOCUMENT_ROOT'}${dir}/${name}";
							}
							unless (-s "$ENV{'DOCUMENT_ROOT'}${dir}/${datename}") {
								`ln -sf "${name}" "$ENV{'DOCUMENT_ROOT'}${dir}/${datename}"` if ($found);
							}
							last;
						}
					}
					close PAGE;
				}
			}
			$url = "${dir}/${datename}" if $found;
			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') {
			if (($lwday != 1) && ($lwday != 3) && ($lwday != 5)) {
				print "Mondays, Wednesdays, Fridays only!\n" unless $pick;
			} else {
				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, $lwday);
			} 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;
			}
			unless ($found) 
			{
				my $num = 1;
				
				
				
				$link = sprintf('cartoons/me%06u.jpg', $num);
				$found = img_chk("${url}${link}");
				if (! $found) {
					$link = sprintf('cartoons/me%06u.gif', $num);
					$found = img_chk("${url}${link}");
				}
				# img("${url}${link}", $tag, $lyear, $lmonth, $lday, 1, $found);
				
				# First: 1992? 2001? 1998-06-08? http://www.madameve.co.za/cartoons/me000001.jpg
				# Dated: 2013-09-26 - http://www.madameve.co.za/cartoons/me005583.jpg
				# Last: http://www.madameve.co.za/cartoons/me006838.jpg
				# Some are .gif
				
				# Homepage:
				# <td valign="top"><!-- Today's cartoon -->
				# <img src="/cartoons/me007096.jpg"><br>Fri 13 Dec 2019

			}
			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('/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, $lwday);
				#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);
			# UTF8 entities - plus: &#x271A;
			print "<a href=\"${addlink}\">&#x271A;</a> <b>$titles{$tit}</b><br>\n";
		}
	}
}

# UTF8 entities - left: &#x25C0;&#xFE0E;  cross: &#x2716;&#xFE0E;  right: &#x25B6;&#xFE0E;  
#print "<table width=600 cellspacing=0 cellpadding=0><tr><td width=200 align=left>\n";
#print "<a href=\"$ENV{SCRIPT_NAME}?${yestlink}\">&#x25C0;&#xFE0E;</a>\n" if $yestlink;
#print "</td><td width=200 align=center>\n";
#print "<a href=\"$ENV{SCRIPT_NAME}?${todaylink}\">&#x2716;&#xFE0E;</a>\n" if ($todaylink && $sortmode);
#print "</td><td width=200 align=right>\n";
#print "<a href=\"$ENV{SCRIPT_NAME}?${tomolink}\">&#x25B6;&#xFE0E;</a>\n" if $tomolink;
#print "</td></tr></table><br>\n\n";
print "<div><div align=left>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${yestlink}\">&#x25C0;&#xFE0E;</a>\n" if $yestlink;
print "</div><div align=center>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${todaylink}\">&#x2716;&#xFE0E;</a>\n" if ($todaylink && $sortmode);
print "</div><div align=right>\n";
print "<a href=\"$ENV{SCRIPT_NAME}?${tomolink}\">&#x25B6;&#xFE0E;</a>\n" if $tomolink;
print "</div><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;

printf "<p><font size=\"-2\">Processed: %04d-%02d-%02d %02d:%02d:%02d (UTC %+d h)</font></p>\n", $cyear, $cmonth, $cday, $hour, $min, $sec, $TZ_offs;

print "</body>\n";

