Mit dem morgigen FHEM Update und jetzt schon im SVN ist eine Version von ASC wo ich alle Prototypen raus gemacht habe und eine verbesserte RegEx Variante genommen habe.
Grüße
Marko
Über das Wort Prototypen stolpere ich die letzten Tage nun öfters, meine Versuche via Tante Google für mich verständliche Erklärungen zu finden sind bisher gescheitert.
Aber da ich eh einer der ganz großen Abschreiber bin : Hast du mal aus deinem Modul ein Stückchen vorher/nachher zur Hand ?
IsDay($@) {
}
Würde zu
IsDay {
}
Somit kommt es zu keinen Prototypmismatch.
Das ist jetzt nur so ein Beispiel aus dem Kopf.
Es gibt also keine feste Regel für die Funktion was ihr wie übergeben wird.
Du kannst Skalare oder Hashs oder Array übergeben. Wichtig ist aber das Du darauf achtest was die Funktion dann verarbeitet. Bei eigenem Code ist es leicht, wenn andere Deine Funktion verwenden sollen musst Du Fehler in der Übergabe abfangen.
perl critic meckert über meine Prototypen auch.
Was ist denn in Kurzform der Grund, diese nicht zu verwenden? Schließlich muss ich ja in der Funktion schon wissen, was ich das reinbekomme.
Es gibt keinen handfesten Grund.
Im Grunde halte ich mich persönlich an PBPund das was ich so in anderen Perlprojekten sehe.
https://www.perl-community.de/bat/poard/start
Es ist also eher eine persönliche Entscheidung auf Basis der Erfahrung anderer und dem PBP.
So lange Du selbst der Autor der Funktion bist und Du selbst diese nur aufrufst weißt Du es ja. Für andere Belange gibt es die Codekommentare. Und wenn Du Dir große Perlprojekten an schaust das ist die Hälfte des Textes in einer Datei Kommentar. ;D
Grüße
Zitat von: CoolTux am 26 März 2020, 17:29:07
Es gibt keinen handfesten Grund.
https://forum.fhem.de/index.php/topic,109526.0.html
und insbesondere
https://forum.fhem.de/index.php/topic,109526.msg1035260.html#msg1035260
Ich sehe das so:
Stell' Dir vor Du hast ein Auto bei dem in 99% der Fälle der Sicherheitsgurt versagt. Es scheint nun zwei Herangehensweisen zu geben wie man mit diesem Problem umgehen soll:
Herangehensweise 1) "Besser 1% als nix, wir lassen das so."
Herangehensweise 2) "Wir verwenden die Sicherheitsgurte nicht und machen stattdessen unsere eigenen oder nerven den Hersteller. Ggf. fangen wir an nachzubohren und finden heraus, dass das gar keine Sicherheitsgurte sind, sondern nur die vergessenen Hosenträger eines Automechanikers. Auf jeden Fall machen wir was mit der Situation um uns nicht in falscher Sicherheit zu wiegen."
Herangehensweise 2) ist anstrengender, aber für mich handfest genug, so dass ich sie propagiere.
Zitat von: Dr. Boris Neubert am 26 März 2020, 17:22:42
perl critic meckert über meine Prototypen auch.
Perl::Critic - guter Einwurf:
Subroutine prototypes used at line 53, column 1. See page 194 of PBP. (Severity: 5)
perlcritic verweist auf die Seite 194 im PBP als Erklärung warum Prototypen nicht so doll sind. Das ist auch die Kurzform.
@Richard,
Das mit perlcritic wäre doch auch eine gute Begründung für Deinen Einführungsthread.
Zitat von: CoolTux am 26 März 2020, 17:44:40
@Richard,
Das mit perlcritic wäre doch auch eine gute Begründung für Deinen Einführungsthread.
Dafür bin ich ethisch und moralisch viel zu unbefleckt. ;)
perlcritic
IST die prozeduralisierte Form von PBP. Perlcritic ist als Lösung entworfen worden, damit nicht Leute wie ich mit dem PBP Buch in der Hand rumlaufen müssen und anderen Leuten Seitenzahlen daraus aufsagen.
Ergo, mit perlcritic für PBP zu argumentieren wäre ein hinterlistiger Zirkelschluss.
Zitat von: RichardCZ am 26 März 2020, 17:50:53
perlcritic IST die prozeduralisierte Form von PBP. Perlcritic ist als Lösung entworfen worden, damit nicht Leute wie ich mit dem PBP Buch in der Hand rumlaufen müssen und anderen Leuten Seitenzahlen daraus aufsagen.
Nett.
Nur damit DAM's wie ich nicht in die changelogs zu Modulen sehen müssen, von deren Existenz sie bisher nicht mal was geahnt hatten: Irgendwo hatte ich aufgeschnappt, das 20 (oder 20%?) der PBP zwischenzeitlich überholt seien. Jetzt kann ich mir entweder die Fleißaufgabe stellen rauszufinden, welche das denn genau sind (oder clever danach suchen), oder mal mit der Annahme starten, dass Perl::Critic nicht nur die prozeduralisierte Form ist, sondern auch noch den aktuellen Stand der Dinge wiedergibt.
Daher die Frage nach der Abkürzung: Sagt mir dieses Modul, was der aktuelle Stand der PBP ist?
Zitat von: Beta-User am 26 März 2020, 18:03:46
Nur damit DAM's wie ich nicht in die changelogs zu Modulen sehen müssen, von deren Existenz sie bisher nicht mal was geahnt hatten: Irgendwo hatte ich aufgeschnappt, das 20 (oder 20%?) der PBP zwischenzeitlich überholt seien. Jetzt kann ich mir entweder die Fleißaufgabe stellen rauszufinden, welche das denn genau sind (oder clever danach suchen), oder mal mit der Annahme starten, dass Perl::Critic nicht nur die prozeduralisierte Form ist, sondern auch noch den aktuellen Stand der Dinge wiedergibt.
Daher die Frage nach der Abkürzung: Sagt mir dieses Modul, was der aktuelle Stand der PBP ist?
Dieses Modul (Perl::Critic), bzw. das Skript, das mitkommt "perlcritic" gibt ein wenig mehr Infos unter anderem eine "severity", also in etwa wie schlimm das ist was da gefunden wurde. Absteigend von 5 bis 1
Severity 5 ist eine thermonukleare Explosion
...
Severity 1 ist ein fast unsichtbarer Knick im Papier, der nur einen obsessiv-kompulsiven Autisten stört
So. Den Dynamikumfang habe ich aufgespannt, die Stufen dazwischen kann sich jeder selbst interpolieren. :)
DIe heute wenig bis nicht mehr relevanten Punkte sind alesamt in den Stufen 1,2 ... vielleicht etwas in 3 zu finden
Aus Erfahrung weiß ich, dass selbst die pedantischsten Perl Projekte selten alles in 2 hinbiegen wollen. Will sagen: Gemach! Man muss keine Angst haben, dass wenn man perlcritic auf Stufe 4 mundtot macht (ohne
## no critic Morphium), dass man irgendwo sinnlose Arbeit vollbracht hat.
Genau genommen, wer das in seinem Modul schafft, wird von mir erstmal lange nix hören. Motivation? ;D
edit:
Ich schiebe aber gleich hinterher, dass wenn diese Arbeit in einem Code erfolgt, den man hinterher eh als Altlast/überflüssig wegschmeisst, dann gilt das mit der sinnlosen Arbeit nicht mehr. Momentan gehe ich hier langsam Severity 5 Punkte durch, die einfach nur erstmal "Grundhygiene" sind. Damit man erstmal den groben Schmutz wegbekommt,
Hallo Richard,
Zitat von: RichardCZ am 26 März 2020, 18:18:14
Genau genommen, wer das in seinem Modul schafft, wird von mir erstmal lange nix hören. Motivation? ;D
Nichts gegen pointiertes Aufzeigen von wesentlichen Problemen in meinem Code. Aber das hört sich für mich wie der Missionar an, der mit der Perl-Bibel ungefragt ins Dorf kommt, und die Heiden wenigstens zu Stufe 5 bekehren möchte. Ich kann damit umgehen und das wenn es so weit kommen sollte auch sehr gut ignorieren. Aber die Gefahr besteht, dass die anderen Dorfbewohner den Missionar rösten. Wenn Du wirklich etwas erreichen willst, solltest Du die Situation und Bedürfnisse der Zielgruppe berücksichtigen. Die Abwehrreaktionen sind Dir ja nicht verborgen geblieben.
Viele Grüße
Boris
Ist es notwendig des CoolTuxes thread zu hijacken? Nota bene mit einem Nicht-Thema (siehe unsere Mini-Netiquette hier: https://forum.fhem.de/index.php/topic,109515.0.html) Als Moderator sollte man da mit gutem Beispiel vorangehen - habe ich neulich heute Morgen gehört. Für globale gilt das bestimmt 10-fach.
Zitat von: Dr. Boris Neubert am 26 März 2020, 18:30:54
Nichts gegen pointiertes Aufzeigen von wesentlichen Problemen in meinem Code. Aber das hört sich für mich wie der Missionar an, der mit der Perl-Bibel ungefragt ins Dorf kommt, und die Heiden wenigstens zu Stufe 5 bekehren möchte.
In dieser Aussage sind die folgenden Fehler:
- Ich weiß noch nicht einmal welchen Code Du maintainst. Sollte ich irgendwo bei meinen Wanderungen durch den FHEM code auf Dein Modul gestossen sein und mich irgendwie darüber geäußert haben, dann war das nicht zielgesteuert, bzw. ist mir nicht bewusst.
- Es gibt keine Heide/Missionar Kategorien. Das ist ein - vermutlich unbewusster - unredlicher Versuch künstlich eine Kluft zu konstruieren. Das macht man nicht. Viel mehr bin ich - ja: ungefragt - in ein Dorf namens "FHEM" gekommen, wo ich gerne bleiben möchte. Als Nutzer. Ergo Heide. Ich sage nun nicht: "Hey, reisst das Dorf ein und zieht ins OpenHAB Dorf", als Mitglied der Dorfgemeinschaft mit bestimmten Skills - ich bin ein guter Dachdecker - blutet mir das Herz, wenn es in viele Hütten reintropft.
Ich sage ja nur, unser Dorf soll schöner werden.
Zitat
Ich kann damit umgehen und das wenn es so weit kommen sollte auch sehr gut ignorieren.
Ah - verstehe. Du meinst das vorsorglich.
Solltest Du die Befürchtung hegen, ich würde Dich oder irgendwen irgendwann via PM belästigen mit dem PBP in der Hand und aktiv auffordern doch was an Deinem Code zu machen, dann kann ich Dich beruhigen, das mache ich nicht. Ich helfe gerne Leuten die zu mir kommen und JA, ich nehme mir die Freiheit raus neutral über irgendwelche Probleme in irgendeinem Code zu referieren. Wenn der Code gut ist, sage ich das. Wenn der Code doof ist, sage ich das. Wer der Maintainer ist, interessiert dabei nicht und ist auch nicht wichtig.
Du weisst schon, dass diese Freiheit die GPL auch abdeckt? ;)
Zitat
Wenn Du wirklich etwas erreichen willst, solltest Du die Situation und Bedürfnisse der Zielgruppe berücksichtigen. Die Abwehrreaktionen sind Dir ja nicht verborgen geblieben.
Nichts anderes als die Zielgruppe berücksichtigen mache ich. Deswegen gibt es hier eine Perl Ecke und wer hier reinkommt, dem wird geholfen, wer "nix mit diesem neumodischen Programmierkram am Hut haben will", der muss ja nicht hierher und muss auch keine Angst haben, dass ich irgendwo da draussen wie ein Zeuge Jehovas vor seiner Tür stehen werde.
Aber ich würde schon darum bitten, dann auch dieser Ecke fernzubleiben und nicht unnötig reinzukotzen (wie KölnSolar), wenn man fachlich nix beitragen kann. Verschiedene Ansichten auf der technischen Ebene, wie z.B. mit justme sind vielleicht anstrengend, aber in letzter Konsequenz doch fruchtbar. Das würde ich jetzt nicht als Abwehrreaktion klassifizieren.
Im Gegenteil - um mal Deine Nomenklatur zu adoptieren - bevor ich irgendeinen Finger krumm mache, stelle ich auch gerne sicher, dass ich keinem falschen Propheten aufgesessen bin.
Ich habe für mich z.B. beschlossen es mit FHEM zu probieren, also dass noch nicht Hopfen und Malz verloren ist. Natürlich sind in meinem Dunstkreis noch ein paar "so Spinner wie ich", die sind noch nicht überzeugt, aber sollten wir FHEM ein wenig qualitativer hinbekommen, dann kommen die auch noch. Das wird ein Tanz. Bitte keine schlaflosen Nächte jetzt. ;)
Fein, dass wir das geklärt haben.
*plonk*
@Richard
ZitatVariable declared in conditional statement at line 3463, column 5. Declare variables outside of the condition. (Severity: 5)
my ( $value3, $value4 ) = split( ':', $values[1] )
if ( defined( $values[1] ) );
wie kann ich das sauberer schreiben?
In zwei Statements. Mit sowas bin ich schon auf die Nase gefallen: die Zeile wird nur dann ausgefuehrt, wenn if zuschlaegt, sonst gelten die Werte aus dem vorherigen Lauf.
Bei meinem Glück habe ich Dich bestimmt wieder nicht korrekt verstanden ;D
Aber meinst Du sowas wie
my ( $value3, $value4 );
( $value3, $value4 ) = split( ':', $values[1] )
if ( defined( $values[1] ) );
Oder meinst Du eine separate Befüllung von $value3 und $value4?
Ich meinte es so, wie Du es in dem Code-Tag gezeigt hast.
Prinzipiell ist ein
my $variable = 1 if ($bedingung);
zu vermeiden. Böse hinterhältige Sache. Wird "my" ausgeführt wenn Bedingung nicht zutrifft?
Meist will man vermutlich
my $variable;
$variable = 1 if ($bedingung);
Relativ elegant in einer zeile geht es mit einem Ternary:
my $variable = $bedingung ? 1 : undef;
Ich danke Euch beiden. Werde es entsprechend an passen.
Grüße
return
if ( !exists( $hash->{helper} )
or !defined( $hash->{helper}->{shuttersList} )
or ref( $hash->{helper}->{shuttersList} ) ne 'ARRAY'
or scalar( @{ $hash->{helper}->{shuttersList} } ) == 0
or !defined( $shutters->getSunriseUnixTime )
or !defined( $shutters->getSunsetUnixTime ) );
Mixed high and low-precedence booleans at line 3337, column 12. See page 70 of PBP. (Severity: 4)
Ich bilde mir ein zu verstehen was er da anmeckert. Leider weiß ich nicht wie ich es besser schreiben sollte :-[
Jemand eine Idee?
Hat sich erledigt. Ich habe es gefunden. Lesen bildet. Lach
Zitat von: CoolTux am 28 März 2020, 14:51:34
Mixed high and low-precedence booleans at line 3337, column 12. See page 70 of PBP. (Severity: 4)
Ich bilde mir ein zu verstehen was er da anmeckert. Leider weiß ich nicht wie ich es besser schreiben sollte :-[
Jemand eine Idee?
or => ||
and => &&
not => !
die ausgeschriebenen logischen Operatoren haben so einen niedrigen Vorrang, dass sogar der Komma-Operator höher steht.
Deswegen kann man bedenkenlos ein
open my $FH, '>', $file or die 'blah';machen. Ganz krass ist, dass diese Formen sogar eine niedrigere Priorität als "=" haben.
my $x = shift || 'default';macht was man denkt,
my $x = shift or 'default';ist eigentlich
(my $x = shift) || 'default'Urgs.
https://perldoc.perl.org/perlop.html#Operator-Precedence-and-Associativity
Die perlcritic Fehlermeldung mosert an, dass man mischt. In diesem Fall "!" und "or". Das kann ziemlich in die Hose gehen. Hier mal andersrum:
if ( not defined $x || y < 5)selbst wenn man es gut meint:
if ( not (defined $x) || (y < 5) )ist es halt dennoch gleichbedeutend mit
if ( not (defined $x || y < 5) )Ergo: ersetze or durch ||
oder ! durch "not"
Ich empfehle ersteres (generell sollte man ! || && in logischen Termen verwenden. Die ausgeschriebene Form nur zur Programmflusskontrolle (siehe open or die).
if ( grep /^userAttrList:.rolled.out$/, @{$events} ) {
Das würde ich gerne sauberer machen.
Hierzu hatte ich in meinen jugendlichen Leichtsinn folgendes draus gemacht
Da @{$events} ja ein multiliner ist dachte ich an
if ( @{$events} =~ m{\AuserAttrList:.rolled.out\z}xms )
Aber er kommt mit @{$events} nicht klar. Wie wäre hier der saubere Weg?
Zitat von: CoolTux am 28 März 2020, 15:12:23
if ( grep /^userAttrList:.rolled.out$/, @{$events} ) {
Das würde ich gerne sauberer machen.
Hierzu hatte ich in meinen jugendlichen Leichtsinn folgendes draus gemacht
Es geht um
if ( grep /^userAttrList:.rolled.out$/, @{$events} ) {
unless ( scalar( @{ $hash->{helper}{shuttersList} } ) == 0 ) {
WriteReadingsShuttersList($hash);
UserAttributs_Readings_ForShutters( $hash, 'add' );
InternalTimer( gettimeofday() + 3,
'FHEM::AutoShuttersControl::RenewSunRiseSetShuttersTimer',
$hash );
InternalTimer( gettimeofday() + 5,
'FHEM::AutoShuttersControl::AutoSearchTwilightDev', $hash );
}
}
elsif ( grep /^partyMode:.off$/, @{$events} ) {
EventProcessingPartyMode($hash);
}
elsif ( grep /^sunriseTimeWeHoliday:.(on|off)$/, @{$events} ) {
RenewSunRiseSetShuttersTimer($hash);
}nehme ich an? Da würde ich in meinem jugendlichen Leichtsinn das hier daraus machen:
my $found_event = { # container to memoize specific found events
rolledout => 0,
partyoff => 0,
sunrise => 0,
};
# iterate the event list just ONCE
for my $event (@{$events}) {
$found_event{rolledout}++ if ($event =~ m{^userAttrList:.rolled.out$}xms);
$found_event{partyoff}++ if ($event =~ m{^partyMode:.off$}xms);
$found_event{sunrise}++ if ($event =~ m{^sunriseTimeWeHoliday:.(on|off)$}xms);
}
# handle found events according to their priority
if ($found_event{rolledout} && @{$hash->{helper}{shuttersList}}) {
WriteReadingsShuttersList($hash);
UserAttributs_Readings_ForShutters($hash, 'add');
InternalTimer( gettimeofday() + 3,
'FHEM::AutoShuttersControl::RenewSunRiseSetShuttersTimer',
$hash );
InternalTimer( gettimeofday() + 5,
'FHEM::AutoShuttersControl::AutoSearchTwilightDev', $hash );
}
elsif ($found_event{partyoff}) {
EventProcessingPartyMode($hash);
}
elsif ($found_event{sunrise}) {
RenewSunRiseSetShuttersTimer($hash);
}Aber nur so aus der Hüfte geschossen. grep in den Ifs knüppelt jedes Mal die liste durch "matche gegen die ganze Liste ... nix gefunden: matche nochmal was anderes gegen die selbe ganze Liste ..."
Ist ungetestet, kann also der ein oder andere Bug drin sein. Ein wenig Bauchweh habe ich mit den Punkten in den Regexen. Meintest Du \s ?
besonders stolz bin ich ja auf
unless ( scalar( @{ $hash->{helper}{shuttersList} } ) == 0
->
@{ $hash->{helper}{shuttersList} }
Danke das funktioniert ja bestens. Kleiner Fehler in Deinem Code nur damit andere die hier lesen nicht in ein Problem rennen
my $found_event = { # container to memoize specific found events
rolledout => 0,
partyoff => 0,
sunrise => 0,
};
# iterate the event list just ONCE
for my $event (@{$events}) {
$found_event{rolledout}++ if ($event =~ m{^userAttrList:.rolled.out$}xms);
$found_event{partyoff}++ if ($event =~ m{^partyMode:.off$}xms);
$found_event{sunrise}++ if ($event =~ m{^sunriseTimeWeHoliday:.(on|off)$}xms);
}
my $found_event = { # container to memoize specific found events
rolledout => 0,
partyoff => 0,
sunrise => 0,
};
# iterate the event list just ONCE
for my $event (@{$events}) {
$found_event->{rolledout}++ if ($event =~ m{^userAttrList:.rolled.out$}xms);
$found_event->{partyoff}++ if ($event =~ m{^partyMode:.off$}xms);
$found_event->{sunrise}++ if ($event =~ m{^sunriseTimeWeHoliday:.(on|off)$}xms);
}
$found_event ist kein Hash sondern eine Hash Referenz.
Grüße
if (
!(
CheckIfShuttersWindowRecOpen($shuttersDev) == 2
&& $shutters->getShuttersPlace eq 'terrace'
)
)
Ich habe vor einiger Zeit (anderswo hier im Forum) den Begriff "De Morgan Transformation" in den Raum geschmissen. Das blieb ohne Reaktion, also reagiere ich nochmal. ;)
Zum Beispiel:
!(A && B) = !A || !B
für den obigen Code würde das bedeuten:
if (CheckIfShuttersWindowRecOpen($shuttersDev) != 2
|| $shutters->getShuttersPlace ne 'terrace')
Ob man das nun macht oder nicht, ist häufig Geschmacksfrage, bzw. wie intuitiv man den booleschen Ausdruck haben möchte.
An einigen Stellen (die erwähnt das PBP auch) ist die Kenntnis dieser Transformationen beim Übergang unless(x) -> if(!x)
aber durchaus hilfreich.
Man stelle sich sowas vor wie unless ($x ne 'foo') - das kann man noch einfach als die doppelte Negation erkennen => if ($x eq 'foo')
aber schon ein
unless ( !$x && $z ne 'bar')
... da windet man dann die ganze Zeit sein Hirn drum und in Wirklichkeit ist das
if ($x || $z eq 'bar')
Aber das würde die Bedingung falsch machen.
Es muss ja heißen
Wenn das Fenster 2 ist UND der Fensterplatz eine Terrasse
Im Umkehrschluss also z.B.
Ist das Fenster 2 aber der Fensterplatz keine Terasse mache es trotzdem
Zitat von: CoolTux am 11 April 2020, 15:01:02
Aber das würde die Bedingung falsch machen.
Es muss ja heißen
Wenn das Fenster 2 ist UND der Fensterplatz eine Terrasse
Nö. :)
Zitat von: RichardCZ am 11 April 2020, 15:04:50
Nö. :)
Das würde also dennoch auch gehen
Ist das Fenster 2 aber der Fensterplatz keine Terasse mache es trotzdem
Zitat von: CoolTux am 11 April 2020, 15:05:56
Das würde also dennoch auch gehen
Ist das Fenster 2 aber der Fensterplatz keine Terasse mache es trotzdem
if (CheckIfShuttersWindowRecOpen($shuttersDev) != 2
|| $shutters->getShuttersPlace ne 'terrace')
Ich weiß nicht. Das würde doch bei sowohl als auch die Bedingung erfüllen.
Ich habe ein
Falls nicht gilt: Fenster ist 2 UND Fensterplatz ist Terasse
zu einem:
Falls: Fenster nicht 2 ODER Fensterplatz ist nicht Terasse
gemacht. Und ohne nachzuprüfen behaupte ich, das ist dasselbe.
Zitat von: RichardCZ am 11 April 2020, 15:08:45
Ich habe ein
Falls nicht gilt: Fenster ist 2 UND Fensterplatz ist Terasse
zu einem:
Falls: Fenster nicht 2 ODER Fensterplatz ist nicht Terasse
gemacht. Und ohne nachzuprüfen behaupte ich, das ist dasselbe.
Ok.
Bin mal wieder verwirrt. Machen wir es ander. Was will ich?
Wenn Fensterstatus 2 ist UND der Fensterplatz ist eine Terrasse dann Bedingung NICHT erfüllt.
Wenn also Fensterstatus 2 ist und der Fensterplatz ist Fenster dann Bedingung erfüllt.
Wenn also Fensterstatus ungleich 2 und Fensterplatz ist eine Terrasse dann Bedingung auch erfüllt.
https://de.wikipedia.org/wiki/De_Morgansche_Gesetze
Ich weiß nicht ob die bedingung richtig ist. Ich weiß nur, dass beide immer den selben Wahrheitsgehalt annehmen.
Falls Du also eine davon als nicht richtig ansiehst, bedeutet das, dass auch die andere nicht richtig ist.
Das passiert schon manchmal. ;)
Daher ist diese Kenntnis um diese zwei einfachen Regeln hilfreich um einen vor if-Fehlkonstruktionen zu bewahren.
(und um den Code leserlicher zu machen)
Ich brauche Kaffee
Ich muss das noch etwas im Kopf rumgehen lassen aber laut meiner letzten Überlegung könntest Du Recht haben.
Engel und Teufel streiten aber noch ;D