Ich kam letztens einfach nicht umher meinen alten C# Ordner zu durchstöbern. Ich hatte mich damals wenige Wochen mit C# beschäftigt. Also beschäftigt im Sinne von: Einsteigerkurse in der S-Bahn lesen, paar Tutorials im Netz und los gehts 😀
Ein Projekt hatte ich damals tatsächlich realisieren wollen. Ein kleines Programm, mit dem ich eine kleine Investition rechtfertigen und strategisch präsentieren konnte.
Damals wollte ich mir nämlich einen Kaffeevollautomaten kaufen, der gerade im Angebot war. Solch ein Gerät ist ja nicht gerade günstig, also habe ich die Ersparnisse, die mit so einem Gerät möglich sind, versucht einfach zu verdeutlichen.

Und somit, let me proudly introduce to you:

Kaffe-Kalkulator

DIE Rechtfertigung, wenn es um den Kauf eines Kaffeevollautomaten geht!

Der Sinn dieser Software ist einfach: sie soll die Rechenarbeit bei der Frage „Lohnt sich der Kauf eines Kaffeevollautomaten?“ für euch erledigen.
Das Programm fragt nach einigen Grundangaben aus denen dann ein kurzer Infotext gebastelt wird.

Simple thing, huh?! 🙂

Wie gesagt war das ein recht kurzer Abstecher in die C# Welt, der Code ist jetzt also nicht sonderlich cool.
Ich habe mich gestern und heute kurz damit beschäftigt und den Code stark gereinigt und umgeschrieben, Funktionen geschrieben, Fehler abgefangen, Code gekürzt und sowas. Aber mittlerweile würde ich einige Schritte anders realisieren (Stichwort „.“ bei Kaffeebohnenpreis und MaskedTextBoxes) und würde auch einige andere Details ändern (z.B. variabler durchschnittlicher Verbrauch von Kaffeebohnen pro Tasse (ist ja je nach Tassengröße unterschiedlich)) aber wichtig ist das alles nicht. Dazu müsste das Programm grundlegend umgestaltet werden und so viel Langeweile habe ich ja nun auch wieder nicht. Es funktioniert grundlegend und erfüllt seine Aufgabe mit Stolz. 🙂

Code

Code anzeigenDen Code könnt ihr bequem mit den Links/Rechts Pfeiltasten horizontal bewegen.

