95_holiday.pm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. #######################################################################
  2. # $Id: 95_holiday.pm 15433 2017-11-15 09:51:10Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. use POSIX;
  7. sub holiday_refresh($;$$);
  8. #####################################
  9. sub
  10. holiday_Initialize($)
  11. {
  12. my ($hash) = @_;
  13. $hash->{DefFn} = "holiday_Define";
  14. $hash->{GetFn} = "holiday_Get";
  15. $hash->{SetFn} = "holiday_Set";
  16. $hash->{UndefFn} = "holiday_Undef";
  17. $hash->{AttrList} = $readingFnAttributes;
  18. }
  19. #####################################
  20. sub
  21. holiday_Define($$)
  22. {
  23. my ($hash, $def) = @_;
  24. return holiday_refresh($hash->{NAME}, undef, 1) if($init_done);
  25. InternalTimer(gettimeofday()+1, "holiday_refresh", $hash->{NAME}, 0);
  26. return undef;
  27. }
  28. sub
  29. holiday_Undef($$)
  30. {
  31. my ($hash, $name) = @_;
  32. RemoveInternalTimer($name);
  33. return undef;
  34. }
  35. sub
  36. holiday_refresh($;$$)
  37. {
  38. my ($name, $fordate, $showAvailable) = (@_);
  39. my $hash = $defs{$name};
  40. my $fromTimer=0;
  41. return if(!$hash); # Just deleted
  42. my $nt = gettimeofday();
  43. my @lt = localtime($nt);
  44. my @fd;
  45. if(!$fordate) {
  46. $fromTimer = 1;
  47. $fordate = sprintf("%02d-%02d", $lt[4]+1, $lt[3]);
  48. @fd = @lt;
  49. } else {
  50. my ($m,$d) = split("-", $fordate);
  51. @fd = localtime(mktime(1,1,1,$d,$m-1,$lt[5],0,0,-1));
  52. }
  53. Log3 $name, 5, "holiday_refresh $name called for $fordate ($fromTimer)";
  54. my $dir = $attr{global}{modpath} . "/FHEM";
  55. my ($err, @holidayfile) = FileRead("$dir/$name.holiday");
  56. if($err) {
  57. $dir = $attr{global}{modpath}."/FHEM/holiday";
  58. ($err, @holidayfile) = FileRead("$dir/$name.holiday");
  59. $hash->{READONLY} = 1;
  60. } else {
  61. $hash->{READONLY} = 0;
  62. }
  63. if($err) {
  64. if($showAvailable) {
  65. my @ret;
  66. if(configDBUsed()) {
  67. @ret = cfgDB_FW_fileList($dir,".*.holiday",@ret);
  68. map { s/\.configDB$//;$_ } @ret;
  69. } else {
  70. if(opendir(DH, $dir)) {
  71. @ret = grep { m/\.holiday$/ } readdir(DH);
  72. closedir(DH);
  73. }
  74. }
  75. $err .= "\nAvailable holiday files: ".
  76. join(" ", map { s/.holiday//;$_ } @ret);
  77. } else {
  78. Log 1, "$name: $err";
  79. }
  80. return $err;
  81. }
  82. $hash->{HOLIDAYFILE} = "$dir/$name.holiday";
  83. my @foundList;
  84. foreach my $l (@holidayfile) {
  85. next if($l =~ m/^\s*#/);
  86. next if($l =~ m/^\s*$/);
  87. my $found;
  88. if($l =~ m/^1/) { # Exact date: 1 MM-DD Holiday
  89. my @args = split(" +", $l, 3);
  90. if($args[1] eq $fordate) {
  91. $found = $args[2];
  92. }
  93. } elsif($l =~ m/^2/) { # Easter date: 2 +1 Ostermontag
  94. ###mh new code for easter sunday calc w.o. requirement for
  95. # DateTime::Event::Easter
  96. # replace $a1 with $1 !!!
  97. # split line from file into args '2 <offset from E-sunday> <tagname>'
  98. my @a = split(" ", $l, 3);
  99. # get month & day for E-sunday
  100. my ($Om,$Od) = western_easter(($lt[5]+1900));
  101. my $timex = mktime(0,0,12,$Od,$Om-1, $lt[5],0,0,-1); # gen timevalue
  102. $timex = $timex + $a[1]*86400; # add offset days
  103. my ($msecond, $mminute, $mhour,
  104. $mday, $mmonth, $myear, $mrest) = localtime($timex);
  105. $myear = $myear+1900;
  106. $mmonth = $mmonth+1;
  107. #Log 1, "$name: Ostern:".sprintf("%04d-%02d-%02d", $lt[5]+1900, $Om, $Od).
  108. # " Target:".sprintf("%04d-%02d-%02d", $myear, $mmonth, $mday);
  109. next if($mday != $fd[3] || $mmonth != $fd[4]+1);
  110. $found = $a[2];
  111. Log 4, "$name: Match day: $a[2]\n";
  112. } elsif($l =~ m/^3/) { # Relative date: 3 -1 Mon 03 Holiday
  113. my @a = split(" +", $l, 5);
  114. my %wd = ("Sun"=>0, "Mon"=>1, "Tue"=>2, "Wed"=>3,
  115. "Thu"=>4, "Fri"=>5, "Sat"=>6);
  116. my @md = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  117. $md[1]=29 if(schaltjahr($fd[5]+1900) && $fd[4] == 1);
  118. my $wd = $wd{$a[2]};
  119. if(!defined($wd)) {
  120. Log 1, "Wrong timespec: $l";
  121. next;
  122. }
  123. next if($wd != $fd[6]); # Weekday
  124. next if($a[3] != ($fd[4]+1)); # Month
  125. if($a[1] > 0) { # N'th day from the start
  126. my $d = $fd[3] - ($a[1]-1)*7;
  127. next if($d < 1 || $d > 7);
  128. } elsif($a[1] < 0) { # N'th day from the end
  129. my $d = $fd[3] - ($a[1]+1)*7;
  130. my $md = $md[$fd[4]];
  131. next if($d > $md || $d < $md-6);
  132. }
  133. $found = $a[4];
  134. } elsif($l =~ m/^4/) { # Interval: 4 MM-DD MM-DD Holiday
  135. my @args = split(" +", $l, 4);
  136. if($args[1] le $fordate && $args[2] ge $fordate) {
  137. $found = $args[3];
  138. }
  139. } elsif($l =~ m/^5/) { # nth weekday since MM-DD / before MM-DD
  140. my @a = split(" +", $l, 6);
  141. # arguments: 5 <distance> <weekday> <month> <day> <name>
  142. my %wd = ("Sun"=>0, "Mon"=>1, "Tue"=>2, "Wed"=>3,
  143. "Thu"=>4, "Fri"=>5, "Sat"=>6);
  144. my $wd = $wd{$a[2]};
  145. if(!defined($wd)) {
  146. Log 1, "Wrong weekday spec: $l";
  147. next;
  148. }
  149. next if $wd != $fd[6]; # check wether weekday matches today
  150. my $yday=$fd[7];
  151. # create time object of target date - mktime counts months and their
  152. # days from 0 instead of 1, so subtract 1 from each
  153. my $tgt=mktime(0,0,1,$a[4],$a[3]-1,$fd[5],0,0,-1);
  154. my $tgtmin=$tgt;
  155. my $tgtmax=$tgt;
  156. my $weeksecs=7*24*60*60; # 7 days, 24 hours, 60 minutes, 60seconds each
  157. my $cd=mktime(0,0,1,$fd[3],$fd[4],$fd[5],0,0,-1);
  158. if ( $a[1] =~ /^-([0-9])*$/ ) {
  159. $tgtmin -= $1*$weeksecs; # Minimum: target date minus $1 weeks
  160. $tgtmax = $tgtmin+$weeksecs; # Maximum: one week after minimum
  161. # needs to be lower than max and greater than or equal to min
  162. if( ($cd ge $tgtmin) && ( $cd lt $tgtmax) ) {
  163. $found=$a[5];
  164. }
  165. } elsif ( $a[1] =~ /^\+?([0-9])*$/ ) {
  166. $tgtmin += ($1-1)*$weeksecs; # Minimum: target date plus $1-1 weeks
  167. $tgtmax = $tgtmin+$weeksecs; # Maximum: one week after minimum
  168. # needs to be lower than or equal to max and greater min
  169. if( ($cd gt $tgtmin) && ( $cd le $tgtmax) ) {
  170. $found=$a[5];
  171. }
  172. } else {
  173. Log 1, "Wrong distance spec: $l";
  174. next;
  175. }
  176. }
  177. push @foundList, $found if($found);
  178. }
  179. push @foundList, "none" if(!int(@foundList));
  180. my $found = join(", ", @foundList);
  181. if($fromTimer) {
  182. RemoveInternalTimer($name);
  183. $nt -= ($lt[2]*3600+$lt[1]*60+$lt[0]); # Midnight
  184. $nt += 86400 + 2; # Tomorrow
  185. $hash->{TRIGGERTIME} = $nt;
  186. InternalTimer($nt, "holiday_refresh", $name, 0);
  187. readingsBeginUpdate($hash);
  188. readingsBulkUpdate($hash, 'state', $found);
  189. readingsBulkUpdate($hash, 'yesterday', CommandGet(undef,"$name yesterday"));
  190. readingsBulkUpdate($hash, 'tomorrow', CommandGet(undef,"$name tomorrow"));
  191. readingsEndUpdate($hash,1);
  192. return undef;
  193. } else {
  194. return $found;
  195. }
  196. }
  197. sub
  198. holiday_Set($@)
  199. {
  200. my ($hash, @a) = @_;
  201. return "unknown argument $a[1], choose one of createPrivateCopy:noArg"
  202. if($a[1] ne "createPrivateCopy");
  203. return "Already a private version" if(!$hash->{READONLY});
  204. my $fname = $attr{global}{modpath}."/FHEM/holiday/$hash->{NAME}.holiday";
  205. my ($err, @holidayfile) = FileRead($fname);
  206. return $err if($err);
  207. $fname = $attr{global}{modpath}."/FHEM/$hash->{NAME}.holiday";
  208. $err = FileWrite($fname, @holidayfile);
  209. holiday_refresh($hash->{NAME});
  210. return $err;
  211. }
  212. sub
  213. holiday_Get($@)
  214. {
  215. my ($hash, @a) = @_;
  216. shift(@a) if($a[1] && $a[1] eq "MM-DD");
  217. return "argument is missing" if(int(@a) < 2);
  218. my $arg;
  219. if($a[1] =~ m/^[01]\d-[0-3]\d/) {
  220. $arg = $a[1];
  221. } elsif($a[1] =~ m/^(yesterday|today|tomorrow)$/) {
  222. my $t = time();
  223. $t += 86400 if($a[1] eq "tomorrow");
  224. $t -= 86400 if($a[1] eq "yesterday");
  225. my @a = localtime($t);
  226. $arg = sprintf("%02d-%02d", $a[4]+1, $a[3]);
  227. } elsif($a[1] eq "days") {
  228. my $t = time() + ($a[2] ? int($a[2]) : 0)*86400;
  229. my @a = localtime($t);
  230. $arg = sprintf("%02d-%02d", $a[4]+1, $a[3]);
  231. } else {
  232. return "unknown argument $a[1], choose one of ".
  233. "yesterday:noArg today:noArg tomorrow:noArg days:2,3,4,5,6,7 MM-DD";
  234. }
  235. return holiday_refresh($hash->{NAME}, $arg);
  236. }
  237. sub
  238. schaltjahr($)
  239. {
  240. my($jahr) = @_;
  241. return 0 if $jahr % 4; # 2009
  242. return 1 unless $jahr % 400; # 2000
  243. return 0 unless $jahr % 100; # 2100
  244. return 1; # 2012
  245. }
  246. ### mh sub western_easter copied from cpan Date::Time::Easter
  247. ### mh changes marked with # mh
  248. ### mh
  249. ### mh calling parameter is 4 digit year
  250. ### mh
  251. sub
  252. western_easter($)
  253. {
  254. my $year = shift;
  255. my $golden_number = $year % 19;
  256. #quasicentury is so named because its a century, only its
  257. # the number of full centuries rather than the current century
  258. my $quasicentury = int($year / 100);
  259. my $epact = ($quasicentury - int($quasicentury/4) -
  260. int(($quasicentury * 8 + 13)/25) + ($golden_number*19) + 15) % 30;
  261. my $interval = $epact - int($epact/28)*
  262. (1 - int(29/($epact+1)) * int((21 - $golden_number)/11) );
  263. my $weekday = ($year + int($year/4) + $interval +
  264. 2 - $quasicentury + int($quasicentury/4)) % 7;
  265. my $offset = $interval - $weekday;
  266. my $month = 3 + int(($offset+40)/44);
  267. my $day = $offset + 28 - 31* int($month/4);
  268. return $month, $day;
  269. }
  270. 1;
  271. =pod
  272. =item summary define holidays in a local file
  273. =item summary_DE Urlaubs-/Feiertagskalender aus einer lokalen Datei
  274. =begin html
  275. <a name="holiday"></a>
  276. <h3>holiday</h3>
  277. <ul>
  278. <a name="holidaydefine"></a>
  279. <b>Define</b>
  280. <ul>
  281. <code>define &lt;name&gt; holiday</code>
  282. <br><br>
  283. Define a set of holidays. The module will try to open the file
  284. &lt;name&gt;.holiday in the <a href="#modpath">modpath</a>/FHEM directory
  285. first, then in the modpath/FHEM/holiday directory, the latter containing a
  286. set of predefined files. The set will be shown if an error occures at the
  287. time of the definietion.<br>
  288. If entries in the holiday file match the current day, then the STATE of
  289. this holiday instance displayed in the <a href="#list">list</a> command
  290. will be set to the corresponding values, else the state is set to the text
  291. none. Most probably you'll want to query this value in some perl script:
  292. see Value() in the <a href="#perl">perl</a> section or the global attribute
  293. <a href="#holiday2we"> holiday2we</a>.<br> The file will be reread once
  294. every night, to compute the value for the current day, and by each get
  295. command (see below).<br>
  296. <br>
  297. Holiday file definition:<br>
  298. The file may contain comments (beginning with #) or empty lines.
  299. Significant lines begin with a number (type) and contain some space
  300. separated words, depending on the type. The different types are:<br>
  301. <ul>
  302. <li>1<br>
  303. Exact date. Arguments: &lt;MM-DD&gt; &lt;holiday-name&gt;<br>
  304. Exampe: 1 12-24 Christmas
  305. </li>
  306. <li>2<br>
  307. Easter-dependent date. Arguments: &lt;day-offset&gt;
  308. &lt;holiday-name&gt;.
  309. The offset is counted from Easter-Sunday.
  310. <br>
  311. Exampe: 2 1 Easter-Monday<br>
  312. Sidenote: You can check the easter date with:
  313. fhem> { join("-", western_easter(2011)) }
  314. </li>
  315. <li>3<br>
  316. Month dependent date. Arguments: &lt;nth&gt; &lt;weekday&gt;
  317. &lt;month &lt;holiday-name&gt;.<br>
  318. Examples:<br>
  319. <ul>
  320. 3 1 Mon 05 First Monday In May<br>
  321. 3 2 Mon 05 Second Monday In May<br>
  322. 3 -1 Mon 05 Last Monday In May<br>
  323. 3 0 Mon 05 Each Monday In May<br>
  324. </ul>
  325. </li>
  326. <li>4<br>
  327. Interval. Arguments: &lt;MM-DD&gt; &lt;MM-DD&gt; &lt;holiday-name&gt;
  328. .<br>
  329. Note: An interval cannot contain the year-end.
  330. Example:<br>
  331. <ul>
  332. 4 06-01 06-30 Summer holiday<br>
  333. 4 12-20 01-10 Winter holiday # DOES NOT WORK.
  334. Use the following 2 lines instead:<br>
  335. 4 12-20 12-31 Winter holiday<br>
  336. 4 01-01 01-10 Winter holiday<br>
  337. </ul>
  338. </li>
  339. <li>5<br>
  340. Date relative, weekday fixed holiday. Arguments: &lt;nth&gt;
  341. &lt;weekday&gt; &lt;month&gt; &lt;day&gt; &lt; holiday-name&gt;<br>
  342. Note that while +0 or -0 as offsets are not forbidden, their behaviour
  343. is undefined in the sense that it might change without notice.<br>
  344. Examples:<br>
  345. <ul>
  346. 5 -1 Wed 11 23 Buss und Bettag (first Wednesday before Nov, 23rd)<br>
  347. 5 1 Mon 01 31 First Monday after Jan, 31st (1st Monday in February)<br>
  348. </ul>
  349. </li>
  350. </ul>
  351. </ul>
  352. <br>
  353. <a name="holidayset"></a>
  354. <b>Set</b>
  355. <ul>
  356. <li>createPrivateCopy<br>
  357. <ul>
  358. if the holiday file is opened from the FHEM/holiday directory (which is
  359. refreshed by FHEM-update), then it is readonly, and should not be
  360. modified. With createPrivateCopy the file will be copied to the FHEM
  361. directory, where it can be modified.
  362. </ul></li>
  363. </ul><br>
  364. <a name="holidayget"></a>
  365. <b>Get</b>
  366. <ul>
  367. <code>get &lt;name&gt; &lt;MM-DD&gt;</code><br>
  368. <code>get &lt;name&gt; yesterday</code><br>
  369. <code>get &lt;name&gt; today</code><br>
  370. <code>get &lt;name&gt; tomorrow</code><br>
  371. <code>get &lt;name&gt; days <offset></code><br>
  372. <br><br>
  373. Return the holiday name of the specified date or the text none.
  374. <br><br>
  375. </ul>
  376. <br>
  377. <a name="holidayattr"></a>
  378. <b>Attributes</b><ul>N/A</ul><br>
  379. </ul>
  380. =end html
  381. =begin html_DE
  382. <a name="holiday"></a>
  383. <h3>holiday</h3>
  384. <ul>
  385. <a name="holidaydefine"></a>
  386. <b>Define</b>
  387. <ul>
  388. <code>define &lt;name&gt; holiday</code>
  389. <br><br>
  390. Definiert einen Satz mit Urlaubsinformationen. Das Modul versucht die
  391. Datei &lt;name&gt;.holiday erst in <a href="#modpath">modpath</a>/FHEM zu
  392. &ouml;ffnen, und dann in modpath/FHEM/holiday, Letzteres enth&auml;lt eine
  393. Liste von per FHEM-update verteilten Dateien f&uuml;r diverse
  394. (Bundes-)L&auml;nder. Diese Liste wird bei einer Feherlmeldung angezeigt.
  395. Wenn Eintr&auml;ge im der Datei auf den aktuellen Tag passen wird der STATE
  396. der Holiday-Instanz die im <a href="#list">list</a> Befehl angezeigt wird
  397. auf die entsprechenden Werte gesetzt. Andernfalls ist der STATE auf den
  398. Text "none" gesetzt.
  399. Meistens wird dieser Wert mit einem Perl Script abgefragt: siehe Value() im
  400. <a href="#perl">perl</a> Abschnitt oder im globalen Attribut <a
  401. href="#holiday2we"> holiday2we</a>.<br> Die Datei wird jede Nacht neu
  402. eingelesen um den Wert des aktuellen Tages zu erzeugen. Auch jeder "get"
  403. Befehl liest die Datei neu ein.
  404. <br><br>
  405. Holiday file Definition:<br>
  406. Die Datei darf Kommentare, beginnend mit #, und Leerzeilen enthalten. Die
  407. entscheidenden Zeilen beginnen mit einer Zahl (Typ) und enthalten durch
  408. Leerzeichen getrennte W&ouml;rter, je nach Typ. Die verschiedenen Typen
  409. sind:<br>
  410. <ul>
  411. <li>1<br>
  412. Genaues Datum. Argument: &lt;MM-TT&gt; &lt;Feiertag-Name&gt;<br>
  413. Beispiel: 1 12-24 Weihnachten
  414. </li>
  415. <li>2<br>
  416. Oster-abh&auml;ngiges Datum. Argument: &lt;Tag-Offset&gt;
  417. &lt;Feiertag-Name&gt;.
  418. Der Offset wird vom Oster-Sonntag an gez&auml;hlt.
  419. <br>
  420. Beispiel: 2 1 Oster-Montag<br>
  421. Hinweis: Das Osterdatum kann vorher gepr&uuml;ft werden:
  422. fhem> { join("-", western_easter(2011)) }
  423. </li>
  424. <li>3<br>
  425. Monats-abh&auml;ngiges Datum. Argument: &lt;X&gt; &lt;Wochentag&gt;
  426. &lt;Monat&gt; &lt;Feiertag-Name&gt;.<br>
  427. Beispiel:<br>
  428. <ul>
  429. 3 1 Mon 05 Erster Montag In Mai<br>
  430. 3 2 Mon 05 Zweiter Montag In Mai<br>
  431. 3 -1 Mon 05 Letzter Montag In Mai<br>
  432. 3 0 Mon 05 Jeder Montag In Mai<br>
  433. </ul>
  434. </li>
  435. <li>4<br>
  436. Intervall. Argument: &lt;MM-TT&gt; &lt;MM-TT&gt; &lt;Feiertag-Name&gt;
  437. .<br>
  438. Achtung: Ein Intervall darf kein Jahresende enthalten.
  439. Beispiel:<br>
  440. <ul>
  441. 4 06-01 06-30 Sommerferien<br>
  442. 4 12-20 01-10 Winterferien # FUNKTIONIER NICHT,
  443. stattdessen folgendes verwenden:<br>
  444. 4 12-20 12-31 Winterferien<br>
  445. 4 01-01 01-10 Winterferien<br>
  446. </ul>
  447. </li>
  448. <li>5<br>
  449. Datum relativ, Wochentags ein fester Urlaubstag/Feiertag. Argument:
  450. &lt;X&gt; &lt;Wochentag&gt; &lt;Monat&gt; &lt;Tag&gt;
  451. &lt;Feiertag-Name&gt;<br> Hinweis: Da +0 oder -0 als Offset nicht
  452. verboten sind, ist das Verhalten hier nicht definiert, kann sich also
  453. ohne Info &auml;ndern;<br>
  454. Beispiel:<br>
  455. <ul>
  456. 5 -1 Wed 11 23 Buss und Bettag (erster Mittwoch vor dem 23. Nov)<br>
  457. 5 1 Mon 01 31 Erster Montag in Februar<br>
  458. </ul>
  459. </li>
  460. </ul>
  461. </ul>
  462. <br>
  463. <a name="holidayset"></a>
  464. <b>Set</b>
  465. <ul>
  466. <li>createPrivateCopy<br>
  467. <ul>
  468. Falls die Datei in der FHEM/holiday Verzeichnis ge&ouml;ffnet wurde,
  469. dann ist sie nicht beschreibbar, da dieses Verzeichnis mit FHEM
  470. update aktualisiert wird. Mit createPrivateCopy kann eine private Kopie
  471. im FHEM Verzeichnis erstellt werden.
  472. </ul></li>
  473. </ul><br>
  474. <a name="holidayget"></a>
  475. <b>Get</b>
  476. <ul>
  477. <code>get &lt;name&gt; &lt;MM-DD&gt;</code><br>
  478. <code>get &lt;name&gt; yesterday</code><br>
  479. <code>get &lt;name&gt; today</code><br>
  480. <code>get &lt;name&gt; tomorrow</code><br>
  481. <code>get &lt;name&gt; days <offset></code><br>
  482. <br><br>
  483. Gibt den Name des Feiertages zum angebenenen Datum zur&uuml;ck oder den
  484. Text none.
  485. <br><br>
  486. </ul>
  487. <br>
  488. <a name="holidayattr"></a>
  489. <b>Attributes</b><ul>
  490. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  491. </ul><br>
  492. </ul>
  493. =end html_DE
  494. =cut