[submodule "exec"]
path = exec
url = ../../../botm/exec
+[submodule "botm-common"]
+ path = botm-common
+ url = ../../../botm/common-perl
--- /dev/null
+Subproject commit 111fb5f38624401ac7f332dd8bf7fa65e7bf5b23
-#!/usr/bin/perl
-#
+###RUN_PERL: #!/usr/bin/perl
+
# /mscha/frame
-# 04.03.2020
# mscha time frame
#
-# Copyright (C) 2020 Balthasar Szczepański
+# Copyright (C) 2020, 2024 Balthasar Szczepański
#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+# 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 Affero General Public License for more details.
#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
use strict;
+use utf8;
+# use Encode::Locale ('decode_argv');
+use Encode ('encode', 'decode');
+
+###PERL_LIB: use lib /botm/lib/mscha
+use botm_common (
+ 'HTTP_STATUS',
+ 'fail_method', 'fail_content_type',
+ 'read_header_env',
+ 'url_query_decode',
+ 'merge_settings'
+);
+use mscha_lib (
+ 'redirect',
+ 'get_time_frame'
+);
-#use warnings;
-use lib '/eizm/lib/ottbackup/mscha/';
-use mscha_lib qw(failpage gethttpheader getcgi gettimeframe redirect);
+binmode STDIN, ':encoding(UTF-8)';
+binmode STDOUT, ':encoding(UTF-8)';
+binmode STDERR, ':encoding(UTF-8)';
+# decode_argv();
my $time = time();
srand ($time+$$);
my %http;
my %cgi;
-my %cgipost;
-my %frameinfo;
+my %cgi_post;
+my %frame_info;
my $method;
my $frame;
my $mode;
-# my $embed;
-my $embedUrl;
+my $embed_URL;
my $header;
my $title;
my $message;
if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
- $method=$1;
+ $method = $1;
}
else{
- exit failpage("Status: 405 Method Not Allowed\nAllow: GET, POST, HEAD\n","405 Method Not Allowed","The interface does not support the $ENV{'REQUEST_METHOD'} method.",$method);
+ exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
}
-%http = gethttpheader (\%ENV);
-%cgi = getcgi($ENV{'QUERY_STRING'});
+%http = read_header_env(\%ENV);
+%cgi = url_query_decode($ENV{'QUERY_STRING'});
if ($method eq 'POST') {
if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
- my %cgipost=getcgi( <STDIN> );
- foreach my $ind (keys %cgipost) {
- $cgi{$ind}=$cgipost{$ind};
- }
+ my %cgi_post = url_query_decode( <STDIN> );
+ %cgi = merge_settings(\%cgi, \%cgi_post);
}
# multipart not supported
else{
- exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}.");
+ exit fail_content_type($method, $http{'content-type'});
}
}
-# $embed=lc($cgi{'embed'});
-
if ($ENV{'PATH_INFO'} =~ /^\/([^\/]+)(\/(.+))?$/) {
$frame = $1;
$mode = lc($3);
$frame = '1';
$mode = '';
}
-if ($cgi{'period'} ne '') {
- $frame=$cgi{'period'};
+
+if ($cgi{'frameNo'} ne '') {
+ $frame = $cgi{'frameNo'};
}
-if ($cgi{'frame'} ne '') {
- $frame=$cgi{'frame'};
+elsif ($cgi{'frame'} ne '') {
+ $frame = $cgi{'frame'};
}
-if ($cgi{'frameNo'} ne '') {
- $frame=$cgi{'frameNo'};
+elsif ($cgi{'period'} ne '') {
+ $frame = $cgi{'period'};
}
+
if ($cgi{'mode'} ne '') {
- $mode=lc($cgi{'mode'});
+ $mode = lc($cgi{'mode'});
}
if ($mode !~ /^(orig|diff)$/) {
$mode = '';
}
-%frameinfo = gettimeframe($frame,$time);
+%frame_info = get_time_frame($frame, $time);
-if (($mode eq 'diff') && ($frameinfo{'diffUrl'} eq '')) {
+if (($mode eq 'diff') && ($frame_info{'diffUrl'} eq '')) {
$mode = '';
}
if ($mode eq 'orig') {
- $embedUrl = $frameinfo{'downloadedUrl'};
-} elsif ($mode eq 'diff') {
- $embedUrl = $frameinfo{'diffUrl'};
-} else {
- $embedUrl = ($frameinfo{'xkcdUrl'} ne '')?$frameinfo{'xkcdUrl'}:$frameinfo{'downloadedUrl'};
+ $embed_URL = $frame_info{'downloadedUrl'};
+}
+elsif ($mode eq 'diff') {
+ $embed_URL = $frame_info{'diffUrl'};
+}
+else {
+ $embed_URL = ($frame_info{'xkcdUrl'} ne '') ?
+ $frame_info{'xkcdUrl'} :
+ $frame_info{'downloadedUrl'};
}
-# if ($embedUrl !~ /^http/) {
- # $embedUrl = 'http://1190.bicyclesonthemoon.info'.$embedUrl;
-# }
-redirect($embedUrl, !!%cgi, $method);
+redirect($method, $embed_URL, HTTP_STATUS->{'see_other'});
-#!/usr/bin/perl
+###RUN_PERL: #!/usr/bin/perl
#
# /mscha/frameaftertime
-# 04.03.2020
# mscha TaT frame
#
-# Copyright (C) 2020 Balthasar Szczepański
+# Copyright (C) 2020, 2024 Balthasar Szczepański
#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+# 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 Affero General Public License for more details.
#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
use strict;
-
-#use warnings;
-use lib '/eizm/lib/ottbackup/mscha/';
-use mscha_lib qw(failpage gethttpheader getcgi gettatframe redirect);
+use utf8;
+# use Encode::Locale ('decode_argv');
+use Encode ('encode', 'decode');
+
+###PERL_LIB: use lib /botm/lib/mscha
+use botm_common (
+ 'HTTP_STATUS',
+ 'fail_method', 'fail_content_type',
+ 'read_header_env',
+ 'url_query_decode',
+ 'merge_settings'
+);
+use mscha_lib (
+ 'redirect',
+ 'get_tat_frame'
+);
+
+binmode STDIN, ':encoding(UTF-8)';
+binmode STDOUT, ':encoding(UTF-8)';
+binmode STDERR, ':encoding(UTF-8)';
+# decode_argv();
my $time = time();
srand ($time+$$);
my %http;
my %cgi;
-my %cgipost;
-my %frameinfo;
+my %cgi_post;
+my %frame_info;
my $method;
my $frame;
my $mode;
-# my $embed;
-my $embedUrl;
-# my $tatName;
+my $embed_URL;
if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
- $method=$1;
+ $method = $1;
}
else{
- exit failpage("Status: 405 Method Not Allowed\nAllow: GET, POST, HEAD\n","405 Method Not Allowed","The interface does not support the $ENV{'REQUEST_METHOD'} method.",$method);
+ exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
}
-%http = gethttpheader (\%ENV);
-%cgi = getcgi($ENV{'QUERY_STRING'});
+%http = read_header_env(\%ENV);
+%cgi = url_query_decode($ENV{'QUERY_STRING'});
if ($method eq 'POST') {
if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
- my %cgipost=getcgi( <STDIN> );
- foreach my $ind (keys %cgipost) {
- $cgi{$ind}=$cgipost{$ind};
- }
+ my %cgi_post = url_query_decode( <STDIN> );
+ %cgi = merge_settings(\%cgi, \%cgi_post);
}
# multipart not supported
else{
- exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}.");
+ exit fail_content_type($method, $http{'content-type'});
}
}
-# $embed=lc($cgi{'embed'});
-
if ($ENV{'PATH_INFO'} =~ /^\/([^\/]+)(\/(.+))?$/) {
$frame = $1;
$mode = lc($3);
$frame = '1';
$mode = '';
}
-if ($cgi{'frame'} ne '') {
- $frame=$cgi{'frame'};
-}
+
if ($cgi{'frameNo'} ne '') {
- $frame=$cgi{'frameNo'};
+ $frame = $cgi{'frameNo'};
+}
+elsif ($cgi{'frame'} ne '') {
+ $frame = $cgi{'frame'};
}
+
if ($cgi{'mode'} ne '') {
- $mode=lc($cgi{'mode'});
+ $mode = lc($cgi{'mode'});
}
if ($mode !~ /^(orig|diff)$/) {
$mode = '';
}
-%frameinfo = gettatframe($frame,$time);
+%frame_info = get_tat_frame($frame, $time);
-if (($mode eq 'diff') && ($frameinfo{'diffUrl'} eq '')) {
+if (($mode eq 'diff') && ($frame_info{'diffUrl'} eq '')) {
$mode = '';
}
-# if ($frameinfo{'match'} !~ /^(frameNo|downloadedUrl|tatUrl)$/) {
- # $frame = $frameinfo{'frameNo'};
-# }
-
-if (($mode eq '') && ($frameinfo{'match'} eq 'downloadedUrl')) {
+if (($mode eq '') && ($frame_info{'match'} eq 'downloadedUrl')) {
$mode = 'orig';
}
if ($mode eq 'orig') {
- $embedUrl = $frameinfo{'downloadedUrl'};
-} elsif ($mode eq 'diff') {
- $embedUrl = $frameinfo{'diffUrl'};
-} else {
- $embedUrl = $frameinfo{'tatUrl'};
+ $embed_URL = $frame_info{'downloadedUrl'};
+}
+elsif ($mode eq 'diff') {
+ $embed_URL = $frame_info{'diffUrl'};
+}
+else {
+ $embed_URL = $frame_info{'tatUrl'};
}
-# if ($embedUrl !~ /^http/) {
- # $embedUrl = 'http://1190.bicyclesonthemoon.info'.$embedUrl;
-# }
-redirect($embedUrl, !!%cgi, $method);
+redirect($method, $embed_URL, HTTP_STATUS->{'see_other'});
LIB=\
+botm-common/botm_common.pm\
mscha_lib.pm
DIR=\
LIB=\
+botm-common/botm_common.pm\
mscha_lib.pm
DIR=\
# Library of functions
#
-# Library of functions
-#
# Copyright (C) 2020, 2024 Balthasar Szczepański
#
# This program is free software: you can redistribute it and/or modify
@ISA = qw(Exporter);
@EXPORT = ();
@EXPORT_OK = (
- 'failpage',
- 'entityencode',
- 'gethttpheader',
- 'getcgi',
- 'urldecode',
- 'gettimeframe',
- 'urlencode'
- 'printframeselection',
- 'gettatframe',
- 'redirect'
+ 'get_time_frame', 'get_tat-frame',
+ 'print_frame_selection'
);
###PERL_LIB: use lib /botm/lib/ottbackub/mscha
+use botm_common (
+ 'http_status', 'http_header_line', 'http_header_location',
+ 'html_entity_encode_dec',
+ 'open_encoded'
+)
-use constant entitycode => {
- 'amp' => '&',
- 'gt' => '>',
- 'lt' => '<',
- 'quot' => '"',
- 'acute' => '´',
- 'cedil' => '¸',
- 'circ' => 'ˆ',
- 'macr' => '¯',
- 'middot' => '·',
- 'tilde' => '˜',
- 'uml' => '¨',
- 'Aacute' => 'Á',
- 'aacute' => 'á',
- 'Acirc' => 'Â',
- 'acirc' => 'â',
- 'AElig' => 'Æ',
- 'aelig' => 'æ',
- 'Agrave' => 'À',
- 'agrave' => 'à',
- 'Aring' => 'Å',
- 'aring' => 'å',
- 'Atilde' => 'Ã',
- 'atilde' => 'ã',
- 'Auml' => 'Ä',
- 'auml' => 'ä',
- 'Ccedil' => 'Ç',
- 'ccedil' => 'ç',
- 'Eacute' => 'É',
- 'eacute' => 'é',
- 'Ecirc' => 'Ê',
- 'ecirc' => 'ê',
- 'Egrave' => 'È',
- 'egrave' => 'è',
- 'ETH' => 'Ð',
- 'eth' => 'ð',
- 'Euml' => 'Ë',
- 'euml' => 'ë',
- 'Iacute' => 'Í',
- 'iacute' => 'í',
- 'Icirc' => 'Î',
- 'icirc' => 'î',
- 'Igrave' => 'Ì',
- 'igrave' => 'ì',
- 'Iuml' => 'Ï',
- 'iuml' => 'ï',
- 'Ntilde' => 'Ñ',
- 'ntilde' => 'ñ',
- 'Oacute' => 'Ó',
- 'oacute' => 'ó',
- 'Ocirc' => 'Ô',
- 'ocirc' => 'ô',
- 'OElig' => 'Œ',
- 'oelig' => 'œ',
- 'Ograve' => 'Ò',
- 'ograve' => 'ò',
- 'Oslash' => 'Ø',
- 'oslash' => 'ø',
- 'Otilde' => 'Õ',
- 'otilde' => 'õ',
- 'Ouml' => 'Ö',
- 'ouml' => 'ö',
- 'Scaron' => 'Š',
- 'scaron' => 'š',
- 'szlig' => 'ß',
- 'THORN' => 'Þ',
- 'thorn' => 'þ',
- 'Uacute' => 'Ú',
- 'uacute' => 'ú',
- 'Ucirc' => 'Û',
- 'ucirc' => 'û',
- 'Ugrave' => 'Ù',
- 'ugrave' => 'ù',
- 'Uuml' => 'Ü',
- 'uuml' => 'ü',
- 'Yacute' => 'Ý',
- 'yacute' => 'ý',
- 'yuml' => 'ÿ',
- 'Yuml' => 'Ÿ',
- 'cent' => '¢',
- 'curren' => '¤',
- 'euro' => '€',
- 'pound' => '£',
- 'yen' => '¥',
- 'brvbar' => '¦',
- 'bull' => '•',
- 'copy' => '©',
- 'dagger' => '†',
- 'Dagger' => '‡',
- 'frasl' => '⁄',
- 'hellip' => '…',
- 'iexcl' => '¡',
- 'image' => 'ℑ',
- 'iquest' => '¿',
- 'lrm' => '',
- 'mdash' => '—',
- 'ndash' => '–',
- 'not' => '¬',
- 'oline' => '‾',
- 'ordf' => 'ª',
- 'ordm' => 'º',
- 'para' => '¶',
- 'permil' => '‰',
- 'prime' => '′',
- 'Prime' => '″',
- 'real' => 'ℜ',
- 'reg' => '®',
- 'rlm' => '',
- 'sect' => '§',
- 'shy' => '',
- 'sup1' => '¹',
- 'trade' => '™',
- 'weierp' => '℘',
- 'bdquo' => '„',
- 'laquo' => '«',
- 'ldquo' => '“',
- 'lsaquo' => '‹',
- 'lsquo' => '‘',
- 'raquo' => '»',
- 'rdquo' => '”',
- 'rsaquo' => '›',
- 'rsquo' => '’',
- 'sbquo' => '‚',
- 'emsp' => ' ',
- 'ensp' => ' ',
- 'nbsp' => ' ',
- 'thinsp' => ' ',
- 'zwj' => '',
- 'zwnj' => '',
- 'deg' => '°',
- 'divide' => '÷',
- 'frac12' => '½',
- 'frac14' => '¼',
- 'frac34' => '¾',
- 'ge' => '≥',
- 'le' => '≤',
- 'minus' => '−',
- 'sup2' => '²',
- 'sup3' => '³',
- 'times' => '×',
- 'alefsym' => 'ℵ',
- 'and' => '∧',
- 'ang' => '∠',
- 'asymp' => '≈',
- 'cap' => '∩',
- 'cong' => '≅',
- 'cup' => '∪',
- 'empty' => '∅',
- 'equiv' => '≡',
- 'exist' => '∃',
- 'fnof' => 'ƒ',
- 'forall' => '∀',
- 'infin' => '∞',
- 'int' => '∫',
- 'isin' => '∈',
- 'lang' => '⟨',
- 'lceil' => '⌈',
- 'lfloor' => '⌊',
- 'lowast' => '∗',
- 'micro' => 'µ',
- 'nabla' => '∇',
- 'ne' => '≠',
- 'ni' => '∋',
- 'notin' => '∉',
- 'nsub' => '⊄',
- 'oplus' => '⊕',
- 'or' => '∨',
- 'otimes' => '⊗',
- 'part' => '∂',
- 'perp' => '⊥',
- 'plusmn' => '±',
- 'prod' => '∏',
- 'prop' => '∝',
- 'radic' => '√',
- 'rang' => '⟩',
- 'rceil' => '⌉',
- 'rfloor' => '⌋',
- 'sdot' => '⋅',
- 'sim' => '∼',
- 'sub' => '⊂',
- 'sube' => '⊆',
- 'sum' => '∑',
- 'sup' => '⊃',
- 'supe' => '⊇',
- 'there4' => '∴',
- 'Alpha' => 'Α',
- 'alpha' => 'α',
- 'Beta' => 'Β',
- 'beta' => 'β',
- 'Chi' => 'Χ',
- 'chi' => 'χ',
- 'Delta' => 'Δ',
- 'delta' => 'δ',
- 'Epsilon' => 'Ε',
- 'epsilon' => 'ε',
- 'Eta' => 'Η',
- 'eta' => 'η',
- 'Gamma' => 'Γ',
- 'gamma' => 'γ',
- 'Iota' => 'Ι',
- 'iota' => 'ι',
- 'Kappa' => 'Κ',
- 'kappa' => 'κ',
- 'Lambda' => 'Λ',
- 'lambda' => 'λ',
- 'Mu' => 'Μ',
- 'mu' => 'μ',
- 'Nu' => 'Ν',
- 'nu' => 'ν',
- 'Omega' => 'Ω',
- 'omega' => 'ω',
- 'Omicron' => 'Ο',
- 'omicron' => 'ο',
- 'Phi' => 'Φ',
- 'phi' => 'φ',
- 'Pi' => 'Π',
- 'pi' => 'π',
- 'piv' => 'ϖ',
- 'Psi' => 'Ψ',
- 'psi' => 'ψ',
- 'Rho' => 'Ρ',
- 'rho' => 'ρ',
- 'Sigma' => 'Σ',
- 'sigma' => 'σ',
- 'sigmaf' => 'ς',
- 'Tau' => 'Τ',
- 'tau' => 'τ',
- 'Theta' => 'Θ',
- 'theta' => 'θ',
- 'thetasym' => 'ϑ',
- 'upsih' => 'ϒ',
- 'Upsilon' => 'Υ',
- 'upsilon' => 'υ',
- 'Xi' => 'Ξ',
- 'xi' => 'ξ',
- 'Zeta' => 'Ζ',
- 'zeta' => 'ζ',
- 'crarr' => '↵',
- 'darr' => '↓',
- 'dArr' => '⇓',
- 'harr' => '↔',
- 'hArr' => '⇔',
- 'larr' => '←',
- 'lArr' => '⇐',
- 'rarr' => '→',
- 'rArr' => '⇒',
- 'uarr' => '↑',
- 'uArr' => '⇑',
- 'clubs' => '♣',
- 'diams' => '♦',
- 'hearts' => '♥',
- 'spades' => '♠',
- 'loz' => '◊',
-};
-
-use constant time_data => '/eizm/www/time/mscha/time-data';
-use constant time_data_period => '/eizm/www/time/mscha/time-data-period';
-use constant tat_data => '/eizm/www/time/mscha/tat-data';
-
-
-# Function to show an error page
-# arguments: 1 - header fields, 2 - page title, 3 - error message, 4 method
-sub failpage {
- (my $header, my $title, my $message, my $method)=@_;
- if($header ne ''){
- print $header;
- }
- if($method eq 'HEAD') {
- print "\n";
- return;
- }
- print "Content-type: text/html\n\n";
- print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
- print '<html lang="en"><head>'."\n";
- if($title ne ''){
- print '<title>'.entityencode($title).'</title>'."\n";
- }
- print '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
- print '</head><body>'."\n";
- if($title ne ''){
- print '<h1>'.entityencode($title).'</h1>'."\n";
- }
- if($message ne ''){
- print '<p>'.entityencode($message).'</p>'."\n";
- }
- print '</body></html>'."\n";
-}
-
-# HTTP redirection
-sub redirect {
- (my $url, my $temporary, my $method)=@_;
- $url =~ s/\n//g;
- my $status = $temporary?'302 Found':'301 Moved Permanently';
- my $en_url = entityencode($url);
-
- print 'Status: '.$status."\n";
- print 'Location: '.$url."\n";
- if($method eq 'HEAD') {
- print "\n";
- return;
- }
- print "Content-type: text/html\n\n";
- print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
- print '<html lang="en"><head>'."\n";
- print '<title>'.$status.'</title>'."\n";
- print '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
- print '</head><body>'."\n";
- print '<h1>'.$status.'</h1>'."\n";
- print '<p><a href="'.$en_url.'">'.$en_url.'</a></p>'."\n";
- print '</body></html>'."\n";
-}
-
-# function to encode entities, decimal,
-sub entityencode {
- (my $t, my $all) = @_;
- if ($all) {
- $t =~ s/(.)/sprintf('\&#%02hu;',ord($1))/eg;
- }
- else {
- $t =~ s/([\"=><\&])/sprintf('&#%02hu;',ord($1))/eg;
- }
- return $t;
-}
-
-# function to get values of http header fields. Returns a hash. names of header
-# fields are lowercase
-sub gethttpheader {
- (my $env) = @_;
-
- my %http;
-
- foreach my $ind (keys %$env) {
- my $name = '';
- my $value= '';
-
- if ($ind =~ /^HTTP_([A-Z0-9_]+)$/) {
- $name=$1;
- }
- elsif ($ind =~ /^(CONTENT_[A-Z0-9_]+)$/) {
- $name=$1;
- }
- else{
- next;
- }
- $name =~ s/_/-/g;
- $name = lc($name);
- if ($$env{$ind} =~ /^([\x20-\x7e]*)$/) {
- $value=$1;
- }
- else {
- next;
- }
- $http{$name}=$value;
- }
- return %http;
-}
-
-# The function to get CGI parameters from string.
-# Format is: name=url_encoded_value&name=url_encoded_value& ... &name=url_encoded_value
-sub getcgi {
- my $arg;
- my $val;
- my %cgi;
- my $i = $_[0];
- $i =~ s/[\r\n]//g;
- my @s = split('&',$i);
- foreach my $l ( @s) {
- ($arg,$val)=split('=',$l);
- $cgi{$arg}=urldecode($val);
- }
- return %cgi;
-}
-
-# Function for decoding URL-encoded text
-sub urldecode {
- my $t = $_[0];
- $t =~ s/\+/ /g;
- $t =~ s/%([a-fA-F0-9]{2})/chr(hex($1))/eg;
- return $t;
-}
-
-# Function for URL-encoding
-sub urlencode {
- (my $t, my $all) = @_;
- if ($all) {
- $t =~ s/(.)/sprintf('%%%02hX',ord($1))/eg;
- }
- else {
- $t =~ s/([^0-9A-Za-z.~\-_])/sprintf('%%%02hX',ord($1))/eg;
- }
- return $t;
-}
+###PERL_WWW_TAT_DATA_PATH: WWW_TAT_DATA_PATH = /botm/www/1190/mscha/tat-data
+###PERL_WWW_TIME_DATA_PATH: WWW_TIME_DATA_PATH = /botm/www/1190/mscha/time-data
+###PERL_WWW_TIME_DATA_PERIOD_PATH: WWW_TIME_DATA_PERIOD_PATH = /botm/www/1190/mscha/time-data-period
# Function to find a frame and get its options
-sub gettimeframe {
+sub get_time_frame {
(my $id, my $time) = @_;
- my %frameinfo;
+ my %frame_info;
my %fallback;
- my $datafile;
+ my $fh;
- my $mschaID;
- my $aubronwoodID;
+ my $mscha_ID;
+ my $aubronwood_ID;
my $geekwagonID;
my $hash;
my $timetext;
my $filename;
- my $firstline=1;
+ my $firstline = 1;
my $found = '';
my @tab;
$id = lc($id);
}
- if ($id =~ /^([0-9]+[a-z]?)$/) {
- $mschaID = $1;
+ if ($id =~ /^[0-9]+[a-z]?$/) {
+ $mscha_ID = $&;
}
- if ($id =~ /^ba([0-9]+?)$/) {
- $aubronwoodID = $1;
+ if ($id =~ /^ba([0-9]+)$/) {
+ $aubronwood_ID = $1;
}
- if ($id =~ /^gw([0-9]+?)$/) {
+ if ($id =~ /^gw([0-9]+)$/) {
$geekwagonID = $1;
}
- if ($id =~ /^([0-9a-f]+)$/) {
- $hash = $1;
+ if ($id =~ /^[0-9a-f]+$/) {
+ $hash = $&;
}
- if ($id =~ /^([0-9]{8}_[0-9]{4})$/) {
- $timetext = $1;
+ if ($id =~ /^[0-9]{8}_[0-9]{4}$/) {
+ $timetext = $&;
}
if ($id eq 'ung') {
- my @timetab=gmtime($time);
- $timetext=sprintf('2013%02d%02d_%02d%02d',$timetab[4]+1,$timetab[3],$timetab[2],$timetab[1]);
+ my @timetab = gmtime($time);
+ $timetext = sprintf(
+ '2013%02d%02d_%02d%02d',
+ $timetab[4]+1, $timetab[3], $timetab[2], $timetab[1]
+ );
}
if ($id eq 'random') {
- $aubronwoodID = int(rand(3102))+1; #aubronwood has best numbering for this purpose
+ $aubronwood_ID = int(rand(3102))+1; #aubronwood has best numbering for this purpose
}
- unless (open ($datafile, '<', time_data)) {
- return %frameinfo;
+ unless (open_encoded ($fh, '<:encoding(utf8)', WWW_TIME_DATA_PATH())) {
+ return %frame_info;
}
if ($id eq 'randomsound') {
my $soundcount = 0;
my @soundtab;
- while (defined(my $line = <$datafile>)) {
- $line =~ s/(\r)?\n$//g;
+ while (defined(my $line = <$fh>)) {
+ $line =~ s/(\r)?\n$//gs;
if ($firstline) {
$firstline = '';
- $frameinfo{'match'} = '';
+ $frame_info{'match'} = '';
next;
}
}
}
if ($soundcount > 0) {
- $mschaID = $soundtab[int(rand($soundcount))];
+ $mscha_ID = $soundtab[int(rand($soundcount))];
} else {
- $mschaID = '1';
+ $mscha_ID = '1';
}
- seek($datafile, 0, 0);
+ seek($fh, 0, 0);
$firstline=1;
}
- while (defined(my $line = <$datafile>)) {
+ while (defined(my $line = <$fh>)) {
$line =~ s/(\r)?\n$//g;
if ($firstline) {
$firstline = '';
- $frameinfo{'match'} = '';
+ $frame_info{'match'} = '';
next;
}
@tab = split (/\t/, $line);
if ($found) {
- $frameinfo{'next'} = $tab[0];
+ $frame_info{'next'} = $tab[0];
last;
}
if ($timetext ne '') {
- if ($frameinfo{'match'} ne 'dateTime') {
- $frameinfo{'match'} = 'dateTime';
+ if ($frame_info{'match'} ne 'dateTime') {
+ $frame_info{'match'} = 'dateTime';
} else {
my $toolate = '';
my $LYear = int(substr($tab[2], 0,4));
}
if ($toolate) {
- $found=1;
+ $found = 1;
next;
}
}
}
- $frameinfo{'prev'} = $frameinfo{'frameNo'};
- $frameinfo{'frameNo'} = $tab[0];
- $frameinfo{'apocryphal'} = $tab[1];
- $frameinfo{'dateTime'} = $tab[2];
- $frameinfo{'epoch'} = $tab[3];
- $frameinfo{'hash'} = $tab[4];
- $frameinfo{'downloadedUrl'} = $tab[5];
- $frameinfo{'xkcdUrl'} = $tab[6];
- $frameinfo{'diffUrl'} = $tab[7];
- $frameinfo{'gwFrameNo'} = $tab[8];
- $frameinfo{'baFrameNo'} = $tab[9];
- $frameinfo{'botmEnhance'} = $tab[10];
- $frameinfo{'alt'} = $tab[11];
- $frameinfo{'soundUrl'} = $tab[12];
+ $frame_info{'prev' } = $frame_info{'frameNo'};
+ $frame_info{'frameNo' } = $tab[0];
+ $frame_info{'apocryphal' } = $tab[1];
+ $frame_info{'dateTime' } = $tab[2];
+ $frame_info{'epoch' } = $tab[3];
+ $frame_info{'hash' } = $tab[4];
+ $frame_info{'downloadedUrl'} = $tab[5];
+ $frame_info{'xkcdUrl' } = $tab[6];
+ $frame_info{'diffUrl' } = $tab[7];
+ $frame_info{'gwFrameNo' } = $tab[8];
+ $frame_info{'baFrameNo' } = $tab[9];
+ $frame_info{'botmEnhance' } = $tab[10];
+ $frame_info{'alt' } = $tab[11];
+ $frame_info{'soundUrl' } = $tab[12];
- if($fallback{'match'} eq ''){
- %fallback = %frameinfo;
- $fallback{'match'}='fallback';
- } elsif ($fallback{'next'} eq ''){
- $fallback{'next'} = $frameinfo{'frameNo'};
+ if ($fallback{'match'} eq '') {
+ %fallback = %frame_info;
+ $fallback{'match'} = 'fallback';
+ } elsif ($fallback{'next'} eq '') {
+ $fallback{'next'} = $frame_info{'frameNo'};
}
- if ($mschaID ne '') {
- if ($mschaID eq lc($frameinfo{'frameNo'})) {
- $frameinfo{'match'}='frameNo';
- $found=1;
+ if ($mscha_ID ne '') {
+ if ($mscha_ID eq lc($frame_info{'frameNo'})) {
+ $frame_info{'match'} = 'frameNo';
+ $found = 1;
next;
}
}
- if ($aubronwoodID ne '') {
- if ($aubronwoodID eq $frameinfo{'baFrameNo'}) {
+ if ($aubronwood_ID ne '') {
+ if ($aubronwood_ID eq $frame_info{'baFrameNo'}) {
if($id eq 'random') {
- $frameinfo{'match'}='random';
+ $frame_info{'match'} ='random';
} else {
- $frameinfo{'match'}='baFrameNo';
+ $frame_info{'match'} ='baFrameNo';
}
- $found=1;
+ $found = 1;
next;
}
}
if ($geekwagonID ne '') {
- if ($geekwagonID eq $frameinfo{'gwFrameNo'}) {
- $frameinfo{'match'}='gwFrameNo';
- $found=1;
+ if ($geekwagonID eq $frame_info{'gwFrameNo'}) {
+ $frame_info{'match'} = 'gwFrameNo';
+ $found = 1;
next;
}
}
if ($hash ne '') {
- if ($hash eq lc($frameinfo{'hash'})) {
- $frameinfo{'match'}='hash';
- $found=1;
+ if ($hash eq lc($frame_info{'hash'})) {
+ $frame_info{'match'} ='hash';
+ $found = 1;
next;
}
}
- if ($frameinfo{'downloadedUrl'} =~ /\/([^\/\.]+)\./) {
+ if ($frame_info{'downloadedUrl'} =~ /\/([^\/\.]+)\./) {
$filename = lc($1);
if ($id eq $filename) {
- $frameinfo{'match'}='downloadedUrl';
- $found=1;
+ $frame_info{'match'} = 'downloadedUrl';
+ $found = 1;
next;
}
}
}
- close ($datafile);
+ close ($fh);
- if ($frameinfo{'match'} ne '') {
- return %frameinfo;
+ if ($frame_info{'match'} ne '') {
+ return %frame_info;
} else {
return %fallback;
}
}
# Function to find a TaT frame and get its options
-sub gettatframe {
+sub get_tat_frame {
(my $id) = @_;
- my %frameinfo;
+ my %frame_info;
my %fallback;
- my $datafile;
+ my $fh;
- my $mschaID;
+ my $mscha_ID;
my $randomID;
my $hash;
my $timetext;
$id = lc($id);
}
- if ($id =~ /^([0-9]+([a-z]|½)?)$/) {
- $mschaID = $1;
+ if ($id =~ /^[0-9]+([a-z]|½)?$/) {
+ $mscha_ID = $&;
}
- if ($hash =~ /^([0-9a-zA-Z\-\+]+)$/) {
- $hash = $1;
+ if ($hash =~ /^[0-9a-zA-Z\-\+]+$/) {
+ $hash = $&;
} else {
$hash = '';
}
- if ($id =~ /^([0-9]{8}_[0-9]{4})$/) {
- $timetext = $1;
+ if ($id =~ /^[0-9]{8}_[0-9]{4}$/) {
+ $timetext = $&;
}
if ($id eq 'random') {
$randomID = int(rand(2561));
}
- unless (open ($datafile, '<', tat_data)) {
- return %frameinfo;
+ unless (open_encoded ($fh, '<:encoding(utf8)', WWW_TAT_DATA_PATH())) {
+ return %frame_info;
}
- while (defined(my $line = <$datafile>)) {
+ while (defined(my $line = <$fh>)) {
$line =~ s/(\r)?\n$//g;
if ($firstline) {
$firstline = '';
- $frameinfo{'match'} = '';
+ $frame_info{'match'} = '';
next;
}
@tab = split (/\t/, $line);
if ($found) {
- $frameinfo{'next'} = $tab[0];
+ $frame_info{'next'} = $tab[0];
last;
}
if ($timetext ne '') {
- if ($frameinfo{'match'} ne 'dateTime') {
- $frameinfo{'match'} = 'dateTime';
+ if ($frame_info{'match'} ne 'dateTime') {
+ $frame_info{'match'} = 'dateTime';
} else {
my $toolate = '';
my $LYear = int(substr($tab[1], 0,4));
}
if ($toolate) {
- $found=1;
+ $found = 1;
next;
}
}
}
- $frameinfo{'prev'} = $frameinfo{'frameNo'};
- $frameinfo{'frameNo'} = $tab[0];
- $frameinfo{'dateTime'} = $tab[1];
- $frameinfo{'epoch'} = $tab[2];
- $frameinfo{'downloadedUrl'} = $tab[3];
- $frameinfo{'tatUrl'} = $tab[4];
- $frameinfo{'diffUrl'} = $tab[5];
- $frameinfo{'origName'} = $tab[6];
- $frameinfo{'botmName'} = $tab[7];
- $frameinfo{'botmFrameNo'} = $tab[8];
- $frameinfo{'botmEnhance'} = $tab[9];
- $frameinfo{'random'} = $tab[10];
- $frameinfo{'alt'} = $tab[11];
+ $frame_info{'prev' } = $frame_info{'frameNo'};
+ $frame_info{'frameNo' } = $tab[0];
+ $frame_info{'dateTime' } = $tab[1];
+ $frame_info{'epoch' } = $tab[2];
+ $frame_info{'downloadedUrl'} = $tab[3];
+ $frame_info{'tatUrl' } = $tab[4];
+ $frame_info{'diffUrl' } = $tab[5];
+ $frame_info{'origName ' } = $tab[6];
+ $frame_info{'botmName' } = $tab[7];
+ $frame_info{'botmFrameNo' } = $tab[8];
+ $frame_info{'botmEnhance' } = $tab[9];
+ $frame_info{'random' } = $tab[10];
+ $frame_info{'alt' } = $tab[11];
- if($fallback{'match'} eq ''){
- %fallback = %frameinfo;
- $fallback{'match'}='fallback';
- } elsif ($fallback{'next'} eq ''){
- $fallback{'next'} = $frameinfo{'frameNo'};
+ if ($fallback{'match'} eq '') {
+ %fallback = %frame_info;
+ $fallback{'match'} ='fallback';
+ } elsif ($fallback{'next'} eq '') {
+ $fallback{'next'} = $frame_info{'frameNo'};
}
- if ($mschaID ne '') {
- if ($mschaID eq lc($frameinfo{'frameNo'})) {
- $frameinfo{'match'}='frameNo';
- $found=1;
+ if ($mscha_ID ne '') {
+ if ($mscha_ID eq lc($frame_info{'frameNo'})) {
+ $frame_info{'match'} = 'frameNo';
+ $found = 1;
next;
}
}
if ($randomID ne '') {
- if ($randomID eq lc($frameinfo{'random'})) {
- $frameinfo{'match'}='random';
- $found=1;
+ if ($randomID eq lc($frame_info{'random'})) {
+ $frame_info{'match'} = 'random';
+ $found = 1;
next;
}
}
- if ($frameinfo{'origName'} =~ /^([^\.]*)\./) {
+ if ($frame_info{'origName'} =~ /^([^\.]*)\./) {
$filename = $1;
if ($hash eq $filename) {
- $frameinfo{'match'}='origName';
- $found=1;
+ $frame_info{'match'} = 'origName';
+ $found = 1;
next;
}
}
- if ($frameinfo{'downloadedUrl'} =~ /\/([^\/\.]+)\./) {
+ if ($frame_info{'downloadedUrl'} =~ /\/([^\/\.]+)\./) {
$filename = lc($1);
if ($id eq $filename) {
- $frameinfo{'match'}='downloadedUrl';
- $found=1;
+ $frame_info{'match'} = 'downloadedUrl';
+ $found = 1;
next;
}
}
- if ($frameinfo{'tatUrl'} =~ /\/([^\/\.]+)\./) {
+ if ($frame_info{'tatUrl'} =~ /\/([^\/\.]+)\./) {
$filename = lc($1);
if ($id eq $filename) {
- $frameinfo{'match'}='tatUrl';
- $found=1;
+ $frame_info{'match'} = 'tatUrl';
+ $found = 1;
next;
}
}
}
- close ($datafile);
+ close ($fh);
- if ($frameinfo{'match'} ne '') {
- return %frameinfo;
+ if ($frame_info{'match'} ne '') {
+ return %frame_info;
} else {
return %fallback;
}
}
-sub printframeselection {
+sub print_frame_selection {
(my $id) = @_;
- my $datafile;
- my $firstline=1;
+ my $fh;
+ my $firstline = 1;
my @tab;
- my $class='';
- my $value='';
- my $name='';
- my $found='';
+ my $class = '';
+ my $value = '';
+ my $name = '';
+ my $_class;
+ my $_value;
+ my $_name;
+ my $found = '';
$id = int($id);
- unless (open ($datafile, '<', time_data_period)) {
+ unless (open_encoded ($fh, '<:encoding(uft8)', WWW_TIME_DATA_PERIOD_PATH)) {
return;
}
- while (defined(my $line = <$datafile>)) {
+ while (defined(my $line = <$fh>)) {
$line =~ s/(\r)?\n$//g;
if ($firstline) {
$firstline = '';
@tab = split (/\t/, $line);
if ($value ne '') {
- print '<option class="'.entityencode($class).'"';
+ print '<option class="'.$_class.'"';
if (!$found && (int($tab[1]) > $id)) {
$found = 1;
print ' selected';
}
- print ' value="'.entityencode($value).'">'.entityencode($name).'</option>';
+ print ' value="'.$_value.'">'.$_name.'</option>';
}
$class = $tab[0];
$value = $tab[1];
$name = $tab[2];
+ $_class = html_entity_encode_dec($class);
+ $_value = html_entity_encode_dec($value);
+ $_name = html_entity_encode_dec($name);
}
- close ($datafile);
+ close ($fh);
if ($value ne '') {
- print '<option class="'.entityencode($class);
+ print '<option class="'.$_class;
if (!$found) {
print ' selected';
}
- print ' value="'.entityencode($value).'">'.entityencode($name).'</option>';
+ print ' value="'.$_value.'">'.$_name.'</option>';
}
}
logs_uncompressed: 2
logs_total: 10
oldlogs_schedule: #0 3 * * *
+
+scheme : http
+website : 1190.bicyclesonthemoon.info
+
+tat_viewer : /aftertime/viewer
+aubronwood : http://xkcd.aubronwood.com
+geekwagon : http://geekwagon.net/projects/xkcd1190
+
_cgi_view_path = @_PATH($cgi_path, viewer )
_cgi_view_2_path = @_PATH($cgi_path, view.fcgi )
+_www_path = @_PATH($www_path, )
+_www_tat_data_data_path = @_PATH($www_path, tat_data )
+_www_time_data_path = @_PATH($www_path, time_data )
+_www_time_data_period_path = @_PATH($www_path, time_data_period)
+
_conf_path = @_PATH($conf_path, $name\.conf)
_lib_path = @_PATH($lib_path,)
_log_path = @_PATH($log_path,)
-_www_path = @_PATH($www_path,)
CONF_BIN = $_bin_path
PERL_EXPORT_VERSION = @_PERL_OUR_STR( VERSION, $_version)
-# PERL_PATH_SEPARATOR = @_PERL_CONSTANT_STR( PATH_SEPARATOR, $_PATH_SEPARATOR)
\ No newline at end of file
+# PERL_PATH_SEPARATOR = @_PERL_CONSTANT_STR( PATH_SEPARATOR, $_PATH_SEPARATOR)
+
+PERL_WWW_TAT_DATA_PATH = @_PERL_CONSTANT_STR( WWW_TAT_DATA_PATH, $_www_tat_data_path )
+PERL_WWW_TIME_DATA_PATH = @_PERL_CONSTANT_STR( WWW_TIME_DATA_PATH, $_www_time_data_path )
+PERL_WWW_TIME_DATA_PERIOD_PATH = @_PERL_CONSTANT_STR( WWW_TIME_DATA_PERIOD_PATH, $_www_time_data_period_path)
+
+PERL_SCHEME = @_PERL_CONSTANT_STR( SCHEME , $scheme )
+PERL_WEBSITE = @_PERL_CONSTANT_STR( WEBSITE, $website)
-#!/usr/bin/perl
+###RUN_PERL: #!/usr/bin/perl
#
# /mscha/viewer
-# 07.04.2021
# mscha time viewer
#
-# Copyright (C) 2020-2021 Balthasar Szczepański
+# Copyright (C) 2020, 2021, 2024 Balthasar Szczepański
#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+# 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 Affero General Public License for more details.
#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
use strict;
+use utf8;
+# use Encode::Locale ('decode_argv');
+use Encode ('encode', 'decode');
-#use warnings;
-use lib '/eizm/lib/ottbackup/mscha/';
-use mscha_lib qw(failpage gethttpheader getcgi gettimeframe urlencode entityencode printframeselection);
+###PERL_LIB: use lib /botm/lib/mscha
+use botm_common (
+ 'HTTP_STATUS',
+ 'fail_method', 'fail_content_type',
+ 'read_header_env',
+ 'url_encode',
+ 'url_query_decode',
+ 'http_entity_encode_dec',
+ 'merge_settings',
+ 'merge_url'
+);
+use mscha_lib (
+ 'redirect',
+ 'get_time_frame',
+ 'print_frame_selection'
+);
+
+###PERL_SCHEME: SCHEME = http
+###PERL_WEBSITE: WEBSITE = 1190.bicyclesonthemoon.info
+
+binmode STDIN, ':encoding(UTF-8)';
+binmode STDOUT, ':encoding(UTF-8)';
+binmode STDERR, ':encoding(UTF-8)';
+# decode_argv();
my $time = time();
srand ($time+$$);
my %http;
my %cgi;
-my %cgipost;
-my %frameinfo;
+my %cgi_post;
+my %frame_info;
my $method;
my $frame;
my $mode;
my $embed;
-my $embedUrl;
if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
- $method=$1;
+ $method = $1;
}
else{
- exit failpage("Status: 405 Method Not Allowed\nAllow: GET, POST, HEAD\n","405 Method Not Allowed","The interface does not support the $ENV{'REQUEST_METHOD'} method.",$method);
+ exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
}
-%http = gethttpheader (\%ENV);
-%cgi = getcgi($ENV{'QUERY_STRING'});
+%http = read_header_env(\%ENV);
+%cgi = url_query_decode($ENV{'QUERY_STRING'});
if ($method eq 'POST') {
if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
- my %cgipost=getcgi( <STDIN> );
- foreach my $ind (keys %cgipost) {
- $cgi{$ind}=$cgipost{$ind};
- }
+ my %cgi_post = url_query_decode( <STDIN> );
+ %cgi = merge_settings(\%cgi, \%cgi_post);
}
# multipart not supported
else{
- exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}.");
+ exit fail_content_type($method, $http{'content-type'});
}
}
-$embed=lc($cgi{'embed'});
+$embed = lc($cgi{'embed'});
if ($ENV{'PATH_INFO'} =~ /^\/([^\/]+)(\/(.+))?$/) {
$frame = $1;
$frame = '1';
$mode = '';
}
-if ($cgi{'period'} ne '') {
- $frame=$cgi{'period'};
+
+if ($cgi{'frameNo'} ne '') {
+ $frame = $cgi{'frameNo'};
}
-if ($cgi{'frame'} ne '') {
- $frame=$cgi{'frame'};
+elsif ($cgi{'frame'} ne '') {
+ $frame = $cgi{'frame'};
}
-if ($cgi{'frameNo'} ne '') {
- $frame=$cgi{'frameNo'};
+elsif ($cgi{'period'} ne '') {
+ $frame = $cgi{'period'};
}
+
if ($cgi{'mode'} ne '') {
$mode=lc($cgi{'mode'});
}
$mode = '';
}
-%frameinfo = gettimeframe($frame,$time);
+%frame_info = get_time_frame($frame, $time);
-if (($mode eq 'diff') && ($frameinfo{'diffUrl'} eq '')) {
+if (($mode eq 'diff') && ($frame_info{'diffUrl'} eq '')) {
$mode = '';
}
+my $website_full_url = merge_url(
+ {
+ 'scheme' => SCHEME(),
+ 'host' => WEBSITE()
+ }
+);
+my $embedUrl;
+
if ($mode eq 'orig') {
- $embedUrl = $frameinfo{'downloadedUrl'};
-} elsif ($mode eq 'diff') {
- $embedUrl = $frameinfo{'diffUrl'};
-} else {
- $embedUrl = ($frameinfo{'xkcdUrl'} ne '')?$frameinfo{'xkcdUrl'}:$frameinfo{'downloadedUrl'};
+ $embedUrl = $frame_info{'downloadedUrl'};
+}
+elsif ($mode eq 'diff') {
+ $embedUrl = $frame_info{'diffUrl'};
+}
+else {
+ $embedUrl = ($frame_info{'xkcdUrl'} ne '')?$frame_info{'xkcdUrl'}:$frame_info{'downloadedUrl'};
}
if ($embedUrl !~ /^http/) {
- $embedUrl = 'http://1190.bicyclesonthemoon.info'.$embedUrl;
-}
-
-if ($frameinfo{'match'} !~ /^(frameNo|gwFrameNo|baFrameNo)$/) {
- $frame = $frameinfo{'frameNo'};
-}
-
-my $url_frame = urlencode($frame);
-my $url_amp_mode = ($mode ne '')?('&mode='.urlencode($mode)):'';
-my $url_botmEnhance = urlencode($frameinfo{'botmEnhance'});
-my $url_frameNo = urlencode($frameinfo{'FrameNo'});
-my $url_gwFrameNo = urlencode($frameinfo{'gwFrameNo'});
-my $url_baFrameNo = urlencode($frameinfo{'baFrameNo'});
-
-my $en_frame = entityencode($frame);
-my $en_mode = entityencode($mode);
-my $en_frameNo = entityencode($frameinfo{'frameNo'});
-my $en_gwFrameNo = entityencode($frameinfo{'gwFrameNo'});
-my $en_baFrameNo = entityencode($frameinfo{'baFrameNo'});
-my $en_next = entityencode($frameinfo{'next'});
-my $en_prev = entityencode($frameinfo{'prev'});
-my $en_diffUrl = entityencode($frameinfo{'diffUrl'});
-my $en_xkcdUrl = entityencode($frameinfo{'xkcdUrl'});
-my $en_downloadedUrl = entityencode($frameinfo{'downloadedUrl'});
-my $en_soundUrl = entityencode($frameinfo{'soundUrl'});
+ $embedUrl = merge_url(
+ $website_full_url,
+ {'path' => $embedUrl}
+ );
+}
+
+if ($frame_info{'match'} !~ /^(frameNo|gwFrameNo|baFrameNo)$/) {
+ $frame = $frame_info{'frameNo'};
+}
+
+my %base_url_query = (
+ 'frame' => $frame,
+ 'uri' => CGI_VIEW_PATH()
+);
+my $viewer_first_url = merge_url(
+ {'path' => CGI_VIEW_PATH()},
+ {'path' => '1'}
+);
+my $viewer_prev_url = ($frame_info{'prev'} ne '') ?
+ merge_url(
+ {'path' => CGI_VIEW_PATH()},
+ {'path' => $frame_info{'prev'}}
+ );
+my $viewer_next_url = ($frame_info{'prev'} ne '') ?
+ merge_url(
+ {'path' => CGI_VIEW_PATH()},
+ {'path' => $frame_info{'prev'}}
+ );
+my $viewer_last_url = merge_url(
+ {'path' => CGI_VIEW_PATH()},
+ {'path' => '3094'}
+);
+my $viewer_random_url = merge_url(
+ {'path' => CGI_VIEW_PATH()},
+ {'path' => 'random'}
+);
+my $viewer_rsound_url = merge_url(
+ {'path' => CGI_VIEW_PATH()},
+ {'path' => 'randomsound'}
+);
+if ($mode ne '') {
+ $base_url_query{'mode'} = $mode;
+ $viewer_first_url = merge_url(
+ {'path' => $viewer_first_url},
+ {'path' => $mode}
+ );
+ if ($viewer_prev_url ne '') {
+ $viewer_prev_url = merge_url(
+ {'path' => $viewer_prev_url},
+ {'path' => $mode}
+ );
+ }
+ if ($viewer_next_url ne '') {
+ $viewer_next_url = merge_url(
+ {'path' => $viewer_next_url},
+ {'path' => $mode}
+ );
+ }
+ $viewer_last_url = merge_url(
+ {'path' => $viewer_last_url},
+ {'path' => $mode}
+ );
+}
+my $base_url = merge_url(
+ {
+ 'path' => CGI_VIEW_2_PATH(),
+ 'query' => \%base_url_query
+ }
+);
+
+my $viewer_xkcd_url = merge_url(
+ {'path' => CGI_VIEW_PATH()},
+ {'path' => $frame_info{'frameNo'}}
+);
+my $viewer_orig_url = merge_url(
+ {'path' => $viewer_xkcd_url},
+ {'path' => 'orig'}
+);
+my $viewer_diff_url = merge_url(
+ {'path' => $viewer_xkcd_url},
+ {'path' => 'diff'}
+);
+my $geekwagon_url = ($frame_info{'gwFrameNo'} ne '') ?
+ merge_url(
+ GEEKWAGON_URL(),
+ {'query' => {'frame' => $frame_info{'gwFrameNo'}}}
+ ) : '';
+my $aubronwood_url = ($frame_info{'baFrameNo'} ne '') ?
+ merge_url(
+ AUBRONWOOD_URL(),
+ {'query' => {
+ 'i' => $frame_info{'baFrameNo'},
+ 'playing' => '0'
+ }}
+ ) : '';
+my $moon_url = merge_url(
+ TAT_VIEWER_URL(),
+ {'query' => {
+ 'story' => 'time',
+ 'f' => $frame_info{'frameNo'}
+ }}
+);
+my $moon_enhance_url = ($frame_info{'botmEnhance'} ne '') ?
+ merge_url(
+ $moon_url,
+ {
+ 'query' => {'e' => $frame_info{'botmEnhance'}},
+ 'append_query' => 1
+ }
+ ) : '';
+my $frame_url =
+ ($mode eq 'diff') ?
+ $frame_info{'diffUrl'} : (
+ (($mode ne 'orig') && ($frame_info{'xkcdUrl'} ne '')) ?
+ $frame_info{'xkcdUrl'} :
+ $frame_info{'downloadedUrl'}
+ );
+my $jumpUrl = merge_url(
+ {'path' => CGI_VIEW_PATH()},
+ {'path' => '_FRAMENO_'}
+);
+if ($mode ne '') {
+ $jumpUrl = merge_url(
+ {'path' => $jumpUrl},
+ {'path' => $mode}
+ );
+}
+
+
+my $title2 =
+ (($frame_info{'match'} eq 'baFrameNo') ? (' (Book of Aubron: '.$frame_info{'baFrameNo'}.')') : '').
+ (($frame_info{'match'} eq 'gwFrameNo') ? (' (Geekwagon: '.$frame_info{'gwFrameNo'}.')'):'');
+my $title = 'xkcd Timeframe '.$frame_info{'frameNo'}.$title2
+
+my $_website_full_url = html_entity_encode_dec($website_full_url);
+my $_base_url = html_entity_encode_dec($base_url);
+my $_viewer_first_url = html_entity_encode_dec($viewer_first_url);
+my $_viewer_next_url = html_entity_encode_dec($viewer_next_url);
+my $_viewer_last_url = html_entity_encode_dec($viewer_last_url);
+my $_viewer_random_url= html_entity_encode_dec($viewer_random_url);
+my $_viewer_rsound_url= html_entity_encode_dec($viewer_rsound_url);
+my $_viewer_xkcd_url = html_entity_encode_dec($viewer_xkcd_url);
+my $_viewer_orig_url = html_entity_encode_dec($viewer_orig_url);
+my $_viewer_diff_url = html_entity_encode_dec($viewer_diff_url);
+my $_geekwagon_url = html_entity_encode_dec($geekwagon_url);
+my $_aubronwood_url = html_entity_encode_dec($aubronwood_url);
+my $_moon_url = html_entity_encode_dec($moon_url);
+my $_moon_enhance_url = html_entity_encode_dec($moon_enhance_url);
+my $_frame_url = html_entity_encode_dec($frame_url);
+my $_css_url = html_ebtity_encode_dec(CGI_CSS_PATH()); #/mscha/view1.css
+my $_logo_url = html_ebtity_encode_dec(CGI_LOGO_PATH()); #/mscha/botmlogo2.spng
+my $_icon_url = html_ebtity_encode_dec(CGI_ICON_PATH()); #/mscha/cuegan32.png
+my $_jquery_url = html_ebtity_encode_dec(CGI_JQUERY_PATH()); #/mscha/js/1.11.0.jquery.min.js
+my $_jquery_ui_url = html_ebtity_encode_dec(CGI_JQUERY_UI_PATH()); #/mscha/js/1.10.4.jquery-ui.min.js
+my $_jquery_cook_url = html_ebtity_encode_dec(CGI_JQUERY_COOK_PATH()); #/mscha/js/jquery.cookie.js
+my $_js_url = html_ebtity_encode_dec(CGI_VIEW_JS_PATH()); #/mscha/js/jquery.cookie.js
+my $_title = html_ebtity_encode_dec($title);
+my $_title2 = html_ebtity_encode_dec($title2);
+my $_website = html_ebtity_encode_dec($WEBSITE());
+my $_jumpUrl = html_ebtity_encode_dec($jumpUrl);
+my $_frameNo = html_entity_encode_dec($frame_info{'frameNo'});
+my $_alt = html_entity_encode_dec($frame_info{'alt'});
+my $_next = html_entity_encode_dec($frame_info{'next'});
+my $_prev = html_entity_encode_dec($frame_info{'prev'});
+
+#my $_baFrameNo = html_entity_encode_dec($frame_info{'baFrameNo'});
+#my $_gwFrameNo = html_entity_encode_dec($frame_info{'gwFrameNo'});
+
+
+my $url_frame = url_encode($frame);
+my $url_amp_mode = ($mode ne '')?('&mode='.url_encode($mode)):'';
+my $url_botmEnhance = url_encode($frame_info{'botmEnhance'});
+my $url_frameNo = url_encode($frame_info{'FrameNo'});
+my $url_gwFrameNo = url_encode($frame_info{'gwFrameNo'});
+my $url_baFrameNo = url_encode($frame_info{'baFrameNo'});
+
+my $en_frame = html_entity_encode_dec($frame);
+my $en_mode = html_entity_encode_dec($mode);
+
+
+my $en_diffUrl = html_entity_encode_dec($frame_info{'diffUrl'});
+my $en_xkcdUrl = html_entity_encode_dec($frame_info{'xkcdUrl'});
+my $en_downloadedUrl = html_entity_encode_dec($frame_info{'downloadedUrl'});
+my $en_soundUrl = html_entity_encode_dec($frame_info{'soundUrl'});
my $en_embedUrl = $embedUrl;
-my $en_alt = entityencode($frameinfo{'alt'});
-my $en_sl_mode = ($mode ne '')?('/'.entityencode($mode)):'';
-my $en_dateTime = entityencode(substr($frameinfo{'dateTime'},0,4).'-'.substr($frameinfo{'dateTime'},5,2).'-'.substr($frameinfo{'dateTime'},8,2).' '.substr($frameinfo{'dateTime'},11,2).':'.substr($frameinfo{'dateTime'},14,2));
-my $en_epoch = entityencode($frameinfo{'epoch'});
-my $en_hash = entityencode($frameinfo{'hash'});
+
+my $en_sl_mode = ($mode ne '')?('/'.html_entity_encode_dec($mode)):'';
+my $en_dateTime = html_entity_encode_dec(
+ substr($frame_info{'dateTime'}, 0, 4).'-'.
+ substr($frame_info{'dateTime'}, 5, 2).'-'.
+ substr($frame_info{'dateTime'}, 8, 2).' '.
+ substr($frame_info{'dateTime'},11, 2).':'.
+ substr($frame_info{'dateTime'},14, 2)
+);
+my $en_epoch = html_entity_encode_dec($frame_info{'epoch'});
+my $en_hash = html_entity_encode_dec($frame_info{'hash'});
print "Content-type: text/html\n";
print "\n";
print '<!DOCTYPE html>'."\n";
print '<html>'."\n";
-print '<head>'."\n";
-print '<base href="/mscha/view.fcgi?frame='.$url_frame.$url_amp_mode.'&uri=%2Fmscha%2Fviewer">'."\n";
-print '<meta charset="utf-8">'."\n";
-print '<meta name="viewport" content="width=device-width">'."\n";
-print '<title>xkcd Timeframe '.$en_frameNo.(($frameinfo{'match'} eq 'baFrameNo')?(' (Book of Aubron: '.$en_baFrameNo.')'):'').(($frameinfo{'match'} eq 'gwFrameNo')?(' (Geekwagon: '.$en_gwFrameNo.')'):'').'</title>'."\n";
-print '<link type="text/css" rel="stylesheet" href="/mscha/view1.css">'."\n";
-print '<link rel="icon" type="image/png" href="/mscha/cuegan32.png">'."\n";
-if ($frameinfo{'next'} ne '') {
- print '<link rel="prefetch" href="/mscha/viewer/'.$en_next.$en_sl_mode.'">'."\n";
-}
-print '<script src="/mscha/js/1.11.0.jquery.min.js"></script>'."\n";
-print '<script src="/mscha/js/1.10.4.jquery-ui.min.js"></script>'."\n";
-print '<script src="/mscha/js/jquery.cookie.js"></script>'."\n";
-print '<script>//<![CDATA['."\n";
-print "\n";
-print 'var jumpUrl = \'/mscha/viewer/_FRAMENO_'.$en_sl_mode.'\';'."\n";
-print "\n";
-print '//]]></script><script src="/mscha/view.js"></script>'."\n";
-print '</head>'."\n";
-print '<body>'."\n";
-print '<span id="top"><a href="http://1190.bicyclesonthemoon.info"><img src="/img/botmlogo2.png" alt="1190.bicyclesonthemoon.info" border="0"></a><br>Redundant copy of <a href="http://xkcd.mscha.org">xkcd.mscha.org</a>.</span>'."\n";
-print '<h1>xkcd <a href="http://xkcd.com/1190/" target="_blank">Time</a>frame '.$en_frameNo.'</h1>'."\n";
-if ($frameinfo{'match'} eq 'baFrameNo') {
- print '<h2> (Book of Aubron: '.$en_baFrameNo.')</h2>'."\n";
+print ' <head>'."\n";
+print ' <meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
+print ' <base href="'.$_base_url;.'">'."\n";
+print ' <meta name="viewport" content="width=device-width">'."\n";
+print ' <title>xkcd Timeframe '.$_title.'</title>'."\n";
+print ' <link type="text/css" rel="stylesheet" href="'.$_css_url.'">'."\n";
+print ' <link rel="icon" type="image/png" href=".'$_icon_url.'">'."\n";
+if ($viewer_prev_url ne '') {
+ print ' <link rel="next" href="'.$_viewer_prev_url.'">'."\n";
+ print ' <link rel="prefetch" href="'.$_viewer_prev_url.'">'."\n";
}
-if ($frameinfo{'match'} eq 'gwFrameNo') {
- print '<h2> (Geekwagon: '.$en_gwFrameNo.')</h2>'."\n";
+if ($viewer_next_url ne '') {
+ print ' <link rel="next" href="'.$_viewer_next_url.'">'."\n";
+ print ' <link rel="prefetch" href="'.$_viewer_next_url.'">'."\n";
}
-print ''."\n";
-print '<span class="comic"><img src="';
-if ($mode eq 'diff') {
- print $en_diffUrl."\n";
-} elsif (($mode ne 'orig')&&($frameinfo{'xkcdUrl'} ne '')) {
- print $en_xkcdUrl."\n";
-} else {
- print $en_downloadedUrl."\n";
+print ' <script src="'.$_jquery_url.'"></script>'."\n";
+print ' <script src="'.$_jquery_ui_url.'"></script>'."\n";
+print ' <script src="'.$_jquery_cook_url.'"></script>'."\n";
+print ' <script>//<![CDATA['."\n";
+print " \n";
+print ' var jumpUrl = \''.$_jumpUrl.'\';'."\n";
+print " \n";
+print ' //]]></script>'."\n";
+print ' <script src="'.$_js_url.'"></script>'."\n";
+print ' </head>'."\n";
+print ' <body>'."\n";
+print ' <span id="top"><a href="'.$_website_full_url.'"><img src="'.$_logo_url.'" alt="'.$_website.'" border="0"></a><br>Redundant copy of <a href="http://xkcd.mscha.org">xkcd.mscha.org</a>.</span>'."\n";
+print ' <h1>xkcd <a href="http://xkcd.com/1190/" target="_blank">Time</a>frame '.$_frameNo.'</h1>'."\n";
+if ($title2 ne '') {
+ print ' <h2>'.$_title2.'</h2>'."\n";
}
-print '" class="comic" alt="Time" title="'.$en_alt.'"></span>'."\n";
-print ''."\n";
-print '<div class="type">'."\n";
+print " \n";
+print ' <span class="comic"><img src="'.$_frame_url.'" class="comic" alt="Time" title="'.$_alt.'"></span>'."\n";
+print " \n";
+print ' <div class="type">'."\n";
if ($mode ne '') {
- print '<a href="/mscha/viewer/'.$en_frameNo.'" title="Current frame at xkcd servers">xkcd</a>'."\n";
+ print ' <a href="'.$_viewer_xkcd_url.'" title="Current frame at xkcd servers">xkcd</a>'."\n";
} else {
- print '<strong title="Current frame at xkcd servers">xkcd</strong>'."\n";
+ print ' <strong title="Current frame at xkcd servers">xkcd</strong>'."\n";
}
-print '•'."\n";
+print ' •'."\n";
if ($mode ne 'orig') {
- print '<a href="/mscha/viewer/'.$en_frameNo.'/orig" title="Frame as originally downloaded">original</a>'."\n";
+ print ' <a href="'.$_viewer_orig_url.'" title="Frame as originally downloaded">original</a>'."\n";
} else {
- print '<strong title="Frame as originally downloaded">original</strong>'."\n";
+ print ' <strong title="Frame as originally downloaded">original</strong>'."\n";
}
-if ($frameinfo{'diffUrl'} ne '') {
- print '•'."\n";
+if ($frame_info{'diffUrl'} ne '') {
+ print ' •'."\n";
if ($mode ne 'diff') {
- print '<a href="/mscha/viewer/'.$en_frameNo.'/diff" title="Difference between original and current frame">difference</a>'."\n";
+ print ' <a href="'.$viewer_diff_url.'" title="Difference between original and current frame">difference</a>'."\n";
} else {
- print '<strong title="Difference between original and current frame">difference</strong>'."\n";
+ print ' <strong title="Difference between original and current frame">difference</strong>'."\n";
}
}
-if ($frameinfo{'botmEnhance'} ne '') {
- print '<br>'."\n";
- print '<a href="http://1190.bicyclesonthemoon.info/aftertime/viewer/?story=time&f='.$url_frameNo.'&e='.$url_botmEnhance.'" target="_blank" style="font-size: 85%;">ENHANCE</a>'."\n";
+if ($moon_enhance_url ne '') {
+ print ' <br>'."\n";
+ print ' <a href="'.$_moon_enhance_url.'" target="_blank" style="font-size: 85%;">ENHANCE</a>'."\n";
}
-print '</div>'."\n";
-print "\n";
-print '<div class="nav">'."\n";
-print '<a id="linkFirst" title="First frame (press <Home>)" href="/mscha/viewer/1'.$en_sl_mode.'"><<1<<</a>'."\n";
-if($frameinfo{'prev'} ne '') {
- print '<a id="linkPrev" title="Previous frame (press <←> or <PgUp>)" href="/mscha/viewer/'.$en_prev.$en_sl_mode.'"><'.$en_prev.'<</a>'."\n";
+print ' </div>'."\n";
+print " \n";
+print ' <div class="nav">'."\n";
+print ' <a id="linkFirst" title="First frame (press <Home>)" href="'.$_viewer_first_url.'"><<1<<</a>'."\n";
+if ($viewer_prev_url ne '') {
+ print ' <a id="linkPrev" title="Previous frame (press <←> or <PgUp>)" href="'.$_viewer_prev_url.'"><'.$_prev.'<</a>'."\n";
} else {
- print '<span class="placeholder"></span>'."\n";
+ print ' <span class="placeholder"></span>'."\n";
}
-if($frameinfo{'next'} ne '') {
- print '<a id="linkNext" title="Next frame (press <→> or <PgDn>)" href="/mscha/viewer/'.$en_next.$en_sl_mode.'">>'.$en_next.'></a>'."\n";
+if($viewer_next_url{'next'} ne '') {
+ print ' <a id="linkNext" title="Next frame (press <→> or <PgDn>)" href="'.$_viewer_next_url.'">>'.$_next.'></a>'."\n";
} else {
- print '<span class="placeholder"></span>'."\n";
+ print ' <span class="placeholder"></span>'."\n";
}
-print '<a id="linkLast" title="Last frame (press <End>)" href="/mscha/viewer/3094'.$en_sl_mode.'">>>3094>></a>'."\n";
-print '<br>'."\n";
-print '<a id="linkRandom" class="center2" title="Random frame (press <?>)" href="/mscha/viewer/random'.$en_sl_mode.'">Random</a>'."\n";
-print '<a id="linkRandomSound" title="Random frame with sound" href="/mscha/viewer/randomsound'.$en_sl_mode.'">with sound</a>'."\n";
-print '</div>'."\n";
-print "\n";
-if ($frameinfo{'soundUrl'} ne '') {
+print ' <a id="linkLast" title="Last frame (press <End>)" href="'.$_viewer_last_url.'">>>3094>></a>'."\n";
+print ' <br>'."\n";
+print ' <a id="linkRandom" class="center2" title="Random frame (press <?>)" href="'.$_viewer_random_url.'">Random</a>'."\n";
+print ' <a id="linkRandomSound" title="Random frame with sound" href="'.$_viewer_rsound_url.'">with sound</a>'."\n";
+print ' </div>'."\n";
+print " \n";
+if ($frame_info{'soundUrl'} ne '') {
print '<div class="dialogue">'."\n";
print '<audio controls title="Play dialogue">'."\n";
print '<source src="'.$en_soundUrl.'" type="audio/mpeg">'."\n";
print "\n";
print '<div class="metadata">'."\n";
print '<strong>Date/time:</strong> '.$en_dateTime.' UTC <span id="localtime" data-epoch="'.$en_epoch.'"></span><br>'."\n";
-print '<strong>Hash:</strong> '.(($frameinfo{'hash'} ne '')?$en_hash:'<i>unknown</i>')."\n";
+print '<strong>Hash:</strong> '.(($frame_info{'hash'} ne '')?$en_hash:'<i>unknown</i>')."\n";
print '</div>'."\n";
print "\n";
print '<div class="jump"><form method="get" action="/mscha/viewer">'."\n";
print '<b>Jump to:</b> '."\n";
print '<select id="period" name="period">';
-printframeselection ($frameinfo{'frameNo'});
+print_frame_selection ($frame_info{'frameNo'});
print '</select>'."\n";
print '<br>'."\n";
print '<b>Or go to frame:</b>'."\n";
print ''."\n";
print '<div class="external">'."\n";
print '<strong>This frame on other sites:</strong><br>'."\n";
-if ($frameinfo{'gwFrameNo'} ne '') {
+if ($frame_info{'gwFrameNo'} ne '') {
print 'Geekwagon:'."\n";
print '<a href="http://geekwagon.net/projects/xkcd1190/?frame='.$url_gwFrameNo.'" target="_blank">frame '.$en_gwFrameNo.'</a>'."\n";
print '<br>'."\n";
}
-if ($frameinfo{'baFrameNo'} ne '') {
+if ($frame_info{'baFrameNo'} ne '') {
print 'Book of Aubron:'."\n";
print '<a href="http://xkcd.aubronwood.com/?i='.$url_baFrameNo.'&playing=0" target="_blank">frame '.$en_baFrameNo.'</a>'."\n";
print '<br>'."\n";
}
print 'The moon:'."\n";
print '<a href="http://1190.bicyclesonthemoon.info/aftertime/viewer?story=time&f='.$url_frameNo.'" target="_blank">Time/'.$en_frameNo.'</a>'."\n";
-if ($frameinfo{'botmEnhance'} ne '') {
+if ($frame_info{'botmEnhance'} ne '') {
print '(<a href="http://1190.bicyclesonthemoon.info/aftertime/viewer?story=time&e='.$url_botmEnhance.'&f='.$url_frameNo.'" target="_blank" style="font-size: 85%;">ENHANCE</a>)'."\n";
}
print '<br>'."\n";