public partial class Main : Form
    {
        // Variablen einzeln setzen, für Kommentare
        const char nl = (char)10; // Zeilenumbruch als Konstante
        double PrUn = 0; // Preisunterschied zwischen eigenem und alternativem Kaffee
        double PrKa = 0; // Preis der eigenen Tasse
        double PrAlKa = 0; // Preis des altern. Kaffees
        double MaxKaBo = 0; // maximale Anzahl der Tassen pro voller Kaffeebohnenpackung
        double DuVeKaBo = 20; // Durchschnittlicher Kaffeebohnenverbrauch pro Tasse
        double KaAuBezWo = 0; // Anzahl an Wochen die man braucht um mit dem Preisunterschied den Kaffeevollautomaten zu bezahlen
        bool empty = true; // Felder leer?
        
        public Main() {
            InitializeComponent();
        }

        void btnBerechne_Click(object sender, EventArgs e) {
            try {
                // Setze intern berechnete Variablen zurück
                initReset(false, true);
                // GET: Preis des alternativen Kaffees
                PrAlKa = checkPrAlKa();

                if (PrAlKa == 0 || checkEmpty() == true)
                    emptyErr();
                else {
                    if (checkNegative() == true) showStats("negative");
                    else showStats("positive");
                }
            }
            catch {
                unknownErr();
            }
        }

        void negativeErr() {
            lblStatistik.Text = "Die berechnete Statistik zeigt, dass du mit deinen Angaben keinen Gewinn machen würdest. Der Kaffee deines Vollautomaten ist teurer als der Kaffee, den du dir im Laden kaufst.";
            gbxStatistik.Visible = true;
        }

        void emptyErr() {
            lblStatistik.Text = "Fehler bei der Eingabe. Es wurden nicht alle Felder ausgefüllt.";
            gbxStatistik.Visible = true;
        }

        void unknownErr() {
            lblStatistik.Text = "Ein unbekannter Fehler ist aufgetreten... sorry...\nPrüfe deine Eingaben, irgendetwas stimmt hier nicht ;)";
            gbxStatistik.Visible = true;
        }

        double checkPrAlKa() {
            switch (cbxPrAlKa.Text) {
                case "": { return 0; break; }
                case "0,50€ - Berlin Ost billig": { return 50; break; }
                case "0,80€ - Berlin West billig": { return 80; break; }
                case "1,00€ - Berlin Mitte billig": { return 100; break; }
                case "1,30€ - Berlin Mitte normal": { return 130; break; }
                case "2,00€ - Berlin Mitte teuer": { return 200; break; }
                case "3,50€ - Berlin Fucking Luxus": { return 350; break; }
                case "6,00€ - Scheiße wo trinkst du Kaffee?!": { return 600; break; }
                default: { return 0; break; }
            }
        }

        bool checkEmpty() {
            // CHECK: leere Eingaben
            if (tbxAnKaWo.Text == "" || tbxMeKaBo.Text == "" || tbxPrKaAu.Text == "" || tbxPrKaBo.Text == "")
                return true;
            else
                return false;
        }

        bool checkNegative() {
            // CALC: Preis der eigenen Tasse in Cent
            PrKa = (((double.Parse(tbxPrKaBo.Text) * 100) / double.Parse(tbxMeKaBo.Text)) * DuVeKaBo);
            // CALC: Preisunterschied zwischen eigenem und alternativem Kaffee
            PrUn = PrAlKa - PrKa;
            // CALC: maximale Anzahl der Tassen pro voller Kaffeebohnenpackung beim angegebenen Durchschnittsverbrauch pro Tasse
            MaxKaBo = Math.Round((double.Parse(tbxMeKaBo.Text) / DuVeKaBo), 1);
            // CALC: Anzahl an Wochen die man braucht um mit dem Preisunterschied den Kaffeevollautomaten zu bezahlen
            KaAuBezWo = double.Parse(tbxPrKaAu.Text) / (PrUn * double.Parse(tbxAnKaWo.Text));
            // PRINT: Preis der eigenen Tasse in €
            tbxPrTaKa.Text = Math.Round((PrKa / 100), 2).ToString();
            // PRINT: Preisunterschied zwischen eigenem und alternativem Kaffee in €
            tbxPrUn.Text = Math.Round((PrUn / 100), 2).ToString();

            if (PrUn < 0) return true;
            else return false;
        }

        void showStats(string pon) {
            if (pon == "positive") {
                // PRINT: Statistiktext
                lblStatistik.Text = tbxMeKaBo.Text
                    + "g Kaffeebohnen kosten " + tbxPrKaBo.Text
                    + " €. Für eine kleine Tasse werden " + DuVeKaBo
                    + "g Kaffeebohnen verbraucht, mit den " + tbxMeKaBo.Text
                    + "g Kaffeebohnen lassen sich also bis zu " + MaxKaBo
                    + " Tassen machen." + nl
                    + "Eine Tasse Kaffee zu Hause kostet nur " + tbxPrTaKa.Text
                    + " € ! Günstig, oder?! Und dann noch lecker Kakao drin, hhmmmm lecker." + nl
                    + "Wenn ein gekaufter Kaffee in der Stadt " + Math.Round((PrAlKa / 100), 2)
                    + " € kostet, ist ein selbstgemachter Kaffee also " + Math.Round((PrUn / 100), 2)
                    + " € günstiger!" + nl
                    + "Bei " + tbxAnKaWo.Text
                    + " Tassen Kaffee pro Woche sparst du also " +
                    // CALC: Ersparnis pro Woche: Anzahl der Tassen pro Woche * Preisunterschied in € gerundet auf 2 Stellen
                    Math.Round((double.Parse(tbxAnKaWo.Text) * Math.Round((PrUn / 100), 2)), 2)
                    + " € pro Woche, " +
                    // CALC: Ersparnis pro Monat: Anz. d. Tassen pro Woche / 7 (Ersparnis pro Tag) * 30.416 (durchschnittliche Tagesanzahl pro Monat) gerundet auf 2 Stellen
                    Math.Round(((Math.Round((double.Parse(tbxAnKaWo.Text) * Math.Round((PrUn / 100), 2)), 2) / 7) * 30.416), 2)
                    // Math.Round((double.Parse(tbxAnKaWo.Text) * Math.Round((PrUn / 100), 2) * 30.416), 2)
                    + " € pro Monat und ganze " +
                    // CALC: Ersparnis pro Jahr: Anz. d. Tassen pro Woche / 7 (Ersparnis pro Tag) * 365,25 (durchschnittliche Tagesanzahl pro Jahr) gerundet auf 2 Stellen
                    Math.Round(((Math.Round((double.Parse(tbxAnKaWo.Text) * Math.Round((PrUn / 100), 2)), 2) / 7) * 365.25), 2)
                    //Math.Round((double.Parse(tbxAnKaWo.Text) * Math.Round((PrUn / 100), 2) * 365.25), 2)
                    + " € im Jahr!!" + nl
                    + "Es erklärt sich also von selbst, dass der Kaffeevollautomat bei einem Preis von satten " + tbxPrKaAu.Text
                    + ",00 € bereits nach " +
                    //CALC: Wochen die zum Abbezahlen nötig sind: (Preis der Automats / Ersparnis pro Tag) / 7
                    Math.Round(((double.Parse(tbxPrKaAu.Text) / Math.Round(((Math.Round((double.Parse(tbxAnKaWo.Text) * Math.Round((PrUn / 100), 2)), 2) / 7)), 2)) / 7), 1)
                    + " Wochen abbezahlt ist!" + nl
                    + "Danach sparst du bei jeder Tasse wirklich die " + Math.Round((PrUn / 100), 2)
                    + " €.";
                gbxStatistik.Visible = true;
            }
            else if (pon == "negative") {
                negativeErr();
            }
        }

        void resetToolStripMenuItem_Click(object sender, EventArgs e) {
            initReset(true, true);
        }

        void btnReset_Click(object sender, EventArgs e) {
            initReset(true, true);
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e) {
            Form2 About = new Form2();
            About.Show();
        }

        private void beendenToolStripMenuItem_Click(object sender, EventArgs e) {
            Application.Exit();
        }

        void initReset (bool elems,bool vars) {
            if (elems==true) resetElements();
            if (vars==true) resetVars();
        }

        void resetElements() {
            tbxMeKaBo.Text = tbxPrKaAu.Text = tbxPrKaAu.Text = 
            tbxPrKaBo.Text = tbxPrTaKa.Text = tbxPrUn.Text = 
            tbxAnKaWo.Text = "";
            cbxPrAlKa.ResetText();
            gbxStatistik.Visible = false;
            tbxPrKaAu.Focus();
        }

        void resetVars() {
            PrUn=PrKa=PrAlKa=MaxKaBo=KaAuBezWo=0;
            DuVeKaBo = 20;
        }
    }
