line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
####################################################### |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# Family Tree generation program, v2.0 |
4
|
|
|
|
|
|
|
# Written by Ferenc Bodon and Simon Ward, March 2000 (simonward.com) |
5
|
|
|
|
|
|
|
# Copyright (C) 2000 Ferenc Bodon, Simon K Ward |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or |
8
|
|
|
|
|
|
|
# modify it under the terms of the GNU General Public License |
9
|
|
|
|
|
|
|
# as published by the Free Software Foundation; either version 2 |
10
|
|
|
|
|
|
|
# of the License, or (at your option) any later version. |
11
|
|
|
|
|
|
|
# |
12
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
13
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
14
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15
|
|
|
|
|
|
|
# GNU General Public License for more details. |
16
|
|
|
|
|
|
|
# |
17
|
|
|
|
|
|
|
# For a copy of the GNU General Public License, visit |
18
|
|
|
|
|
|
|
# http://www.gnu.org or write to the Free Software Foundation, Inc., |
19
|
|
|
|
|
|
|
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
20
|
|
|
|
|
|
|
# |
21
|
|
|
|
|
|
|
####################################################### |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
package Ftree::FamilyTreeInfo; |
24
|
|
|
|
|
|
|
|
25
|
1
|
|
|
1
|
|
1465
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
27
|
|
26
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
26
|
|
27
|
|
|
|
|
|
|
|
28
|
1
|
|
|
1
|
|
5
|
use Ftree::FamilyTreeBase; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
29
|
|
|
|
|
|
|
|
30
|
1
|
|
|
1
|
|
170
|
use Switch; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8
|
|
31
|
1
|
|
|
1
|
|
244928
|
use Params::Validate qw(:all); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
272
|
|
32
|
1
|
|
|
1
|
|
7
|
use Sub::Exporter -setup => { exports => [ qw(new main) ] }; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
15
|
|
33
|
1
|
|
|
1
|
|
468
|
use Encode qw(decode_utf8); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
80
|
|
34
|
1
|
|
|
1
|
|
6
|
use utf8; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
8
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
our $VERSION = '2.3.27'; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my $q = new CGI; |
39
|
|
|
|
|
|
|
|
40
|
1
|
|
|
1
|
|
70
|
use base 'Ftree::FamilyTreeBase'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
3767
|
|
41
|
|
|
|
|
|
|
sub new{ |
42
|
0
|
|
|
0
|
0
|
|
my $type = shift; |
43
|
0
|
|
|
|
|
|
my $self = $type->SUPER::new(@_); |
44
|
|
|
|
|
|
|
$self->{family_tree_data} = |
45
|
0
|
|
|
|
|
|
Ftree::FamilyTreeDataFactory::getFamilyTree( $self->{settings}{data_source} ); |
46
|
0
|
|
|
|
|
|
$self->{pagetype} = undef; |
47
|
0
|
|
|
|
|
|
return $self; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub main{ |
51
|
0
|
|
|
0
|
0
|
|
my ($self) = validate_pos(@_, {type => HASHREF} ); |
52
|
0
|
|
|
|
|
|
$self->_process_parameters(); |
53
|
0
|
|
|
|
|
|
$self->_password_check(); |
54
|
|
|
|
|
|
|
|
55
|
0
|
|
|
|
|
|
switch ($self->{pagetype}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
56
|
0
|
0
|
|
|
|
|
case "" {$self->_draw_index_page();} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
57
|
0
|
0
|
|
|
|
|
case 'subfamily' {$self->_draw_same_surname_page();} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
58
|
0
|
0
|
|
|
|
|
case 'snames' {$self->_draw_surname_page();} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
59
|
0
|
0
|
|
|
|
|
case 'faces' {$self->_draw_facehall_page();} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
60
|
0
|
0
|
|
|
|
|
case 'emails' {$self->_draw_general_page(\&Person::get_email, 'email', $self->{textGenerator}->{Emails}, |
|
0
|
|
|
|
|
|
|
61
|
0
|
|
|
|
|
|
$self->{textGenerator}->{Total_with_email});} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
62
|
0
|
0
|
|
|
|
|
case 'hpages' {$self->_draw_general_page(\&Person::get_homepage, 'homepage', $self->{textGenerator}->{Homepages}, |
|
0
|
|
|
|
|
|
|
63
|
0
|
|
|
|
|
|
$self->{textGenerator}->{Total_with_homepage});} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
64
|
0
|
0
|
|
|
|
|
case 'bdays' {$self->_draw_birthday_page();} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
65
|
0
|
|
|
|
|
|
else { $self->_draw_invalid_page(); } |
66
|
0
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
|
return; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
####################################################### |
72
|
|
|
|
|
|
|
# processing the parameters (type and passwd) |
73
|
|
|
|
|
|
|
sub _process_parameters { |
74
|
0
|
|
|
0
|
|
|
my ( $self ) = validate_pos(@_, {type => HASHREF} ); |
75
|
0
|
|
|
|
|
|
$self->SUPER::_process_parameters(); |
76
|
0
|
|
|
|
|
|
$self->{pagetype} = $self->{cgi}->param('type'); |
77
|
0
|
0
|
|
|
|
|
$self->{pagetype} = "" unless(defined $self->{pagetype}); |
78
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
|
return; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# private functions |
83
|
|
|
|
|
|
|
sub _draw_people_table { |
84
|
0
|
|
|
0
|
|
|
my ($self, $people, $column_number) = validate_pos(@_, |
85
|
|
|
|
|
|
|
{type => HASHREF}, {type => ARRAYREF}, {defaulf => 5}); |
86
|
0
|
0
|
|
|
|
|
$column_number = 5 unless defined $column_number; #AAARRRRGGGHHH |
87
|
0
|
|
|
|
|
|
my $nr_of_man = 0; |
88
|
0
|
|
|
|
|
|
my $nr_of_woman= 0; |
89
|
0
|
|
|
|
|
|
print $self->{cgi}->start_table({-cellpadding => '5', -border=>'1', -align=>'center'}),"\n"; |
90
|
|
|
|
|
|
|
|
91
|
0
|
|
|
|
|
|
for my $index (0 .. @{$people} - 1 ) { |
|
0
|
|
|
|
|
|
|
92
|
0
|
0
|
|
|
|
|
print $self->{cgi}->start_Tr() if ( $index % $column_number == 0 ); |
93
|
0
|
|
|
|
|
|
my $class = $self->get_cell_class( |
94
|
|
|
|
|
|
|
$people->[$index], \$nr_of_man, \$nr_of_woman); |
95
|
0
|
|
|
|
|
|
print $self->{cgi}->td({-class => $class}, |
96
|
|
|
|
|
|
|
$self->aref_tree($people->[$index]->get_name()->get_long_name(), $people->[$index])), "\n"; |
97
|
0
|
0
|
|
|
|
|
print $self->{cgi}->end_Tr() if ( ($index % $column_number) == $column_number-1 ); |
98
|
|
|
|
|
|
|
} |
99
|
0
|
0
|
|
|
|
|
print $self->{cgi}->end_Tr(),"\n" if ( (@{$people} % $column_number) != 1 ); |
|
0
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
print $self->{cgi}->end_table(),"\n", $self->{cgi}->br, |
102
|
0
|
|
|
|
|
|
$self->{textGenerator}->summary(scalar(@{$people})), |
103
|
|
|
|
|
|
|
" ($self->{textGenerator}{man}: ", $nr_of_man, |
104
|
|
|
|
|
|
|
", $self->{textGenerator}{woman}: ", $nr_of_woman, |
105
|
0
|
|
|
|
|
|
", $self->{textGenerator}{unknown}: ", scalar(@{$people}) - $nr_of_man - $nr_of_woman, ')' ; |
|
0
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
return; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
######################################################### |
110
|
|
|
|
|
|
|
# INDEX PAGE |
111
|
|
|
|
|
|
|
######################################################### |
112
|
|
|
|
|
|
|
sub _draw_index_page { |
113
|
0
|
|
|
0
|
|
|
my ($self, $column_number) = validate_pos(@_, |
114
|
|
|
|
|
|
|
{type => HASHREF}, {type => SCALAR, optional => 1}); |
115
|
0
|
|
|
|
|
|
my @people = grep {defined $_->get_name()} $self->{family_tree_data}->get_all_people(); |
|
0
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
|
@people = sort{$a->get_name()->get_full_name() cmp $b->get_name()->get_full_name()} @people; |
|
0
|
|
|
|
|
|
|
117
|
0
|
|
|
|
|
|
$self->_toppage($self->{textGenerator}->{members}); |
118
|
0
|
|
|
|
|
|
$self->_draw_people_table(\@people, $column_number); |
119
|
0
|
|
|
|
|
|
$self->_endpage(); |
120
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
|
return; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
######################################################### |
125
|
|
|
|
|
|
|
# Same surname people |
126
|
|
|
|
|
|
|
######################################################### |
127
|
|
|
|
|
|
|
sub _draw_same_surname_page { |
128
|
0
|
|
|
0
|
|
|
my ($self, $column_number) = validate_pos(@_, |
129
|
|
|
|
|
|
|
{type => HASHREF}, {type => SCALAR, optional => 1}); |
130
|
0
|
|
|
|
|
|
my $surname = decode_utf8($self->{cgi}->param('surname')); |
131
|
0
|
0
|
|
|
|
|
$surname = "" unless(defined $surname); |
132
|
0
|
0
|
|
|
|
|
my @people = grep {defined $_->get_name() && |
133
|
|
|
|
|
|
|
$_->get_name()->get_last_name() eq $surname} |
134
|
0
|
|
|
|
|
|
$self->{family_tree_data}->get_all_people(); |
135
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
|
@people = sort{$a->get_name()->get_full_name() cmp $b->get_name()->get_full_name()} (@people); |
|
0
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
|
$self->_toppage($self->{textGenerator}->People_with_surname($surname)); |
138
|
0
|
|
|
|
|
|
$self->_draw_people_table(\@people, $column_number); |
139
|
0
|
|
|
|
|
|
$self->_endpage(); |
140
|
|
|
|
|
|
|
|
141
|
0
|
|
|
|
|
|
return; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
######################################################### |
145
|
|
|
|
|
|
|
# SURNAME PAGE |
146
|
|
|
|
|
|
|
######################################################### |
147
|
|
|
|
|
|
|
sub _draw_surname_page { |
148
|
0
|
|
|
0
|
|
|
my ($self, $column_number) = validate_pos(@_, |
149
|
|
|
|
|
|
|
{type => HASHREF}, {type => SCALAR, optional => 1}); |
150
|
0
|
0
|
|
|
|
|
$column_number = 8 unless( defined $column_number); |
151
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
require Set::Scalar; |
153
|
0
|
|
|
|
|
|
my $last_name_set = Set::Scalar->new; |
154
|
0
|
|
|
|
|
|
for my $person ($self->{family_tree_data}->get_all_people()) { |
155
|
0
|
0
|
0
|
|
|
|
$last_name_set->insert($person->get_name()->get_last_name()) |
156
|
|
|
|
|
|
|
if((defined $person->get_name()) && (defined $person->get_name()->get_last_name())); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
$self->_toppage($self->{textGenerator}->{Surnames}); |
160
|
|
|
|
|
|
|
|
161
|
0
|
|
|
|
|
|
while ( defined( my $a_last_name = $last_name_set->each ) ) { |
162
|
0
|
|
|
|
|
|
push @{ $self->{nodes} }, $a_last_name; |
|
0
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
} |
164
|
0
|
|
|
|
|
|
my @sortednodes = sort @{ $self->{nodes} }; |
|
0
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
|
print $self->{cgi}->start_table({-cellpadding => '5', -border=>'1', -align=>'center'}),"\n"; |
167
|
0
|
|
|
|
|
|
for my $people_count (0 .. $#sortednodes) { |
168
|
0
|
0
|
|
|
|
|
print $self->{cgi}->start_Tr() if ( $people_count % $column_number == 0 ); |
169
|
0
|
|
|
|
|
|
print $self->{cgi}->td($self->{cgi}->a({-href => "$self->{treeScript}?type=subfamily&surname=$sortednodes[$people_count]&lang=$self->{lang}"}, |
170
|
|
|
|
|
|
|
$sortednodes[$people_count])); |
171
|
0
|
0
|
|
|
|
|
print $self->{cgi}->end_Tr(),"\n" if ( $people_count % $column_number == $column_number - 1 ); |
172
|
|
|
|
|
|
|
} |
173
|
0
|
0
|
|
|
|
|
print $self->{cgi}->end_Tr(),"\n" if ( $#sortednodes % $column_number != 0 ); |
174
|
|
|
|
|
|
|
print $self->{cgi}->end_table(),"\n", $self->{cgi}->br, |
175
|
0
|
|
|
|
|
|
$self->{textGenerator}->{Total}.' '.$last_name_set->size.' '.$self->{textGenerator}->{people}; |
176
|
0
|
|
|
|
|
|
$self->_endpage(); |
177
|
|
|
|
|
|
|
|
178
|
0
|
|
|
|
|
|
return; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub _draw_general_table { |
182
|
0
|
|
|
0
|
|
|
my ($self, $func, $attribute, $people_with_type_r, $text2) = validate_pos(@_, |
183
|
|
|
|
|
|
|
{type => HASHREF}, {type => CODEREF}, {type => SCALAR}, {type => ARRAYREF}, {type => SCALAR}); |
184
|
0
|
|
|
|
|
|
my $nr_of_man=0; |
185
|
0
|
|
|
|
|
|
my $nr_of_woman=0; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
print $self->{cgi}->start_table({-cellpadding => '5', -border=>'1', -align=>'center'}),"\n", |
188
|
|
|
|
|
|
|
$self->{cgi}->Tr($self->{cgi}->th($self->{textGenerator}{photo}), $self->{cgi}->th($self->{textGenerator}{name}), |
189
|
0
|
|
|
|
|
|
$self->{cgi}->th($self->{textGenerator}{$attribute})); |
190
|
|
|
|
|
|
|
|
191
|
0
|
|
|
|
|
|
foreach my $a_person ( @{$people_with_type_r} ) { |
|
0
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
|
my $class = $self->get_cell_class( |
193
|
|
|
|
|
|
|
$a_person, \$nr_of_man, \$nr_of_woman); |
194
|
|
|
|
|
|
|
print $self->{cgi}->start_Tr({-class => $class}), |
195
|
|
|
|
|
|
|
$self->{cgi}->td($self->html_img($a_person)), |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
$self->{cgi}->td($self->aref_tree($a_person->get_name()->get_full_name(), $a_person)), |
198
|
|
|
|
|
|
|
$self->{cgi}->td($func->($a_person)), |
199
|
0
|
|
|
|
|
|
$self->{cgi}->end_Tr, "\n"; |
200
|
|
|
|
|
|
|
} |
201
|
0
|
|
|
|
|
|
print $self->{cgi}->end_table, "\n", $self->{cgi}->br, $text2, scalar(@{$people_with_type_r}), |
202
|
|
|
|
|
|
|
" ($self->{textGenerator}{man}: ", $nr_of_man, |
203
|
|
|
|
|
|
|
", $self->{textGenerator}{woman}: ", $nr_of_woman, |
204
|
0
|
|
|
|
|
|
", $self->{textGenerator}{unknown}: ", scalar(@{$people_with_type_r}) - $nr_of_man - $nr_of_woman, ")" ; |
|
0
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
return; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
######################################################### |
209
|
|
|
|
|
|
|
# GENERAL PAGE |
210
|
|
|
|
|
|
|
######################################################### |
211
|
|
|
|
|
|
|
sub _draw_general_page { |
212
|
0
|
|
|
0
|
|
|
my ($self, $func, $attribute, $title, $text2) = validate_pos(@_, |
213
|
|
|
|
|
|
|
{type => HASHREF}, {type => CODEREF}, {type => SCALAR}, |
214
|
|
|
|
|
|
|
{type => SCALAR}, {type => SCALAR}); |
215
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
my @people_with_type = grep {defined $func->($_)} |
217
|
0
|
|
|
|
|
|
(grep {defined $_->get_name()} $self->{family_tree_data}->get_all_people()); |
|
0
|
|
|
|
|
|
|
218
|
0
|
|
|
|
|
|
@people_with_type = sort{$a->get_name()->get_full_name() cmp $b->get_name()->get_full_name()} (@people_with_type); |
|
0
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
|
220
|
0
|
|
|
|
|
|
$self->_toppage($title); |
221
|
0
|
|
|
|
|
|
$self->_draw_general_table($func, $attribute, \@people_with_type, $text2); |
222
|
0
|
|
|
|
|
|
$self->_endpage(); |
223
|
|
|
|
|
|
|
|
224
|
0
|
|
|
|
|
|
return; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
######################################################### |
229
|
|
|
|
|
|
|
# BIRTHDAYS PAGE |
230
|
|
|
|
|
|
|
######################################################### |
231
|
|
|
|
|
|
|
sub _draw_birthday_page { |
232
|
0
|
|
|
0
|
|
|
my ($self) = validate_pos(@_, {type => HASHREF}); |
233
|
0
|
|
|
|
|
|
my $months = $self->{textGenerator}->{months_array}; |
234
|
0
|
|
|
|
|
|
my $month = decode_utf8($self->{cgi}->param('month')); |
235
|
|
|
|
|
|
|
|
236
|
0
|
0
|
|
|
|
|
if ( ! defined $month ) { |
237
|
0
|
|
|
|
|
|
$month = (localtime)[4] + 1; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
else { |
240
|
0
|
|
|
|
|
|
my $index = 0; |
241
|
0
|
|
|
|
|
|
++$index while($months->[$index] ne $month); |
242
|
0
|
|
|
|
|
|
$month = $index + 1; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
my @people_with_bday = grep {defined $_->get_name() && |
247
|
|
|
|
|
|
|
defined $_->get_date_of_birth() && !defined $_->get_date_of_death() && |
248
|
0
|
0
|
0
|
|
|
|
defined $_->get_date_of_birth()->{month} && $_->get_date_of_birth()->{month} == $month} |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
249
|
0
|
|
|
|
|
|
($self->{family_tree_data}->get_all_people()); |
250
|
|
|
|
|
|
|
|
251
|
0
|
|
|
|
|
|
my $title = $self->{textGenerator}->birthday_reminder($month-1); |
252
|
0
|
|
|
|
|
|
$self->_toppage($title); |
253
|
0
|
|
|
|
|
|
@people_with_bday = sort{$a->get_name()->get_full_name() cmp $b->get_name()->get_full_name()} (@people_with_bday); |
|
0
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
$self->_draw_general_table(\&Person::get_date_of_birth, 'date_of_birth', \@people_with_bday, |
256
|
0
|
|
|
|
|
|
$self->{textGenerator}->total_living_with_birthday($month-1)); |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# Add the button for other months |
259
|
|
|
|
|
|
|
print $self->{cgi}->start_form({-action => $self->{treeScript}, |
260
|
|
|
|
|
|
|
-method => 'get' }), |
261
|
|
|
|
|
|
|
"\n$self->{textGenerator}->{CheckAnotherMonth}:\n", |
262
|
0
|
|
|
|
|
|
$self->{cgi}->start_Select({-name => 'month', |
263
|
|
|
|
|
|
|
-size => 1}), "\n"; |
264
|
0
|
|
|
|
|
|
for my $index (0 .. 11) { |
265
|
0
|
0
|
|
|
|
|
if ( $index == ( $month - 1 ) ) { |
266
|
0
|
|
|
|
|
|
print $self->{cgi}->option({-selected => "selected"}, $months->[$index]), "\n"; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
else { |
269
|
0
|
|
|
|
|
|
print $self->{cgi}->option( $months->[$index]), "\n"; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
print $self->{cgi}->end_Select, "\n", $self->{cgi}->input({-type => 'hidden', -name => "type", -value => "bdays"}), "\n", |
273
|
|
|
|
|
|
|
$self->{cgi}->input({-type => 'hidden', -name => 'password', -value => $self->{settings}{password}}), "\n", |
274
|
|
|
|
|
|
|
$self->{cgi}->input({-type => 'hidden', -name => 'lang', -value => $self->{lang}}), "\n", |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
$self->{cgi}->input({-type => "submit", -value => "$self->{textGenerator}->{Go}"}), |
277
|
0
|
|
|
|
|
|
$self->{cgi}->end_form; |
278
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
$self->_endpage(); |
280
|
|
|
|
|
|
|
|
281
|
0
|
|
|
|
|
|
return; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
######################################################### |
284
|
|
|
|
|
|
|
# Facehall page |
285
|
|
|
|
|
|
|
######################################################### |
286
|
|
|
|
|
|
|
sub _draw_facehall_page { |
287
|
0
|
|
|
0
|
|
|
my ($self) = validate_pos(@_, {type => HASHREF}); |
288
|
0
|
|
|
|
|
|
my $column_number = 5; |
289
|
|
|
|
|
|
|
|
290
|
0
|
0
|
|
|
|
|
my @people_with_photo = grep {defined $_->get_name() && |
291
|
|
|
|
|
|
|
defined $_->get_default_picture()} |
292
|
0
|
|
|
|
|
|
($self->{family_tree_data}->get_all_people()); |
293
|
0
|
|
|
|
|
|
@people_with_photo = sort{ $a->get_name()->get_full_name() cmp |
|
0
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
$b->get_name()->get_full_name() } (@people_with_photo); |
295
|
|
|
|
|
|
|
|
296
|
0
|
|
|
|
|
|
$self->_toppage($self->{textGenerator}->{Hall_of_faces}); |
297
|
|
|
|
|
|
|
|
298
|
0
|
|
|
|
|
|
my $nr_of_man = 0; |
299
|
0
|
|
|
|
|
|
my $nr_of_woman = 0; |
300
|
0
|
|
|
|
|
|
print $self->{cgi}->start_table({-cellpadding => '7', -align=>'center'}),"\n"; |
301
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
foreach my $index (0 .. $#people_with_photo) { |
303
|
0
|
0
|
|
|
|
|
print $self->{cgi}->start_Tr,"\n" if ( $index % $column_number == 0 ); |
304
|
0
|
|
|
|
|
|
my $class = $self->get_cell_class( |
305
|
|
|
|
|
|
|
$people_with_photo[$index], \$nr_of_man, \$nr_of_woman); |
306
|
|
|
|
|
|
|
print $self->{cgi}->start_td({-class => $class, -align=>'center'}), |
307
|
|
|
|
|
|
|
$self->aref_tree($self->html_img($people_with_photo[$index]), $people_with_photo[$index]), $self->{cgi}->br, |
308
|
0
|
|
|
|
|
|
$people_with_photo[$index]->get_name()->get_full_name(), $self->{cgi}->end_td; |
309
|
0
|
0
|
|
|
|
|
print $self->{cgi}->end_Tr,"\n" if ( $index % $column_number == $column_number-1 ); |
310
|
|
|
|
|
|
|
} |
311
|
0
|
0
|
|
|
|
|
print $self->{cgi}->end_Tr,"\n" if ( $#people_with_photo % $column_number != 0 ); |
312
|
|
|
|
|
|
|
print $self->{cgi}->end_table,"\n", $self->{cgi}->br, |
313
|
0
|
|
|
|
|
|
$self->{textGenerator}->{Total_with_photo}, scalar(@people_with_photo), |
314
|
|
|
|
|
|
|
" ($self->{textGenerator}{man}: ", $nr_of_man, |
315
|
|
|
|
|
|
|
", $self->{textGenerator}{woman}: ", $nr_of_woman, |
316
|
|
|
|
|
|
|
", $self->{textGenerator}{unknown}: ", scalar(@people_with_photo) - $nr_of_man - $nr_of_woman, ")" ; |
317
|
0
|
|
|
|
|
|
print $self->{cgi}->start_table({-cellpadding => '7', -align=>'center'}),"\n"; |
318
|
0
|
|
|
|
|
|
print $self->{cgi}->start_Tr; |
319
|
0
|
|
|
|
|
|
print $self->{cgi}->start_td({-align=>'center'}); |
320
|
0
|
|
|
|
|
|
print $self->{cgi}->br, " $self->{textGenerator}{Prayer_for_the_living}: "; |
321
|
|
|
|
|
|
|
|
322
|
0
|
|
|
|
|
|
foreach my $index (0 .. $#people_with_photo) { |
323
|
0
|
0
|
|
|
|
|
if ($people_with_photo[$index]->get_is_living()){ |
324
|
0
|
|
|
|
|
|
print $self->{cgi}->br,$people_with_photo[$index]->get_name()->get_first_name(),' (',$people_with_photo[$index]->get_name()->get_full_name(),')'; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
0
|
|
|
|
|
|
print $self->{cgi}->end_td; |
329
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
|
print $self->{cgi}->start_td({-align=>'center'}); |
331
|
0
|
|
|
|
|
|
print $self->{cgi}->br, " $self->{textGenerator}{Prayer_for_the_departed}: "; |
332
|
0
|
|
|
|
|
|
foreach my $index (0 .. $#people_with_photo) { |
333
|
0
|
0
|
|
|
|
|
if (!$people_with_photo[$index]->get_is_living()){ |
334
|
0
|
|
|
|
|
|
print $self->{cgi}->br,$people_with_photo[$index]->get_name()->get_first_name(),' (',$people_with_photo[$index]->get_name()->get_full_name(),')'; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
0
|
|
|
|
|
|
print $self->{cgi}->end_td; |
338
|
|
|
|
|
|
|
|
339
|
0
|
|
|
|
|
|
print $self->{cgi}->end_Tr,"\n"; |
340
|
|
|
|
|
|
|
|
341
|
0
|
|
|
|
|
|
print $self->{cgi}->end_table,"\n", $self->{cgi}->br; |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
|
344
|
0
|
|
|
|
|
|
$self->_endpage(); |
345
|
|
|
|
|
|
|
|
346
|
0
|
|
|
|
|
|
return; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
######################################################### |
349
|
|
|
|
|
|
|
# INVALID PAGE TYPE ERROR |
350
|
|
|
|
|
|
|
######################################################### |
351
|
|
|
|
|
|
|
sub _draw_invalid_page { |
352
|
0
|
|
|
0
|
|
|
my ($self) = validate_pos(@_, {type => HASHREF}); |
353
|
0
|
|
|
|
|
|
$self->_toppage($self->{textGenerator}->{Error}); |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
print $self->{textGenerator}->{Invalid_option}, $self->{cgi}->br, "\n", |
356
|
0
|
|
|
|
|
|
$self->{textGenerator}->{Valid_options}; |
357
|
|
|
|
|
|
|
|
358
|
0
|
|
|
|
|
|
$self->_endpage(); |
359
|
0
|
|
|
|
|
|
exit 1; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
1; |
363
|
|
|
|
|
|
|
__END__ |
364
|
|
|
|
|
|
|
=encoding utf-8 |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=for stopwords |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=head1 NAME |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
Ftree - family tree generator |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
=head1 EXAMPLE |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
L<https://still-lowlands-7377.herokuapp.com> |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=head1 SYNOPSIS |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
installator for Windows 7 32bit |
379
|
|
|
|
|
|
|
L<https://sourceforge.net/projects/family-tree-32/files/latest/download?source=navbar> |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
#If install it |
382
|
|
|
|
|
|
|
cpanm https://cpan.metacpan.org/authors/id/M/MI/MISHIN/FamilyTreeInfo-2.3.16.tar.gz |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
#copy the folder cgi-bin from the distribution |
385
|
|
|
|
|
|
|
cp cgi-bin c:\ftree\cgi-bin |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
#then got to it directory |
388
|
|
|
|
|
|
|
c:\ftree\cgi-bin |
389
|
|
|
|
|
|
|
#and run |
390
|
|
|
|
|
|
|
plackup |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
#HTTP::Server::PSGI: Accepting connections at http://0:5000/ |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
#now go to the browser |
395
|
|
|
|
|
|
|
http://127.0.0.1:5000/ |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
#and we can see a family tree, and |
398
|
|
|
|
|
|
|
#to his Office just need to edit the file |
399
|
|
|
|
|
|
|
c:\ftree\cgi-bin\tree.xls |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
#or the file with a different name, but then this name must indicate file |
402
|
|
|
|
|
|
|
ftree.config |
403
|
|
|
|
|
|
|
#changing parameter |
404
|
|
|
|
|
|
|
file_name tree.xls |
405
|
|
|
|
|
|
|
#on your |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
#and pictures of relatives should be 3 x 4 |
408
|
|
|
|
|
|
|
#and they need to be put in the directory |
409
|
|
|
|
|
|
|
c:\ftree\cgi-bin\pictures |
410
|
|
|
|
|
|
|
#where the name of the picture must be a person id + .jpg |
411
|
|
|
|
|
|
|
#all works! |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
#for Unix you will need to fix option |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
photo_dir c:/ftree/cgi-bin/pictures/ |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
#on your |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=head1 OTHER Guts (you never need to read it) |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=head1 PACKAGE CONTENTS: |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
readme.txt This file |
424
|
|
|
|
|
|
|
config/PerlSettingsImporter.pm Settings file |
425
|
|
|
|
|
|
|
cgi/ftree.cgi The main perl script |
426
|
|
|
|
|
|
|
cgi/*.pm Other perl modules |
427
|
|
|
|
|
|
|
tree.txt, tree.xls, royal.ged Example family tree data files |
428
|
|
|
|
|
|
|
license.txt The GNU GPL license details |
429
|
|
|
|
|
|
|
changes.txt Change history |
430
|
|
|
|
|
|
|
pictures/*.[gif,png,jpg,tif] The pictures of the relatives |
431
|
|
|
|
|
|
|
graphics/*.gif The system graphic files |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head1 OVERVIEW: |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
When I designed the Family Tree Generator, I wanted more than just an online version of a traditional tree. With this software it is possible to draw a tree of ancestors and descendants for any person, showing any number of generations (where the information exists). |
436
|
|
|
|
|
|
|
Most other web-based "trees" are little more than text listings of people. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
A simple datafile contains details of people and their relationships. All the HTML pages are generated on the fly. This means that the tree is easy to maintain. |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
Note that the tree shows the "genetic" family tree. It contains no information about marriages and adaptation. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
For a demonstration of this software, visit http://www.ilab.sztaki.hu/~bodon/Simpsons/cgi/ftree.cgi or http://www.ilab.sztaki.hu/~bodon/ftree2/cgi/ftree.cgi. |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
The program is written in Perl. |
445
|
|
|
|
|
|
|
It runs as a CGI program - its output is the HTML of the page that you see. |
446
|
|
|
|
|
|
|
The program reads in the data file, and analyzes the relationships to determine the ancestors, siblings and descendants of the person selected. |
447
|
|
|
|
|
|
|
HTML tables are generated to display these trees, linking in the portrait images where they exist. |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head1 INSTALLATION INSTRUCTIONS: |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
1. Set up your web server (apache or IIS) so that it can run Perl scripts (e.g. mod-perl). |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
2. Uncompress and copy the demo package (make sure that you reserve the rights, i.e. files with extension pm, gif, jpg, png, tif, csv, txt, xls must be readable, files with extension cgi and pl must be executable). |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
3. Modify tree.xls so that it contains the details of your family. Tip: Select the second row, click on menu Window and select Freeze Panels. This will freeze the first row and you can see the title of columns. |
456
|
|
|
|
|
|
|
See format description below. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
4. Update the config/PerlSettingsImporter.pm file (you can specify the administrator's email, homepage, default language etc.). |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
5. Copy the pictures of your family members to the pictures directory. |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
6. That's it. |
463
|
|
|
|
|
|
|
Call the ftree.cgi script with no parameters to get your index page. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
7. If you are unhappy with the style and colors of the output then point the css_filename entry in PerlSettingsImporter.pm into your stly sheet. |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=head1 INSTALLATION INSTRUCTIONS FOR XAMPP for Windows 5.6.12: |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
Download I use xampp XAMPP for Windows 5.6.12 (https://www.apachefriends.org/ru/download.html) to install and configure Apache |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
<IfModule alias_module> |
472
|
|
|
|
|
|
|
ScriptAlias /cgi-bin/ "C:/xampp/cgi-bin/ftree/cgi/" |
473
|
|
|
|
|
|
|
</IfModule> |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
<Directory "C:/xampp/cgi-bin/ftree/cgi"> |
476
|
|
|
|
|
|
|
AllowOverride All |
477
|
|
|
|
|
|
|
Options None |
478
|
|
|
|
|
|
|
Require all granted |
479
|
|
|
|
|
|
|
</Directory> |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
My shebang in ftree.cgi is #!"c:\Dwimperl\perl\bin\perl.exe" (by Gabor Sabo) |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
copy c:\xampp\cgi-bin\ftree\graphics\ |
484
|
|
|
|
|
|
|
to |
485
|
|
|
|
|
|
|
c:\xampp\htdocs\graphics\ |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
to correct show images |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
I catch error couldn't create child process: 720002 |
490
|
|
|
|
|
|
|
------------------------ |
491
|
|
|
|
|
|
|
It was the first line in the .cgi file that needed to be adapted to Xamp's configuration: |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
#!"c:\xampp\perl\bin\perl.exe" |
494
|
|
|
|
|
|
|
Instead of: |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
#!"c:\perl\bin\perl.exe" |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
https://forum.xojo.com/20697-couldn-t-create-child-process-720002-error-when-deploying-on-wi/0 |
499
|
|
|
|
|
|
|
http://open-server.ru/forum/viewtopic.php?f=6&t=1059 |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=head1 NAME OF THE PICTURE: |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
One picture may belong to each person. |
504
|
|
|
|
|
|
|
No image put here and name=id.jpg |
505
|
|
|
|
|
|
|
c:\xampp\cgi-bin\ftree\pictures\ |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=head1 DATAFILE FORMAT: |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
The program can handle excel, csv (txt), gedcom, serialized files and can get data from database. Follow these rules to decide which one to use: |
510
|
|
|
|
|
|
|
1, Use gedcom if you already have your family tree data in a gedcom file and the fields that the program is able to import is sufficient. |
511
|
|
|
|
|
|
|
2, Use the excel format if you just started to build your family tree data. |
512
|
|
|
|
|
|
|
3, Convert your data file into serialized format if the data file contains many people (like some thousand) and you would like to reduce response time and memory need. |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
Data format history: |
515
|
|
|
|
|
|
|
Originally the input file was a csv flat file with semicolon as the separator. It could store 6 fields for each person (name, father name, mother name, email, webpage, date of birth/death). As new fields were required (like gender, place of birth, cemetery, etc.) and the number of optional fields increased from 5 to 22, the csv format turned out to be hard to maintain. Although it is possible to be imported/exported into excel, it would be better to use excel spreadsheets directly. From version 2.2 this is possible. For backward compatibility it is still possible to use csv files. The new fields can be used in csv fields as well. From version 2.3 gedcom files can also be used. |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
We encourage everybody to use the excel format. To convert from the csv format to the excel format, use script script/convertFormat.pl |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
TIP 1.: Maintain your family tree data in excel using the Form option. Select all the columns, then press DATA->Form. It is convenient to add new people or to modify information of existing persons. |
520
|
|
|
|
|
|
|
TIP 2.: Freeze the first line so that header does not disappear when scrolling down. |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
=head1 The excel format: |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
The excel format is quite straightforward based on the example file. Each row (except the header) represents a person. The fields are: |
525
|
|
|
|
|
|
|
* ID: the ID of the person. It can be anything (like 123 or Bart_Simpson), but it should only contain alphanumeric characters and underscore (no whitespace is allowed). |
526
|
|
|
|
|
|
|
* title: like: Dr., Prof. |
527
|
|
|
|
|
|
|
* prefix: like: sir |
528
|
|
|
|
|
|
|
* first name |
529
|
|
|
|
|
|
|
* middle name |
530
|
|
|
|
|
|
|
* last Name |
531
|
|
|
|
|
|
|
* suffix: like: VIII |
532
|
|
|
|
|
|
|
* nickname |
533
|
|
|
|
|
|
|
* father's ID |
534
|
|
|
|
|
|
|
* mother's ID |
535
|
|
|
|
|
|
|
* email |
536
|
|
|
|
|
|
|
* webpage |
537
|
|
|
|
|
|
|
* date of birth: the format is day/month/year, like: 24/3/1977 |
538
|
|
|
|
|
|
|
* date of death: the format is day/month/year, like: 24/3/1977 |
539
|
|
|
|
|
|
|
* gender: 0 for male, 1 female |
540
|
|
|
|
|
|
|
* is living?: 0 for live 1 for dead |
541
|
|
|
|
|
|
|
* place of birth: the format is: "country" "city". The city part may be omitted. Quotation marks are mandatory. |
542
|
|
|
|
|
|
|
* place of death: the format is: "country" "city". The city part may be omitted. Quotation marks are mandatory. |
543
|
|
|
|
|
|
|
* cemetery: the format is: "country" "city" "cemetery", like: "USA" "Washington D.C." "Arlington National Cemetery" |
544
|
|
|
|
|
|
|
* schools: use comma as separator, like: Harward, MIT |
545
|
|
|
|
|
|
|
* jobs: use comma as separator |
546
|
|
|
|
|
|
|
* work places: use comma as separator |
547
|
|
|
|
|
|
|
* places of living: places separated by comma, like: "USA" "Springfield", "USA" "Connecticut" |
548
|
|
|
|
|
|
|
* general: you would typically write something general about the person. |
549
|
|
|
|
|
|
|
Note, that the extension of an excel data file must be xls. |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
Tip: Select the second row, click on menu Window and select Freeze Panels. |
552
|
|
|
|
|
|
|
This will freeze the first row and you can see the title of columns. |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=head1 The csv format: |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
Semicolon is the separator. The fields are: |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
1. Full name. |
559
|
|
|
|
|
|
|
Middle names can be included in this field. |
560
|
|
|
|
|
|
|
If more than one person share the same name, a number can be appended (not shown in the displayed output). For example, "Bart Simpson2". |
561
|
|
|
|
|
|
|
2. Father (optional - leave blank if not known). No middle names. |
562
|
|
|
|
|
|
|
3. Mother (optional) |
563
|
|
|
|
|
|
|
4. email address (optional) |
564
|
|
|
|
|
|
|
5. web page (optional) |
565
|
|
|
|
|
|
|
6. Dates, birth-death (both optional). |
566
|
|
|
|
|
|
|
Examples: "17/10/49-24/11/83", "10/69-" |
567
|
|
|
|
|
|
|
Note that the year of birth is not displayed for people who are still alive. |
568
|
|
|
|
|
|
|
7. Gender (0 for male, 1 for female) |
569
|
|
|
|
|
|
|
8. title: like: Dr., Prof. |
570
|
|
|
|
|
|
|
9. prefix: like: sir |
571
|
|
|
|
|
|
|
10. suffix: like: VIII |
572
|
|
|
|
|
|
|
11. is living?: 0 for live 1 for dead |
573
|
|
|
|
|
|
|
12. place of birth: the format is: "country" "city". The city part may be omitted. Quotation marks are mandatory. |
574
|
|
|
|
|
|
|
13. place of death: the format is: "country" "city". The city part may be omitted. Quotation marks are mandatory. |
575
|
|
|
|
|
|
|
14. cemetery: the format is: "country" "city" "cemetery", like: "USA" "Washington D.C." "Arlington National Cemetery" |
576
|
|
|
|
|
|
|
15. schools: use comma as separator, like: Harward,MIT |
577
|
|
|
|
|
|
|
16. jobs: use comma as separator |
578
|
|
|
|
|
|
|
17. work places: use comma as separator |
579
|
|
|
|
|
|
|
18. places of living: places separated by comma, like: "USA" "Springfield", "USA" "Connecticut" |
580
|
|
|
|
|
|
|
19. general: you would typically write something general about the person. |
581
|
|
|
|
|
|
|
Note, that the extension of a csv data file must be either csv or txt. To define the encoding of the file use option encoding in the config file. |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=head1 Convert from csv (txt) format to excel format: |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
To switch from comma separated value file to excel spreadsheet, do the following: |
586
|
|
|
|
|
|
|
cd ftree2 |
587
|
|
|
|
|
|
|
perl ./scripts/convertFormat.pl ./tree.txt ./tree.xls |
588
|
|
|
|
|
|
|
This will generate (overwrite) a tree.xls file. |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
The GEDCOM format: |
591
|
|
|
|
|
|
|
GEDCOM, an acronym for GEnealogical Data COMmunication, is a specification for exchanging genealogical data between different genealogy software. GEDCOM was developed by The Church of Jesus Christ of Latter-day Saints as an aid in their extensive genealogical research. A GEDCOM file is plain text (an obscure text encoding named ANSEL, though often in ASCII in the United States) containing genealogical information about individuals, and data linking these records together. Most genealogy software supports importing from and/or exporting to GEDCOM format. |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
Beside the father, mother relationships, the program handles the following information of a person: |
594
|
|
|
|
|
|
|
1, gender |
595
|
|
|
|
|
|
|
2, date of birth |
596
|
|
|
|
|
|
|
3, date of death |
597
|
|
|
|
|
|
|
4, place of birth (only city and country are extracted) |
598
|
|
|
|
|
|
|
5, place of death (only city and country are extracted) |
599
|
|
|
|
|
|
|
6, cemetery (only cemetery, city and country are extracted) |
600
|
|
|
|
|
|
|
7, email address |
601
|
|
|
|
|
|
|
8, homepage |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
It is possible to switch from GEDCOM to excel (or serialized) format. Use the scripts/convertFormat.pl script. For example |
604
|
|
|
|
|
|
|
cd ftree2 |
605
|
|
|
|
|
|
|
perl ./scripts/convertFormat.pl ./tree.ged ./tree.xls |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
The ser format: |
608
|
|
|
|
|
|
|
The drawback of excel, csv and GEDCOM format is that it has to be parsed and processed every time the program runs. It is possible to speed-up the program (and hence reduce response time) and reduce memory usage if you use the serialized format. The serialized format cannot be edited directly. Basically you maintain your family tree data in excel (or in csv or GEDCOM) then create a serialized file using scripts/convertFormat.pl program. If the name of the family tree data is ftree.xls then, the following commands will generate the serialized file: |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
cd ftree2 |
611
|
|
|
|
|
|
|
perl ./scripts/convertFormat.pl ./tree.xls ./tree.ser |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
Don't forget to set the data_source to "../tree.ser" in the PerlSettingsImporter.pm file. |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
Note, that the extension of a serialized data file must be ser. Also keep in mind that different versions of perl may produce incompatible serialized versions. It is advised to run the convertFormat.pl script on the same mashine where the webserver runs. |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
=head1 NAME OF THE PICTURE: |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
One picture may belong to each person. The name of the picture file reflects the person it belongs to. The picture file is obtained from the lowercased full name by substituting spaces with underscores and adding the file extension to it. From example from "Ferenc Bodon3" we get "ferenc_bodon3.jpg". |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
=head1 PERFORMANCE ISSUES: |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
This sofware was not designed so that it can handle very large family trees. It can easily cope with few thousands of members, but latency (time till page is generated) grows as the size of the family tree increases. |
624
|
|
|
|
|
|
|
The main bottleneck of performance is that (1.) mod_perl is not used, therefore perl interpreter is starts for every request (2.) family tree is not cached but data file is parsed and tree is built-up for every request (using serialized format helps a little). |
625
|
|
|
|
|
|
|
Since the purpose of this software is to provide a free and simple tool for those who would like to maintain their family tree themself, performance is not the primary concern. |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
=head1 SECURITY ISSUES: |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
The protection provided by password request (set in config file) is quite primitive, i.e. it is easy to break it. |
630
|
|
|
|
|
|
|
Ther are historical reasons for being available. We suggest to use server side protection like .htaccess files in case of apache web servers. |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head1 AUTHORS |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
Dr. Ferenc Bodon and Simon Ward and Nikolay Mishin |
635
|
|
|
|
|
|
|
http://www.cs.bme.hu/~bodon/en/index.html |
636
|
|
|
|
|
|
|
http://simonward.com |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
=head1 MAINTAINER |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
Nikolay Mishin |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
=head1 COPYRIGHT |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
Copyright 2015- Dr. Ferenc Bodon and Simon Ward and Nikolay Mishin |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
=head1 LICENSE |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
649
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
I am in debt to the translators: |
654
|
|
|
|
|
|
|
Csaba Kiss (French) |
655
|
|
|
|
|
|
|
Gergely Kovacs (German), |
656
|
|
|
|
|
|
|
Przemek Swiderski (Polish), |
657
|
|
|
|
|
|
|
Rober Miles (Italian), |
658
|
|
|
|
|
|
|
Lajos Malozsak (Romanian), |
659
|
|
|
|
|
|
|
Vladimir Kangin (Russian) |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
I also would like to thank the feedback/help of (in no particular order) Alex Roitman, Anthony Fletcher, |
662
|
|
|
|
|
|
|
Richard Bos, Sylvia McKenzie and Sean Symes. |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
=head1 SEE ALSO |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=cut |
667
|
|
|
|
|
|
|
|