#!/usr/bin/perl
# gentree.pl - Generate family tree HTML files
# gentree.pl [-help] [-test] [-nogen] [-d <debuglevel>] [-ged <gedfile>] [-mod <modeldir>] [-html <htmldir>] [-del <surname>]

use strict;
use warnings;
my $old_stdout = select(STDOUT);
$| = 1;
select($old_stdout);
my $old_stderr = select(STDERR);
$| = 1;
select($old_stderr);

my $debug="";
my $test=0;
my $nogen=0;
my $gedfile="gedfile.ged";
my $htmldir="htmldir";
my $modeldir="modeldir";
my $delname="";
my $debugfile="gentree.debug";
my $placfile="gentree.places";
my $searchfs="href=\"https://www.familysearch.org/search/tree/results?count=100&q.anyDate.from=xDTx&q.anyPlace=xPLx&q.givenName=xGNx&q.surname=xSNx\"";
my $searchfg="href=\"https://www.findagrave.com/memorial/search?firstname=xFNx&lastname=xLNx&birthyear=xBYx&deathyear=xDYx\"";
my $valDT;
my $valPL;
my $valGN;
my $valSN;
my $valFN;
my $valLN;
my $valBY;
my $valDY;
my $val1;
my $val2;
my $val3;
my $val4;
my $valrest;
my $atagdata="?";
my $indfile;
my $famfile;
my $namfile;
my $modfile;
my $htmlfile;
my $line;
my $eline;
my $cntr;
my $lev;
my $typ;
my $val;
my $i;
my $j;
my $x;
my $work;
my $newtablecolumn;
my $nochildren;
my $key="";
my $hkey="";
my $hpkey="";
my $hfkey="";
my $hmkey="";
my $wkey="";
my $wpkey="";
my $wfkey="";
my $wmkey="";
my $numerickey;
my $savekey;
my $lev0typ="";
my $lev1typ="";
my $lev2typ="";
my $lev3typ="";
my $lev4typ="";
my $ignore=0;
my $numnames=0;
my $lev0notenum=0;
my $numevents=0;
my $numfams=0;
my $numfamc=0;
my $numchild=0;
my $gseqno=0;
my $lev1evtyp;
my %rin;
my %numericrin;
my %fullname;
my %fullnameplus;
my %altnum;
my %altnames;
my %altdata;
my %altcolor;
my %givenname;
my %surname;
my %cemeteryname;
my %cemeterynote;
my %givennamezzz;
my %surnamezzz;
my %birthdatezzz;
my %birthplacezzz;
my %cemeterynamezzz;
my %nameprefix;
my %namesuffix;
my %ixsurname;
my %ixgiven;
my %chgdate;
my %chgtime;
my %sex;
my %sexcolor;
my %uid;
my %birthdate;
my %birthage;
my %birthplace;
my %birthaddr;
my %birthaddrnote;
my %birthnote;
my %birthdata;
my %birthcolor;
my %chrdate;
my %chrage;
my %chrplace;
my %chraddr;
my %chraddrnote;
my %chrnote;
my %chrdata;
my %chrcolor;
my %dead;
my %deathdate;
my %deathage;
my %deathplace;
my %deathaddr;
my %deathaddrnote;
my %deathnote;
my %deathdata;
my %deathcolor;
my %deathcause;
my %burdate;
my %burplace;
my %buraddr;
my %buraddrnote;
my %burnote;
my %burcrem;
my %burlati;
my %burlong;
my %burdata;
my %burcolor;
my %lev0note;
my %lev0notekey;
my %lev1note;
my %notedata;
my %notecolor;
my %eventnum;
my %eventage;
my %eventtype;
my %eventdesc;
my %eventdate;
my %eventplace;
my %eventnote;
my %eventdescplacenote;
my %fsftid;
my %fslink;
my %fgrave;
my %fglink;
my %indfamc;
my %indfamcnum;
my %preffamkey;
my %famlink;
my %indfams;
my %indfamsnum;
my %indstat;
my %rinorder;
my %surnameorder;
my %givenorder;

my %husbkey;
my %wifekey;
my %husbpref;
my %wifepref;
my %husbtitl;
my %wifetitl;
my %mardate;
my %marplace;
my %mardateplace;
my %mardateinplace;
my %marstat;
my %marwin;
my %statdate;
my %childpref;
my %childkeynum;
my %allchildkeynum;
my %childkey;
my $eventstat;
my $eventlcnt;
my @eventltab;
my $childstat;
my $childlcnt;
my @childltab;
my %childfamkey;
my %childfullname;
my %childsexcolor;
my %childdata;
my %famrin;
my %husbfathhref;
my %husbfather;
my %husbmothhref;
my %husbmother;
my %wifefathhref;
my %wifefather;
my %wifemothhref;
my %wifemother;
my %husbhref;
my %husbfullname;
my %husbbirthdateplace;
my %husbchrdateplace;
my %husbdeathdateplace;
my %husbburdateplace;
my %husbdeathcause;  
my %husbnumspouses;
my %husbspouselink;
my %husbspousename;
my %husbfglink;
my %husbfgid;
my %wifehref;
my %wifefullname;
my %wifebirthdateplace;
my %wifechrdateplace;
my %wifedeathdateplace;
my %wifeburdateplace;
my %wifedeathcause;  
my %wifenumspouses;
my %wifespouselink;
my %wifespousename;
my %wifefglink;
my %wifefgid;

my $ixtype;
my $ixcolor;
my $ixname;
my $ixsex;
my $ixfglink;
my $ixfgrave;
my $ixfslink;
my $ixfsftid;
my $bdateseq;
my $cemprefix;
my $cemloc;
my $cemloc1;
my $cemloc2;
my $cemloc3;
my $cemloc4;
my $bplaceloc;
my $bplaceloc1;
my $bplaceloc2;
my $bplaceloc3;
my $bplaceloc4;
my $cplaceloc1;
my $cplaceloc2;
my $cplaceloc3;
my $cplaceloc4;
my $dplaceloc1;
my $dplaceloc2;
my $dplaceloc3;
my $dplaceloc4;
my $numixlines;
my $xlinestat;
my $xlinelcnt;
my @xlineltab;
my @keysbyrin;
my @keysbysurname;
my @keysbygivenname;
my @keysbybirthdate;
my @keysbybirthplace;
my @keysbycemeteryname;

my %indrec;
my %famrec;
my %namrec;

Getopts();
if ($debug eq "") { $debug=" "; }
if ($debug ne " ") {
    open (DOUT,">$debugfile") or die "Can't open $debugfile: $!";
}