Download

Kaffee-Kalkulator [.exe]

Ich denke nicht, dass es eine ausgebaute Version 2 des Programms geben wird aber trotzdem; Kritik, Verbesserungsvorschläge, Ausbauvorschläge, Spam und puren Stuss, einfach Kommentar schreiben.

PS: Was haltet ihr von meiner neuen „Code anzeigen“ Methode? Ich dachte mir so bleibt die Übersichtlichkeit meines Blogs unverändert und ich kann trotzdem lange Codeschnipsel präsentieren. Ob und wenn ja wie der Code dann allerdings im RSS Reader erscheint weiß ich noch nicht. Werden display:none divs im RSS beachtet? Naja mal sehen.

Mein letzter Post erklärte die spezielle Behandlung von Internet Explorer 6 (und jünger) in meinem Blog. Es wird statt dem eigentlich Inhalt ein bisschen Text und Links zu vernünftigen Browsern angezeigt.
Ich wollte dieses „Feature“ jetzt mit nur 1 Zeile realisieren. Den CSS und HTML Code in der tatsächlich index stehen zu haben ist unschön.
Daher präsentiere ich:

IE-Buster

a small jQuery Anti-IE Plugin

Frei nach dem Motto:
„If there’s something strange
in the internet.
Who ya gonna call?“

IE-Buster!!!
😉



Das Plugin ist nur 2,3KB groß und damit ein Leichtgewicht im Anti IE Geschäft. Es epfiehlt sich also wenn man keinen besonders hübschen und funktionsreichen Abgang beim IE sucht, sondern etwas kleines, schnelles und unkompliziertes.
Einzige Voraussetzung: jQuery muss eingebunden sein!

