aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2019-12-08 02:43:03 +0000
committerGitHub <noreply@github.com>2019-12-08 02:43:03 +0000
commit25ab3d060ac07d68f1b8d55dc9b56c40f4ca4b35 (patch)
tree24484c7380443a046b5c3c571434514f96907fa9
parenta2c9f8a6f959b1d096849a0ac9fa482b30e10c34 (diff)
parent160a35f23323fde107420f9cb6237660b01fb543 (diff)
downloadperlweeklychallenge-club-25ab3d060ac07d68f1b8d55dc9b56c40f4ca4b35.tar.gz
perlweeklychallenge-club-25ab3d060ac07d68f1b8d55dc9b56c40f4ca4b35.tar.bz2
perlweeklychallenge-club-25ab3d060ac07d68f1b8d55dc9b56c40f4ca4b35.zip
Merge pull request #1009 from dcw803/master
imported my solutions to challenge037
-rw-r--r--challenge-037/duncan-c-white/README68
-rwxr-xr-xchallenge-037/duncan-c-white/perl5/ch-1-Date-Manip.pl58
-rw-r--r--challenge-037/duncan-c-white/perl5/ch-1-in-postscript.ps355
-rwxr-xr-xchallenge-037/duncan-c-white/perl5/ch-1.pl97
-rwxr-xr-xchallenge-037/duncan-c-white/perl5/ch-2.pl228
5 files changed, 788 insertions, 18 deletions
diff --git a/challenge-037/duncan-c-white/README b/challenge-037/duncan-c-white/README
index fff0e6a452..c71e2a54c9 100644
--- a/challenge-037/duncan-c-white/README
+++ b/challenge-037/duncan-c-white/README
@@ -1,27 +1,59 @@
-Challenge 1: "Write a program to validate a given Vehicle Identification Number
- (VIN). For more information, please checkout
- https://en.wikipedia.org/wiki/Vehicle_identification_number
+Challenge 1: "Write a script to calculate the total number of weekdays (Mon-Fri) in each month of the year 2019.
+Jan: 23 days
+Feb: 20 days
+Mar: 21 days
+Apr: 22 days
+May: 23 days
+Jun: 20 days
+Jul: 23 days
+Aug: 22 days
+Sep: 21 days
+Oct: 23 days
+Nov: 21 days
+Dec: 22 days
"
-My notes: sounds rather tedious, lots of tables of codes, and optional
-bits only enforced in some countries. Do we have to validate all the
-optional bits?
+My notes: sounds rather straightforward, with or without date manipulation
+modules. Might even have a crack at this in an unconventional language
+as well as Perl - how about Adobe Postscript?
+Afternotes: I did 3 versions of this:
-Challenge 2: "Write a program to solve the Knapsack Problem.
+ch-1-Date-Manip.pl: first version uses Date::Manip's Date_DaysInMonth(m,y) and
+ Date_DayOfWeek(m,d,y) functions.
-There are 5 color coded boxes with varying weights and amounts in
-GBP. Which boxes should be choosen to maximize the amount of money while
-still keeping the overall weight under or equal to 15 kgs?
+ch-1.pl: second version does it ourselves from scratch.
-R: (weight = 1 kg, amount = £1)
-B: (weight = 1 kg, amount = £2)
-G: (weight = 2 kg, amount = £2)
-Y: (weight = 12 kg, amount = £4)
-P: (weight = 4 kg, amount = £10)
+ch-1-in-postscript.ps: translated ch-1.pl into Postscript. Yes, the language
+ mostly used for printer page layout, can be used as a
+ full-blown programming language. However, you have to
+ include functions to append strings and produce a
+ variety of debugging messages down the page, before
+ you start on the actual program logic.
-Bonus task, what if you were allowed to pick only 2 boxes or 3 boxes or
-4 boxes? Find out which combination of boxes is the most optimal?
+
+Challenge 2: "Write a script to find out the DayLight gain/loss in
+the month of December 2019 as compared to November 2019 in the city of
+London. You can find out London sunrise and sunset data for November 2019 here:
+https://www.timeanddate.com/sun/uk/london?month=11&year=2019
+
+and for December 2019 here:
+https://www.timeanddate.com/sun/uk/london?month=12&year=2019
"
-My notes: sounds interesting!
+My notes: most of this problem is fetching the web pages and parsing the
+information out of the first table in each page: that's a typical
+HTML::Parser state machine, easy enough. But once we have that information,
+eg. for each month a day->daylight duration mapping, what exactly does the
+question mean us to do?
+
+I think this problem means
+
+"calculate the difference between the amount of daylight on 1st Nov and on
+30th Nov, do the same for December (1st and 31st), and find out which
+"within month daylight duration" is smaller."
+
+btw, if I'm right the smaller duration is obviously between 1st-31st Dec
+than between 1st-30th Nov, because in November the days are getting shorter
+throughout the whole month, whereas in December they get shorter from
+1st-21st Dec, and then get longer again!
diff --git a/challenge-037/duncan-c-white/perl5/ch-1-Date-Manip.pl b/challenge-037/duncan-c-white/perl5/ch-1-Date-Manip.pl
new file mode 100755
index 0000000000..83fa046f5e
--- /dev/null
+++ b/challenge-037/duncan-c-white/perl5/ch-1-Date-Manip.pl
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+#
+# Challenge 1: "Write a script to calculate the total number of weekdays (Mon-Fri) in each month of the year 2019.
+# Jan: 23 days
+# Feb: 20 days
+# Mar: 21 days
+# Apr: 22 days
+# May: 23 days
+# Jun: 20 days
+# Jul: 23 days
+# Aug: 22 days
+# Sep: 21 days
+# Oct: 23 days
+# Nov: 21 days
+# Dec: 22 days
+# "
+#
+# My notes: sounds rather straightforward, with or without date manipulation
+# modules. This first version uses Date::Manip's Date_DaysInMonth(m,y) and
+# Date_DayOfWeek(m,d,y) functions.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use Date::Manip;
+
+
+die "Usage: ch-1.pl [YEAR]\n" if @ARGV>1;
+
+my @month = qw(X Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+
+
+#
+# my $n = countweekdays( $y, $m );
+# Find how many week days (Monday..Friday) there are in month $month
+# (1..12) in year $y.
+#
+fun countweekdays( $year, $month )
+{
+ my $n = 0;
+ my $ndays = Date_DaysInMonth( $month,$year );
+ foreach my $dayno (1..$ndays)
+ {
+ my $day = Date_DayOfWeek( $month, $dayno, $year );
+ $n++ if $day < 6;
+ }
+ return $n;
+}
+
+
+my $y = shift // 2019;
+foreach my $m (1..12)
+{
+ my $n = countweekdays( $y, $m );
+ print $month[$m], " $y: $n weekdays\n";
+}
diff --git a/challenge-037/duncan-c-white/perl5/ch-1-in-postscript.ps b/challenge-037/duncan-c-white/perl5/ch-1-in-postscript.ps
new file mode 100644
index 0000000000..ae7c894215
--- /dev/null
+++ b/challenge-037/duncan-c-white/perl5/ch-1-in-postscript.ps
@@ -0,0 +1,355 @@
+%!PS-Adobe-3.0
+%%Pages: 1
+%%EndComments
+%
+% ch-1-in-postscript.ps: translated ch-1.pl into Postscript.
+%
+% Yes, the language mostly used for printer page layout, can be used as a
+% full-blown programming language. However, you have to include functions
+% to append strings and produce a variety of debugging messages down the
+% page, before you start on the actual program logic.
+%
+% Debugging....
+
+% const debuglm: left margin of debug messages
+/debuglm 0.5 72 mul def
+
+% const debugtop: top of debug messages - 11 inches up.
+/debugtop 11 72 mul def
+
+% const debugdown: how far to go down each line
+/debugdown 20 def
+
+
+% debugorigin():
+% move to debugging origin
+/debugorigin
+{
+ debuglm debugtop moveto
+ (Debugging log:) show
+ newline
+} bind def
+
+
+% debugn( name );
+% display a single string $name on a debug line.
+/debugn
+{
+ 30 0 rmoveto
+ show % show name
+ newline
+} bind def
+
+
+% debugnv( name, value );
+% display name and value on a debug line.
+% keep this as it's so much simpler than debug() below
+% and also debug() has commented out invocations to
+% this throughout it:-)
+/debugnv
+{
+ % initially: stack top: value, name
+ 30 0 rmoveto
+ exch % stack top: name, value
+ show % show name, stack top: value
+ (: ) show
+ 50 string cvs show % show convert_to_string(value)
+ newline
+} bind def
+
+
+% debug( array_of_pairs );
+% display a single message, combining every pair of items (name,value)
+% in <array> as name: value, and comma-separating them.
+% eg debug( [(x) x (y) y (z) z] ) produces
+% "x: value_of_x, y: value_of_y, z: value_of_z"
+% (whether or not the values are strings or integers)
+/debug
+{
+ 6 dict begin % next N items defined are in a local dictionary
+ /array exch def % localize parameter name, removing it from stack
+ /len 0 def % local variable - length of array
+ /pos 0 def % local variable - position in array
+ /name () def % local variable - an array element
+ /value () def % local variable - next array element
+ /first 1 def % local variable - first time round loop?
+
+ 30 0 rmoveto
+
+ /len array length def
+
+ %Perl for pos = 0 to $#array step 2
+ 0 2 len 1 sub
+ {
+ /pos exch def
+
+ %Perl $name = $array[$pos];
+ /name array pos get def
+
+ %Perl $value = $array[$pos+1];
+ /value array pos 1 add get def
+
+ %Perl print "," unless first
+ first 0 eq {
+ (, ) show
+ } if
+
+ %Perl print "$name: $value";
+ name 50 string cvs show
+ (: ) show
+ value 50 string cvs show
+
+ %Perl $first=0;
+ /first 0 def
+ } for
+
+ newline
+
+ end % local dictionary destroyed here
+
+} def
+
+
+% newline();
+% go to left margin of next line for debug messages
+/newline
+{
+ currentpoint debugdown sub % decrement Y pos
+ exch pop % drop old X
+ debuglm exch % form (debuglm,Y) on stack
+ moveto % go there!
+} def
+
+
+% result = append( string1, string2 )
+% Concatenates two strings together. Some languages
+% already know how to do stuff like this!!!
+/append
+{
+ % Initial stack: s1 s2 <-- top of stack
+ 2 copy % s1 s2 s1 s2
+ length % s1 s2 s1 len(s2)
+ exch % s1 s2 len(s2) s1
+ length add % s1 s2 len(s1)+len(s2)
+ string dup % s1 s2 r r
+ 4 2 roll % r r s1 s2
+ 2 index % r r s1 s2 r
+ 0 % r r s1 s2 r 0
+ 3 index % r r s1 s2 r 0 s1
+ putinterval % strcpy( r+0, s1 )
+ % r r s1 s2
+ exch % r r s2 s1
+ length % r r s2 len(s1)
+ exch % r r len(s1) s2
+ putinterval % strcpy( r+len(s1), s2 )
+ % return r
+} bind def
+
+
+% isleap = isleapyear( y );
+% Return 1 if year $y is a leap year; 0 if not.
+%
+%Perl code: return 0 if y % 4 != 0;
+%Perl code: return 1 if y % 100 != 0;
+%Perl code: return 0 if y % 400 != 0;
+%Perl code: return 1;
+%
+/isleapyear
+{
+ 2 dict begin % next N items defined are in a local dictionary
+ /y exch def % localize parameter name, removing it from stack
+ /isleap 0 def % local variable - the return value, boolean
+
+ %[ (debug: is leap year y) y (isleap) isleap ] debug
+
+ % if y%4 == 0 then
+ y 4 mod 0 eq { % 1st if..then
+ % if y%100 != 0 then isleap=1..
+ y 100 mod 0 ne {
+ /isleap 1 def
+ % else [y%100 == 0]
+ } {
+ % isleap=1 if y%400 == 0
+ y 400 mod 0 eq {
+ /isleap 1 def
+ } if
+ } ifelse
+ } if
+
+ isleap % leave result on stack
+
+ end % local dictionary destroyed here
+} def
+
+
+% dow = dayofweek1stjanyear( year );
+% Find and return the day-of-the-week
+% (0=Monday, 1=Tuesday.. 4=Friday, 5=Saturday, 6=Sunday)
+% of 1st Jan $year (only valid for year>=1900).
+%
+/dayofweek1stjanyear
+{
+ 4 dict begin % next N items defined are in a local dictionary
+ /year exch def % localize parameter name, removing it from stack
+ /dow 0 def % local variable: day-of-week, return value
+ % why initial value 0? 1st Jan 1900 was Monday==0..
+ /y 0 def % local variable: for loop variable
+ /days 0 def % local variable: how many days to add (2 in leap years, 1 otherwise)
+
+ % year--
+ year 1 sub /year exch def
+
+ % foreach my $y (1900..$year)
+ % {
+ 1900 1 year
+ {
+ /y exch def
+% (y) y debugnv
+
+ /days y isleapyear 1 add def
+% (days) days debugnv
+
+% %print "$y: advance $days days\n";
+% (y:) y 50 string cvs append (: advance ) append
+% days 50 string cvs append ( days) debugnv
+
+ % dow = (dow + days) % 7;
+ dow days add 7 mod /dow exch def
+
+% % print "dow=$dow"
+% (dow) dow debugnv
+ % }
+ } for
+
+ dow % leave value on stack
+
+ end % local dictionary destroyed here
+} def
+
+
+%
+% mdays = daysinmonth( m, isleap );
+% Return the number of days in month $m (0..11), adjusting
+% number of days in February is $isleap is true.
+%
+/daysinmonth
+{
+ 3 dict begin % next N items defined are in a local dictionary
+ /isleap exch def% parameter - boolean, are we in a leap year?
+ /m exch def % parameter - month number 0..11
+ /d 0 def % local variable
+
+ %Perl my @d = (31,28,31,30,31,30,31,31,30,31,30,31);
+ /d [31 28 31 30 31 30 31 31 30 31 30 31] def
+
+ %Perl $d[1]=29 if $isleap;
+ isleap 1 eq {
+ d 1 29 put
+ } if
+
+ %Perl return $d[$m];
+ d m get
+
+ end % local dictionary destroyed here
+} def
+
+
+% showweekdays( $y );
+% Show each month in year $y and the number of week days (Monday-Friday)
+% in that month.
+%
+/showweekdays
+{
+ 8 dict begin % next N items defined are in a local dictionary
+ /y exch def % parameter - the year
+ /isleap 0 def % local variable - boolean, is $y a leap year?
+ /dow 0 def % local variable - day-of-week: 0..6
+ /m 0 def % local variable - month: 0..11
+ /mdays 0 def % local variable - number of days in month $m
+ /monthname 0 def% local variable - name of month $m
+ /weekdays 0 def % local variable - number of week days in month $m
+ /d 0 def % local variable - day number 1..$mdays
+
+ %Perl my @monthname = qw(Jan Feb Mar Apr May Jun Jul
+ %Perl Aug Sep Oct Nov Dec);
+ /monthname [(Jan) (Feb) (Mar) (Apr) (May) (Jun) (Jul)
+ (Aug) (Sep) (Oct) (Nov) (Dec)] def
+
+ %Perl my $isleap = isleapyear( $y );
+ /isleap y isleapyear def
+
+ %#Perl print "isleap[ $y ]: $isleap\n";
+ %(isleap[ ) y 50 string cvs append ( ] ) append isleap debugnv
+
+ %Perl my $dow = dayofweek1stjanyear( $y );
+ /dow y dayofweek1stjanyear def
+
+ %#Perl print "day-of-week[ 1st Jan $year ]: $dow\n";
+ %(day-of-week[ 1st Jan ) y 50 string cvs append ( ] ) append dow debugnv
+
+ %Perl foreach my $m (0..11)
+ %Perl {
+ 0 1 11
+ {
+ /m exch def
+
+ %Perl my $mdays = daysinmonth( $m, $isleap );
+ /mdays m isleap daysinmonth def
+
+ %Perl my $mname = monthname[m];
+ /mname monthname m get def
+ %(monthname) mname debugnv
+
+ %#Perl print "days in month[$mname, " $y]: $mdays\n";
+ %(days in month[) mname append
+ %( ) append
+ %y 50 string cvs append
+ %(]) append
+ %mdays debugnv
+
+ %Perl my $weekdays = 0;
+ /weekdays 0 def
+
+ %Perl foreach my $d (1..$mdays)
+ %Perl {
+ 1 1 mdays
+ {
+ /d exch def
+ %[ (d) d (dow) dow (weekdays) weekdays ] debug
+
+ %Perl $weekdays++ if $dow < 5;
+ dow 5 lt {
+ weekdays 1 add /weekdays exch def
+ } if
+
+ % dow = (dow + 1) % 7;
+ dow 1 add 7 mod /dow exch def
+
+ %Perl }
+ } for
+
+ %Perl print "$mname $y: $weekdays weekdays\n";
+ mname ( ) append
+ y 50 string cvs append
+ (: ) append
+ weekdays 50 string cvs append
+ ( weekdays) append
+ debugn
+
+ %Perl }
+ } for
+
+ end % local dictionary destroyed here
+} def
+
+
+%%Page: 1 1
+%%PageOrientation: Portrait
+
+/Helvetica-Bold findfont 13 scalefont setfont
+
+debugorigin
+
+2019 showweekdays
+
+showpage
diff --git a/challenge-037/duncan-c-white/perl5/ch-1.pl b/challenge-037/duncan-c-white/perl5/ch-1.pl
new file mode 100755
index 0000000000..d149d0116c
--- /dev/null
+++ b/challenge-037/duncan-c-white/perl5/ch-1.pl
@@ -0,0 +1,97 @@
+#!/usr/bin/perl
+#
+# Challenge 1: "Write a script to calculate the total number of weekdays (Mon-Fri) in each month of the year 2019.
+# Jan 2019: 23 weekdays
+# Feb 2019: 20 weekdays
+# Mar 2019: 21 weekdays
+# Apr 2019: 22 weekdays
+# May 2019: 23 weekdays
+# Jun 2019: 20 weekdays
+# Jul 2019: 23 weekdays
+# Aug 2019: 22 weekdays
+# Sep 2019: 21 weekdays
+# Oct 2019: 23 weekdays
+# Nov 2019: 21 weekdays
+# Dec 2019: 22 weekdays
+# "
+#
+# My notes: sounds rather straightforward, even without date manipulation
+# modules. This second version does it ourselves from scratch.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+
+
+die "Usage: ch-1.pl [YEAR]\n" if @ARGV>1;
+
+my @month = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+
+
+#
+# my $isleap = isleapyear( $y );
+# Return 1 if year $y is a leap year; 0 if not.
+#
+fun isleapyear( $y )
+{
+ return 0 unless $y % 4 == 0;
+ return 1 unless $y % 100 == 0;
+ return 0 unless $y % 400 == 0;
+ return 1;
+}
+
+
+#
+# my $dow = dayofweek1stjanyear( $y );
+# Find the day-of-the-week
+# (0=Monday, 1=Tuesday.. 4=Friday, 5=Saturday, 6=Sunday)
+# of 1st Jan $y (only valid for y>=1900). Return it.
+#
+fun dayofweek1stjanyear( $y )
+{
+ # first, calculate dow in range 0..6
+ my $dow = 0; # 1st Jan 1900 was a Monday..
+ foreach my $y (1900..$y-1)
+ {
+ my $days = isleapyear($y) ? 2 : 1;
+ #print "$y: advance $days days\n";
+ $dow += $days;
+ $dow %= 7;
+ }
+ return $dow;
+}
+
+
+#
+# my $daysinmonth = daysinmonth( $m, $isleap );
+# Return the number of days in month $m (0..11), adjusting
+# number of days in February is $isleap is true.
+#
+fun daysinmonth( $m, $isleap )
+{
+ my @d = (31,28,31,30,31,30,31,31,30,31,30,31);
+ $d[1]=29 if $isleap;
+ return $d[$m];
+}
+
+
+my $y = shift // 2019;
+my $isleap = isleapyear( $y );
+my $dow = dayofweek1stjanyear( $y );
+#print "1st Jan $y is day-of-week $dow\n";
+
+foreach my $m (0..11)
+{
+ my $daysinmonth = daysinmonth( $m, $isleap );
+ #print $month[$m], " $y: had $daysinmonth days\n";
+ my $weekdays = 0;
+ foreach my $d (1..$daysinmonth)
+ {
+ $weekdays++ if $dow < 5;
+ $dow++;
+ $dow %= 7;
+ }
+ print $month[$m], " $y: $weekdays weekdays\n";
+}
diff --git a/challenge-037/duncan-c-white/perl5/ch-2.pl b/challenge-037/duncan-c-white/perl5/ch-2.pl
new file mode 100755
index 0000000000..678f899a39
--- /dev/null
+++ b/challenge-037/duncan-c-white/perl5/ch-2.pl
@@ -0,0 +1,228 @@
+#!/usr/bin/perl
+#
+# Challenge 2: "Write a script to find out the DayLight gain/loss in
+# the month of December 2019 as compared to November 2019 in the city of
+# London. You can find out London sunrise and sunset data for November 2019 here:
+# https://www.timeanddate.com/sun/uk/london?month=11&year=2019
+#
+# and for December 2019 here:
+# https://www.timeanddate.com/sun/uk/london?month=12&year=2019
+# "
+#
+# My notes: most of this problem is fetching the web pages and parsing the
+# information out of the first table in each page: that's a typical
+# HTML::Parser state machine, easy enough. But once we have that information,
+# eg. for each month a day->daylight duration mapping, what exactly does the
+# question mean us to do?
+#
+# I think this problem means
+#
+# "calculate the difference between the amount of daylight on 1st Nov and on
+# 30th Nov, do the same for December (1st and 31st), and find out which
+# "within month daylight duration" is smaller."
+#
+# btw, if I'm right the smaller duration is obviously between 1st-31st Dec
+# than between 1st-30th Nov, because in November the days are getting shorter
+# throughout the whole month, whereas in December they get shorter from
+# 1st-21st Dec, and then get longer again!
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use LWP::Simple;
+use HTML::Parser;
+use File::Slurp;
+use Time::Piece;
+use Data::Dumper;
+
+my $novurl = "https://www.timeanddate.com/sun/uk/london?month=11&year=2019";
+my $decurl = "https://www.timeanddate.com/sun/uk/london?month=12&year=2019";
+
+
+my $debug_parse=0;
+
+fun start( $t, $p )
+{
+ print "start<$t>\n" if $debug_parse;
+ #print Dumper($p) if $debug_parse;
+ #die;
+ if( $t eq "table" )
+ {
+ $p->{tableno}++;
+ print "in table $p->{tableno}, want_table = $p->{want_table}\n" if $debug_parse;
+ $p->{inwantedtable} =
+ ($p->{tableno} == $p->{want_table}) ? 1 : 0;
+ return unless $p->{inwantedtable};
+ print "in wanted table: table $p->{tableno}\n" if $debug_parse;
+ $p->{rowno} = -1;
+ return;
+ }
+ if( $p->{inwantedtable} && $t eq "tr" )
+ {
+ $p->{rowno}++;
+ print "in wanted table: table $p->{tableno}, row $p->{rowno}\n" if $debug_parse;
+ $p->{colno} = -1;
+ $p->{row} = [];
+ return;
+ }
+ if( $p->{inwantedtable} && $t =~ /^(td|th)$/ )
+ {
+ $p->{colno}++;
+ print "in wanted table: table $p->{tableno}, ".
+ "row $p->{rowno}, column $p->{colno}\n" if $debug_parse;
+ $p->{inwantedcell} =
+ $p->{want_columns}->{ $p->{colno} } ? 1 : 0;
+ if( $p->{inwantedcell} )
+ {
+ print "capturing wanted cell column $p->{colno} in ".
+ "row $p->{rowno}\n" if $debug_parse;
+ $p->{celltext} = '';
+ }
+ }
+}
+
+
+fun text( $t, $p )
+{
+ return unless $p->{inwantedcell};
+ print "text<$t> in wanted cell\n" if $debug_parse;
+ $t =~ s/^\s+//m;
+ $t =~ s/\s+$//m;
+ $p->{celltext} .= $t;
+ print "debug: text: <<$t>>, celltext after: <<$p->{celltext}>>\n" if $debug_parse;
+}
+
+
+fun end( $t, $p )
+{
+ print "end<$t>\n" if $debug_parse;
+ if( $t eq "table" )
+ {
+ print "leaving table $p->{tableno}\n" if $debug_parse;
+ $p->{inwantedtable} = 0;
+ $p->{inwantedcell} = 0;
+ } elsif( $p->{inwantedcell} && $t =~ /^(td|th)$/ )
+ {
+ $p->{inwantedcell} = 0;
+ push @{$p->{row}}, $p->{celltext};
+ print "at end of wantedcell, celltext=$p->{celltext}, row=", Dumper($p->{row}) if $debug_parse;
+ $p->{celltext} = '';
+ } elsif( $p->{inwantedtable} && $t eq "tr" )
+ {
+ push @{$p->{info}}, [ @{$p->{row}} ] if @{$p->{row}};
+ print "ending row in wantedtable: p->{info} is ", Dumper( $p->{info} ) if $debug_parse;
+ $p->{row} = [];
+ $p->{colno} = -1;
+ $p->{inwantedcell} = 0;
+ }
+}
+
+
+#
+# my %info = parse_table( $htmltext, %want );
+# Given an HTML page $htmltext, and a specification of what parts
+# of what table we want, find and parse the corresponding table,
+# extract the wanted columns of each row, and build and return @info:
+# an array of [ those column values ] tuples.
+#
+fun parse_table( $htmltext, %want )
+{
+ my $p = HTML::Parser->new( api_version => 3,
+ start_h => [\&start, "tagname, self"],
+ end_h => [\&end, "tagname, self"],
+ text_h => [\&text, "dtext, self"],
+ unbroken_text => 1,
+ );
+
+ $p->{want_table} = $want{tableno}; # which table we want..
+
+ # set of which columns we want
+ $p->{want_columns} = { map { $_ => 1 } @{$want{columns}} };
+ #die Dumper $p->{want_columns};
+
+ $p->{tableno} = -1; # how many tables seen so far?
+ $p->{inwantedtable} = 0; # are we in the WANTED table?
+ $p->{colno} = -1; # which column in now?
+ $p->{rowno} = -1; # which row no we're in now?
+ $p->{inwantedcell} = 0; # want this table cell?
+ $p->{celltext} = ''; # cell text we're building
+ $p->{row} = []; # row we're building
+ $p->{info} = []; # the answer - list of rows
+
+ #die Dumper $p;
+
+ # Parse document text
+ $p->parse($htmltext);
+
+ my @result = @{$p->{info}};
+
+ $p->eof; # signal end of document
+
+ return @result;
+}
+
+
+#
+# my( $diff, $diffms ) = duration( $name, @month );
+# Given a month info array for month $name, a list of
+# [ dayno, dayduration ] pairs, calculate the difference in
+# dayduration between the 1st dayno and the last. Return it
+# in two forms: as an integer (seconds) and as an mm{m}ss{s} string.
+#
+fun duration( $name, @month )
+{
+ my $first = $month[0][1];
+ print "\nduration 1st of $name: $first\n";
+ my $novdays = @month;
+ my $last = $month[$novdays-1][1];
+ print "duration last day in $name: $last\n";
+
+ my $t1 = Time::Piece->strptime( $last, '%H:%M:%S' );
+ my $t2 = Time::Piece->strptime( $first, '%H:%M:%S' );
+ my $diff = $t2 - $t1;
+
+ my $mins = int($diff/60);
+ my $secs = $diff%60;
+ my $hs = "${mins}m${secs}s";
+ print "$name diff: $diff ($hs)\n";
+
+ return( $diff, $hs );
+}
+
+
+my %want;
+$want{tableno} = 0; # want first table..
+$want{columns} = [ 0,3 ]; # which columns we want
+
+#my $html = read_file( "eg.html" );
+#my @info = parse_table( $html, %want );
+
+my $html = get($novurl) || die "can't get $novurl\n";
+my @nov = parse_table( $html, %want );
+
+# only want 2-tuples where both values start with a digit..
+@nov = grep { @$_ == 2 && $_->[0] =~ /^\d/ && $_->[1] =~ /^\d/ } @nov;
+
+$html = get($decurl) || die "can't get $decurl\n";
+my @dec = parse_table( $html, %want );
+
+# only want 2-tuples where both values start with a digit..
+@dec = grep { @$_ == 2 && $_->[0] =~ /^\d/ && $_->[1] =~ /^\d/ } @dec;
+
+#print "nov: ", Dumper \@nov;
+#print "dec: ", Dumper \@dec;
+
+my( $nd, $ndhs ) = duration( "Nov", @nov );
+my( $dd, $ddhs ) = duration( "Dec", @dec );
+
+print "\n";
+
+if( $nd < $dd )
+{
+ print "Nov diff smaller: $nd: $ndhs\n";
+} else
+{
+ print "Dec diff smaller: $dd: $ddhs\n";
+}