tbrehm
2010-07-13 3250e5e37c27acf09d03c89270b5b8e98b7072fa
commit | author | age
9200ad 1 <?php
T 2
3 /*
4 Copyright (c) 2007, Till Brehm, projektfarm Gmbh
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without modification,
8 are permitted provided that the following conditions are met:
9
10     * Redistributions of source code must retain the above copyright notice,
11       this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright notice,
13       this list of conditions and the following disclaimer in the documentation
14       and/or other materials provided with the distribution.
15     * Neither the name of ISPConfig nor the names of its contributors
16       may be used to endorse or promote products derived from this software without
17       specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /*
32     This function returns a string that describes the installed
33     linux distribution. e.g. debian40 for Debian Linux 4.0
34 */
35
c87c0a 36
P 37
38 /*
39 Comments to completion forever ;-)
40 commandline arguments
41 $argv[1]
42
43
44 <?
45 echo "Total argument passed are : $argc \n";
46 for( $i = 0 ; $i <= $argc -1 ;$i++)
47 {
48 echo "Argument $i : $argv[$i] \n";
49 }
50 ?> 
51
52 */
53 error_reporting(E_ALL|E_STRICT);
54
55
56 $FILE = realpath('../install.php');
57
cc3fb3 58 //** Get distribution identifier
220bb9 59 //** IMPORTANT!
V 60 //   This is the same code as in /server/mods-available/monitor_core_module.inc.php
61 //   So if you change it here, you also have to change it in
62 //   /server/mods-available/monitor_core_module.inc.php!
9200ad 63 function get_distname() {
cc3fb3 64     
f629e2 65     $distname = '';
1b40a8 66     $distver = '';
T 67     $distid = '';
68     $distbaseid = '';
f629e2 69     
T 70     //** Debian or Ubuntu
cc3fb3 71     if(file_exists('/etc/debian_version')) {
O 72     
73         if(trim(file_get_contents('/etc/debian_version')) == '4.0') {
344393 74             $distname = 'Debian';
T 75             $distver = '4.0';
76             $distid = 'debian40';
90511b 77             $distbaseid = 'debian';
03ade5 78             swriteln("Operating System: Debian 4.0 or compatible\n");
1cb2e1 79         } elseif(strstr(trim(file_get_contents('/etc/debian_version')),'5.0')) {
344393 80             $distname = 'Debian';
1cb2e1 81             $distver = 'Lenny';
344393 82             $distid = 'debian40';
90511b 83             $distbaseid = 'debian';
1cb2e1 84             swriteln("Operating System: Debian Lenny or compatible\n");
F 85         } elseif(strstr(trim(file_get_contents('/etc/debian_version')),'6.0') || trim(file_get_contents('/etc/debian_version')) == 'squeeze/sid') {
86             $distname = 'Debian';
87             $distver = 'Squeeze/Sid';
94927b 88             $distid = 'debian60';
1cb2e1 89             $distbaseid = 'debian';
94927b 90             swriteln("Operating System: Debian 6.0 (Squeeze/Sid) or compatible\n");
1b40a8 91         }  else {
T 92             $distname = 'Debian';
93             $distver = 'Unknown';
94             $distid = 'debian40';
95             $distbaseid = 'debian';
96             swriteln("Operating System: Debian or compatible, unknown version.\n");
cc3fb3 97         }
O 98     }
99     
7d89f5 100     //** OpenSuSE
T 101     elseif(file_exists("/etc/SuSE-release")) {
102         if(stristr(file_get_contents('/etc/SuSE-release'),'11.0')) {
344393 103             $distname = 'openSUSE';
T 104             $distver = '11.0';
105             $distid = 'opensuse110';
90511b 106             $distbaseid = 'opensuse';
7d89f5 107             swriteln("Operating System: openSUSE 11.0 or compatible\n");
1b40a8 108         } elseif(stristr(file_get_contents('/etc/SuSE-release'),'11.1')) {
a21c72 109             $distname = 'openSUSE';
T 110             $distver = '11.1';
111             $distid = 'opensuse110';
112             $distbaseid = 'opensuse';
113             swriteln("Operating System: openSUSE 11.1 or compatible\n");
1b40a8 114         } elseif(stristr(file_get_contents('/etc/SuSE-release'),'11.2')) {
T 115             $distname = 'openSUSE';
df7e6d 116             $distver = '11.2';
T 117             $distid = 'opensuse112';
1b40a8 118             $distbaseid = 'opensuse';
T 119             swriteln("Operating System: openSUSE 11.2 or compatible\n");
120         }  else {
121             $distname = 'openSUSE';
122             $distver = 'Unknown';
df7e6d 123             $distid = 'opensuse112';
1b40a8 124             $distbaseid = 'opensuse';
T 125             swriteln("Operating System: openSUSE or compatible, unknown version.\n");
a21c72 126         }
7d89f5 127     }
T 128     
129     
cc3fb3 130     //** Redhat
0711af 131     elseif(file_exists("/etc/redhat-release")) {
T 132         
133         $content = file_get_contents('/etc/redhat-release');
134         
135         if(stristr($content,'Fedora release 9 (Sulphur)')) {
344393 136             $distname = 'Fedora';
T 137             $distver = '9';
138             $distid = 'fedora9';
90511b 139             $distbaseid = 'fedora';
0711af 140             swriteln("Operating System: Fedora 9 or compatible\n");
1b40a8 141         } elseif(stristr($content,'Fedora release 10 (Cambridge)')) {
5939ea 142             $distname = 'Fedora';
F 143             $distver = '10';
144             $distid = 'fedora9';
145             $distbaseid = 'fedora';
146             swriteln("Operating System: Fedora 10 or compatible\n");
e08bdc 147         } elseif(stristr($content,'Fedora release 10')) {
T 148             $distname = 'Fedora';
149             $distver = '11';
150             $distid = 'fedora9';
151             $distbaseid = 'fedora';
152             swriteln("Operating System: Fedora 11 or compatible\n");
1b40a8 153         } elseif(stristr($content,'CentOS release 5.2 (Final)')) {
663619 154             $distname = 'CentOS';
T 155             $distver = '5.2';
156             $distid = 'centos52';
157             $distbaseid = 'fedora';
158             swriteln("Operating System: CentOS 5.2 or compatible\n");
1b40a8 159         } elseif(stristr($content,'CentOS release 5.3 (Final)')) {
T 160             $distname = 'CentOS';
161             $distver = '5.3';
edebc4 162             $distid = 'centos53';
1b40a8 163             $distbaseid = 'fedora';
T 164             swriteln("Operating System: CentOS 5.3 or compatible\n");
165         } else {
166             $distname = 'Redhat';
167             $distver = 'Unknown';
168             $distid = 'fedora9';
169             $distbaseid = 'fedora';
170             swriteln("Operating System: Redhat or compatible, unknown version.\n");
663619 171         }
cb8c86 172     }
W 173     
174     //** Gentoo
175      elseif(file_exists("/etc/gentoo-release")) {
176          
177          $content = file_get_contents('/etc/gentoo-release');
178  
179         preg_match_all('/([0-9]{1,2})/', $content, $version);
180          $distname = 'Gentoo';
181          $distver = $version[0][0].$version[0][1];
182          $distid = 'gentoo';
183          $distbaseid = 'gentoo';
184          swriteln("Operating System: Gentoo $distver or compatible\n");
0711af 185         
7d89f5 186     } else {
T 187         die('unrecognized linux distribution');
cc3fb3 188     }
O 189     
90511b 190     return array('name' => $distname, 'version' => $distver, 'id' => $distid, 'baseid' => $distbaseid);
9200ad 191 }
T 192
193 function sread() {
ba66cd 194     $input = fgets(STDIN);
9200ad 195     return rtrim($input);
T 196 }
197
239ce8 198 function swrite($text = '') {
9200ad 199     echo $text;
T 200 }
201
239ce8 202 function swriteln($text = '') {
9200ad 203     echo $text."\n";
T 204 }
205
206 function ilog($msg){
66b4f9 207       exec("echo `date` \"- [ISPConfig] - \"".$msg." >> ".ISPC_LOG_FILE);
9200ad 208 }
T 209
210 function error($msg){
c87c0a 211     ilog($msg);
P 212     die($msg."\n");
9200ad 213 }
T 214
215 function caselog($command, $file = '', $line = '', $success = '', $failure = ''){
c87c0a 216     exec($command,$arr,$ret_val);
P 217     $arr = NULL;
218     if(!empty($file) && !empty($line)){
219         $pre = $file.', Line '.$line.': ';
220     } else {
221         $pre = '';
222     }
223     if($ret_val != 0){
224         if($failure == '') $failure = 'could not '.$command;
225         ilog($pre.'WARNING: '.$failure);
226     } else {
227         if($success == '') $success = $command;
228         ilog($pre.$success);
229     }
9200ad 230 }
T 231
232 function phpcaselog($ret_val, $msg, $file = '', $line = ''){
c87c0a 233     if(!empty($file) && !empty($line)){
P 234         $pre = $file.', Line '.$line.': ';
235     } else {
236         $pre = '';
237     }
238     if($ret_val == true){
239         ilog($pre.$msg);
240     } else {
241         ilog($pre.'WARNING: could not '.$msg);
242     }
243     return $ret_val;
9200ad 244 }
T 245
246 function mkdirs($strPath, $mode = '0755'){
2ffaf4 247     if(isset($strPath) && $strPath != ''){
c87c0a 248         //* Verzeichnisse rekursiv erzeugen
P 249         if(is_dir($strPath)){
250             return true;
251         }
252         $pStrPath = dirname($strPath);
253         if(!mkdirs($pStrPath, $mode)){
254             return false;
255         }
256         $old_umask = umask(0);
257         $ret_val = mkdir($strPath, octdec($mode));
258         umask($old_umask);
259         return $ret_val;
260     }
261     return false;
9200ad 262 }
T 263
264 function rf($file){
c87c0a 265     clearstatcache();
b77113 266     if(is_file($file)) {
T 267         if(!$fp = fopen ($file, 'rb')){
268             ilog('WARNING: could not open file '.$file);
269         }
270         return filesize($file) > 0 ? fread($fp, filesize($file)) : '';
271     } else {
272         return '';
c87c0a 273     }
9200ad 274 }
T 275
276 function wf($file, $content){
c87c0a 277     mkdirs(dirname($file));
P 278     if(!$fp = fopen ($file, 'wb')){
279         ilog('WARNING: could not open file '.$file);
280     }
281     fwrite($fp, $content);
282     fclose($fp);
9200ad 283 }
T 284
285 function af($file, $content){
c87c0a 286     mkdirs(dirname($file));
P 287     if(!$fp = fopen ($file, 'ab')){
288         ilog('WARNING: could not open file '.$file);
289     }
290     fwrite($fp,$content);
291     fclose($fp);
9200ad 292 }
T 293
294 function aftsl($file, $content){
c87c0a 295     if(!$fp = fopen ($file, 'ab')){
P 296         ilog('WARNING: could not open file '.$file);
297     }
298     fwrite($fp,$content);
299     fclose($fp);
9200ad 300 }
T 301
302 function unix_nl($input){
c87c0a 303     $output = str_replace("\r\n", "\n", $input);
P 304     $output = str_replace("\r", "\n", $output);
305     return $output;
9200ad 306 }
T 307
308 function remove_blank_lines($input, $file = 1){
c87c0a 309     //TODO ? Leerzeilen l�schen
P 310     if($file){
311         $content = unix_nl(rf($input)); // WTF -pedro !
312     }else{
313         $content = $input;
314     }
315     $lines = explode("\n", $content);
316     if(!empty($lines)){
317         foreach($lines as $line){
318             if(trim($line) != '') $new_lines[] = $line;
319         }
320     }
321     if(is_array($new_lines)){
322         $content = implode("\n", $new_lines);
323     } else {
324         $content = '';
325     }
326     if($file){
327         wf($input, $content);
328     }else{
329         return $content;
330     }
9200ad 331 }
T 332
333 function no_comments($file, $comment = '#'){
c87c0a 334     $content = unix_nl(rf($file));
P 335     $lines = explode("\n", $content);
336     if(!empty($lines)){
337         foreach($lines as $line){
338             if(strstr($line, $comment)){
339                 $pos = strpos($line, $comment);
340                 if($pos != 0){
341                     $new_lines[] = substr($line,0,$pos);
342                 }else{
343                     $new_lines[] = '';
344                 }
345             }else{
346                 $new_lines[] = $line;
347             }
348         }
349     }
350     if(is_array($new_lines)){
351         $content_without_comments = implode("\n", $new_lines);
352         $new_lines = NULL;
353         return $content_without_comments;
354     } else {
355         return '';
356     }
9200ad 357 }
T 358
359 function find_includes($file){
360   global $httpd_root;
361   clearstatcache();
362   if(is_file($file) && filesize($file) > 0){
363     $includes[] = $file;
364     $inhalt = unix_nl(no_comments($file));
365     $lines = explode("\n", $inhalt);
366     if(!empty($lines)){
367       foreach($lines as $line){
2ffaf4 368         if(stristr($line, 'include ')){
P 369           $include_file = str_replace("\n", '', trim(shell_exec("echo \"$line\" | awk '{print \$2}'")));
370           if(substr($include_file,0,1) != '/'){
371             $include_file = $httpd_root.'/'.$include_file;
9200ad 372           }
T 373           if(is_file($include_file)){
374             if($further_includes = find_includes($include_file)){
375               $includes = array_merge($includes, $further_includes);
376             }
377           } else {
2ffaf4 378             if(strstr($include_file, '*')){
9200ad 379               $more_files = explode("\n", shell_exec("ls -l $include_file | awk '{print \$9}'"));
T 380               if(!empty($more_files)){
381                 foreach($more_files as $more_file){
382                   if(is_file($more_file)){
383                     if($further_includes = find_includes($more_file)){
384                       $includes = array_merge($includes, $further_includes);
385                     }
386                   }
387                 }
388               }
389               unset($more_files);
390               $more_files = explode("\n", shell_exec("ls -l $include_file | awk '{print \$10}'"));
391               if(!empty($more_files)){
392                 foreach($more_files as $more_file){
393                   if(is_file($more_file)){
394                     if($further_includes = find_includes($more_file)){
395                       $includes = array_merge($includes, $further_includes);
396                     }
397                   }
398                 }
399               }
400             }
401           }
402         }
403       }
404     }
405   }
406   if(is_array($includes)){
407     $includes = array_unique($includes);
408     return $includes;
409   } else {
410     return false;
411   }
412 }
413
414 function comment_out($file, $string){
c87c0a 415     $inhalt = no_comments($file);
P 416     $gesamt_inhalt = rf($file);
417     $modules = explode(',', $string);
418     foreach($modules as $val){
419         $val = trim($val);
420         if(strstr($inhalt, $val)){
421             $gesamt_inhalt = str_replace($val, '##ISPConfig INSTALL## '.$val, $gesamt_inhalt);
422         }
423     }
424     wf($file, $gesamt_inhalt);
9200ad 425 }
T 426
427 function is_word($string, $text, $params = ''){
c87c0a 428   //* params: i ??
P 429   return preg_match("/\b$string\b/$params", $text);
430   /*
9200ad 431   if(preg_match("/\b$string\b/$params", $text)) {
T 432     return true;
433   } else {
434     return false;
435   }
c87c0a 436   */
9200ad 437 }
T 438
439 function grep($content, $string, $params = ''){
440   // params: i, v, w
441   $content = unix_nl($content);
442   $lines = explode("\n", $content);
443   foreach($lines as $line){
444     if(!strstr($params, 'w')){
445       if(strstr($params, 'i')){
446         if(strstr($params, 'v')){
447           if(!stristr($line, $string)) $find[] = $line;
448         } else {
449           if(stristr($line, $string)) $find[] = $line;
450         }
451       } else {
452         if(strstr($params, 'v')){
453           if(!strstr($line, $string)) $find[] = $line;
454         } else {
455           if(strstr($line, $string)) $find[] = $line;
456         }
457       }
458     } else {
459       if(strstr($params, 'i')){
460         if(strstr($params, 'v')){
461           if(!is_word($string, $line, 'i')) $find[] = $line;
462         } else {
463           if(is_word($string, $line, 'i')) $find[] = $line;
464         }
465       } else {
466         if(strstr($params, 'v')){
467           if(!is_word($string, $line)) $find[] = $line;
468         } else {
469           if(is_word($string, $line)) $find[] = $line;
470         }
471       }
472     }
473   }
474   if(is_array($find)){
475     $ret_val = implode("\n", $find);
476     if(substr($ret_val,-1) != "\n") $ret_val .= "\n";
477     $find = NULL;
478     return $ret_val;
479   } else {
480     return false;
481   }
482 }
483
484 function edit_xinetd_conf($service){
c87c0a 485     $xinetd_conf = '/etc/xinetd.conf';
P 486     $contents = unix_nl(rf($xinetd_conf));
487     $lines = explode("\n", $contents);
488     $j = sizeof($lines);
489     for($i=0;$i<sizeof($lines);$i++){
490         if(grep($lines[$i], $service, 'w')){
491             $fundstelle_anfang = $i;
492             $j = $i;
493             $parts = explode($lines[$i], $contents);
494         }
495         if($j < sizeof($lines)){
496             if(strstr($lines[$i], '}')){
497                 $fundstelle_ende = $i;
498                 $j = sizeof($lines);
499             }
500         }
501     }
502     if(isset($fundstelle_anfang) && isset($fundstelle_ende)){
503         for($i=$fundstelle_anfang;$i<=$fundstelle_ende;$i++){
504             if(strstr($lines[$i], 'disable')){
505                 $disable = explode('=', $lines[$i]);
506                 $disable[1] = ' yes';
507                 $lines[$i] = implode('=', $disable);
508             }
509         }
510     }
511     $fundstelle_anfang = NULL;
512     $fundstelle_ende = NULL;
513     $contents = implode("\n", $lines);
514     wf($xinetd_conf, $contents);
9200ad 515 }
T 516
4f7028 517 //* Converts a ini string to array
T 518 function ini_to_array($ini) {
519     $config = '';
520     $ini = str_replace("\r\n", "\n", $ini);
521     $lines = explode("\n", $ini);
522     foreach($lines as $line) {
523         $line = trim($line);                
524         if($line != '') {
525             if(preg_match("/^\[([\w\d_]+)\]$/", $line, $matches)) {
526                 $section = strtolower($matches[1]);
527             } elseif(preg_match("/^([\w\d_]+)=(.*)$/", $line, $matches) && $section != null) {
528                 $item = trim($matches[1]);
529                 $config[$section][$item] = trim($matches[2]);
530             }
531         }
532     }
533     return $config;
534 }
535     
536     
537 //* Converts a config array to a string
a171d6 538 function array_to_ini($config_array = '') {
4f7028 539     if($config_array == '') $config_array = $this->config;
T 540     $content = '';
541     foreach($config_array as $section => $data) {
542         $content .= "[$section]\n";
543         foreach($data as $item => $value) {
544             if($item != ''){
545                 $content .= "$item=$value\n";
546             }
547         }
548         $content .= "\n";
549     }
550     return $content;
551 }
552
b73329 553 function is_user($user){
T 554   global $mod;
555   $user_datei = '/etc/passwd';
556   $users = no_comments($user_datei);
557   $lines = explode("\n", $users);
558   if(is_array($lines)){
559     foreach($lines as $line){
560       if(trim($line) != ""){
561         list($f1, $f2, $f3, $f4, $f5, $f6, $f7) = explode(":", $line);
562         if($f1 == $user) return true;
563       }
564     }
565   }
566   return false;
567 }
568
569 function is_group($group){
570   global $mod;
571   $group_datei = '/etc/group';
572   $groups = no_comments($group_datei);
573   $lines = explode("\n", $groups);
574   if(is_array($lines)){
575     foreach($lines as $line){
576       if(trim($line) != ""){
577         list($f1, $f2, $f3, $f4) = explode(":", $line);
578         if($f1 == $group) return true;
579       }
580     }
581   }
582   return false;
583 }
584
f28f40 585 function replaceLine($filename,$search_pattern,$new_line,$strict = 0,$append = 1) {
663619 586     if($lines = @file($filename)) {
0711af 587         $out = '';
T 588         $found = 0;
589         foreach($lines as $line) {
590             if($strict == 0) {
591                 if(stristr($line,$search_pattern)) {
592                     $out .= $new_line."\n";
593                     $found = 1;
594                 } else {
595                     $out .= $line;
596                 }
597             } else {
598                 if(trim($line) == $search_pattern) {
599                     $out .= $new_line."\n";
600                     $found = 1;
601                 } else {
602                     $out .= $line;
603                 }
604             }
605         }
606         if($found == 0) {
b9dbe7 607             //* add \n if the last line does not end with \n or \r
T 608             if(substr($out,-1) != "\n" && substr($out,-1) != "\r") $out .= "\n";
609             //* add the new line at the end of the file
f28f40 610             if($append == 1) $out .= $new_line."\n";
0711af 611         }
T 612         file_put_contents($filename,$out);
663619 613     }
0711af 614 }
T 615     
616 function removeLine($filename,$search_pattern,$strict = 0) {
663619 617     if($lines = @file($filename)) {
0711af 618         $out = '';
T 619         foreach($lines as $line) {
620             if($strict == 0) {
621                 if(!stristr($line,$search_pattern)) {
622                     $out .= $line;
623                 }
624             } else {
625                 if(!trim($line) == $search_pattern) {
626                     $out .= $line;
627                 }
628             }
629         }
630         file_put_contents($filename,$out);
663619 631     }
0711af 632 }
T 633
0a1f02 634 function is_installed($appname) {
976815 635     exec('which '.escapeshellcmd($appname).' 2> /dev/null',$out);
aee6fd 636     if(isset($out[0]) && stristr($out[0],$appname)) {
0a1f02 637         return true;
T 638     } else {
639         return false;
640     }
641 }
642
3250e5 643 /*
T 644  * Compare ISPConfig version number.
645  * return values:
646  * -1 $current version is newer then $new version (downgrade)
647  * 0 $current version = $new version
648  * 1 $current version is older then new version (update)
649
650 */
651 function compare_ispconfig_version($current,$new) {
652     if( $current == $new) {
653         return 0;
654     }
655     
656     $p = explode('.',$current);
657     $tmp = '';
658     $tmp .= str_pad(intval($p[0]), 3, '0', STR_PAD_LEFT);
659     $tmp .= (isset($p[1]))?str_pad(intval($p[1]), 3, '0', STR_PAD_LEFT):'000';
660     $tmp .= (isset($p[2]))?str_pad(intval($p[2]), 3, '0', STR_PAD_LEFT):'000';
661     $tmp .= (isset($p[3]))?str_pad(intval($p[3]), 3, '0', STR_PAD_LEFT):'000';
662     $current = $tmp;
663     
664     $p = explode('.',$new);
665     $tmp = '';
666     $tmp .= str_pad(intval($p[0]), 3, '0', STR_PAD_LEFT);
667     $tmp .= (isset($p[1]))?str_pad(intval($p[1]), 3, '0', STR_PAD_LEFT):'000';
668     $tmp .= (isset($p[2]))?str_pad(intval($p[2]), 3, '0', STR_PAD_LEFT):'000';
669     $tmp .= (isset($p[3]))?str_pad(intval($p[3]), 3, '0', STR_PAD_LEFT):'000';
670     $new = $tmp;
671     
672     if($new > $current) {
673         return 1;
674     } else {
675         return -1;
676     }
677     
678 }
679
4f7028 680
T 681
d1386a 682 ?>