Code
$(document).ready(function() {
  $("head").append('<!--[if lte IE 6]><style type="text/css">#ie6-warning { display: block; width: 100%; height: 100%; background-color: white; position: absolute; z-index: 1111; top: 0px; left: 0px; color: black; padding: 10%; font-size: 17px; } #ie6-warning td { border: 1px solid #eee; padding: 4px; color: white; } #ie6-warning a { color: blue; }</style><![endif]--><!--[if gt IE 6]><style type="text/css">#ie6-warning { display: none!important; }</style><![endif]-->');
  $("body").append('<div id="ie6-warning">Ihr Browser ist zu alt um diese Internetseite korrekt darzustellen.<br/>Bitte aktualisieren Sie Ihren Browser oder installieren Sie einen anderen modernen Browser.<br/><br/>Your browser is too old to display this website correctly.<br/>Please update your browser or install another modern browser.<br/><br/><br/><table cellpadding="10"><tr><td></td><td>Google Chrome</td><td>Mozilla Firefox</td><td>Opera</td><td>Apple Safari</td><td>Microsoft Internet Explorer</td></tr><tr><td>Download (DE):</td><td><a href="http://www.google.de/chrome/">Link</a></td><td><a href="http://www.mozilla-europe.org/de/firefox/">Link</a></td><td><a href="http://de.opera.com/">Link</a></td><td><a href="http://www.apple.com/de/safari/">Link</a></td><td><a href="http://www.microsoft.com/germany/windows/internet-explorer/">Link</a></td></tr><tr><td>Download (EN):</td><td><a href="http://www.google.com/chrome/">Link</a></td><td><a href="http://www.mozilla-europe.org/en/firefox/">Link</a></td><td><a href="http://www.opera.com/">Link</a></td><td><a href="http://www.apple.com/safari/">Link</a></td><td><a href="http://www.microsoft.com/windows/internet-explorer/">Link</a></td></tr><tr><td>Suchen/Search for:</td><td><a href="http://www.google.com/search?q=chrome">Link</a></td><td><a href="http://www.google.com/search?q=firefox">Link</a></td><td><a href="http://www.google.com/search?q=opera">Link</a></td><td><a href="http://www.google.com/search?q=safari">Link</a></td><td><a href="http://www.google.com/search?q=internet+explorer">Link</a></td></tr></table><br/><br/><span>by <a href="http://it-stack.de">Hannes Schurig</a></span></div>');
});
Download

Download des Plugins v1.2

ie-buster-1.2 [.js] (Rechtsklick -> Speichern unter)
Nicht vergessen, regelmäßig nach Updates schauen.

oder

Einbinden der neuesten Version von meinem Server

<!-- <script type="text/javascript" src="jquery-min.js"></script> // (noch) Voraussetzung: jQuery! -->
<script type="text/javascript" src="http://public.hannes-schurig.de/IE-Buster/ie-buster-latest.js"></script>
Changelog


v1.2 – Anzeigefehler behoben
v1.1 – Anzeigefehler behoben

Gestern habe ich den IETester vorgestellt. Viele Versionen des Internet Explorer in einem Programm. Mir ist mal wieder aufgefallen, dass mein Blog im Internet Explorer 6 (und älter) nicht ansatzweise richtig dargestellt wird. Ich habe mich also (mal wieder) entschlossen, den IE 6 (und älter) aus meinem Blog zu entfernen.
Nachdem ich mehr oder weniger erfolgreich 2, 3 WordPress Plugins und 2, 3 andere Codeschnipsel ausprobiert hatte, was alles nicht so wirklich optimal lief, hab ich mich entschlossen meine eigene Anti-IE6 Warnung zu basteln.

Code
<!--[if lte IE 6]>
<style type="text/css">
.BGC { display: none!important; } 
#ie6-warning td { border: 1px solid #eee; padding: 4px; } 
#ie6-warning { display: block; 600px; height: 100%; color: white; margin: 10%; font-size: 17px; } 
</style>
<![endif]-->