open (GED,"<$gedfile") or die "Can't open $gedfile: $!";
if ($nogen == 0) {
   opendir (*HTMLDIR,"$htmldir") or die "Can't find directory $htmldir: $!";
   closedir (*HTMLDIR);
} else {
   print "Nogen is on, HTML files will not be written\n";
}
opendir (*MODDIR,"$modeldir") or die "Can't find directory $modeldir: $!";
closedir (*MODDIR);
open (PLAC,">$placfile") or die "Can't open $placfile: $!";
print "Reading $gedfile ...\n";
$cntr=0;
while (<GED>) {
       s/\r[\n]*/\n/gm;  # get rid of carriage returns, we only want line feeds
       chomp;
       $line=$_;
       $cntr=$cntr+1;
       Dprint("a","$cntr: $line\n");
       ($lev,$typ,$val) = split(/\s/,$line,3);
       if (!defined $lev) { $lev=""; }
       if (!defined $typ) { $typ=""; }
       if (!defined $val) { $val=""; }
       Dprint("a","lev: $lev\n");
       Dprint("a","typ: $typ\n");
       Dprint("a","val: $val\n");
# Level 0 processing
       if ($lev eq "0") {
           if ($val eq "NOTE") {
               # level 0 NOTE processing
               $lev0notenum=$lev0notenum+1;
               $lev0notekey{$key,$lev0notenum}=$typ;
               $lev0note{$key,$lev0notenum}="";
           } else {
               Processlev0();
               $lev0typ="$val";
               $lev0notenum=0;
               $numevents=0;
               $ignore=0;
               $numnames=0;
               $numfams=0;
               $numfamc=0;
               $numchild=0;
               Dprint(0,"Level 0: $typ $val\n");
               if ($val eq "INDI") {
                   $key=$typ;
                   Initind();
                   $rin{$key}=$key;
                   $numerickey=$key;
                   $numerickey=~s/[^\d.]//g;       # digits only
                   $numericrin{$key}=$numerickey; 
                   $eventnum{$key}=0;
              } elsif ($val eq "FAM") {
                   $key=$typ;
                   Initfam();
                   $famrin{$key}=$key;
                   $numerickey=$key;
                   $numerickey=~s/[^[A-Z,0-9]//g;  # digits and capital letters only
                   $numericrin{$key}=$numerickey; 
                   $eventnum{$key}=0;
               } elsif ($val eq "_STORY") {
                   $lev0typ="";
                   $ignore=1;
               } elsif ($val eq "SOUR") {
                   $lev0typ="";
                   $ignore=1;
               } elsif ($val eq "REPO") {
                   $lev0typ="";
                   $ignore=1;
              } elsif ($typ eq "_TODO") {
                   $lev0typ="";
                   $ignore=1;  
              } elsif ($typ eq "_PLAC_DEFN") {
                   $lev0typ="";
                   $ignore=1;
               } elsif ($typ eq "_EVENT_DEFN") {
                   $lev0typ="";
                   $ignore=1;
               } elsif ($typ eq "_HASHTAG_DEFN") {
                   $lev0typ="";
                   $ignore=1;
               } elsif ($val eq "SUBM") {
                   $lev0typ="";
                   $ignore=1;
               } elsif ($typ eq "HEAD") {
                   $lev0typ="";
                   $ignore=1;
               } elsif ($typ eq "TRLR") {
                   $lev0typ="";
                   $ignore=1;
               } elsif ($typ eq "SOUR") {
                   $lev0typ="";
                   $ignore=1;
               } else {
                 print "Unhandled level 0 entry at line $cntr: $typ $val\n";
                 if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
               } 
           }
       } elsif ($ignore == 1) {
       } elsif ($lev0typ eq "INDI") {
# INDI Level 1 processing
           if ($lev eq "1") {
               $lev1typ=$typ;
               Dprint(1,"Level 1: $typ $val\n");
               if (($typ eq "CONC") || ($typ eq "CONT")) {
                   Dprint("c","Found in level 1: NOTE $typ\n");
               } elsif ($typ eq "NOTE") {
                   Dprint("n","Found in level 1: $lev0typ $typ\n");
               }
               if ($lev0notenum > 0) {
                   if ($typ eq "CONC") {
                       $lev0note{$key,$lev0notenum}=$lev0note{$key,$lev0notenum} . $val;
                   } elsif ($typ eq "CONT") {
                       $lev0note{$key,$lev0notenum}=$lev0note{$key,$lev0notenum} . "\n" . $val;
                   } else {
                       print "Unhandled level 1 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif ($typ eq "SEX") {
                  if ($val eq "M") {
                      $sex{$key}="Male";
                      $sexcolor{$key}="blue";
                  } elsif ($val eq "F") {
                      $sex{$key}="Female";
                      $sexcolor{$key}="red";
                  } else {
                      $sex{$key}="Unknown";
                      $sexcolor{$key}="black";
                  }
               } elsif ($typ eq "NAME") {
                   $numnames=$numnames+1;
                   $givenname{$key,$numnames}="";
                   $surname{$key,$numnames}="";
                   $nameprefix{$key,$numnames}="";
                   $namesuffix{$key,$numnames}="";
               } elsif ($typ eq "BIRT") {
               } elsif ($typ eq "CHR") {
               } elsif ($typ eq "DEAT") {
                   $dead{$key}="y";
                   if ($val eq "Y") {
                      $deathdate{$key}="Yes";
                   }
               } elsif ($typ eq "BURI") {
               } elsif ($typ eq "RESN") {
               } elsif ($typ eq "_PPEXCLUDE") {
               } elsif ($typ eq "OCCU") {    # Occupation
                   $lev1evtyp="Occupation";
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "EDUC") {    # Education
                   $lev1evtyp="Education";
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "GRAD") {    # Education
                   $lev1evtyp="Graduation";
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "NATU") {    # Naturalized
                   $lev1evtyp="Naturalized";
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "IMMI") {    # Immigrated
                   $lev1evtyp="Immigrated";
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "DIV") {     # Divorced
                   $lev1evtyp="Divorced"; 
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "CENS") {    # Census
                   $lev1evtyp="Census"; 
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "RESI") {    # Residence
                   $lev1evtyp="Residence"; 
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "ORDN") {    # Ordination
                   $lev1evtyp="Ordination"; 
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "EVEN") {
                   $lev1evtyp="Unknown";
               } elsif ($typ eq "_FSFTID") {
                   $fsftid{$key}=$val;
               } elsif ($typ eq "_FSLINK") {
                   if ($val ne "") {
                      $fslink{$key}="href=\"$val\"";
                   }
               } elsif ($typ eq "_FGRAVE") {
                   $fgrave{$key}=$val;
               } elsif ($typ eq "_FGLINK") {
                   if ($val ne "") {
                      $fglink{$key}="href=\"$val\"";
                   }
               } elsif ($typ eq "_STAT") {
                   $indstat{$key}=$val;
               } elsif ($typ eq "CHAN") {
               } elsif ($typ eq "FAMS") {
                   $numfams=$numfams+1;
                   $indfams{$key,$numfams}=$val;
               } elsif ($typ eq "FAMC") {
                   $numfamc=$numfamc+1;
                   $indfamc{$key,$numfamc}=$val;
               } elsif ($typ eq "_UID") {
                   $uid{key}=$val;
               } elsif ($typ eq "NOTE") {
                   # level 1 NOTE processing, there is only one of these per lev 0
                   $lev1note{$key}=$val;
               } elsif ($typ eq "AFN") {
                   Dprint("s","Ignoring in level 1: $lev0typ $typ\n");
               } elsif ($typ eq "OBJE") {
                   Dprint("s","Ignoring in level 1: $lev0typ $typ\n");
               } elsif ($typ eq "_TODO") {
                   Dprint("s","Ignoring in level 1: $lev0typ $typ\n");
               } elsif ($typ eq "_STORY") {
                   Dprint("s","Ignoring in level 1: $lev0typ $typ\n");
               } elsif ($typ eq "_HASHTAG") {
                   Dprint("s","Ignoring in level 1: $lev0typ $typ\n");
               } else {
                   print "Unhandled level 1 entry at line $cntr: $typ $val\n";
                   if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
               }
               if ($typ eq "EVEN") {
                   # level 1 EVEN processing
                   $numevents=$numevents+1;
                   $eventnum{$key}=$numevents;
                   $eventtype{$key,$numevents}=$lev1evtyp;
                   $eventdesc{$key,$numevents}=$val;
                   $eventdate{$key,$numevents}="";
                   $eventage{$key,$numevents}="";
                   $eventplace{$key,$numevents}="";
                   $eventnote{$key,$numevents}="";
                   $eventdescplacenote{$key,$numevents}="";
               }
           } elsif ($lev eq "2") {
# INDI Level 2 processing
               $lev2typ=$typ;
               Dprint(2,"Level 2: $typ $val\n"); 
               if (($typ eq "CONC") || ($typ eq "CONT")) {
                   Dprint("c","Found in level 2: $lev0typ $lev1typ $typ\n");
               } elsif ($typ eq "NOTE") {
                   Dprint("n","Found in level 2: $lev0typ $lev1typ $typ\n");
               }
               if ($typ eq "SOUR") {
                   Dprint("s","Found in level 2: $lev0typ $lev1typ $typ\n");
               } elsif ($typ eq "_SHAR") {
                   Dprint("s","Ignoring in level 2: $lev0typ $lev1typ $typ\n");
               } elsif (($lev1typ eq "OBJE") || ($lev2typ eq "OBJE")) {
                   Dprint("s","Ignoring in level 2: $lev0typ $lev1typ $typ\n");
               } elsif ($lev1typ eq "_TODO") {
                   Dprint("s","Ignoring in level 2: $lev0typ $lev1typ $typ\n");
               } elsif ($lev1typ eq "NAME") {
                   if ($typ eq "GIVN") {
                       $givenname{$key,$numnames}=$val;
                   } elsif ($typ eq "SURN") {
#
# Special delete for specific surname
#
                       if ($delname ne "") {
                          if (($val eq $delname) && ($numnames == 1)) {
                              $givenname{$key,$numnames}="";
                              $val="Deleted";
                              $ignore=1;
                          }
                       }
                       $surname{$key,$numnames}=$val;
                   } elsif ($typ eq "NPFX") {
                       $nameprefix{$key,$numnames}=$val;
                   } elsif ($typ eq "NSFX") {
                       $namesuffix{$key,$numnames}=$val;
                   }
               } elsif ($lev1typ eq "BIRT") {
                   if ($typ eq "DATE") {
                       $birthdate{$key}=$val;
                   } elsif ($typ eq "PLAC") {
                       $birthplace{$key}=$val;
                       Doplac($key,"1BIRT",$val);
                   } elsif ($typ eq "ADDR") {
                       $birthaddr{$key}=$val;
                   } elsif ($typ eq "NOTE") {
                       $birthnote{$key}=$val;
                   }
               } elsif ($lev1typ eq "CHR") {
                   if ($typ eq "DATE") {
                       $chrdate{$key}=$val;
                   } elsif ($typ eq "PLAC") {
                       $chrplace{$key}=$val;
                       Doplac($key,"2CHR",$val);
                   } elsif ($typ eq "ADDR") {
                       $chraddr{$key}=$val;
                   } elsif ($typ eq "NOTE") {
                       $chrnote{$key}=$val;
                   }
               } elsif ($lev1typ eq "DEAT") {
                   if ($typ eq "DATE") {
                       $deathdate{$key}=$val;
                   } elsif ($typ eq "PLAC") {
                       $deathplace{$key}=$val;
                       Doplac($key,"6DEAT",$val);
                   } elsif ($typ eq "ADDR") {
                       $deathaddr{$key}=$val;
                   } elsif ($typ eq "NOTE") {
                       $deathnote{$key}=$val;
                   } elsif ($typ eq "CAUS") {
                       $deathcause{$key}=$val;
                   }
               } elsif ($lev1typ eq "BURI") {
                   if ($typ eq "DATE") {
                       $burdate{$key}=$val;
                       $dead{$key}="y";
                   } elsif ($typ eq "PLAC") {
                       $burplace{$key}=$val;
                       Doplac($key,"7BURI",$val);
                   } elsif ($typ eq "ADDR") {
                       $buraddr{$key}=$val;
                   } elsif ($typ eq "NOTE") {
                       $burnote{$key}=$val;
                   } elsif ($typ eq "CREM") {
                       $burcrem{$key}="Cremated";
                   }
               } elsif ($lev1typ eq "EVEN") {
                   if ($typ eq "TYPE") {
                       Dprint("e","Event type $val set for $key event number $numevents\n"); 
                       $eventtype{$key,$numevents}=$val;
                   } elsif ($typ eq "NOTE") {
                       $eventnote{$key,$numevents}=$val;
                   } elsif ($typ eq "ADDR") {
                       Dprint("e","Event addr $val ignored for $key event number $numevents\n"); 
                   } elsif ($typ eq "PLAC") {
                       $eventplace{$key,$numevents}=$val;
                       Doplac($key,"3EVEN",$val);
                   } elsif ($typ eq "DATE") {
                       $eventdate{$key,$numevents}=$val;

                   } else {
                       print "Unhandled level 2 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif ($lev1typ eq "CHAN") {
                   if ($typ eq "DATE") {
                       $chgdate{$key}=$val;
                   } 
               }
# INDI Level 3 processing
           } elsif ($lev eq "3") {
               $lev3typ=$typ;
               Dprint(3,"Level 3: $typ $val\n");
               if (($typ eq "CONC") || ($typ eq "CONT")) {
                   Dprint("c","Found in level 3: $lev0typ $lev1typ $lev2typ $typ\n");
               } elsif ($typ eq "NOTE") {
                   Dprint("n","Found in level 3: $lev0typ $lev1typ $lev2typ $typ\n");
               } 
               if ($lev2typ eq "SOUR") {
                   Dprint("s","Ignoring level 3 because level 2 type is SOUR\n");
               } elsif ($lev1typ eq "_TODO") {
                   Dprint("s","Ignoring in level 3: $lev0typ $lev1typ $lev2typ $typ\n");
               } elsif ($typ eq "ROLE") {
                   Dprint("s","Ignoring in level 3: $lev0typ $lev1typ $lev2typ $typ\n");
               } elsif ($typ eq "CONC") {
                   # so far CONC and CONT in level 3 are all for event type notes
                   if ($lev1typ eq "EVEN") {
                      if ($lev2typ eq "NOTE") {
                          $eventnote{$key,$numevents}=$eventnote{$key,$numevents} . $val;
                      }
                   } elsif ($lev1typ eq "BIRT") { 
                       $birthnote{$key}=$birthnote{$key} . $val;
                   } elsif ($lev1typ eq "CHR") { 
                       $chrnote{$key}=$chrnote{$key} . $val;
                   } elsif ($lev1typ eq "DEAT") { 
                       $deathnote{$key}=$deathnote{$key} . $val;
                   } elsif ($lev1typ eq "BURI") { 
                       $burnote{$key}=$burnote{$key} . $val;
                   } else {
                       print "Unhandled level 3 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif ($typ eq "CONT") {
                   if ($lev1typ eq "EVEN") {
                      if ($lev2typ eq "NOTE") {
                          $eventnote{$key,$numevents}=$eventnote{$key,$numevents} . "\n" . $val;
                      }
                   } elsif ($lev1typ eq "BIRT") { 
                       $birthnote{$key}=$birthnote{$key} . "\n" . $val;
                   } elsif ($lev1typ eq "CHR") { 
                       $chrnote{$key}=$chrnote{$key} . "\n" . $val;
                   } elsif ($lev1typ eq "DEAT") { 
                       $deathnote{$key}=$deathnote{$key} . "\n" . $val;
                   } elsif ($lev1typ eq "BURI") { 
                       $burnote{$key}=$burnote{$key} . "\n" . $val;
                   } else {
                       print "Unhandled level 4 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif ($lev1typ eq "CHAN") {
                   if ($typ eq "TIME") {
                       $chgtime{$key}=$val;
                   } 
               } elsif ($lev1typ eq "BIRT") {
                   if ($lev2typ eq "ADDR") {
                       if ($typ eq "NOTE") {
                           $birthaddrnote{$key}=$val;
                       }
                   }
               } elsif ($lev1typ eq "CHR") {
                   if ($lev2typ eq "ADDR") {
                       if ($typ eq "NOTE") {
                           $chraddrnote{$key}=$val;
                       }
                   }
               } elsif ($lev1typ eq "DEAT") {
                   if ($lev2typ eq "ADDR") {
                       if ($typ eq "NOTE") {
                           $deathaddrnote{$key}=$val;
                       }
                   }
               } elsif ($lev1typ eq "BURI") {
                   if ($lev2typ eq "ADDR") {
                       if ($typ eq "NOTE") {
                           $buraddrnote{$key}=$val;
                       }
                   }
               }
# INDI Level 4 processing
           } elsif ($lev eq "4") {
               $lev4typ=$typ;
               Dprint(4,"Level 4: $typ $val\n");
               if (($typ eq "CONC") || ($typ eq "CONT")) {
                   Dprint("c","Found in level 4: $lev0typ $lev1typ $lev2typ $lev3typ $typ\n");
               } elsif ($typ eq "NOTE") {
                   Dprint("n","Found in level 4: $lev0typ $lev1typ $lev2typ $lev3typ $typ\n");
               }
               if ($lev2typ eq "SOUR") {
                   Dprint("s","Ignoring level 4 because level 2 type is SOUR\n");
               } elsif (($typ eq "CONC") && ($lev2typ eq "ADDR")) {
                   # currently handle CONC and CONT in level 4 only for addr notes 
                   if ($lev1typ eq "BIRT") { 
                       $birthaddrnote{$key}=$birthaddrnote{$key} . $val;
                   } elsif ($lev1typ eq "CHR") { 
                       $chraddrnote{$key}=$chraddrnote{$key} . $val;
                   } elsif ($lev1typ eq "DEAT") { 
                       $deathaddrnote{$key}=$deathaddrnote{$key} . $val;
                   } elsif ($lev1typ eq "BURI") { 
                       $buraddrnote{$key}=$buraddrnote{$key} . $val;
                   } else {
                       print "Unhandled level 4 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif (($typ eq "CONT") && ($lev2typ eq "ADDR")) {
                   if ($lev1typ eq "BIRT") { 
                       $birthaddrnote{$key}=$birthaddrnote{$key} . "\n" . $val;
                   } elsif ($lev1typ eq "CHR") { 
                       $chraddrnote{$key}=$chraddrnote{$key} . "\n" . $val;
                   } elsif ($lev1typ eq "DEAT") { 
                       $deathaddrnote{$key}=$deathaddrnote{$key} . "\n" . $val;
                   } elsif ($lev1typ eq "BURI") { 
                       $buraddrnote{$key}=$buraddrnote{$key} . "\n" . $val;
                   } else {
                       print "Unhandled level 4 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif (($lev1typ eq "BURI") && ($lev2typ eq "ADDR")) {
                   if ($typ eq "LATI") {
                       $burlati{$key}=$val;
                   } elsif ($typ eq "LONG") {
                       $burlong{$key}=$val;
                   }
               } else {
                   print "Unhandled level 4 entry at line $cntr: $typ $val\n";
                   if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
               }
           } else {
               if ($lev2typ eq "SOUR") {
                   Dprint("s","Ignoring level $lev because level 2 type is SOUR\n");
               } else {
                   print "Unhandled level $lev entry at line $cntr: $typ $val\n";
                   if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
               }
           }
       } elsif ($lev0typ eq "FAM") {
# FAM Level 1 processing
           if ($lev eq "1") {
               $lev1typ=$typ;
               Dprint(1,"Level 1: $typ $val\n");
               if ($lev0notenum > 0) {
                   if ($typ eq "CONC") {
                       $lev0note{$key,$lev0notenum}=$lev0note{$key,$lev0notenum} . $val;
                   } elsif ($typ eq "CONT") {
                       $lev0note{$key,$lev0notenum}=$lev0note{$key,$lev0notenum} . "\n" . $val;
                   } else {
                       print "Unhandled level 1 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif ($typ eq "HUSB") {
                   $husbkey{$key}=$val;
               } elsif ($typ eq "WIFE") {
                   $wifekey{$key}=$val;
               } elsif ($typ eq "_STAT") {
                   $marstat{$key}=$val;
               } elsif ($typ eq "MARR") {
               } elsif ($typ eq "_MARRIED") {
               } elsif ($typ eq "CHIL") {
                   $numchild=$numchild+1;
                   $childkey{$key,$numchild}=$val;
               } elsif ($typ eq "_NONE") {  # No children
                   if ($numchild > 0) {
                      print "Number of children for family $key is $numchild\n";
                      die "Invalid level 1 entry at line $cntr: $typ $val, aborting\n";
                   } 
               } elsif ($typ eq "MARL") {   # Marriage License
                   $lev1evtyp="Marriage License";
                   $lev1typ="EVEN";
                   $typ="EVEN";
               } elsif ($typ eq "EVEN") {
                   $lev1evtyp="Unknown";
               } elsif ($typ eq "CHAN") {
               } else {
                   print "Unhandled level 1 entry at line $cntr: $typ $val\n";
                   if ($test == 0) { die "Aborting due to unhandeled entry in $gedfile file\n"; }
               }
               if ($typ eq "EVEN") {
                   # level 1 EVEN processing
                   $numevents=$numevents+1;
                   $eventnum{$key}=$numevents;
                   $eventtype{$key,$numevents}=$lev1evtyp;
                   $eventdesc{$key,$numevents}=$val;
                   $eventdate{$key,$numevents}="";
                   $eventage{$key,$numevents}="";
                   $eventplace{$key,$numevents}="";
                   $eventnote{$key,$numevents}="";
                   $eventdescplacenote{$key,$numevents}="";
               }
           } elsif ($lev eq "2") {
# FAM Level 2 processing
               $lev2typ=$typ;
               Dprint(2,"Level 2: $typ $val\n");
               if (($typ eq "CONC") || ($typ eq "CONT")) {
                   Dprint("c","Found in level 2: $lev0typ $lev1typ $typ\n");
               } elsif ($typ eq "NOTE") {
                   Dprint("n","Found in level 2: $lev0typ $lev1typ $typ\n");
               }
               if ($typ eq "SOUR") {
                   Dprint("s","Found in level 2: $lev0typ $lev1typ $typ\n");
               } elsif ($typ eq "CONC") {
                   if ($lev1typ eq "EVEN") {
                      if ($lev2typ eq "NOTE") {
                          $eventnote{$key,$numevents}=$eventnote{$key,$numevents} . $val;
                      }
                   } else {
                       print "Unhandled level 3 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif ($typ eq "CONT") {
                   if ($lev1typ eq "EVEN") {
                      if ($lev2typ eq "NOTE") {
                          $eventnote{$key,$numevents}=$eventnote{$key,$numevents} . "\n" . $val;
                      }
                   } else {
                       print "Unhandled level 2 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif ($lev1typ eq "HUSB") {
                   if ($typ eq "_PREF") {
                       $husbpref{$key}=$val;
                   }
               } elsif ($lev1typ eq "WIFE") {
                   if ($typ eq "_PREF") {
                       $wifepref{$key}=$val;
                   }
               } elsif ($lev1typ eq "CHIL") {
                   if ($typ eq "_PREF") {
                       # Assume only one child in a family is preferred 
                       if ($childpref{$key} ne "") {
                          print "Family $key has preferred child $childpref{$key}\n";
                          print "Invalid level 2 entry at line $cntr: $typ $val\n";
                          if ($test == 0) { die "Aborting due to invalid entry in $gedfile file\n"; }
                       } else {
                          $childpref{$key}=$childkey{$key,$numchild};
                       }
                   } 
               } elsif ($lev1typ eq "MARR") {
                   if ($typ eq "DATE") {
                       $mardate{$key}=$val;
                   } elsif ($typ eq "PLAC") {
                       $marplace{$key}=$val;
                       Doplac($husbkey{$key},"4MARR",$val);
                       Doplac($wifekey{$key},"4MARR",$val);
                   } elsif ($typ eq "ADDR") {
                       $buraddr{$key}=$val;
                   }
               } elsif ($lev1typ eq "_STAT") {
                   if ($typ eq "DATE") {
                       $statdate{$key}=$val;
                   }
               } elsif ($lev1typ eq "EVEN") {
                   if ($typ eq "TYPE") {
                       Dprint("e","Event type $val set for $key event number $numevents\n"); 
                       $eventtype{$key,$numevents}=$val;
                   } elsif ($typ eq "NOTE") {
                       $eventnote{$key,$numevents}=$val;
                   } elsif ($typ eq "PLAC") {
                       $eventplace{$key,$numevents}=$val;
                       Doplac($husbkey{$key},"5MAEV",$val);
                       Doplac($wifekey{$key},"5MAEV",$val);
                   } elsif ($typ eq "DATE") {
                       $eventdate{$key,$numevents}=$val;
                   } else {
                       print "Unhandled level 2 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandeled entry in $gedfile file\n"; }
                   }
               } elsif ($lev1typ eq "CHAN") {
                   if ($typ eq "DATE") {
                       $chgdate{$key}=$val;
                   } 
               } 
           } elsif ($lev eq "3") {
# FAM Level 3 processing
               $lev3typ=$typ;
               Dprint(3,"Level 3: $typ $val\n"); 
               if ($lev2typ eq "SOUR") {
                   Dprint("s","Ignoring level 3 because level 2 type is SOUR\n");
               } elsif ($typ eq "SOUR") {
                   Dprint("s","Found in level 3: $lev0typ $lev1typ $lev2typ $typ\n");
               } elsif ($typ eq "CONC") {
                   # so far CONC and CONT in level 3 are all for event type notes
                   if ($lev1typ eq "EVEN") {
                      if ($lev2typ eq "NOTE") {
                          $eventnote{$key,$numevents}=$eventnote{$key,$numevents} . $val;
                      }
                   } else {
                       print "Unhandled level 3 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif ($typ eq "CONT") {
                   if ($lev1typ eq "EVEN") {
                      if ($lev2typ eq "NOTE") {
                          $eventnote{$key,$numevents}=$eventnote{$key,$numevents} . "\n" . $val;
                      }
                   } else {
                       print "Unhandled level 4 entry at line $cntr: $typ $val\n";
                       if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
                   }
               } elsif ($lev1typ eq "CHAN") {
                   if ($typ eq "TIME") {
                       $chgtime{$key}=$val;
                   } 
               } elsif ($lev1typ eq "MARR") {
                   if ($typ eq "_HTITL") {
                       $husbtitl{$key}=$val;
                   } elsif ($typ eq "_WTITL") {
                       $wifetitl{$key}=$val;
                   } 
               }
           } else {
               if (($lev2typ eq "SOUR") || ($lev3typ eq "SOUR")) {
                   Dprint("s","Ignoring level $lev because level 2 type is SOUR\n");
               } else {
                   print "Unhandled level $lev entry at line $cntr: $typ $val\n";
                   if ($test == 0) { die "Aborting due to unhandled entry in $gedfile file\n"; }
               }
           }
       }
}
close GED;
close PLAC;
Processlev0();
Checkinds();
Processfams();
Genhtmlfiles();
Genkeydatafiles();

print "Done\n"; 

if ($debug ne " ") {
    close DOUT;
}
exit;

sub Doplac {
    my $plackey=$_[0];
    my $plactyp=$_[1];
    my $placdata=$_[2];
    my $placdate="";
    my $placevtyp="";
    if ($plactyp eq "1BIRT") {
       if (exists $birthdate{$key}) {
          $placdate=$birthdate{$key};
       }
    } elsif ($plactyp eq "2CHR") {
       if (exists $chrdate{$key}) {
          $placdate=$chrdate{$key};
       }
    } elsif ($plactyp eq "6DEAT") {
       if (exists $deathdate{$key}) {
          $placdate=$deathdate{$key};
       }
    } elsif ($plactyp eq "7BURI") {
       if (exists $burdate{$key}) {
          $placdate=$burdate{$key};
       }
    } elsif ($plactyp eq "3EVEN") {
       if (exists $eventdate{$key,$numevents}) {
          $placdate=$eventdate{$key,$numevents};
       }
       if (exists $eventtype{$key,$numevents}) {
          $placevtyp=$eventtype{$key,$numevents};
       }
    } elsif ($plactyp eq "4MARR") {
       if (exists $mardate{$key}) {
          $placdate=$mardate{$key};
       }
    } elsif ($plactyp eq "5MAEV") {
       if (exists $eventdate{$key,$numevents}) {
          $placdate=$eventdate{$key,$numevents};
       }
       if (exists $eventtype{$key,$numevents}) {
          $placevtyp=$eventtype{$key,$numevents};
       }
    }
    $placevtyp=uc($placevtyp);
    $placdata=~s/, /,/g;       # remove space after commas
    PrintPLAC("$plackey $plactyp $placevtyp $placdate :#$placdata\n");
}

sub PrintPLAC {
    my $poutdata=$_[0];
    print PLAC "$poutdata";
}

sub Initind {
    $altcolor{$key}="blue";
    $birthcolor{$key}="blue";
    $chrcolor{$key}="blue";
    $deathcolor{$key}="blue";
    $burcolor{$key}="blue";
    $notecolor{$key}="blue";
    $sex{$key}="";
    $sexcolor{$key}="";
    $uid{$key}="";
    $ixgiven{$key}="";
    $ixsurname{$key}="";
    $birthdate{$key}="";
    $birthage{$key}="";
    $birthplace{$key}="";
    $birthaddr{$key}="";
    $birthaddrnote{$key}="";
    $birthnote{$key}="";
    $chrdate{$key}="";
    $chrage{$key}="";
    $chrplace{$key}="";
    $chraddr{$key}="";
    $chraddrnote{$key}="";
    $chrnote{$key}="";
    $dead{$key}="";
    $deathdate{$key}="";
    $deathage{$key}="";
    $deathplace{$key}="";
    $deathaddr{$key}="";
    $deathaddrnote{$key}="";
    $deathnote{$key}="";
    $deathcause{$key}="";
    $burdate{$key}="";
    $burplace{$key}="";
    $buraddr{$key}="";
    $buraddrnote{$key}="";
    $burnote{$key}="";
    $burcrem{$key}="";
    $burlati{$key}="";
    $burlong{$key}="";
    $cemeteryname{$key}="";
    $cemeterynote{$key}="";
    $lev1note{$key}="";
    $indstat{$key}="";
    $indfamc{$key,1}="";
    $preffamkey{$key}="";
    $famlink{$key}=""; 
    $fsftid{$key}="";
    $fslink{$key}="";
    $fgrave{$key}="";
    $fglink{$key}="";
    $chgdate{$key}="";
    $chgtime{$key}="";
    $rinorder{$key}=0;
    $surnameorder{$key}=0;
    $givenorder{$key}=0;
}

sub Initfam {
    $chgdate{$key}="";
    $chgtime{$key}="";
    $husbkey{$key}="";
    $wifekey{$key}="";
    $husbpref{$key}="";
    $wifepref{$key}="";
    $husbtitl{$key}="Husband";
    $wifetitl{$key}="Wife";
    $mardate{$key}="";
    $marplace{$key}="";
    $marstat{$key}="";
    $statdate{$key}="";
    $childpref{$key}="";
    $husbfathhref{$key}="";
    $husbfather{$key}=" ";
    $husbmothhref{$key}="";
    $husbmother{$key}=" ";
    $wifefathhref{$key}="";
    $wifefather{$key}=" ";
    $wifemothhref{$key}="";
    $wifemother{$key}=" ";
    $husbhref{$key}="";
    $husbfullname{$key}=" ";
    $husbbirthdateplace{$key}="";
    $husbchrdateplace{$key}="";
    $husbdeathdateplace{$key}="";
    $husbburdateplace{$key}="";
    $husbdeathcause{$key}="";  
    $husbnumspouses{$key}="";
    $husbspouselink{$key}="";
    $husbspousename{$key}="";
    $husbfglink{$key}="";
    $husbfgid{$key}="";
    $wifehref{$key}="";
    $wifefullname{$key}=" ";
    $wifebirthdateplace{$key}="";
    $wifechrdateplace{$key}="";
    $wifedeathdateplace{$key}="";
    $wifeburdateplace{$key}="";
    $wifedeathcause{$key}="";  
    $wifenumspouses{$key}="";
    $wifespouselink{$key}="";
    $wifespousename{$key}="";
    $wifefglink{$key}="";
    $wifefgid{$key}="";
    $mardateinplace{$key}="";
    $marwin{$key}="";
    $mardateplace{$key}="";
}

sub Processlev0 {
    if ($lev0typ eq "INDI") {
        Dprint("i","\nProcessing INDI\n"); 
        Dprint("i","For RIN: $rin{$key}\n");
        Dprint("i","Sex: $sex{$key}\n");
        Dprint("i","Sex color: $sexcolor{$key}\n");
        Dprint("i","Number of names: $numnames\n");
        $altnum{$key}=$numnames;
        $altnames{$key}="";
        $i=1;
        while ($i <= $numnames) {
           Dprint("i","Name prefix: $nameprefix{$key,$i}\n");
           Dprint("i","Given name: $givenname{$key,$i}\n");
           Dprint("i","Surname: $surname{$key,$i}\n");
           Dprint("i","Name suffix: $namesuffix{$key,$i}\n");
           # Compose fullname
           if (($surname{$key,$i} eq "") && ($givenname{$key,$i} eq "")) {
               $fullname{$key,$i}="Unknown";
           } elsif ($surname{$key,$i} eq "") {
               $fullname{$key,$i}=$givenname{$key,$i};
           } elsif ($givenname{$key,$i} eq "") {
               $fullname{$key,$i}=$surname{$key,$i};
           } else {
               $fullname{$key,$i}=$givenname{$key,$i} . " " . $surname{$key,$i};
           }               
           if ($nameprefix{$key,$i} ne "") {           
               $fullname{$key,$i}=$nameprefix{$key,$i} . " " . $fullname{$key,$i};
           }
           if ($namesuffix{$key,$i} ne "") {           
               $fullname{$key,$i}=$fullname{$key,$i} . " " . $namesuffix{$key,$i};
           }
           if ($i == 2) {
               $altnames{$key}=$fullname{$key,$i};
           } elsif ($i > 2) {
               $altnames{$key}=$altnames{$key} . "\n" . $fullname{$key,$i};
           }
           $i=$i+1;
        } 
        # Compose index given name
        if (($surname{$key,1} eq "") && ($givenname{$key,1} eq "")) {
            $ixgiven{$key}="UNKNOWN";
        } elsif ($surname{$key,1} eq "") {
            $ixgiven{$key}=$givenname{$key,1};
        } elsif ($givenname{$key,1} eq "") {
            $ixgiven{$key}=$surname{$key,1};
        } else {
            $ixgiven{$key}=$givenname{$key,1} . ", " . $surname{$key,1};
        }               
        if ($nameprefix{$key,1} ne "") {           
            $ixgiven{$key}=$ixgiven{$key} . " " . $nameprefix{$key,1};
        }
        if ($namesuffix{$key,1} ne "") {           
           $ixgiven{$key}=$ixgiven{$key} . " " . $namesuffix{$key,1};
        }
        # Compose index surname
        if (($surname{$key,1} eq "") && ($givenname{$key,1} eq "")) {
            $ixsurname{$key}="UNKNOWN";
        } elsif ($surname{$key,1} eq "") {
            $ixsurname{$key}=$givenname{$key,1};
        } elsif ($givenname{$key,1} eq "") {
            $ixsurname{$key}=$surname{$key,1};
        } else {
            $ixsurname{$key}=$surname{$key,1} . ", " . $givenname{$key,1};
        }               
        if ($nameprefix{$key,1} ne "") {           
            $ixsurname{$key}=$ixsurname{$key} . " " . $nameprefix{$key,1};
        }
        if ($namesuffix{$key,1} ne "") {           
            $ixsurname{$key}=$ixsurname{$key} . " " . $namesuffix{$key,1};
        }
        # Calculate year date range to add to fullname
        $i=Calcyear($birthdate{$key});
        $j=Calcyear($deathdate{$key});
        if (($i eq "") && ($j eq "")) {
           $work="";
        } else {
           $work=" ($i-$j)";
        }
        $fullnameplus{$key}=$fullname{$key,1} . $work;
        if ($deathcause{$key} ne "") { Dprint(9,"Death cause: $deathcause{$key}\n"); }

        # Resolve any notes that are keys
        if ($birthnote{$key} =~ /^@\w@$/) {
            $birthnote{$key}=Fixnote("birthnote",$birthnote{$key});
        }
        if ($chrnote{$key} =~ /^@\w@$/) {
            $chrnote{$key}=Fixnote("chrnote",$chrnote{$key});
        }
        if ($deathnote{$key} =~ /^@\w@$/) {
            $deathnote{$key}=Fixnote("deathnote",$deathnote{$key});
        }
        if ($burnote{$key} =~ /^@\w@$/) {
            $burnote{$key}=Fixnote("burnote",$burnote{$key});
        }
        if ($lev1note{$key} =~ /^@\w@$/) {
            $lev1note{$key}=Fixnote("lev1note",$lev1note{$key});
        }
        if ($birthaddrnote{$key} =~ /^@\w@$/) {
            $birthaddrnote{$key}=Fixnote("birthaddrnote",$birthaddrnote{$key});
        }
        if ($chraddrnote{$key} =~ /^@\w@$/) {
            $chraddrnote{$key}=Fixnote("chraddrnote",$chraddrnote{$key});
        }
        if ($deathaddrnote{$key} =~ /^@\w@$/) {
            $deathaddrnote{$key}=Fixnote("deathaddrnote",$deathaddrnote{$key});
        }
        if ($buraddrnote{$key} =~ /^@\w@$/) {
            $buraddrnote{$key}=Fixnote("buraddrnote",$buraddrnote{$key});
        }
        # Fix up burial notes to include cremated, longitude and latitude
        if ($burcrem{$key} ne "") {
           $burnote{$key}=$burnote{$key} . "\n" . $burcrem{$key};
        }
        if ($burlati{$key} ne "") {
           $buraddrnote{$key}=$buraddrnote{$key} . "\nLatitude: " . $burlati{$key};
        } 
        if ($burlong{$key} ne "") {
           $buraddrnote{$key}=$buraddrnote{$key} . "\nLongitude: " . $burlong{$key};
        }

        if ($altnames{$key} eq "") {
            $work="(none)";
        } else {
            $work=$altnames{$key};
            $altcolor{$key}="red";
        }
        $altdata{$key}=Genalert("Alternate Names",$work);
        if (($birthaddr{$key} eq "") && ($birthaddrnote{$key} eq "") && ($birthnote{$key} eq "")) {
            $work="(none)";
        } else {
            $work=""; 
            $birthcolor{$key}="red";
        }
        if ($birthaddr{$key} ne "") {
            $work="Address:\n$birthaddr{$key}\n\n";
        }  
        if ($birthaddrnote{$key} ne "") {
            $work=$work . "$birthaddrnote{$key}\n\n";
        }  
        if ($birthnote{$key} ne "") {
            $work=$work . "Note:\n$birthnote{$key}\n\n";
        }  
        $birthdata{$key}=Genalert("Birth Data",$work);
        if (($chraddr{$key} eq "") && ($chraddrnote{$key} eq "") && ($chrnote{$key} eq "")) {
            $work="(none)";
        } else {
            $work=""; 
            $chrcolor{$key}="red";
        }
        if ($chraddr{$key} ne "") {
            $work="Address:\n$chraddr{$key}\n\n";
        }  
        if ($chraddrnote{$key} ne "") {
            $work=$work . "$chraddrnote{$key}\n\n";
        }  
        if ($chrnote{$key} ne "") {
            $work=$work . "Note:\n$chrnote{$key}\n\n";
        }  
        $chrdata{$key}=Genalert("Christening Data",$work);
        if (($deathaddr{$key} eq "") && ($deathaddrnote{$key} eq "") && ($deathnote{$key} eq "")) {
            $work="(none)";
        } else {
            $work=""; 
            $deathcolor{$key}="red";
        }
        if ($deathaddr{$key} ne "") {
            $work="Address:\n$deathaddr{$key}\n\n";
        }  
        if ($deathaddrnote{$key} ne "") {
            $work=$work . "$deathaddrnote{$key}\n\n";
        }  
        if ($deathnote{$key} ne "") {
            $work=$work . "Note:\n$deathnote{$key}\n\n";
        }  
        $deathdata{$key}=Genalert("Death Data",$work);
        if (($buraddr{$key} eq "") && ($buraddrnote{$key} eq "") && ($burnote{$key} eq "")) {
            $work="(none)";
        } else {
            $work=""; 
            $burcolor{$key}="red";
        }
        if ($buraddr{$key} ne "") {
            $work="Address:\n$buraddr{$key}\n\n";
        }  
        if ($buraddrnote{$key} ne "") {
            $work=$work . "$buraddrnote{$key}\n\n";
        }  
        if ($burnote{$key} ne "") {
            $work=$work . "Note:\n$burnote{$key}\n\n";
        }  
        $burdata{$key}=Genalert("Burial Data",$work);
        if ($lev1note{$key} eq "") {
            $work="(none)";
        } else {
            $work=$lev1note{$key};
            $notecolor{$key}="red";
        }
        $notedata{$key}=Genalert("Notes",$work);

        $birthage{$key}=Calcage($birthdate{$key});
        $chrage{$key}=Calcage($chrdate{$key});
        $deathage{$key}=Calcage($deathdate{$key});
        Dprint("i","Number of events: $numevents\n");
        if ($numevents > 0) {
            $i=1;
            while ($i <= $numevents) {
                   $eventage{$key,$i}=Calcage($eventdate{$key,$i});
                   if ($eventnote{$key,$i} =~ /^@\w@$/) {
                       $eventnote{$key,$i}=Fixnote("eventnote",$eventnote{$key,$i});
                   }
                   if (($eventplace{$key,$i} ne "") && ($eventnote{$key,$i} ne "")) {
                       $eventdescplacenote{$key,$i}=$eventplace{$key,$i} . "/" . $eventnote{$key,$i};
                   } else {
                       $eventdescplacenote{$key,$i}=$eventplace{$key,$i} . $eventnote{$key,$i};
                   }
                   if (($eventdesc{$key,$i} ne "") && ($eventdescplacenote{$key,$i} ne "")) {
                       $eventdescplacenote{$key,$i}=$eventdesc{$key,$i} . "/" . $eventdescplacenote{$key,$i};
                   } else {
                       $eventdescplacenote{$key,$i}=$eventdesc{$key,$i} . $eventdescplacenote{$key,$i};
                   }
                   Dprint("9","eventdescplacenote{$key,$i}=$eventdescplacenote{$key,$i}\n");
                   $i=$i+1;
            } 
        }
        $indfamcnum{$key}=$numfamc;
        Dprint("i","Number of child families for individual $key is $numfamc\n");
        if ($numfamc > 0) {
            $i=0;
            while ($i < $numfamc) {
                   $i=$i+1;
                   Dprint("i","Child family: $indfamc{$key,$i}\n");
            } 
        } else {
            Dprint("i","No Child family for individual $key\n");
        }
        $indfamsnum{$key}=$numfams;
        Dprint("i","Number of families: $numfams\n");        
        if ($numfams > 0) {
            $i=0;
            while ($i < $numfams) {
                   $i=$i+1;
                   Dprint("i","Family: $indfams{$key,$i}\n");
            } 
        }
        if ($chgdate{$key} ne "") { Dprint(9,"Change date: $chgdate{$key}\n"); }
        if ($chgtime{$key} ne "") { Dprint(9,"Change time: $chgtime{$key}\n"); }
    } elsif ($lev0typ eq "FAM") {
        Dprint("f","\nProcessing FAM\n");
        Dprint("f","For family RIN: $famrin{$key}\n");
        Dprint("f","Husband RIN: $husbkey{$key}\n");
        Dprint("f","Wife: RIN: $wifekey{$key}\n");
        if ($numevents > 0) {
            $i=0;
            while ($i < $numevents) {
                   $i=$i+1;
                   if ($eventnote{$key,$i} =~ /^@\w@$/) {
                       $eventnote{$key,$i}=Fixnote("eventnote",$eventnote{$key,$i});
                   }
                   if (($eventplace{$key,$i} ne "") && ($eventnote{$key,$i} ne "")) {
                       $eventdescplacenote{$key,$i}=$eventplace{$key,$i} . "/" . $eventnote{$key,$i};
                   } else {
                       $eventdescplacenote{$key,$i}=$eventplace{$key,$i} . $eventnote{$key,$i};
                   }
                   if (($eventdesc{$key,$i} ne "") && ($eventdescplacenote{$key,$i} ne "")) {
                       $eventdescplacenote{$key,$i}=$eventdesc{$key,$i} . "/" . $eventdescplacenote{$key,$i};
                   } else {
                       $eventdescplacenote{$key,$i}=$eventdesc{$key,$i} . $eventdescplacenote{$key,$i};
                   }
                   Dprint("f","eventdescplacenote{$key,$i}=$eventdescplacenote{$key,$i}\n");
            } 
        }
        # Process children in the current family now
        $childkeynum{$key}=$numchild;
        Dprint("f","Number of children: $numchild\n");        
        if ($numchild > 0) {
            $i=0;
            while ($i < $numchild) {
                   $i=$i+1;
                   Dprint("f","Child RIN: $childkey{$key,$i}\n");
                   $j=$childkey{$key,$i};
                   if (exists($rin{$j})) {
                      $childfullname{$key,$i}=$fullnameplus{$j};
                      $childsexcolor{$key,$i}=$sexcolor{$j};
                      if ($indfamsnum{$j} == 0) { 
                         $indfams{$j,1}=Genfam($j);
                         # Since this is the only family for this individual it is preferred
                         $preffamkey{$j}=$indfams{$j,1};
                         $indfamsnum{$j}=1;
                      }
                      # Cannot use preferred family for this person because it is not found yet
                      $childfamkey{$key,$i}=$indfams{$j,1};
                   } else {
                      print "Unable to access Individual child record: $j\n"; 
                      if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                      $childsexcolor{$key,$i}="";
                      $childfamkey{$key,$i}="";
                      $childfullname{$key,$i}="";
                   }
                   $childdata{$key,$i}=$childfullname{$key,$i};
            } 
        }
        $allchildkeynum{$key}=$numchild;     # temporarary does not include half-siblings
        if ($chgdate{$key} ne "") { Dprint("f","Change date: $chgdate{$key}\n"); }
        if ($chgtime{$key} ne "") { Dprint("f","Change time: $chgtime{$key}\n"); }
    }
}

sub Genfam {
    my $gindkey=$_[0];
    Dprint("G","Generating family record for $gindkey $fullname{$gindkey,1}\n");
    $gseqno=$gindkey;
    $gseqno=~s/[^\d.]//g;       # digits only
    my $newkey="\@G" . $gseqno . "\@";
    if (exists($famrin{$newkey})) {
        print "Unable to generate family record $newkey because it already exists\n"; 
        die "Aborting due to inconsistent $gedfile file\n";
    }
    $savekey=$key;
    $key=$newkey;
    Initfam();
    $famrin{$key}=$key;
    $numerickey=$key;
    $numerickey=~s/[^[A-Z,0-9]//g;
    $numericrin{$key}=$numerickey; 
    $eventnum{$key}=0;
    $childkeynum{$key}=0;
    $allchildkeynum{$key}=0; 
    if ($sex{$gindkey} eq "Female") {
       # put on right/wifes side
       $wifekey{$key}=$gindkey;
    } else {
       # put on left/husbands side
       $husbkey{$key}=$gindkey;
    }
    $key=$savekey;
    return $newkey;
}

sub Checkinds {
    Dprint("C","\nChecking INDIs FAMs\n");
    foreach $key (keys %rin) {
        if ($altnum{$key} == 0) {
            print "Individual $key has no NAME record\n";
            if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
        }
        if ($indfamc{$key,1} eq "") {
            Dprint("C","Individual $key has no FAMC record\n");
        }
        if ($indfamsnum{$key} == 0) {
            Dprint("C","Individual $key has no FAMS record\n");
        } else {
            # Find preferred family for this individual
            if ($indfamsnum{$key} > 0) { 
               $i=0;
               while ($i < $indfamsnum{$key}) {
                  $i=$i+1;
                  $work=$indfams{$key,$i};      # Key of a individuals family file
                  if (exists($famrin{$work})) {
                     if ($sex{$key} eq "Male") { 
                        if ($wifepref{$work} eq "Y") {
                           Dprint("C","Setting preferred family to $work for husband $key\n");
                           $preffamkey{$key}=$work;
                        }
                     } elsif ($sex{$key} eq "Female") { 
                        if ($husbpref{$work} eq "Y") {
                           Dprint("C","Setting preferred family to $work for wife $key\n");
                           $preffamkey{$key}=$work;
                        }
                     }
                  } else {
                      print "In individual $key, unable to access Family record: $work\n"; 
                      if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                  }
               }
               if ($preffamkey{$key} eq "") {
                  Dprint("C","Did not find preferred family for individual $key\n");
                  $preffamkey{$key}=$indfams{$key,1};
               }
               $famlink{$key}="href=\"FAM$preffamkey{$key}.html\""; 
            } else {
               # If no families for individual just leave preffamkey and famlink empty
            }
        }
    }
}

sub Processfams {
    Dprint("f","\nProcessing FAMs\n");
    # Need to fill in fullnames for husband and wife first
    foreach $key (keys %famrin) {
        Dprint("f","For family RIN: $famrin{$key}\n");
        Dprint("f","Husband RIN: $husbkey{$key}\n");
        $hkey=$husbkey{$key};
        if ($hkey ne "") {
           if (exists($rin{$hkey})) {  
              $husbfullname{$key}=$fullname{$hkey,1};
           } else {
              print "In family $key, unable to access Individual record for husband: $hkey\n"; 
              if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
           }
        }
        Dprint("f","Wife: RIN: $wifekey{$key}\n");
        $wkey=$wifekey{$key};
        if ($wkey ne "") {
           if (exists($rin{$wkey})) {  
              $wifefullname{$key}=$fullname{$wkey,1};
           } else {
              print "In family $key, unable to access Individual record for wife: $wkey\n"; 
              if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
           }
        }
    }
    # Now work on the rest of the family data
    foreach $key (keys %famrin) {
        Dprint("f","For family RIN: $famrin{$key}\n");
        Dprint("f","Husband RIN: $husbkey{$key}\n");
        $hkey=$husbkey{$key};
        if ($hkey ne "") {
           if (exists($rin{$hkey})) {  
              $husbhref{$key}="href=\"IND$hkey.html\"";
              $husbfgid{$key}=$fgrave{$hkey};
              $husbfglink{$key}=$fglink{$hkey};
              $husbbirthdateplace{$key}=Getdateplace($birthdate{$hkey},$birthplace{$hkey},", ");
              $husbchrdateplace{$key}=Getdateplace($chrdate{$hkey},$chrplace{$hkey},", ");
              $husbdeathdateplace{$key}=Getdateplace($deathdate{$hkey},$deathplace{$hkey},", ");
              $husbburdateplace{$key}=Getdateplace($burdate{$hkey},$burplace{$hkey},", ");
              $husbdeathcause{$key}=$deathcause{$hkey};
              # Build table for spouse dropdown menu
              if ($indfamsnum{$hkey} > 0) { 
                 $husbnumspouses{$key}=$indfamsnum{$hkey};
                 $i=0;
                 while ($i < $husbnumspouses{$key}) {
                    $i=$i+1;
                    $work=$indfams{$hkey,$i};      # Key of a husbands family file
                    if (exists($famrin{$work})) {
                       $husbspouselink{$key,$i}="href=\"FAM$work.html\"";
                       $husbspousename{$key,$i}=$wifefullname{$work};
                       if ($wifepref{$work} eq "Y") {
                          $preffamkey{$hkey}=$work;
                       }
                       Addstepchildren($key,$work,$wifekey{$work});
                    } else {
                       print "In family $key, unable to access husbands Family record: $work\n"; 
                       if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                       $husbspouselink{$key,$i}="";
                       $husbspousename{$key,$i}="NOT FOUND";
                    }
                 }
              }
              $hpkey=$indfamc{$hkey,1};
              if ($hpkey ne "") {
                 if (exists($famrin{$hpkey})) {
                    $hfkey=$husbkey{$hpkey};
                    if ($hfkey ne "") {
                       if (exists($rin{$hfkey})) {
                          $husbfathhref{$key}="href=\"FAM$hpkey.html\"";
                          $husbfather{$key}=$fullnameplus{$hfkey};
                       } else {
                          print "In family $key, unable to access Individual record for husbands father: $hfkey\n"; 
                          if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                       } 
                    }
                    $hmkey=$wifekey{$hpkey};
                    if ($hmkey ne "") {
                       if (exists($rin{$hmkey})) {
                          $husbmothhref{$key}="href=\"FAM$hpkey.html\"";
                          $husbmother{$key}=$fullnameplus{$hmkey};
                       } else {
                          print "In family $key, unable to access Individual record for husbands mother: $hmkey\n"; 
                          if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                       } 
                    }
                 } else {
                    print "In family $key, unable to access Family record for husbands parents: $hpkey\n"; 
                    if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                 }
              }
           } else {
              print "In family $key, unable to access Individual record for husband: $hkey\n"; 
              if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
           }
        }
        Dprint("f","Wife: RIN: $wifekey{$key}\n");
        $wkey=$wifekey{$key};
        if ($wkey ne "") {
           if (exists($rin{$wkey})) {  
              $wifehref{$key}="href=\"IND$wkey.html\"";
              $wifefgid{$key}=$fgrave{$wkey};
              $wifefglink{$key}=$fglink{$wkey};
              $wifebirthdateplace{$key}=Getdateplace($birthdate{$wkey},$birthplace{$wkey},", ");
              $wifechrdateplace{$key}=Getdateplace($chrdate{$wkey},$chrplace{$wkey},", ");
              $wifedeathdateplace{$key}=Getdateplace($deathdate{$wkey},$deathplace{$wkey},", ");
              $wifeburdateplace{$key}=Getdateplace($burdate{$wkey},$burplace{$wkey},", ");
              $wifedeathcause{$key}=$deathcause{$wkey};
              # Build table for spouse dropdown menu
              if ($indfamsnum{$wkey} > 0) { 
                 $wifenumspouses{$key}=$indfamsnum{$wkey};
                 $i=0;
                 while ($i < $wifenumspouses{$key}) {
                    $i=$i+1;
                    $work=$indfams{$wkey,$i};      # Key of a wifes family file
                    if (exists($famrin{$work})) {
                       $wifespouselink{$key,$i}="href=\"FAM$work.html\"";
                       $wifespousename{$key,$i}=$husbfullname{$work};
                       if ($husbpref{$work} eq "Y") {
                          $preffamkey{$wkey}=$work;
                       }
                       Addstepchildren($key,$work,$husbkey{$work});
                    } else {
                       print "In family $key, unable to access wifes Family record: $work\n"; 
                       if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                       $wifespouselink{$key,$i}="";
                       $wifespousename{$key,$i}="NOT FOUND";
                    }
                 }
              }
              $wpkey=$indfamc{$wkey,1};
              if ($wpkey ne "") {
                 if (exists($famrin{$wpkey})) {
                    $wfkey=$husbkey{$wpkey};
                    if ($wfkey ne "") {
                       if (exists($rin{$wfkey})) {
                          $wifefathhref{$key}="href=\"FAM$wpkey.html\"";
                          $wifefather{$key}=$fullnameplus{$wfkey};
                       } else {
                          print "In family $key, unable to access Individual record for wifes father: $wfkey\n"; 
                          if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                       } 
                    }
                    $wmkey=$wifekey{$wpkey};
                    if ($wmkey ne "") {
                       if (exists($rin{$wmkey})) {
                          $wifemothhref{$key}="href=\"FAM$wpkey.html\"";
                          $wifemother{$key}=$fullnameplus{$wmkey};
                       } else {
                          print "In family $key, unable to access Individual record for wifes mother: $wmkey\n"; 
                          if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                       } 
                    }
                 } else {
                    print "In family $key, unable to access Family record for wifes parents: $wpkey\n"; 
                    if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                 }
              }
           } else {
              print "In family $key, unable to access Individual record for wife: $wkey\n"; 
              if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
           }
        }
        # Process marriage info
        $mardateplace{$key}=Getdateplace($mardate{$key},$marplace{$key}," - ");
        $mardateinplace{$key}=Getdateplace($mardate{$key},$marplace{$key}," in ");
        # Update the family for the children with the preferred family 
        $numchild=$childkeynum{$key};
        Dprint("P","Number of children: $numchild\n");        
        if ($numchild > 0) {
            $i=0;
            while ($i < $numchild) {
                   $i=$i+1;
                   Dprint("P","Child RIN: $childkey{$key,$i}\n");
                   $j=$childkey{$key,$i};
                   if (exists($rin{$j})) {
                      Dprint("P","Preferred family for individual $j is $preffamkey{$j}\n");
                      Dprint("P","First family for individual $j is $indfams{$j,1}\n");
                      $childfamkey{$key,$i}=$preffamkey{$j};
#                     $childfamkey{$key,$i}=$indfams{$j,1};
                   } else {
                      print "Unable to access Individual child record: $j\n"; 
                      if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
                   }
            } 
        }
    }
}

sub Addstepchildren() {
    my $scfam1=$_[0];
    my $scfam2=$_[1];
    my $scind2=$_[2];
    my $scspouse;
    # Add the step-children to this family 
    Dprint("k","Add step children from individual $scind2 in family $scfam2 to family $scfam1\n");
    my $scnum1=$childkeynum{$scfam1};
    my $scnum2=$childkeynum{$scfam2};
    # Get the given name of the spouse
    if (exists($rin{$scind2})) {
       $scspouse=" (" . $givenname{$scind2,1} . ")";
    } else {
       Dprint("k","Unable to access Individual spouse record $scind2 for family $scfam2\n"); 
       # if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
       $scspouse="";
    }
    if ($scfam1 ne $scfam2) {
       # Add the step children from this family
       if ($scnum2 > 0) {    
          my $sckey;
          my $sci=0;
          my $scj=$allchildkeynum{$scfam1};
          while ($sci < $scnum2) {
             $sci=$sci+1;
             $sckey=$childkey{$scfam2,$sci};
             if (exists($rin{$sckey})) {
                Dprint("k","Adding step-child $sckey from family $scfam2 to family $scfam1\n");
                $scj=$scj+1;
                $childdata{$scfam1,$scj}="½" . $fullnameplus{$sckey} . $scspouse;
                # character code for 1/2 is ½
                $childsexcolor{$scfam1,$scj}=$sexcolor{$sckey};
                # Use preferred family for this person
                $childfamkey{$scfam1,$scj}=$preffamkey{$sckey};
             } else {
                print "Unable to access Individual child record: $sckey\n"; 
                if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
             } 
          }
          $allchildkeynum{$scfam1}=$scj;     # Now includes the children and step-children
          Dprint("k","Now there are $scj children in family $scfam1\n");
       } else {
          Dprint("k","No children in family $scfam2\n");
       }
   }
}

sub Genhtmlfiles {
   if ($nogen == 0) {
      print "Generating IND HTML files ...\n";
   } else {
      print "Working on IND HTML files ...\n";
   }
   foreach $key (keys %rin) {
      $htmlfile="$htmldir/IND$key\.html";
      if ($nogen == 0) {
         open (HTML,">$htmlfile") or die "Can't open $htmlfile: $!";
         Dprint("I","Generating $htmlfile ...\n");
      } else {
         Dprint("I","Working on $htmlfile data ...\n");
      }
      $modfile="$modeldir/indmodel.html";
      open(MOD,"<$modfile") or die "Can't open $modfile: $!";
      Dprint("I","Reading $./modfile ...\n");
      $cntr=0;
      $eventstat=0;
      $eventlcnt=0;
      while (<MOD>) {
          s/\r[\n]*/\n/gm;  # get rid of carriage returns, we only want line feeds
          chomp;
          $line=$_;
          $cntr=$cntr+1;
          Dprint("i","$cntr: $line\n");
          if (($line =~ /^.+xXx/) || ($eventstat == 1)) {
             Dprint("I","Got xXx at line $cntr: $line\n");
             if ($line =~ /^.+xBEGINEVENTx/) {
                $eventstat=1;
             } elsif ($line =~ /^.+xENDEVENTx/) {
                $eventstat=2;
                Dprint("I","Event table has $eventlcnt lines\n");
                Dprint("I","Individual $key has $eventnum{$key} events\n");
                if ($eventnum{$key} > 0) {
                   $i=0;
                   while ($i < $eventnum{$key}) {
                      $i=$i+1;
                      $j=0;
                      while ($j < $eventlcnt) {
                         $j=$j+1;
                         $line=$eventltab[$j];
                         Dprint("I","Event model line: $line\n");
                         $line =~ s/xXxEVENTAGEx/$eventage{$key,$i}/;
                         $line =~ s/xXxEVENTTYPEx/$eventtype{$key,$i}/;
                         $line =~ s/xXxEVENTDATEx/$eventdate{$key,$i}/;
                         $line =~ s/xXxEVENTDESCPLACENOTEx/$eventdescplacenote{$key,$i}/;
                         PrintHTML("$line\n");
                         Dprint("I","Modified event table line: $line\n");
                      }
                   }
                }
             } elsif ($eventstat == 1) {
                # If in middle of event table create event table array
                $eventlcnt=$eventlcnt+1;
                $eventltab[$eventlcnt]=$line;
             } else {
                # Modify line and then write it
                $line =~ s/xXxRINx/$rin{$key}/;
                $line =~ s/xXxFAMLINKx/$famlink{$key}/;
                $line =~ s/xXxINDEXLINKx/href=\"IDXSurname.html\"/;
                $line =~ s/xXxIDESCLINKx/href=\"cgi-bin\/gendesc.cgi?ind=$key\"/;
                $line =~ s/xXxIANCLINKx/href=\"cgi-bin\/genanc.cgi?ind=$key\"/;
                $line =~ s/xXxIRELLINKx/href=\"cgi-bin\/genrel.cgi?ind=$key&sby=r\"/;
                $line =~ s/xXxFULLNAMEx/$fullname{$key,1}/;
                $line =~ s/xXxNUMERICRINx/$numericrin{$key}/;
                $line =~ s/xXxSURNAMEx/$surname{$key,1}/;
                $line =~ s/xXxGIVENNAMEx/$givenname{$key,1}/;
                $line =~ s/xXxNAMEPREFIXx/$nameprefix{$key,1}/;
                $line =~ s/xXxNAMESUFFIXx/$namesuffix{$key,1}/;
                $line =~ s/xXxALTCOLORx/$altcolor{$key}/;
                $line =~ s/xXxALTDATAx/$altdata{$key}/;
                $line =~ s/xXxSEXCOLORx/$sexcolor{$key}/;
                $line =~ s/xXxSEXx/$sex{$key}/;
                $line =~ s/xXxBIRTHDATEx/$birthdate{$key}/;
                $line =~ s/xXxBIRTHPLACEx/$birthplace{$key}/;
                $line =~ s/xXxBIRTHCOLORx/$birthcolor{$key}/;
                $line =~ s/xXxBIRTHDATAx/$birthdata{$key}/;
                $line =~ s/xXxBIRTHAGEx/$birthage{$key}/;
                $line =~ s/xXxCHRDATEx/$chrdate{$key}/;
                $line =~ s/xXxCHRPLACEx/$chrplace{$key}/;
                $line =~ s/xXxCHRCOLORx/$chrcolor{$key}/;
                $line =~ s/xXxCHRDATAx/$chrdata{$key}/;
                $line =~ s/xXxCHRAGEx/$chrage{$key}/;
                $line =~ s/xXxDEATHDATEx/$deathdate{$key}/;
                $line =~ s/xXxDEATHPLACEx/$deathplace{$key}/;
                $line =~ s/xXxDEATHCOLORx/$deathcolor{$key}/;
                $line =~ s/xXxDEATHDATAx/$deathdata{$key}/;
                $line =~ s/xXxDEATHAGEx/$deathage{$key}/;
                $line =~ s/xXxBURDATEx/$burdate{$key}/;
                $line =~ s/xXxBURPLACEx/$burplace{$key}/;
                $line =~ s/xXxBURCOLORx/$burcolor{$key}/;
                $line =~ s/xXxBURDATAx/$burdata{$key}/;
                $line =~ s/xXxDEATHCAUSEx/$deathcause{$key}/;
                $line =~ s/xXxNOTECOLORx/$notecolor{$key}/;
                $line =~ s/xXxNOTEDATAx/$notedata{$key}/;
                $line =~ s/xXxFSLINKx/$fslink{$key}/;
                $line =~ s/xXxFSFTIDx/$fsftid{$key}/;
                $line =~ s/xXxFGLINKx/$fglink{$key}/;
                $line =~ s/xXxFGRAVEx/$fgrave{$key}/;
                PrintHTML("$line\n");
                Dprint("I","Modified model line: $line\n");
             }
                
          } else {
             if (($eventstat == 0) || ($eventstat == 2)) {
                # If not inside event table just write line
                PrintHTML("$line\n");
                Dprint("I","Copy model line: $line\n");
             } else {
                # If in middle of event table create event table array
                $eventlcnt=$eventlcnt+1;
                $eventltab[$eventlcnt]=$line;
             } 
          }
      }
      close MOD;
      if ($nogen == 0) {
         close HTML;
      }
   }
   if ($nogen == 0) {
      print "Generating FAM HTML files ...\n";
   } else {
      print "Working on FAM HTML files ...\n";
   }
   foreach $key (keys %famrin) {
      $htmlfile="$htmldir/FAM$key\.html";
      if ($nogen == 0) {
         open (HTML,">$htmlfile") or die "Can't open $htmlfile: $!";
      }
      Dprint("F","######################################################## $key\n");
      if ($nogen == 0) {
         Dprint("F","Generating $htmlfile ...\n");
      } else {
         Dprint("F","Working on $htmlfile ...\n");
      }
      $modfile="$modeldir/fammodel.html";
      open(MOD,"<$modfile") or die "Can't open $modfile: $!";
      Dprint("F","Reading $modfile ...\n");
      $cntr=0;
      $eventstat=0;
      $eventlcnt=0;
      $childstat=0;
      $childlcnt=0;
      while (<MOD>) {
          s/\r[\n]*/\n/gm;  # get rid of carriage returns, we only want line feeds
          chomp;
          $line=$_;
          $cntr=$cntr+1;
          Dprint("F","$cntr: $line\n");
          if (($line =~ /^.+xXx/) || ($eventstat == 1) || ($childstat == 1)) {
             Dprint("F","Got xXx at line $cntr: $line\n");
             if ($line =~ /^.+xBEGINMARWINx/) {
                $eventstat=1;
             } elsif ($line =~ /^.+xENDMARWINx/) {
                $eventstat=2;
                Dprint("F","Marriage window table has $eventlcnt lines\n");
                Dprint("F","Family $key has $eventnum{$key} events\n");
                $work="";
                $j=0;
                while ($j < $eventlcnt) {
                   $j=$j+1;
                   $eline=$eventltab[$j];
                   Dprint("F","Looking at marriage table line $j: $eline\n");
                   if ($eline =~ /^.+xEVENTTABx/) {
                      $eline =~ s/<!--xXxEVENTLINEx-->//;
                      if ($eventnum{$key} > 0) {
                         Dprint("F","Modified marriage event table: $eline\n");
                         $eline =~ s/\n//g;    # Dont want any newlines
                         $work=$work . $eline;
                      }
                   } elsif ($eline =~ /^.+xEVENTLINEx/) {
                      if ($eventnum{$key} > 0) {
                         $i=0;
                         while ($i < $eventnum{$key}) {
                            $i=$i+1;
                            Dprint("F","eventdescplacenote{$key,$i}=$eventdescplacenote{$key,$i}\n");
                            $eline=$eventltab[$j];           # need to get it again
                            $eline =~ s/<!--xXxEVENTLINEx-->//;
                            Dprint("F","Marriage event model line: $eline\n");
                            $eline =~ s/xXxEVENTTYPEx/$eventtype{$key,$i}/;
                            $eline =~ s/xXxEVENTDATEx/$eventdate{$key,$i}/;
                            $eline =~ s/xXxEVENTDESCPLACENOTEx/$eventdescplacenote{$key,$i}/;
                            Dprint("F","Modified marriage event table line: $eline\n");
                            $eline =~ s/\n//g;    # Dont want any newlines
                            $work=$work . $eline;
                         }
                      }
                   } else {
                      $eline =~ s/xXxMARDATEINPLACEx/$mardateinplace{$key}/;
                      if ($eline =~ /^.+xMARSTATx/) {  
                         if ($marstat{$key} eq "") {
                            $eline="";         # Skip status line if empty
                         } else {
                            $eline =~ s/xXxMARSTATx/$marstat{$key}/;
                         }
                      }
                      if ($eline =~ /^.+xSTATDATEx/) {  
                         if ($statdate{$key} eq "") {
                            $eline="";         # Skip status line if empty
                         } else {
                            $eline =~ s/xXxSTATDATEx/$statdate{$key}/;
                         }
                      }
                      Dprint("F","Modified marriage table line: $eline\n");
                      $eline =~ s/\n//g;    # Dont want any newlines
                      $work=$work . $eline;
                   }
                }
                $marwin{$key}=Genwindow("Marriage Information",$work);
             } elsif ($eventstat == 1) {
                # If in middle of event table create event table array
                $eventlcnt=$eventlcnt+1;
                $eventltab[$eventlcnt]=$line;
             } elsif ($line =~ /^.+xBEGINCHILDx/) {
                $childstat=1;
             } elsif ($line =~ /^.+xENDCHILDx/) {
                $childstat=2;
                Dprint("F","Child table has $childlcnt lines\n");
                Dprint("F","Family $key has $allchildkeynum{$key} children\n");
               if ($allchildkeynum{$key} > 0) {
                   $i=0;
                   while ($i < $allchildkeynum{$key}) {
                      $i=$i+1;
                      if (($i == 5) || ($i == 9)) {
                         # Start a new column
                         Dprint("F","Start new child column\n");
                         PrintHTML("$newtablecolumn\n");
                      }
                      $j=0;
                      while ($j < $childlcnt) {
                         $j=$j+1;
                         $line=$childltab[$j];
                         Dprint("F","Child $i Event model line $j: $line\n");
                         $line =~ s/xXxCHILDSEQNOx/$i/;
                         $line =~ s/xXxCHILDCOLORx/$childsexcolor{$key,$i}/;
                         $line =~ s/xXxCHILDFAMKEYx/$childfamkey{$key,$i}/;
                         $line =~ s/xXxCHILDDATAx/$childdata{$key,$i}/;
                         PrintHTML("$line\n");
                         Dprint("F","Modified event table line: $line\n");
                      }
                   }
                } else {
                   Dprint("F","Indicate no children\n");
                   PrintHTML("$nochildren\n");                   
                }
             } elsif ($childstat == 1) {
                $work=$line;
                if ($work =~ /^xXxNEWTABLECOLUMNx/) {
                  $work =~ s/xXxNEWTABLECOLUMNx //;
                  $newtablecolumn=$work;
                } elsif ($work =~ /^xXxNOCHILDRENx/) {
                  $work =~ s/xXxNOCHILDRENx //;
                  $nochildren=$work;
                } else {  
                   # If in middle of child table create child table array
                   $childlcnt=$childlcnt+1;
                   $childltab[$childlcnt]=$line;
                }
             } elsif ($line =~ /^.+xHUSBSPOUSELINKx/) {
                   if ($husbnumspouses{$key} ne "") {
                      # Build dropdown menu for spouses
                      if ($husbnumspouses{$key} > 0) {
                         $i=0;
                         while ($i < $husbnumspouses{$key}) {
                            $i=$i+1;     
                            $work=$line; 
                            $work =~ s/xXxHUSBSPOUSELINKx/$husbspouselink{$key,$i}/;
                            $work =~ s/xXxHUSBSPOUSENAMEx/$husbspousename{$key,$i}/;
                            PrintHTML("$work\n");
                            Dprint("F","Modified dropdown model line: $work\n");
                         }
                      }
                   } 
             } elsif ($line =~ /^.+xWIFESPOUSELINKx/) {
                   if ($wifenumspouses{$key} ne "") {
                      # Build dropdown menu for spouses
                      if ($wifenumspouses{$key} > 0) {
                         $i=0;
                         while ($i < $wifenumspouses{$key}) {
                            $i=$i+1;     
                            $work=$line; 
                            $work =~ s/xXxWIFESPOUSELINKx/$wifespouselink{$key,$i}/;
                            $work =~ s/xXxWIFESPOUSENAMEx/$wifespousename{$key,$i}/;
                            PrintHTML("$work\n");
                            Dprint("F","Modified dropdown model line: $work\n");
                         }
                      }
                   }  
            } else {
                # Modify line and then write it
                $line =~ s/xXxNUMERICRINx/$numericrin{$key}/;
                $line =~ s/xXxINDEXLINKx/href=\"IDXSurname.html\"/;
                $line =~ s/xXxHDESCLINKx/href=\"cgi-bin\/gendesc.cgi?ind=$husbkey{$key}\"/;
                $line =~ s/xXxHANCLINKx/href=\"cgi-bin\/genanc.cgi?ind=$husbkey{$key}\"/;
                $line =~ s/xXxWDESCLINKx/href=\"cgi-bin\/gendesc.cgi?ind=$wifekey{$key}\"/;
                $line =~ s/xXxWANCLINKx/href=\"cgi-bin\/genanc.cgi?ind=$wifekey{$key}\"/;
                $line =~ s/xXxHUSBFATHHREFx/$husbfathhref{$key}/;
                $line =~ s/xXxHUSBFATHERx/$husbfather{$key}/;
                $line =~ s/xXxHUSBMOTHHREFx/$husbmothhref{$key}/;
                $line =~ s/xXxHUSBMOTHERx/$husbmother{$key}/;
                $line =~ s/xXxWIFEFATHHREFx/$wifefathhref{$key}/;
                $line =~ s/xXxWIFEFATHERx/$wifefather{$key}/;
                $line =~ s/xXxWIFEMOTHHREFx/$wifemothhref{$key}/;
                $line =~ s/xXxWIFEMOTHERx/$wifemother{$key}/;
                $line =~ s/xXxHUSBTITLx/$husbtitl{$key}/;
                $line =~ s/xXxHUSBHREFx/$husbhref{$key}/;
                $line =~ s/xXxHUSBFULLNAMEx/$husbfullname{$key}/;
                $line =~ s/xXxHUSBBIRTHDATEPLACEx/$husbbirthdateplace{$key}/;
                $line =~ s/xXxHUSBCHRDATEPLACEx/$husbchrdateplace{$key}/;
                $line =~ s/xXxHUSBDEATHDATEPLACEx/$husbdeathdateplace{$key}/;
                $line =~ s/xXxHUSBBURDATEPLACEx/$husbburdateplace{$key}/;
                $line =~ s/xXxHUSBDEATHCAUSEx/$husbdeathcause{$key}/;  
                $line =~ s/xXxHUSBNUMSPOUSESx/$husbnumspouses{$key}/;
                $line =~ s/xXxHUSBSPOUSENAMEx/$husbspousename{$key}/;
                $line =~ s/xXxHUSBFGLINKx/$husbfglink{$key}/;
                $line =~ s/xXxHUSBFGIDx/$husbfgid{$key}/;
                $line =~ s/xXxWIFETITLx/$wifetitl{$key}/;
                $line =~ s/xXxWIFEHREFx/$wifehref{$key}/;
                $line =~ s/xXxWIFEFULLNAMEx/$wifefullname{$key}/;
                $line =~ s/xXxWIFEBIRTHDATEPLACEx/$wifebirthdateplace{$key}/;
                $line =~ s/xXxWIFECHRDATEPLACEx/$wifechrdateplace{$key}/;
                $line =~ s/xXxWIFEDEATHDATEPLACEx/$wifedeathdateplace{$key}/;
                $line =~ s/xXxWIFEBURDATEPLACEx/$wifeburdateplace{$key}/;
                $line =~ s/xXxWIFEDEATHCAUSEx/$wifedeathcause{$key}/;  
                $line =~ s/xXxWIFENUMSPOUSESx/$wifenumspouses{$key}/;
                $line =~ s/xXxWIFEFGLINKx/$wifefglink{$key}/;
                $line =~ s/xXxWIFEFGIDx/$wifefgid{$key}/;
                $line =~ s/xXxMARDATEINPLACEx/$mardateinplace{$key}/;
                $line =~ s/xXxMARSTATx/$marstat{$key}/;
                $line =~ s/xXxMARWINx/$marwin{$key}/;
                $line =~ s/xXxMARDATEPLACEx/$mardateplace{$key}/;
                PrintHTML("$line\n");
                Dprint("F","Modified model line: $line\n");
             }
          } else {
             # Handle model lines that do not have xXx 
             if (($eventstat != 1) && ($childstat != 1)) {
                # If not inside event or child table just write line
                PrintHTML("$line\n");
                Dprint("F","Copy model line: $line\n");
             } elsif ($eventstat == 1) {
                   # If in middle of event table create event table array
                   $eventlcnt=$eventlcnt+1;
                   $eventltab[$eventlcnt]=$line;
             } elsif ($childstat == 1) {
                   # If in middle of child table create child table array
                   $eventlcnt=$eventlcnt+1;
                   $eventltab[$eventlcnt]=$line;
             } 
          }
      }
      close MOD;
      if ($nogen == 0) {
         close HTML;
      }
   } 

   if ($nogen == 0) {
      print "Generating Index HTML files ...\n";
   } else {
      print "Working on Index HTML files ...\n";
   }
   # Set up the final keys used for the sort
   # Put "junk" names at the end of the file using zzz
   foreach $key (keys %rin) {
      $surnamezzz{$key}=$surname{$key,1};
      if ($surnamezzz{$key} eq "") {
         $surnamezzz{$key}="zzz";
      }
      $givennamezzz{$key}=$givenname{$key,1}; 
      if ($givennamezzz{$key} eq "") {
         $givennamezzz{$key}="zzz";
      } elsif ($givennamezzz{$key} =~ /^\d.*/) {
         $givennamezzz{$key}="zzz" . $givennamezzz{$key};
      }

      # The birthdate key is composed of a year . month. day
      $bdateseq=Getsortdate($birthdate{$key});
      $birthdatezzz{$key}=$bdateseq;
      Dprint("z","Birthdate sort key for $key: $birthdatezzz{$key}\n");

      # The birthplace key is composed of a country . state . county. city. surname
      if ($birthplace{$key} ne "") {
         $bplaceloc1="";
         $bplaceloc2="";
         $bplaceloc3="";
         $bplaceloc4="";
         ($bplaceloc1,$bplaceloc2,$bplaceloc3,$bplaceloc4) = split(/,/,$birthplace{$key},4);
         if (!defined $bplaceloc1) { $bplaceloc1=""; }
         if (!defined $bplaceloc2) { $bplaceloc2=""; }
         if (!defined $bplaceloc3) { $bplaceloc3=""; }
         if (!defined $bplaceloc4) {
            $bplaceloc4="";
            if ($bplaceloc1 ne "Unknown") {
               print "Invalid birth place for $key $ixsurname{$key}: $birthplace{$key}\n";
            }
         }
         $bplaceloc= $bplaceloc4 . "," . $bplaceloc3 . "," . $bplaceloc2 . "," . $bplaceloc1;
      } else {
         $bplaceloc="zzz";
      }
      $birthplacezzz{$key}=$bplaceloc;
      Dprint("z","Birthplace sort key for $key: $birthplacezzz{$key}\n");

      # Validate the Christening places, not used for index files
      if ($chrplace{$key} ne "") {
         $cplaceloc1="";
         $cplaceloc2="";
         $cplaceloc3="";
         $cplaceloc4="";
         ($cplaceloc1,$cplaceloc2,$cplaceloc3,$cplaceloc4) = split(/,/,$chrplace{$key},4);
         if (!defined $cplaceloc1) { $cplaceloc1=""; }
         if (!defined $cplaceloc2) { $cplaceloc2=""; }
         if (!defined $cplaceloc3) { $cplaceloc3=""; }
         if (!defined $cplaceloc4) {
            $cplaceloc4="";
            if ($cplaceloc1 ne "Unknown") {
               print "Invalid Christening place for $key $ixsurname{$key}: $chrplace{$key}\n";
            }
         }
      }

      # Validate the Death places, not used for index files
      if ($deathplace{$key} ne "") {
         $dplaceloc1="";
         $dplaceloc2="";
         $dplaceloc3="";
         $dplaceloc4="";
         ($dplaceloc1,$dplaceloc2,$dplaceloc3,$dplaceloc4) = split(/,/,$deathplace{$key},4);
         if (!defined $dplaceloc1) { $dplaceloc1=""; }
         if (!defined $dplaceloc2) { $dplaceloc2=""; }
         if (!defined $dplaceloc3) { $dplaceloc3=""; }
         if (!defined $dplaceloc4) {
            $dplaceloc4="";
            if ($dplaceloc1 ne "Unknown") {
               print "Invalid death place for $key $ixsurname{$key}: $deathplace{$key}\n";
            }
         }
      }

      # The cemetery key is composed of a prefix . country . state . county. city. cemetery . surname
      # The prefix separates buried, cremations, unknown
      # If person is cremated "Cremated" string is in burnote and location of ashes may be in buraddr
      if ($burnote{$key} =~ /Cremated/) {
         $cemprefix="C";
         $cemeteryname{$key}="Cremated";
         $cemeterynote{$key}=$buraddr{$key};
      } elsif (($burplace{$key} eq "") && ($buraddr{$key} eq "") && ($buraddrnote{$key} eq "") && ($burnote{$key} eq "")) {
         $cemprefix="U";
      } else {
         $cemprefix="B";
         if ($buraddr{$key} ne "") {
             $cemeteryname{$key}=$buraddr{$key};
             if (($buraddrnote{$key} ne "") && ($burnote{$key} ne "")) {
                $cemeterynote{$key}=$buraddrnote{$key} . " " . $burnote{$key} ;
             } elsif ($buraddrnote{$key} ne "") {
                $cemeterynote{$key}=$buraddrnote{$key};
             } elsif ($burnote{$key} ne "") {
                $cemeterynote{$key}=$burnote{$key};
             }
             $cemprefix= $cemprefix . "K";
         } elsif ($buraddrnote{$key} ne "") {
             $cemeteryname{$key}=$buraddrnote{$key};
             $cemprefix= $cemprefix . "K";
         } else {
             $cemeteryname{$key}="Unknown";
             $cemprefix= $cemprefix . "U";
         }
      }
      if ($burplace{$key} ne "") {
         $cemloc1="";
         $cemloc2="";
         $cemloc3="";
         $cemloc4="";
         ($cemloc1,$cemloc2,$cemloc3,$cemloc4) = split(/,/,$burplace{$key},4);
         if (!defined $cemloc1) { $cemloc1=""; }
         if (!defined $cemloc2) { $cemloc2=""; }
         if (!defined $cemloc3) { $cemloc3=""; }
         if (!defined $cemloc4) {
            $cemloc4="";
            if ($cemloc1 ne "Unknown") {
               print "Invalid burial place for $key $ixsurname{$key}: $burplace{$key}\n";
            }
         }
         $cemloc= $cemloc4 . "," . $cemloc3 . "," . $cemloc2 . "," . $cemloc1;
      } else {
         $cemloc="";
      }
      $cemeterynamezzz{$key}=$cemprefix . $cemloc . $cemeteryname{$key};
      Dprint("z","Cemetery sort key for $key: $cemeterynamezzz{$key}\n");
   }

   @keysbyrin=sort(Sortbyrin keys(%rin));
   @keysbysurname=sort(Sortbysurname keys(%rin));
   @keysbygivenname=sort(Sortbygivenname keys(%rin));
   @keysbybirthdate=sort(Sortbybirthdate keys(%rin));
   @keysbybirthplace=sort(Sortbybirthplace keys(%rin));
   @keysbycemeteryname=sort(Sortbycemeteryname keys(%rin));

   Dprint("s","\nbyrin\n");
   foreach $x (@keysbyrin) {
      Dprint("s","$x $numericrin{$x} $givenname{$x,1} $surname{$x,1}\n");
   }
   Dprint("s","\nbysurname\n");   
   foreach $x (@keysbysurname) {
      Dprint("s","$x $surname{$x,1} $givenname{$x,1}\n");
   }
   Dprint("s","\nbygivenname\n");
   foreach $x (@keysbygivenname) {
      Dprint("s","$x $givenname{$x,1} $surname{$x,1}\n");
   }
   Dprint("s","\nbybirthdate\n");
   foreach $x (@keysbybirthdate) {
      Dprint("s","$x $birthdate{$x} $surname{$x,1}\n");
   }
   Dprint("s","\nbybirthplace\n");
   foreach $x (@keysbybirthplace) {
      Dprint("s","$x $birthplace{$x} $surname{$x,1}\n");
   }
   Dprint("s","\nbycemeteryname\n");
   foreach $x (@keysbycemeteryname) {
      Dprint("s","$x $cemeteryname{$x} $surname{$x,1}\n");
   }
   Dprint("s","\n");

   foreach $ixtype ("RIN","Surname","Given","Bdate","Bplace","Cemetery","IDs") {
      $htmlfile="$htmldir/IDX$ixtype\.html";
      if ($nogen == 0) {
         open (HTML,">$htmlfile") or die "Can't open $htmlfile: $!";
      }
      Dprint("X","######################################################## $ixtype\n");
      if ($nogen == 0) {
         Dprint("X","Generating $htmlfile ...\n");
      } else {
         Dprint("X"."Working on $htmlfile ...\n");
      }
      if ($ixtype eq "Cemetery") {
         $modfile="$modeldir/idxcemmodel.html";
      } elsif ($ixtype eq "IDs") {
         $modfile="$modeldir/idxidsmodel.html";
      } else {
         $modfile="$modeldir/idxmodel.html";
      }
      open(MOD,"<$modfile") or die "Can't open $modfile: $!";
      Dprint("X","Reading $modfile ...\n");
      $cntr=0;
      $xlinestat=0;
      $xlinelcnt=0;
      while (<MOD>) {
          s/\r[\n]*/\n/gm;  # get rid of carriage returns, we only want line feeds
          chomp;
          $line=$_;
          $cntr=$cntr+1;
          Dprint("X","$cntr: $line\n");
          if (($line =~ /^.+xXx/) || ($xlinestat == 1)) {
             Dprint("X","Got xXx at line $cntr: $line\n");
             if ($line =~ /^.+xBEGININDEXLINEx/) {
                $xlinestat=1;
             } elsif ($line =~ /^.+xENDINDEXLINEx/) {
                $xlinestat=2;
                Dprint("X","Index line table has $xlinelcnt lines\n");
                if ($ixtype eq "RIN") {
                   $numixlines=@keysbyrin;
                } elsif ($ixtype eq "Surname") {
                   $numixlines=@keysbysurname;
                } elsif ($ixtype eq "Given") {
                   $numixlines=@keysbygivenname;
                } elsif ($ixtype eq "Bdate") {
                   $numixlines=@keysbybirthdate;
                } elsif ($ixtype eq "Bplace") {
                   $numixlines=@keysbybirthplace;
                } elsif ($ixtype eq "Cemetery") {
                   $numixlines=@keysbycemeteryname;
                } elsif ($ixtype eq "IDs") {
                   $numixlines=@keysbysurname;
                }    
                Dprint("X","$ixtype index has $numixlines lines\n");
               if ($numixlines > 0) {
                   # Note that this array starts with index 0
                   $i=0;
                   while ($i < $numixlines) {
                      if ($ixtype eq "RIN") {
                         $key=$keysbyrin[$i];
                         $rinorder{$key}=$i;
                      } elsif ($ixtype eq "Surname") {
                         $key=$keysbysurname[$i];
                         $surnameorder{$key}=$i;
                      } elsif ($ixtype eq "Given") {
                         $key=$keysbygivenname[$i];
                         $givenorder{$key}=$i;
                      } elsif ($ixtype eq "Bdate") {
                         $key=$keysbybirthdate[$i];
                         $surnameorder{$key}=$i;
                      } elsif ($ixtype eq "Bplace") {
                         $key=$keysbybirthplace[$i];
                         $surnameorder{$key}=$i;
                      } elsif ($ixtype eq "Cemetery") {
                         $key=$keysbycemeteryname[$i];
                         $surnameorder{$key}=$i;
                      } elsif ($ixtype eq "IDs") {
                         $key=$keysbysurname[$i];
                         $surnameorder{$key}=$i;
                      } 
                      Dprint("X","Sorted $ixtype key $i is $key\n");                     
                      $j=0;
                      while ($j < $xlinelcnt) {
                         $j=$j+1;
                         $line=$xlineltab[$j];
                         Dprint("X","Index line $i index table model line $j: $line\n");
                         if ($ixtype eq "Given") {
                            $ixname=$ixgiven{$key};
                         } else {
                            $ixname=$ixsurname{$key};
                         } 
                         if ($sex{$key} eq "Male") {
                            $ixsex="M";
                            $ixcolor="blue";
                         } elsif ($sex{$key} eq "Female") {
                            $ixsex="F";
                            $ixcolor="red";
                         } else {
                            $ixsex="U";
                            $ixcolor="black";
                         }

#                        Set up Ids index to search for FSIDs and FGIDs not yet filled in
                         $ixfglink=$fglink{$key};
                         $ixfgrave=$fgrave{$key};
                         $ixfslink=$fslink{$key};
                         $ixfsftid=$fsftid{$key};
                         if ($ixtype eq "IDs") {
                            if (($givenname{$key,1} ne "") && ($surname{$key,1} ne "") && ($dead{$key} ne "") && ($ixsex ne "U")) {
                               if ($ixfglink eq "") {
                                  ($valFN,$valrest)=split(/\s/,$givenname{$key,1},2);
                                  if (!defined $valFN) { $valFN=""; }
                                  $valLN=$surname{$key,1};
                                  $valBY=(split(/\s/,$birthdate{$key}))[-1];
                                  if (!defined $valBY) { $valBY=""; }
                                  $valDY=(split(/\s/,$deathdate{$key}))[-1];
                                  if (!defined $valDY) { $valDY=""; }
                                  if ($valDY eq "Yes") { $valDY=""; }
                                  $ixfglink=$searchfg;
                                  $ixfglink =~ s/xFNx/$valFN/;
                                  $ixfglink =~ s/xLNx/$valLN/;
                                  $ixfglink =~ s/xBYx/$valBY/;
                                  $ixfglink =~ s/xDYx/$valDY/;
                                  $ixfgrave=$atagdata;
                               }
                               if ($ixfslink eq "") {
                                  ($valGN,$valrest) = split(/\s/,$givenname{$key,1},2);
                                  if (!defined $valGN) { $valGN=""; }
                                  $valSN=$surname{$key,1};
                                  $valDT=(split(/\s/,$birthdate{$key}))[-1];
                                  if (!defined $valDT) { $valDT=""; }
                                  ($val1,$val2,$valPL,$val4)=split(/\,/,$birthplace{$key},4);
                                  if (!defined $valPL) { $valPL=""; }
                                  if ($valPL eq "") {
                                     ($val1,$val2,$valPL,$val4)=split(/\,/,$deathplace{$key},4);
                                     if (!defined $valPL) { $valPL=""; }
                                  }
                                  $ixfslink=$searchfs;
                                  $ixfslink =~ s/xGNx/$valGN/;
                                  $ixfslink =~ s/xSNx/$valSN/;
                                  $ixfslink =~ s/xDTx/$valDT/;
                                  $ixfslink =~ s/xPLx/$valPL/;
                                  $ixfsftid=$atagdata;
                               }
                            }
                         }
      
                         $line =~ s/xXxNUMERICRINx/$numericrin{$key}/;
                         $line =~ s/xXxFAMLINKx/$famlink{$key}/;
                         $line =~ s/xXxINDEXNAMEx/$ixname/;
                         $line =~ s/xXxSEXx/$ixsex/;
                         $line =~ s/xXxCOLORx/$ixcolor/g;
                         $line =~ s/xXxBIRTHDATEx/$birthdate{$key}/;
                         $line =~ s/xXxBIRTHPLACEx/$birthplace{$key}/;
                         $line =~ s/xXxDEATHDATEx/$deathdate{$key}/;
                         $line =~ s/xXxBURPLACEx/$burplace{$key}/;
                         $line =~ s/xXxCEMNAMEx/$cemeteryname{$key}/;
                         $line =~ s/xXxCEMNOTEx/$cemeterynote{$key}/;
                         $line =~ s/xXxFGLINKx/$ixfglink/;
                         $line =~ s/xXxFGRAVEx/$ixfgrave/;
                         $line =~ s/xXxFSLINKx/$ixfslink/;
                         $line =~ s/xXxFSFTIDx/$ixfsftid/;
                         PrintHTML("$line\n");
                         Dprint("X","Modified event table line: $line\n");
                      }
                      $i=$i+1;
                   }
                }
             } elsif ($xlinestat == 1) {
                # If in middle of index line table create index line table array
                $xlinelcnt=$xlinelcnt+1;
                $xlineltab[$xlinelcnt]=$line;
            } else {
                # Modify line and then write it
                $line =~ s/xXxINDEXTYPEx/$ixtype/;
                $line =~ s/xXxRININDEXx/href=\"IDXRIN.html\"/;
                $line =~ s/xXxSURNAMEx/href=\"IDXSurname.html\"/; 
                $line =~ s/xXxGIVENNAMEx/href=\"IDXGiven.html\"/;
                $line =~ s/xXxBDATEORDERx/href=\"IDXBdate.html\"/;
                $line =~ s/xXxBPLACEORDERx/href=\"IDXBplace.html\"/;
                $line =~ s/xXxCEMETERYx/href=\"IDXCemetery.html\"/;
                $line =~ s/xXxIDSx/href=\"IDXIDs.html\"/;
                PrintHTML("$line\n");
                Dprint("X","Modified model line: $line\n");
             }
          } else {
             # Handle model lines that do not have xXx 
             if ($xlinestat == 1) {
                   # If in middle of index line table create index line table array
                   $xlinelcnt=$xlinelcnt+1;
                   $xlineltab[$xlinelcnt]=$line;
             } else {
                # If not inside index line table just write line
                PrintHTML("$line\n");
                Dprint("X","Copy model line: $line\n");
             } 
          }
      }
      close MOD;
      if ($nogen == 0) {
         close HTML;
      }
   } 
}

sub Genkeydatafiles {
   if ($nogen == 0) {
      print "Generating key data files ...\n";
   } else {
      print "Working on key data files ...\n";
   }
   $indfile="$htmldir/indfile";
   if ($nogen == 0) {
      open (IND,">$indfile") or die "Can't open $indfile: $!";
      Dprint("D","Generating $indfile ...\n");
   } else {
      Dprint("D","Working on $indfile ...\n");
   }
   foreach $key (keys %rin) {
      $line=$key . " " . $indfamsnum{$key};
      $i=$indfamc{$key,1};                    # Only use first FAMC record 
      if ($i eq "") { $i="@@"; }
      $line=$line . " " . $i;
      if ($indfamsnum{$key} > 0) {
         $i=0;
         while ($i < $indfamsnum{$key}) {
            $i=$i+1;
            $line=$line . " " . $indfams{$key,$i};
         }
      }
      if ($nogen == 0) { print IND "$line\n"; }
   }
   if ($nogen == 0) {
      close IND;
   }
   $namfile="$htmldir/namfile";
   if ($nogen == 0) {
      open (NAM,">$namfile") or die "Can't open $namfile: $!";
      Dprint("D","Generating $namfile ...\n");
   } else {
      Dprint("D","Working on $namfile ...\n");
   }
   # namfile is in surname order
   $numixlines=@keysbysurname;
   $i=scalar(keys(%rin));
   if ($numixlines != $i) {
       print "$namfile should have $i entries but keysbysurname only has $numixlines entries\n";
       if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
   }      
   if ($numixlines > 0) {
       # Note that this array starts with index 0
       $i=0;
       while ($i < $numixlines) {
           $key=$keysbysurname[$i];
           if ($preffamkey{$key} eq "") {
              $j="@@";
           } else {
              $j=$preffamkey{$key};
           }
           $line=$key . " " . $j . " " . $sexcolor{$key} . " " . $fullnameplus{$key};
           if ($nogen == 0) { print NAM "$line\n"; }
           $i=$i+1;
       }
   }
   if ($nogen == 0) {
      close NAM;
   }
   $famfile="$htmldir/famfile";
   if ($nogen == 0) {
      open (FAM,">$famfile") or die "Can't open $famfile: $!";
      Dprint("D","Generating $famfile ...\n");
   } else {
      Dprint("D","Working on $famfile ...\n");
   }
   foreach $key (keys %famrin) {
      $line=$key . " " . $childkeynum{$key};
      $i=$husbkey{$key};
      if ($i eq "") { $i="@@"; }
      $line=$line . " " . $i; 
      $i=$wifekey{$key};
      if ($i eq "") { $i="@@"; }
      $line=$line . " " . $i; 
      if ($childkeynum{$key} > 0) {
         $i=0;
         while ($i < $childkeynum{$key}) {
            $i=$i+1;
            $line=$line . " " . $childkey{$key,$i};
         }
      }
      if ($nogen == 0) { print FAM "$line\n"; }
   }
   if ($nogen == 0) {
      close FAM;
   }
} 


sub Sortbyrin {
    $numericrin{$a} <=> $numericrin{$b}
       or
    $a cmp $b;
}
sub Sortbysurname {
    $surnamezzz{$a} cmp $surnamezzz{$b}
       or
    $givenname{$a,1} cmp $givenname{$b,1}
       or
    $a cmp $b;
}
sub Sortbygivenname {
    $givennamezzz{$a} cmp $givennamezzz{$b}
       or
    $surname{$a,1} cmp $surname{$b,1}
       or
    $a cmp $b;
}
sub Sortbybirthdate {
    $birthdatezzz{$a} cmp $birthdatezzz{$b}
       or
    $surnamezzz{$a} cmp $surnamezzz{$b}
       or
    $givenname{$a,1} cmp $givenname{$b,1}
       or
    $a cmp $b;
}
sub Sortbybirthplace {
    $birthplacezzz{$a} cmp $birthplacezzz{$b}
       or
    $surnamezzz{$a} cmp $surnamezzz{$b}
       or
    $givenname{$a,1} cmp $givenname{$b,1}
       or
    $a cmp $b;
}
sub Sortbycemeteryname {
    $cemeterynamezzz{$a} cmp $cemeterynamezzz{$b}
       or
    $surnamezzz{$a} cmp $surnamezzz{$b}
       or
    $givenname{$a,1} cmp $givenname{$b,1}
       or
    $a cmp $b;
}

sub Getdateplace {
    my $gdate=$_[0];
    my $gplace=$_[1];
    my $sep=$_[2];
    my $gdateplace="";
    # combine date and place with separator
        if (($gdate eq "") && ($gplace eq "")) {
           # no date or place       
        } elsif ($gdate eq "") {
           $gdateplace=$gplace;
        } elsif ($gplace eq "") {
           $gdateplace=$gdate;
        } else {
           $gdateplace=$gdate . $sep . $gplace;
        }                
    return $gdateplace;
}

sub Fixnote {
    my $fnotetyp=$_[0];
    my $fnotekey=$_[1];
    # Look up notes that are reference by index number
    my $j;
    my $retval="@@";
    if ($lev0notenum > 0) {
        $j=0;
        while ($j < $lev0notenum) {
               $j=$j+1;
               if ($fnotekey eq $lev0notekey{$key,$j}) {
                   $retval=$lev0note{$key,$j};
                   Dprint("n","Replacing note $fnotetyp $fnotekey with $retval at line $cntr\n");
               }
        }
    } 
    if ($retval eq "@@") {
       print "Unable to decode note $fnotetyp $fnotekey at line $cntr\n";
       if ($test == 0) { die "Aborting due to inconsistent $gedfile file\n"; }
    }
    return $retval;
}

sub Genalert {
    my $ahead=$_[0];
    my $awork=$_[1];
    my $adata;
    $awork =~ s/[\"\']/+/g;     # get rid of single,double quotes
    $awork =~ s/\n/<br>/g;      # convert linefeeds to <br>
    $adata="<h2>$ahead</h2><p>$awork</p>";
    return $adata;
}
sub Genwindow {
    my $ahead=$_[0];
    my $awork=$_[1];
    my $adata;  
    $awork =~ s/[\"\']/+/g;     # get rid of single,double quotes
    $adata="<h2>$ahead</h2><p>$awork</p>";
    return $adata;
}

sub Getsortdate {
    my $date=$_[0];
    my $month;
    my $year;
    my $day;
    my $sd;
    my $da;
    my $mo;
    my $yr;
    ($da,$mo,$yr) = split(/\s/,$date,3);
    if (!defined $da) { $da=""; }
    if (!defined $mo) { $mo=""; }
    if (!defined $yr) { $yr=""; }
    Dprint("d","da: $da\n");
    Dprint("d","mo: $mo\n");
    Dprint("d","yr: $yr\n");
    $month=1;
    $day="99";
    if (($da =~ /^\d+$/) && ($mo =~ /^[A-Z][a-z][a-z]$/) && ($yr =~ /^\d+$/)) {
       # 99 Xxx 9999
       if ($da < 9) {
          $day="0".$da;
       } else {
          $day=$da;
       }
       $year=$yr;
    } elsif (($da =~ /^[A-Z][a-z][a-z]$/) && ($mo =~ /^\d+$/) && ($yr eq "")) {
       # Xxx 9999
       $day="00";
       $year=$mo;
       $mo=$da;
    } elsif (($da =~ /^\d+$/) && ($mo eq "") && ($yr eq "")) {       
       # 9999
       $day="00";
       $year=$da;
       $mo="00";
    } else {
       # Invalid date
       $year="9999";
       $mo=99;
    }
    if    ($mo eq "00")  {$mo=0;}  
    elsif ($mo eq "Abt") {$mo=0;}
    elsif ($mo eq "Jan") {$mo=1;}
    elsif ($mo eq "Feb") {$mo=2;}
    elsif ($mo eq "Mar") {$mo=3;}
    elsif ($mo eq "Apr") {$mo=4;}
    elsif ($mo eq "May") {$mo=5;}
    elsif ($mo eq "Jun") {$mo=6;}
    elsif ($mo eq "Jul") {$mo=7;}
    elsif ($mo eq "Aug") {$mo=8;}
    elsif ($mo eq "Sep") {$mo=9;}
    elsif ($mo eq "Oct") {$mo=10;}
    elsif ($mo eq "Nov") {$mo=11;}
    elsif ($mo eq "Dec") {$mo=12;}
    else { 
       # Invalid date
       $mo=99;
    }
    if ($mo < 10) {
       $month="0".$mo;
    } else {
       $month=$mo;
    }
    if (($year < 1000) || ($year > 3000)) {
       # Invalid year 
       $year="9999";
    }
    Dprint("d","year: $year\n");
    Dprint("d","month: $month\n");
    Dprint("d","day: $day\n");
    $sd = $year . $month . $day;
    Dprint("d","sortdate=$sd\n");
    return $sd;
}

sub Calcage {
    my $curdate=$_[0];
    my $bdate=$birthdate{$key};
    my $cur;
    my $bda;
    my $age=-1;
    my $fage;
    Dprint("a","curdate=$curdate\n");
    Dprint("a","bdate=$bdate\n");
    $cur=Calcmonth($curdate);
    if ($cur >= 0) {   
       $bda=Calcmonth($bdate);
       if ($bda >= 0) {
          $fage=($cur-$bda)/12;
          $age=int($fage);
          Dprint("a","age: $age=int($fage)\n");
       } 
    }
    if ($age < 0 ) { $age=""; }
    return $age;
}

sub Calcmonth {
    my $date=$_[0];
    my $month;
    my $da;
    my $mo;
    my $yr;
    ($da,$mo,$yr) = split(/\s/,$date,3);
    if (!defined $da) { $da=""; }
    if (!defined $mo) { $mo=""; }
    if (!defined $yr) { $yr=""; }
    Dprint("a","da: $da\n");
    Dprint("a","mo: $mo\n");
    Dprint("a","yr: $yr\n");
    $month=1;
    if (($da =~ /^\d+$/) && ($mo =~ /^[A-Z][a-z][a-z]$/) && ($yr =~ /^\d+$/)) {
       # 99 Xxx 9999
    } elsif (($da =~ /^[A-Z][a-z][a-z]$/) && ($mo =~ /^\d+$/) && ($yr eq "")) {
       # Xxx 9999
       $yr=$mo;
       $mo=$da;
    } elsif (($da =~ /^\d+$/) && ($mo eq "") && ($yr eq "")) {       
       # 9999
       $yr=$da;
       $mo="0";
    } else {
       # Invalid date
       $month=-1;
    } 
    if ($mo eq "0") { $mo=0;}    
    elsif ($mo eq "Abt") {$mo=0;}
    elsif ($mo eq "Jan") {$mo=1;}
    elsif ($mo eq "Feb") {$mo=2;}
    elsif ($mo eq "Mar") {$mo=3;}
    elsif ($mo eq "Apr") {$mo=4;}
    elsif ($mo eq "May") {$mo=5;}
    elsif ($mo eq "Jun") {$mo=6;}
    elsif ($mo eq "Jul") {$mo=7;}
    elsif ($mo eq "Aug") {$mo=8;}
    elsif ($mo eq "Sep") {$mo=9;}
    elsif ($mo eq "Oct") {$mo=10;}
    elsif ($mo eq "Nov") {$mo=11;}
    elsif ($mo eq "Dec") {$mo=12;}
    else { 
       # Invalid date
       $month=-1;
    }
    if ($month > 0) {
       $month=($yr*12)+$mo;
       Dprint("a","$month=($yr * 12)+$mo\n");
    }
    return $month;
}

sub Calcyear {
    my $date=$_[0];
    my $year;
    my $da;
    my $mo;
    my $yr;
    ($da,$mo,$yr) = split(/\s/,$date,3);
    if (!defined $da) { $da=""; }
    if (!defined $mo) { $mo=""; }
    if (!defined $yr) { $yr=""; }
    Dprint("y","da: $da\n");
    Dprint("y","mo: $mo\n");
    Dprint("y","yr: $yr\n");
    if (($da =~ /^\d+$/) && ($mo =~ /^[A-Z][a-z][a-z]$/) && ($yr =~ /^\d+$/)) {
       # 99 Xxx 9999
       $year=$yr;
    } elsif (($da =~ /^[A-Z][a-z][a-z]$/) && ($mo =~ /^\d+$/) && ($yr eq "")) {
       # Xxx 9999
       $year=$mo;
    } elsif (($da =~ /^\d+$/) && ($mo eq "") && ($yr eq "")) {       
       # 9999
       $year=$da;
    } else {
       $year=0;
    } 
    if (($year < 1000) || ($year > 3000)) {
       # Invalid year 
       $year="";
    }
    Dprint("y","year: $year\n");
    return $year;
}

sub PrintHTML {
    my $htmldata=$_[0];
    if ($nogen == 0) {
       print HTML "$htmldata";
    }
}

sub Getopts {
    if ($#ARGV >= 0) {
       my $i=0;
       while ($i <= $#ARGV) {
          if ($ARGV[$i] eq "-help") {
              Help();
              ++$i;              
          } elsif ($ARGV[$i] eq "-nogen") {
              $nogen=1;
              ++$i;
          } elsif ($ARGV[$i] eq "-test") {
              $test=1;
              ++$i;
          } elsif (($i+1) <= $#ARGV) { 
              if ($ARGV[$i] eq "-d") {
                  # enable debug mode
                  $debug = $ARGV[++$i];
                  ++$i;
              } elsif ($ARGV[$i] eq "-ged") {
                  $gedfile = $ARGV[++$i];
                  ++$i;
              } elsif ($ARGV[$i] eq "-mod") {
                  $modeldir = $ARGV[++$i];
                  ++$i;
              } elsif ($ARGV[$i] eq "-html") {
                  $htmldir = $ARGV[++$i];
                  ++$i;
              } elsif ($ARGV[$i] eq "-del") {
                  $delname = $ARGV[++$i];
                  ++$i;
              } else {
                  Usage();
              }
          } else {
              Usage();
          }
       }
    }
    print "gedfile: $gedfile\n";
    print "modeldir: $modeldir\n";
    print "htmldir: $htmldir\n";
    if ($delname ne "") {
       print "delname: $delname\n";
    }
}

# Debug print
sub Dprint {
    my $dlev=$_[0];
    my $dline=$_[1];
    # See if $dlev is any of the characters in $debug   
    if (($debug eq "all") || ($debug =~ m/$dlev/)) {
       print "$dline";
       print DOUT "$dline";
    }
}

sub Usage {
    die "Usage: $0 [-help] [-test] [-nogen] [-d <debuglevel>] [-ged <gedfile>] [-mod <modeldir>] [-html <htmldir>] [-del <surname>]\n";
}

sub Help {
    print "Usage: $0 [-help] [-test] [-nogen] [-d <debuglevel>] [-ged <gedfile>] [-mod <modeldir>] [-html <htmldir>] [-del <surname>]\n";
    print "-help = Display this help information\n";
    print "-test = Ignore incomplete or inconsistent or unhandled GED file errors\n";         
    print "-nogen = Suppress creating output files in the HTML directory\n";
    print "-d <debuglevel> = Enable printout for various debug levels\n";
    print "-ged <gedfile> = Use <gedfile> as the input GED file (default: gedfile.ged)\n";
    print "-mod <modeldir> = Use <modeldir> as the directory where to find the input model files (default: modeldir)\n";
    print "-html <htmldir> = Write the HTML output files into the <htmldir> directory (default: htmldir)\n";
    print "-del <surname> = Delete any individuals with <surname> from the output files\n";
    exit;
}