[Bio] / FigKernelPackages / HTML.pm Repository:
ViewVC logotype

Annotation of /FigKernelPackages/HTML.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (view) (download) (as text)

1 : efrank 1.1 package HTML;
2 :    
3 :     use Carp;
4 :     use Data::Dumper;
5 :     use LWP::UserAgent;
6 :     use LWP::Simple;
7 :     use URI::URL;
8 :     use HTTP::Request::Common;
9 :    
10 :     sub show_page {
11 :     my($cgi,$html,$no_home) = @_;
12 :     my $i;
13 :    
14 : olson 1.2 #
15 :     # Find the HTML header
16 :     #
17 :    
18 :     my $html_hdr_file = "./Html/html.hdr";
19 :     if (! -f $html_hdr_file)
20 :     {
21 :     $html_hdr_file = "$FIG_Config::fig/CGI/Html/html.hdr";
22 :     }
23 :    
24 :     my $html_tail_file = "./Html/html.tail";
25 :     if (! -f $html_tail_file)
26 :     {
27 :     $html_tail_file = "$FIG_Config::fig/CGI/Html/html.tail";
28 :     }
29 :    
30 : olson 1.15 my @html_hdr = &FIG::file_read($html_hdr_file);
31 :     if (@html_hdr)
32 :     {
33 :     my $insert_stuff;
34 :     my @ver = &FIG::file_head("$FIG_Config::fig_disk/CURRENT_RELEASE", 1);
35 :     my $ver = $ver[0];
36 :     chomp $ver;
37 :     if ($ver =~ /^cvs\.(\d+)$/)
38 :     {
39 :     my $d = asctime(localtime($1));
40 :     chomp($d);
41 :     $ver .= " ($d)";
42 :     }
43 :     my $host = &FIG::get_local_hostname();
44 :     $insert_stuff = "SEED version <b>$ver</b> on $host";
45 :    
46 :     for $_ (@html_hdr)
47 :     {
48 :     s,(href|img\s+src)="/FIG/,\1="$FIG_Config::cgi_base,g;
49 :     if ($_ eq "<!-- HEADER_INSERT -->\n")
50 :     {
51 :     $_ = $insert_stuff;
52 :     }
53 :     }
54 :     }
55 :    
56 : olson 1.2
57 : efrank 1.1 print $cgi->header;
58 : golsen 1.5
59 :     #
60 : golsen 1.6 # The SEED header file goes immediately after <BODY>. Figure out
61 :     # what parts of the HTML document skeleton are there, and fill in
62 :     # missing ones.
63 : golsen 1.5 #
64 : golsen 1.6 # This list should be as comprehensive as feasible:
65 : golsen 1.5 #
66 :    
67 : golsen 1.6 my %head_tag = ( base => 1,
68 :     basefont => 1,
69 :     html => 1,
70 :     isindex => 1,
71 :     link => 1,
72 :     meta => 1,
73 :     nextid => 1,
74 :     style => 1,
75 :     title => 1
76 :     );
77 :    
78 :     #
79 :     # This list need not be comprehensive; it is just stopping conditions:
80 :     #
81 :    
82 :     my %body_tag = ( a => 1,
83 :     br => 1,
84 :     center => 1,
85 :     form => 1,
86 :     h1 => 1,
87 :     h2 => 1,
88 :     h3 => 1,
89 :     hr => 1,
90 :     img => 1,
91 :     p => 1,
92 :     pre => 1,
93 :     table => 1
94 :     );
95 :    
96 :     my $html_line = -1;
97 :     my $head_line = -1;
98 :     my $base_line = -1;
99 :     my $head_end_line = -1;
100 :     my $body_line = -1;
101 :     my $last_head_line = -1; # If no head tags are found, text goes at top.
102 :     my $done = 0;
103 :    
104 :     for ( $i = 0; $i < @$html; $i++ )
105 :     {
106 :     # Some special cases:
107 :    
108 :     if ( $html->[$i] =~ /\<html[^0-9a-z]/i ) { $html_line = $i }
109 :     if ( $html->[$i] =~ /\<head[^0-9a-z]/i ) { $head_line = $i }
110 :     if ( $html->[$i] =~ /\<base[^0-9a-z]/i ) { $base_line = $i }
111 :     if ( $html->[$i] =~ /\<\/head\>/i ) { $head_end_line = $i }
112 :    
113 :     # The content goes after this line:
114 :    
115 :     if ( $html->[$i] =~ /\<body[^0-9a-z]/i )
116 :     {
117 :     $body_line = $i;
118 :     $last;
119 :     }
120 :    
121 :     # Now the general case.
122 :     # Analyze all the html tags on the line:
123 :    
124 :     foreach ( $html->[$i] =~ /\<\/?([0-9a-z]+)/ig )
125 :     {
126 :     # At first body tag, we stop the search and put the text
127 :     # after the last line with a head tag:
128 :    
129 :     if ( $body_tag{ lc $_ } )
130 :     {
131 :     $done = 1;
132 :     last;
133 :     }
134 :    
135 :     # If this is a head tag, then move the marker forward
136 :    
137 :     elsif ( $head_tag{ lc $_ } )
138 :     {
139 :     $last_head_line = $i;
140 :     }
141 :     }
142 :     last if $done; # When done, break loop to avoid increment
143 : efrank 1.1 }
144 : golsen 1.6
145 :     # Some sanity checks on structure:
146 :    
147 :     if ( 1 )
148 : efrank 1.1 {
149 : golsen 1.6 if ( $html_line >= 0 )
150 : efrank 1.1 {
151 : golsen 1.6 if ( ( $head_line >= 0 ) && ( $html_line > $head_line ) )
152 :     {
153 :     print STDERR "<HTML> tag follows <HEAD> tag\n";
154 :     }
155 :     if ( ( $head_end_line >= 0 ) && ( $html_line > $head_end_line ) )
156 :     {
157 :     print STDERR "<HTML> tag follows </HEAD> tag\n";
158 :     }
159 : efrank 1.1 }
160 : golsen 1.6 if ( $head_line >= 0 )
161 : efrank 1.1 {
162 : golsen 1.6 if ( ( $head_end_line >= 0 ) && ( $head_line > $head_end_line ) )
163 :     {
164 :     print STDERR "<HEAD> tag follows </HEAD> tag\n";
165 :     }
166 : efrank 1.1 }
167 :     }
168 :    
169 : golsen 1.6 #
170 :     # Okay. Let's put in the html header file, and missing tags:
171 :     #
172 :     # <BODY> goes after last head line
173 :     #
174 :    
175 :     if ( $body_line < 0 )
176 :     {
177 :     $body_line = $last_head_line + 1;
178 :     splice( @$html, $body_line, 0, "<BODY>\n" );
179 :     }
180 :    
181 :     #
182 :     # Seed page header (if it exists) goes after <BODY>
183 :     #
184 :    
185 : olson 1.15 if (@html_hdr)
186 : golsen 1.6 {
187 : olson 1.15 splice( @$html, $body_line + 1, 0, @html_hdr );
188 : golsen 1.6 }
189 :    
190 :     #
191 :     # </HEAD> goes before <BODY>
192 :     #
193 :    
194 :     if ( $head_end_line < 0 )
195 :     {
196 :     $head_end_line = $body_line;
197 :     splice( @$html, $body_line, 0, "</HEAD>\n" );
198 :     }
199 :    
200 :     #
201 :     # <BASE ...> goes before </HEAD>
202 :     #
203 :    
204 :     if ( $base_line < 0 )
205 :     {
206 :     #
207 :     # Use a relative base address for pages. Also, because I am
208 :     # worried about when FIG_config.pm gets updated (clean installs
209 :     # only, or every update?), I provide an alternative derivation
210 :     # from $cgi_url. -- GJO
211 :     #
212 : olson 1.7 # BASE href needs to be absolute. RDO.
213 :     #
214 :     #
215 :     $base_url = &FIG::cgi_url;
216 :     # my $base_url = $FIG_Config::cgi_base;
217 :     # if ( ! $base_url ) # if cgi_base was not defined
218 :     # {
219 :     # $base_url = $FIG_Config::cgi_url; # get the full cgi url
220 :     # $base_url =~ s~^http://[^/]*~~; # remove protocol and host
221 :     # $base_url =~ m~/$~ || $base_url =~ s~$~/~; # check trailing slash
222 :     # }
223 : golsen 1.6
224 :     $base_line = $head_end_line;
225 : olson 1.8 splice( @$html, $base_line, 0, "<BASE href=\"$base_url/\">\n" );
226 : golsen 1.6 }
227 :    
228 :     #
229 :     # <HTML> goes at the top of the output
230 :     #
231 :    
232 :     if ( $html_line < 0 )
233 :     {
234 :     $html_line = 0;
235 :     splice( @$html, $html_line, 0, "<HTML>\n" );
236 :     }
237 :    
238 :     #
239 :     # <HEAD> goes after <HTML>
240 :     #
241 :    
242 :     if ( $head_line < 0 )
243 :     {
244 :     $head_line = $html_line + 1;
245 :     splice( @$html, $head_line, 0, "<HEAD>\n" );
246 :     }
247 :    
248 :     #
249 :     # Place FIG search link at bottom of page
250 :     #
251 :    
252 :     my @tail = -f $html_tail_file ? `cat $html_tail_file` : ();
253 : efrank 1.1 if (! $no_home)
254 :     {
255 : golsen 1.6 my $user = $cgi->param('user') || "";
256 :     push( @tail, "<hr><a href=\"index.cgi?user=$user\">FIG search</a>\n" );
257 : efrank 1.1 }
258 :    
259 : golsen 1.6 #
260 :     # Figure out where to insert The SEED tail. Before </body>,
261 :     # or before </html>, or at end of page.
262 :     #
263 :    
264 :     my @tags = ();
265 :    
266 :     for ($i=0; ($i < @$html) && ($html->[$i] !~ /\<\/body\>/i); $i++) {}
267 :     if ($i >= @$html) # </body> not found; look for </html>
268 : efrank 1.1 {
269 : golsen 1.6 push @tags, "\n</BODY>\n";
270 :     # Even if tag is not found, index points to correct place for splice
271 :     for ($i=0; ($i < @$html) && ($html->[$i] !~ /\<\/html\>/i); $i++) {}
272 :     if ($i >= @$html) # </html> not found; add it
273 : efrank 1.1 {
274 : golsen 1.6 push @tags, "</HTML>\n";
275 : efrank 1.1 }
276 :     }
277 : golsen 1.6
278 :     if ( @tail )
279 :     {
280 :     splice( @$html, $i, 0, @tail, @tags );
281 :     }
282 :     elsif ( @tags )
283 :     {
284 :     splice( @$html, $i, 0, @tags );
285 :     }
286 :    
287 : efrank 1.1 print @$html;
288 :     }
289 :    
290 :     sub make_table {
291 : overbeek 1.9 my($col_hdrs,$tab,$title) = @_;
292 : efrank 1.1 my(@tab);
293 :    
294 : golsen 1.6 push( @tab, "\n<table border>\n",
295 :     "\t<caption><b>$title</b></caption>\n",
296 :     "\t<tr>\n\t\t<th>"
297 :     . join( "</th>\n\t\t<th>", @$col_hdrs )
298 :     . "</th>\n\t</tr>\n"
299 :     );
300 : overbeek 1.9 my($i);
301 : efrank 1.1
302 : overbeek 1.3 my $row;
303 :     foreach $row (@$tab)
304 : efrank 1.1 {
305 : golsen 1.6 push( @tab, "\t<tr>\n"
306 : overbeek 1.9 . join( "\n", map { &expand($_) } @$row )
307 : golsen 1.6 . "\n\t</tr>\n"
308 :     );
309 : efrank 1.1 }
310 :     push(@tab,"</table>\n");
311 :     return join("",@tab);
312 :     }
313 :    
314 : overbeek 1.3 sub expand {
315 : overbeek 1.9 my($x) = @_;
316 : overbeek 1.3
317 : overbeek 1.9 if ($x =~ /^\@([^:]+)\:(.*)$/)
318 : overbeek 1.3 {
319 : overbeek 1.9 return "\t\t<td $1>$2</td>";
320 : overbeek 1.3 }
321 :     else
322 :     {
323 : overbeek 1.9 return "\t\t<td>$x</td>";
324 : overbeek 1.3 }
325 :     }
326 :    
327 : overbeek 1.11 sub set_ec_links {
328 :     my($cgi,$x) = @_;
329 :     my($before,$match,$after);
330 :    
331 :     if ($x =~ /^(.*)(EC \d+\.\d+\.\d+\.\d+)(.*)/s)
332 :     {
333 :     $before = $1;
334 :     $match = $2;
335 :     $after = $3;
336 :     return &set_ec_links($cgi,$before) . &HTML::ec_link($match) . &set_ec_links($cgi,$after);
337 :     }
338 :     return $x;
339 :     }
340 :    
341 : efrank 1.1 sub ec_link {
342 :     my($role) = @_;
343 :    
344 :     if ($role =~ /(\d+\.\d+\.\d+\.\d+)/)
345 :     {
346 :     return "<a href=\"http://www.genome.ad.jp/dbget-bin/www_bget?ec:$1\">$role</a>";
347 :     }
348 :     else
349 :     {
350 :     return $role;
351 :     }
352 :     }
353 :    
354 :     sub role_link {
355 :     my($cgi,$role) = @_;
356 :    
357 :     my $roleR = ($role =~ /^(\d+\.\d+\.\d+\.\d+)\s+-\s+/) ? $1 : $role;
358 :     my $user = $cgi->param('user');
359 :     if (! $user) { $user = "" }
360 :     my $link = $cgi->url() . "?role=$roleR&user=$user";
361 :     $link =~ s/[a-z]+\.cgi\?/pom.cgi?/;
362 :     return "<a href=$link>$role</a>";
363 :     }
364 :    
365 : olson 1.13 #
366 :     # Local means to eliminate the fig|org.peg from the
367 :     # text of the link.
368 :     #
369 : efrank 1.1 sub fid_link {
370 :     my($cgi,$fid,$local,$just_url) = @_;
371 :     my($n);
372 :    
373 :     if ($fid =~ /^fig\|\d+\.\d+\.([a-z]+)\.(\d+)/)
374 :     {
375 :     if ($local)
376 :     {
377 :     if ($1 eq "peg")
378 :     {
379 :     $n = $2;
380 :     }
381 :     else
382 :     {
383 :     $n = "$1.$2";
384 :     }
385 :     }
386 :     else
387 :     {
388 :     $n = $fid;
389 :     }
390 :     if ($1 ne "peg") { return $n }
391 :     my $user = $cgi->param('user');
392 :     if (! $user) { $user = "" }
393 :     my $trans = $cgi->param('translate') ? "&translate=1" : "";
394 :     my $link = $cgi->url() . "?prot=$fid&user=$user$trans";
395 : overbeek 1.10 $link =~ s/[a-z_A-Z0-9]+\.cgi\?/protein.cgi?/;
396 : olson 1.15 #
397 :     # Elimin the p2p part if we're in that subdir. Ugh.
398 :     #
399 :     $link =~ s,p2p/protein.cgi,protein.cgi,;
400 :    
401 : efrank 1.1 if ($just_url)
402 :     {
403 :     return $link;
404 :     }
405 :     else
406 :     {
407 :     return "<a href=$link>$n</a>";
408 :     }
409 :     }
410 :     return $fid;
411 :     }
412 :    
413 :     sub family_link {
414 :     my($family,$user) = @_;
415 :    
416 :     return $family;
417 :     }
418 :    
419 :     use URI::Escape;
420 :    
421 :     sub get_html {
422 :     my( $url, $type, $kv_pairs) = @_;
423 :     my( $encoded, $ua, $args, @args, $out, @output, $x );
424 :    
425 :     $ua = new LWP::UserAgent;
426 :     $ua->timeout( 900 );
427 :    
428 :     if ($type =~/post/i)
429 :     {
430 :     $args = [];
431 :     foreach $x (@$kv_pairs)
432 :     {
433 :     push(@$args, ( $x->[0], $x->[1]) );
434 :     }
435 :     my $request = POST $url, $args;
436 :     my $response = $ua->request($request);
437 :     $out = $response->content;
438 :     }
439 :     else
440 :     {
441 :     @args = ();
442 :     foreach $x (@$kv_pairs)
443 :     {
444 :     push( @args, "$x->[0]=" . uri_escape($x->[1]) );
445 :     }
446 :    
447 :     if (@args > 0)
448 :     {
449 :     $url .= "?" . join("&",@args);
450 :     }
451 :     $request = new HTTP::Request('GET', $url);
452 :     my $response = $ua->request($request);
453 :    
454 :     if ($response->is_success)
455 :     {
456 :     $out = $response->content;
457 :     }
458 :     else
459 :     {
460 :     $out = "<H1>Error: " . $response->code . "</H1>" . $response->message;
461 :     }
462 :     }
463 :     # set up a document with proper eol characters
464 :     @output = split(/[\012\015]+/,$out);
465 :     foreach $out (@output) { $out .= "\n"; }
466 :    
467 :     # Now splice in a line of the form <base href=URL> to cause all relative links to work
468 :     # properly. Remove the header.
469 :    
470 :     for ($i=0; ($i < @output) && ($output[$i] !~ /^\s*\</); $i++) {}
471 :     if ($i < @output)
472 :     {
473 :    
474 :     splice(@output,0,$i);
475 :     }
476 :    
477 :     for ($i=0; ($i < @output) && ($output[$i] !~ /\<body\>/i); $i++) {}
478 :     if ($i == @output)
479 :     {
480 :     $i = -1;
481 :     }
482 :     splice(@output,$i+1,0,"<base href=\"$url\">\n");
483 :     return @output;
484 :     }
485 :    
486 :     sub trim_output {
487 :     my($out) = @_;
488 :     my $i;
489 :    
490 :     for ($i=0; ($i < @$out) && ($out->[$i] !~ /^\</); $i++) {}
491 :     splice(@$out,0,$i);
492 :    
493 :     for ($i=0; ($i < @$out) && ($out->[$i] !~ /\<body\>/i); $i++) {}
494 :     if ($i == @$out)
495 :     {
496 :     for ($i=0; ($i < @$out) && ($out->[$i] !~ /\<html\>/i); $i++) {}
497 :     if ($i == @$out)
498 :     {
499 :     $i = -1;
500 :     }
501 :     }
502 :     for ($j=$i+1; ($j < @$out) && ($out->[$j] !~ /^\<hr\>$/); $j++) {}
503 :     if ($j < @$out)
504 :     {
505 :     splice(@$out,$i+1,($j-$i));
506 :     }
507 :    
508 :     for ($i=0; ($i < @$out) && ($out->[$i] !~ /\<\/body\>/i); $i++) {}
509 :     if ($i == @$out)
510 :     {
511 :     for ($i=0; ($i < @$out) && ($out->[$i] !~ /\<\/html\>/i); $i++) {}
512 :     }
513 :    
514 :     for ($j=$i-1; ($j > 0) && ($out->[$j] !~ /FIG search/); $j--) {}
515 :     if ($j > 0)
516 :     {
517 : olson 1.2 my @tmp = `cat $html_tail_file`;
518 : efrank 1.1 my $n = @tmp;
519 :     splice(@$out,$j-$n,$n+1);
520 :     }
521 :     }
522 :    
523 :     sub set_prot_links {
524 :     my($cgi,$x) = @_;
525 :     my($before,$match,$after);
526 :    
527 : overbeek 1.11 if ($x =~ /^(.*)(fig\|\d+\.\d+\.peg\.\d+)(.*)/s)
528 : efrank 1.1 {
529 :     $before = $1;
530 :     $match = $2;
531 :     $after = $3;
532 : overbeek 1.11 return &set_prot_links($cgi,$before) . &HTML::fid_link($cgi,$match) . &set_prot_links($cgi,$after);
533 : efrank 1.1 }
534 : overbeek 1.11 elsif ($x =~ /^(.*)(gi\|\d+)(.*)/s)
535 : efrank 1.1 {
536 :     $before = $1;
537 :     $match = $2;
538 :     $after = $3;
539 : overbeek 1.11 return &set_prot_links($cgi,$before) . &HTML::gi_link($cgi,$match) . &set_prot_links($cgi,$after);
540 : efrank 1.1 }
541 : overbeek 1.14 elsif ($x =~ /^(.*)(uni\|[A-Z0-9]{6})(.*)/s)
542 :     {
543 :     $before = $1;
544 :     $match = $2;
545 :     $after = $3;
546 :     return &set_prot_links($cgi,$before) . &HTML::uni_link($cgi,$match) . &set_prot_links($cgi,$after);
547 :     }
548 : overbeek 1.11 elsif ($x =~ /^(.*)(sp\|[A-Z0-9]{6})(.*)/s)
549 : efrank 1.1 {
550 :     $before = $1;
551 :     $match = $2;
552 :     $after = $3;
553 : overbeek 1.11 return &set_prot_links($cgi,$before) . &HTML::sp_link($cgi,$match) . &set_prot_links($cgi,$after);
554 : efrank 1.1 }
555 : overbeek 1.11 elsif ($x =~ /^(.*)(pirnr\|NF\d+)(.*)/s)
556 : efrank 1.1 {
557 :     $before = $1;
558 :     $match = $2;
559 :     $after = $3;
560 : overbeek 1.11 return &set_prot_links($cgi,$before) . &HTML::pir_link($cgi,$match) . &set_prot_links($cgi,$after);
561 : efrank 1.1 }
562 : overbeek 1.12 elsif ($x =~ /^(.*)(kegg\|[a-z]{2,4}:[a-zA-Z_0-9]+)(.*)/s)
563 :     {
564 :     $before = $1;
565 :     $match = $2;
566 :     $after = $3;
567 :     return &set_prot_links($cgi,$before) . &HTML::kegg_link($cgi,$match) . &set_prot_links($cgi,$after);
568 :     }
569 : efrank 1.1 return $x;
570 :     }
571 :    
572 :     sub gi_link {
573 :     my($cgi,$gi) = @_;
574 :    
575 :     if ($gi =~ /^gi\|(\d+)$/)
576 :     {
577 :     return "<a href=http://www.ncbi.nlm.nih.gov:80/entrez/query.fcgi?cmd=Retrieve&db=Protein&list_uids=$1&dopt=GenPept>$gi</a>";
578 :     }
579 :     return $gi;
580 :     }
581 :    
582 : overbeek 1.14 sub uni_link {
583 :     my($cgi,$uni) = @_;
584 :    
585 :     if ($uni =~ /^uni\|(\S+)$/)
586 :     {
587 :     return "<a href=http://www.pir.uniprot.org/cgi-bin/upEntry?id=$1>$uni</a>";
588 :     }
589 :     return $uni;
590 :     }
591 :    
592 : efrank 1.1 sub sp_link {
593 :     my($cgi,$sp) = @_;
594 :    
595 :     if ($sp =~ /^sp\|(\S+)$/)
596 :     {
597 :     return "<a href=http://us.expasy.org/cgi-bin/get-sprot-entry?$1>$sp</a>";
598 :     }
599 :     return $sp;
600 :     }
601 :    
602 :     sub pir_link {
603 :     my($cgi,$pir) = @_;
604 :    
605 :     if ($pir =~ /^pirnr\|(NF\d+)$/)
606 :     {
607 :     return "<a href=http://pir.georgetown.edu/cgi-bin/nfEntry.pl?id=$1>$pir</a>";
608 :     }
609 :     return $pir;
610 :     }
611 :    
612 : overbeek 1.12 sub kegg_link {
613 :     my($cgi,$kegg) = @_;
614 :    
615 :     if ($kegg =~ /^kegg\|([^:]+):(\S+)$/)
616 :     {
617 :     return "<a href=http://www.genome.ad.jp/dbget-bin/www_bget?$1+$2>$kegg</a>";
618 :     }
619 :     return $kegg;
620 :     }
621 :    
622 : overbeek 1.11 sub set_map_links {
623 :     my($cgi,$x) = @_;
624 :     my($before,$match,$after);
625 : efrank 1.1
626 : overbeek 1.11 my $org = ($cgi->param('org') || $cgi->param('genome') || "");
627 :    
628 :     if ($x =~ /^(.*)(MAP\d+)(.*)/s)
629 :     {
630 :     $before = $1;
631 :     $match = $2;
632 :     $after = $3;
633 :     return &set_map_links($cgi,$before) . &map_link($cgi,$match,$org) . &set_map_links($cgi,$after);
634 :     }
635 :     return $x;
636 :     }
637 :    
638 :     sub map_link {
639 :     my($cgi,$map,$org) = @_;
640 :    
641 :     $user = $cgi->param('user');
642 :     $user = $user ? $user : "";
643 :     $org = $org ? $org : "";
644 :     my $url = "$FIG_Config::cgi_url/show_kegg_map.cgi?user=$user&map=$map&org=$org";
645 :     my $link = "<a href=\"$url\">$map</a>";
646 :     return $link;
647 :     }
648 :    
649 : efrank 1.1 1

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3