<body>
<div id="ie6-warning">
  Ihr Browser ist zu alt um diese Internetseite korrekt darzustellen.<br/>
  Bitte aktualisieren Sie Ihren Browser oder installieren Sie einen anderen modernen Browser.<br/><br/>
  Your browser is too old to display this website correctly.<br/>
  Please update your browser or install another modern browser.<br/><br/><br/>
  <table cellpadding="10">
    <tr><td></td><td>Google Chrome</td><td>Mozilla Firefox</td><td>Opera</td><td>Apple Safari</td><td>Microsoft Internet Explorer</td></tr>
    <tr><td>Download (DE):</td><td><a href="http://www.google.de/chrome/">Link</a></td><td><a href="http://www.mozilla-europe.org/de/firefox/">Link</a></td><td><a href="http://de.opera.com/">Link</a></td><td><a href="http://www.apple.com/de/safari/">Link</a></td><td><a href="http://www.microsoft.com/germany/windows/internet-explorer/">Link</a></td></tr>
    <tr><td>Download (EN):</td><td><a href="http://www.google.com/chrome/">Link</a></td><td><a href="http://www.mozilla-europe.org/en/firefox/">Link</a></td><td><a href="http://www.opera.com/">Link</a></td><td><a href="http://www.apple.com/safari/">Link</a></td><td><a href="http://www.microsoft.com/windows/internet-explorer/">Link</a></td></tr>
    <tr><td>Suchen/Search for:</td><td><a href="http://www.google.com/search?q=chrome">Link</a></td><td><a href="http://www.google.com/search?q=firefox">Link</a></td><td><a href="http://www.google.com/search?q=opera">Link</a></td><td><a href="http://www.google.com/search?q=safari">Link</a></td><td><a href="http://www.google.com/search?q=internet+explorer">Link</a></td></tr>
  </table>
  <br/><br/><span>Liebe Grüße, best regards, Hannes Schurig</span>
</div>

Kurz, einfach, schmerzlos, schnell.
Es gibt eine IE < = 6 Weiche, die dann CSS Eigenschaften aktiviert. Diese blenden den Blog (.BGC ist der Blogcontainer) aus und blenden die IE 6 Warnung ein. Das wiederum ist einfach nur etwas Text und eine Tabelle. In der Tabelle biete ich die Downloadseiten der bekanntesten Browser auf deutsch und englisch an, zusätzlich dazu zu jedem Browser noch die Google Suchergebnisse. Leicht angepasst kann man diesen Codeschnipsel in jedem Webprojekt einbauen!

Aufklappbare, verschachtelte Menüs mit gepunkteter Hierarchiehilfe
…das ist jetzt Thema 😀
Die Sache ist ziemlich simpel. Ich brauchte letztens ein aufklappbares Menü mit ebenfalls aufklappbaren Unterpunkten, möglichst unkomplizierter Aufbau, möglichst wenig Code. Irgendwann wird das Menü mit vielen aufgeklappten Untermenüs doch sehr übersichtlich, also habe ich „Hierarchielinien“ hinzugefügt. Keiner Ahnung ob es dafür auch einen normalen Namen gibt.

Verpackt in HTML/CSS und einfach animiert mit einem jQuery Zweizeiler, fertig.

Code

HTML:

<ul id="nav">
	<li class="expand">Über das IQB
		<ul>
			<li>Gründung</li>
			<li>Ziele</li>
			<li>Partner/Links</li>
		</ul>
	</li>
	<li>Personal</li>
	<li class="expand">Bildungsstandards
		<ul>
			<li>Aufgabenbeispiele</li>
			<li>EMSE</li>
			<li class="expand">Downloadserver
				<ul>
					<li>Audiofiles</li>
					<li>Videofiles</li>
				</ul>
			</li>
		</ul>
	</li>
	<li>VERA/Lernstandsvergleich</li>
	<li class="expand">Arbeitsbereiche
		<ul>
			<li>Testentwicklung</li>
			<li>Kompetenzerwerb</li>
			<li class="expand">Implementation
				<ul>
					<li>Was wird</li>
					<li>denn eigentlich</li>
					<li class="expand">so alles
						<ul>
							<li>test</li>
							<li>test2</li>
						</ul>
					</li>
					<li>implementiert??</li>
				</ul>
			</li>
			<li>Bildungsmonitoring</li>
			<li>Datenzentrum (FDZ)</li>
		</ul>
	</li>
</ul>

CSS:

body, html{
	height: 100%;
	width: 100%;
	font-family: "Trebuchet MS";
	margin: 0; padding: 0;
}
a {
	text-decoration:none;
	color: black;
}
ul, li {
	list-style: none;
}
#nav li {
	padding: 2px 2px 2px 15px;
	cursor: default;
}
#nav ul {
	display: none;
	background: url(img/dots.png) repeat-y scroll 10px 0 transparent;
}
#nav li.expand {
	background: url(img/arrow-down.gif) no-repeat scroll 0px 12px transparent;
}
.expanded {
	background: url(img/arrow-up.gif) no-repeat scroll 0px 12px transparent !important;
}

Das tatsächliche Design des Menüs muss jeder selbst basteln.

jQuery:

$(document).ready(function() {
   $(".expand").click(function(e) {
      $(this).toggleClass("expanded");
      $(this).children("ul:first").slideToggle("300");
      e.stopPropagation();
   });	
}); //$(document).ready
Demo:

Link

Download:

folding-nav.zip

Ich habe es mal im Fernwartungs-Tutorial erwähnt und gerade wieder benötigt, das Auslesen der Prozessor Architektur mit CMD/Batch.

Also nochmal kurz erwähnt, der Befehl

echo %processor_architecture%

liefert entweder „x86“ oder „AMD64“ zurück. Eine Abfrage kann also mit

if %PROCESSOR_ARCHITECTURE% == AMD64 goto 64bit
if %PROCESSOR_ARCHITECTURE% == x86 goto 32bit
 
:64bit
echo 64
exit
 
:32bit
echo 32

geschehen.

Wer ganz sicher gehen will prüft das zusätzlich noch in der Registry ab, der Key „PROCESSOR_ARCHITECTURE“ aus

HKLM\System\CurrentControlSet\Control\Session Manager\Environment

bestätigt das und von „PROCESSOR_IDENTIFIER“ erhalten wir noch eine Bestätigung mit 2, 3 CPU Infos mehr.

if %PROCESSOR_ARCHITECTURE% == AMD64 set pa1=AMD64
if %PROCESSOR_ARCHITECTURE% == x86 set pa1=x86
for /f "tokens=2* delims= " %%a in ('reg query "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /v "PROCESSOR_ARCHITECTURE"') do set pa2=%%b
if %pa1%==%pa2% set final-pa=%pa1%
echo %final-pa%

Sollte reichen 🙂

Beim Debuggen größerer PHP Scripte kann es sinnvoll sein, zwischendurch den Inhalt von Variablen oder anderer Abläufe zu überprüfen.
Möglich wäre ein Pop-Up mit dem gewünschten Inhalt als Text oder eine Ausgabe in ein Element der DOM Struktur. Wir schauen jetzt erstmal nur aufs Pop-Up.
Wenn PHP Scripte durch AJAX angesprochen werden bestimmt ein

echo

den Rückgabewert zurück an den AJAX Befehl und gibt daher nichts aus.
Da PHP serverseitig ausgeführt wird gibt es auch keinen vergleichbaren Befehl wie

alert

aus der Javascript Welt.

Also ein Workaround:

Code-Download

Wir erschaffen uns eine „alert“ Funktion, die Javascript Code ausgibt und somit ausführt. Dieser Javascript Code widerum enthält die tatsächliche

alert

Funktion, die den Browser veranlasst, ein Pop-Up anzuzeigen.
Ihr braucht also nur noch

alert(...)

im PHP Code aufrufen, als Parameter z.B. eine Variable, und die Ausgabe wird per Pop-Up beim Laden ausgegeben. Mehrere

alert(...)

s nacheinander sind natürlich kein Problem.

Das wars. Getestet und funzt inmitten laaanger komplizierter PHP Scripte 🙂

Browserweichen durch Conditional Comments, klar soweit. Mich hat nur gerade ein kleines Problem ne Viertelstunde Recherchieren gekostet.

IE Weiche:
html“>

Wie mag dann wohl die Anti-IE Browserweiche aussehen??
html“>

vielleicht

oder

Falsch!

Um alle Browser bis auf den IE anzusprechen muss man die HTML Comment Tags verunstalten, ein „Nicht-Operator: !“ reicht nicht aus. Aus den Comment Tags werden < ! ... >

Anti-IE Weiche:
html“>

via dank Kenny