Copying sources and texts (also in parts) for publishing without our permission is NOT ALLOWED. We are fed up with finding our work on other sites (like stackoverflow).
Das Kopieren von Quellcode und Texten (auch in Auszügen) ist nicht erlaubt. Wir haben es gründlich satt, unsere Arbeit auf anderen Webseiten zu finden.

Copying for non-public usage is allowed.           Das private Kopieren und Benutzen ist natürlich erlaubt und erwünscht.
21. Feb 2010
Teaser

C#: “System.Data.XmlReadMode” enthält keine Definition für “WriteSchema” (CS0117)

Wenn Sie beim Programmieren in C# (CSharp) eine der beiden folgenden Fehlermeldungen erhalten, passen Befehl und Option nicht zueinander.

“System.Data.XmlReadMode” enthält keine Definition für “WriteSchema”. (CS0117) – C:\test\xml_error.cs:186,37

“System.Data.XmlWriteMode” enthält keine Definition für “ReadSchema”. (CS0117) – C:\test\xml_error.cs:186,37

Korrigieren Sie Ihren Befehl entsprechend, denn nur beim XmlReadMode können Sie die Option “ReadSchema” verwenden und nur bei XmlWriteMode die Option “WriteSchema”. In Ihrem Fall werden Sie Befehl und Option miteinander gemixt haben:

Falsch

DataSet ds = new DataSet();
ds.ReadXml("test.xml", XmlReadMode.WriteSchema);

oder

DataSet ds = new DataSet();
ds.WriteXml("test.xml", XmlWriteMode.ReadSchema);

Richtig

DataSet ds = new DataSet();
ds.ReadXml("test.xml", XmlReadMode.ReadSchema);

oder entsprechend

DataSet ds = new DataSet();
ds.WriteXml("test.xml", XmlWriteMode.WriteSchema);
19. Feb 2010
Teaser

C#: SQLite Datenbank einbinden und nutzen (auch für SharpDevelop)

SQLite ist eine dateibasierte Datenbank, welche Sie mit SQL Befehlen (wie mySQL, MS SQL, usw.) verwalten können.

Installation

  • Laden Sie sich die benötigte Komponente herunter:
    ADO.NET 2.0 Provider for SQLite
  • Starten Sie das heruntergeladene Setup und folgen Sie den Installationsanweisungen

Vorbereitungen für Ihr C# Projekt

Sie können die nun installierten ADO.NET SQLite Komponenten nutzen. zur Vereinfachung sollten Sie die benötigten Libraries (DLLs) in Ihren Projektordner kopieren:

  • Öffnen Sie den Ordner “C:\Programme\SQLite.NET\bin”
  • Markieren Sie die benötigte .DLL Datei zum Kopieren.
    Welche Datei Sie in Ihrem Fall brauchen, hängt von Ihrem eingesetzten System ab (I386, AMD64, …).
    Für eine Standardumgebung (Windows 32-Bit System) nutze ich die “System.Data.SQLite.dll”.
  • Öffnen Sie den Ordner “bin\Debug” Ordner in Ihrem Projektverzeichnis.
    In diesem Beispiel nutze ich den Projektnamen “HalloWelt”.
    Im Beispiel ist der Projektordner “C:\tmp\HalloWelt\bin\Debug”
  • Fügen Sie die ausgewählten Dateien ein

In SharpDevelop die DLL als Referenz hinzufügen

  • Zur Projektansicht wechseln (Strg + Alt + L)
  • In Ihrem Projekt den Untereintrag “Referenzen” mit der rechten Maustaste anklicken
  • “Referenz hinzufügen” auswählen und anklicken
  • Den Reiter “.NET Assemblybrowser” auswählen
  • Auf den Button “Suchen” klicken
  • Ihren Projektordner öffnen und die gerade hineinkopierte DLL auswählen
  • “OK” anklicken
    Das Fenster schließt sich und die DLL ist im Bereich “Gewählte Referenzen” zu finden
  • “OK” anklicken
    Die DLL ist in Ihrer Projektliste aufgeführt

SQLite Unterstützung im Projekt einbinden

  • Fügen Sie die folgende Zeile am Anfang Ihrer .CS Datei ein:
using System.Data.SQLite;

Datenbank in C# zur Laufzeit (Runtime) erstellen

  • Eine neue “SQLiteConnection” erstellen
  • Parameter angeben:
    “Data Source” ist die einzige Pflichtangabe. Alle weiteren Parameter sind optional.
    Welche weiteren Parameter ihnen zur Verfügung stehen, finden Sie in der auf Ihrem System installierten .CHM Hilfedatei unter “C:\Programme\SQLite.NET\Doc”.

Beispiel:

SQLiteConnection connection = new SQLiteConnection("Data Source=test.dat");
connection.Open();
connection.Close();

Nachdem Sie den Source des Beispiels ausgeführt haben, finden Sie eine (noch leere) Datenbank “test.dat” im Verzeichnis der ausgeführten .EXE Datei.
In unserem Beispiel liegt diese SQLite Datenbank also unter “C:\tmp\HalloWelt\bin\Debug”.

Datenbank-Tabellen in C# zur Laufzeit erstellen

  • Eine neue “SQLiteConnection” erstellen (s.o.)
  • Den “Create Table” Befehl als SQLiteCommand einbinden
  • Diesen SQL Befehl an die Datenbank übergeben
  • Verbindung zur SQLite Datenbank wieder schließen

Beispiel:

SQLiteConnection connection = new SQLiteConnection("Data Source=test.dat");
connection.Open();

SQLiteCommand command = new SQLiteCommand(connection);
command.CommandText = String.Format("create table {0} (" +
    "  ID integer not null primary key autoincrement," +
    "  Name varchar(100) not null," +
    "  City varchar(100))",
    "Adressen");
command.ExecuteNonQuery();

connection.Close();

Im Beispiel wird eine einzelne Tabelle mit dem Namen “Adressen” und den Feldern “ID, Name, City” erstellt. Das Feld “ID” ist dabei der PK (Primary Key) und wird automatisch bei jedem Datensatz hochgezählt (Increment +1).

Daten in eine Tabelle in C# zur Laufzeit einfügen

Dieses Beispiel steht stellvertretend für jeden weiteren verfügbaren SQL Befehl. Eine Übersicht der anwendbaren SQL Befehle finden Sie in der SQLite Hilfe oder auf der SQLite Webseite:
http://www.sqlite.org/

Wie Sie Daten aus Tabellen abrufen können (SELECT Statements) finden Sie im nächsten Beispiel.

  • Eine neue “SQLiteConnection” erstellen (s.o.)
  • Den Befehl als SQLiteCommand einbinden
  • Diesen SQL Befehl an die Datenbank übergeben
  • Verbindung zur SQLite Datenbank wieder schließen

Beispiel:

SQLiteConnection connection = new SQLiteConnection("Data Source=test.dat");
connection.Open();

SQLiteCommand command = new SQLiteCommand(connection);
command.CommandText = String.Format("insert into Adressen (Name,City) values ('{0}','{1}')",
    "Max Muster",
    "Hamburg");
command.ExecuteNonQuery();

command.CommandText = String.Format("insert into Adressen (Name,City) values ('{0}','{1}')",
    "Bertha Besser",
    "Berlin");
command.ExecuteNonQuery();

connection.Close();

Im Beispiel werden zwei Datensätze in die oben erstellte Tabelle “Adressen” eingefügt:

  1. Max Muster, Hamburg
  2. Bertha Besser, Berlin

Daten aus einer Tabelle in C# zur Laufzeit abfragen

Dieses Beispiel steht stellvertretend für alle weiteren SQL Befehle, mit denen Sie Daten aus Ihrer Datenbank auslesen.

  • Eine neue “SQLiteConnection” erstellen (s.o.)
  • Den Befehl als SQLiteCommand einbinden
  • Diesen SQL Befehl an die Datenbank übergeben
  • Die erhaltenen Daten ggf. weiterverarbeiten
  • Verbindung zur SQLite Datenbank wieder schließen

Beispiel:

SQLiteConnection connection = new SQLiteConnection("Data Source=test.dat");
connection.Open();

SQLiteCommand cmd = new SQLiteCommand("select * from Adressen", connection);
SQLiteDataReader reader = cmd.ExecuteReader();

if (reader.HasRows)
while (reader.Read())
{
  string name = reader.GetString(reader.GetOrdinal("Name"));
  string city = reader.GetString(reader.GetOrdinal("City"));
  MessageBox.Show(string.Format("{0}, {1}", name, city));
}

connection.Close();

Im Beispiel werden alle Datensätze aus der oben erstellten Tabelle “Adressen” eingelesen.
Jeder Datensatz wird dem Benutzer dann als MessageBox angezeigt.

SQLite Datenbank löschen

Ihre Datenbank können Sie (auch aus C# heraus) sehr einfach löschen, indem Sie die Datei “test.dat” (in unserem Beispiel) von der Festplatte löschen.

Voraussetzung ist, dass Sie keine offenen Verbindungen zur Datenbank haben. Ansonsten erhalten Sie einen Zugriffsfehler (“Access denied”).

Achtung:
Wenn Sie die Datendatei Ihrer SQLite Datenbank löschen, verlieren Sie sofort alle gespeicherten Daten !

18. Feb 2010
Teaser

ExtJS: Fehler “unterminated string literal” bei .load()

Wenn Sie auf Ihrer Webseite mit Ext JS und der Funktion “xyz.open()” Daten nachladen, kann es vorkommen, dass Ihre Maske die Daten nicht zeigt und der Ladevorgang nicht beendet wird. Sie sehen dann (sofern Sie es aktiviert haben) die Lademeldung weiterhin auf dem Bildschirm.

Die Meldung in der Fehlerkonsole des Browsers lautet (z.Bsp.):

Fehler: unterminated string literal
Quelldatei: http://localhost/ext/ext-all.js
Zeile: 7, Spalte: 73
Quelltext:
({“count”:1,”success”:true,”items”:[{“id”:1234,”ref”:””,”txt”:”Shell

Grund für den Fehler ist dann meist ein Zeilenumbruch (CRLF) im Text (hier in der Variablen “txt”).

Diesen umbruch kann das JSON Format zwar an Ihre Anwendung übertragen, JavaScript kommt damit dann aber nicht zurecht.

Lösung:

Ersetzen Sie bei der JSON Erstellung (z.Bsp. in PHP) den Umbruch durch ein “\n”:

eregi_replace(chr(13).chr(10),'\n',$to->Text)
16. Feb 2010
Teaser

SVN: Die .svn Ordner rekursiv aus den Verzeichnissen löschen

Wenn Sie SVN Projekte betreiben und die lokalen Verzeichnisse kopieren oder weitergeben möchten, dann stören häufig die .svn Folder (Ordner) in jedem einzelnen Unterverzeichnis.

Um diese einfach und schnell zu löschen, legen Sie sich eine Batchdatei mit folgendem Inhalt an:
??

FOR /F "tokens=*" %%G IN ('DIR /B /AD /S *.svn*') DO RMDIR /S /Q %%G

Direkt auf der Kommandozeile ausgeführt, funktioniert der Befehl leider (meist) nicht.

Um in der Kommandozeile direkt die Batchdatei (hier: “delete_svn.bat”) anzulegen, nutzen Sie folgende Befehle:

copy con delete_svn.bat
FOR /F "tokens=*" %%G IN ('DIR /B /AD /S *.svn*') DO RMDIR /S /Q %%G
^Z

Danach finden Sie im aktuellen Verzeichnis die “delete_svn.bat” und können Sie ausführen.

Achtung:
Die .SVN Ordner werden ohne Rückfrage sofort und rekursiv gelöscht, d.h. auch alle .SVN Ordner in allen Unterverzeichnissen des aktuellen Orderns werden gelöscht.

Sollte das Script mit einem Fehler “” beendet werden, bitte die Anführungszeichen im Befehl entsprechend ändern (z.Bsp. von ” zu ‘ ).

In Linux funktioniert der folgende Befehl:

rm -rf `find . -type d -name .svn`
14. Feb 2010
Teaser

Linux: Datenträger Partitionierungs Tool

Unter Linux (Debian) hilft Ihnen im Textmodus gut und einfach das CFDisk Tools bei der Datenträger- / Festplatten-Partitionierung:

cfdisk /dev/sdc1

Die Oberfläche ist sehr einfach gehalten und gut bedienbar.

Vergessen Sie vor dem Beenden des Programmes nicht den “WRITE” Befehl ausführen zu lassen. Nur dann werden Ihre Änderungen auch auf den entsprechenden Datenträger geschrieben.

14. Feb 2010
Teaser

Apache: Reverse Proxy & Multi Subdomains

Wenn Sie einen Apache2 Webserver als Reverse Proxy betreiben und dabei mehrere Subdomains berücksichtigen möchten, müssen Sie nicht zwangsläufig mehrere virtuellen Hosts (VHosts) in der Apache Konfiguration definieren. Es geht wesentlich einfacher über Parameter in der Konfiguration:

Fügen Sie am Ende der Datei die folgenden beiden Zeilen ein:

ProxyRequests on
ProxyPreserveHost on

Starten Sie anschließend den Apache durch “/etc/init.d/apache2 restart” neu. Fertig.

Wenn Sie WebMin für die Administration nutzen, können Sie die Einstellung auch bequem über die Weboberfläche durchführen:

  • Server
  • Apache Webserver
  • Den entsprechenden virtuellen Server auswählen
  • Proxying
  • “Erhalte originalen Host:-Header” auf “Ja” setzen
  • Oben rechts auf “Änderungen anwenden” klicken
10. Feb 2010
Teaser

Warum man Partitionen einrichten sollte

Bei der Installation eines Betriebsystemes werden Sie meist nach der Einrichtung von Partitionen gefragt.

Eine partition ist die (virtuelle) Unterteilung eines Datenträgers in einzelne Bereiche.

Die jeweils passende Partitionierung hängt davon ab, wie Sie den Computer nutzen möchten.
Eine gute Faustregel ist, dass Sie mit den Partitionen eher großzügig sind und dabei folgendes berücksichtigt:

Jeder Bereich (Verzeichnisbaum), auf den ein Benutzer Schreibzugriff haben soll (z.Bsp. bei Linux auf die Verzeichnisse /home, /tmp und /var/tmp) sollte auf einer separaten Partition liegen. Das senkt das Risiko eines DoS (= Denial of Service) durch einen Benutzer. Das kann z.Bsp. passieren, indem man Ihren “/”-Mountpoint füllt (eine Datei, bis sie den kompletten freien Speicherplatz benötigt) und so das komplette System unbenutzbar macht. Rein technisch ist zwar immer noch ein wenig Platz für den Benutzer “root” – aber ein großes Problem haben Sie trotzdem.

Außerdem schützt dieses Vorgehen vor Hardlink-Angriffen.

    09. Feb 2010
    Teaser

    Ein System per VirtualBox auf einer (realen) Festplatte installieren

    Die Freeware “VirtualBox” erlaubt es Ihnen auf Ihrem Computer andere (virtuelle) System zu installieren und betreiben. Normalerweise nutzt die Software dafür ebenfalls virtuelle Festplatten auf Ihrem eigentlichen (realen) PC.

    Wenn Sie nun ein System auf einer physikalischen Festplatte (im gegensatz zur üblichen virtuellen Festplatte) installieren möchten, stellt Ihnen VirtualBox ab Version 2.2.2 dafür Techniken zur Verfügung. Wir möchten hier kurz zeigen, wie Sie anhand eines Beispieles diese Technik nutzen können:

    1. Schritt: Festplatte mit Ihrem Computer verbinden

    Entweder bauen Sie die zu verwendende Festplatte in Ihren PC ein oder Sie schließen Sie über externe USB Adapter an Ihren Computer an.

    Solche USB Adapter finden Sie unter der Bezeichnung “USB Festplatten Adapter” in den meisten Elektronikfachmärkten.
    Beispiel: Google Produktsuche mit Preisvergleich

    2. Schritt: Kennung der Festplatte herausfinden

    Um die Festplatte für VirtualBox verfügbar zu machen, benötigen wir die eindeutige Kennung (ID) der Festplatte.

    Unter Windows:

    • Öffnen Sie die “Computerverwaltung”
      Start > Einstellungen > Systemsteuerung > Verwaltung > Computerverwaltung
    • Wählen Sie “Datenträgerverwaltung” (in “Datenspeicher”)
    • Im rechten, unteren Fensterbereich finden Sie alle gefundenen Datenträger:

      Bild: Beispiel aus der Datenträgerverwaltung
    • Klicken Sie mit der rechten Maustaste auf den Anfang des entsprechenden Eintrages.
      Wählen Sie “Eigenschaften” aus
    • Im Bereich “Volumes” finden Sie die Kennung bei der Option “Datenträger”:

      In diesem Beispiel wäre die ID also “2”.

    Unter Linux:

    Die Anleitung folgt in Kürze.

    3. Schritt: VirtualBox (.vmdk) Datei erstellen

    Damit die Festplatte in VirtualBox als Festplatte genutzt werden kann, müssen Sie eine .vmdk Datei erstellen.

    Unter Windows:

    • Öffnen Sie eine Kommandozeile
      Start > Ausführen > “cmd” eingeben > “OK” anklicken
    • Wechseln Sie in das VirtualBox Installationsverzeichnis:
      cd "\Programme\Sun\xVM VirtualBox"
    • Hinweis – Bei neueren Installationen liegt das Verzeichnis hier:
      cd "\Programme\Oracle\VirtualBox"
    • Erstellen Sie die benötigte Datei. Passen Sie bitte die Optionen an Ihre Festplatten ID an.
      Hier ist die ID “2” – also “PhysicalDrive2”:

      VBoxManage internalcommands createrawvmdk -filename c:\realhdd.vmdk -rawdisk \\.\PhysicalDrive2
    • Sollten Sie die folgende Fehlermeldung (ggf. leicht abgewandelt) erhalten, …
      Error opening the raw disk '\\.\PhysicalDrive2': VERR_ACCESS_DENIED
      The raw disk vmdk file was not created
    • … dann müssen Sie den o.a. Befehl “VBoxManage ..” als Administrator ausführen.
      Dazu können Sie diesen wenigen Schritten folgen:

      • Öffnen Sie das Windows-Startmenu (Windowstaste drücken)
      • Geben Sie “cmd” ein und warten Sie kurz.
        Ihnen wird “Programme (1)” angezeigt und darunter finden Sie den Eintrag “cmd.exe”
      • Klicken Sie diesen Eintrag mit der rechten Maustaste einmal an
      • Im erschienenen Popupmenü klicken Sie einmal mit der linken Maustaste auf “Als Administrator ausführen”
      • Wieder wird Ihnen ein Fenster mit einer Kommandozeile geöffnet
      • Geben Sie hier nun den o.a. Befehl (“VBoxManage internalcommands …”) nochmals ein
      • Drücken Sie auf Enter (= Return) und die Datei sollte nun erstellt werden
    • Nun finden Sie unter C:\ eine Datei mit dem Namen “realhdd.vmdk”

    Unter Linux:

    • VBoxManage internalcommands createrawvmdk -filename /home/benutzername/sda3.vdmk -rawdisk /dev/sda3 -register

    4. Schritt: Die Festplatte in VirtualBox einrichten

    • Starten Sie VirtualBox
    • Starten Sie den “Manager für virtuelle Medien” (Strg + D)
    • Wählen Sie “Hinzufügen” aus (bei Festplatten)
    • Wählen Sie die o.a. vmdk-Datei aus
      Im Beispiel wäre das “C:\realhdd.vmdk”
    • Schließen Sie das Fenster mit “OK”

    Hier kann (unter Windows) ein ähnliches Problem mit den Berechtigungen auftreten.
    In diesem Fall wird Ihnen die folgende Fehlermeldung angezeigt:

    Die Festplatte c:\realhdd.vmdk konnte nicht geöffnet werden.
    
    Could not open the medium 'c:\realhdd.vmdk'.
    
    VD: error VERR_ACCESS_DENIED opening image file 'c:\realhdd.vmdk' (VERR_ACCESS_DENIED).

    Die Lösung ist, die Berechtigungen für diese Datei zu ändern:

    • Öffnen Sie Ihren Arbeitsplatz (= Explorer) und gehen Sie zu Ihrer Datei (“c:\realhdd.vmdk”)
    • Klicken Sie die Datei einmal mit der rechten Maustaste an
    • Wählen Sie im erschienenen Menü den Eintrag “Eigenschaften” aus
    • Gehen Sie auf den Reiter “Sicherheit” (oben im Fenster)
    • Klicken Sie auf den Button “Erweitert” (unten im Fenster)
    • Wählen Sie im automatisch geöffneten Fenster den Reiter “Besitzer” aus
    • Klicken Sie auf den Button “Bearbeiten”
    • Wählen Sie Ihren Benutzernamen bzw. den Namen, unter welchem VirtualBox laufen wird, aus
    • Klicken Sie im Fenster unten rechts auf “Übernehmen”
    • Bestätigen Sie den ggf. auftauchenden Hinweis mit “OK”
    • Schließen Sie beide geöffneten Fenster durch Anklicken von “OK”

    Sollte dieser Weg keine Lösung auf Ihrem System bringen, so können Sie VirtualBox auch unter dem Benutzer “Administrator” starten:

    • Klicken Sie mit der rechten Maustaste auf Ihrem Desktop auf das “VirtualBox” Symbol
    • Dann klicken Sie im erscheinenden Menü auf “Als Administrator ausführen”
    • Nun können Sie auf die erstellte .vmdk Datei zugreifen und diese nutzen.
      Wenn Sie einen anderen Weg kennen, schreiben Sie uns gerne.

    5. Schritt: Den virtuellen PC mit der realen Festplatte einrichten

    In VirtualBox können Sie nun den virtuellen PC einrichten.

    Dabei können Sie dann die angeschlossene, physikalische Festplatte auswählen und als Datenträger normal nutzen.

    So können Sie z.Bsp. Ihren Server oder Client an Ihrem PC einrichten, installieren oder konfigurieren und die Festplatte später in einem anderen Computer nutzen.

    Dabei sind teilweise Einschränkungen bzgl. der Hardware erkennung zu beachten, denn der virtuelle PC (auf welchem Sie das System installierten) hat ggf. andere Hardware als der spätere Computer. Die meisten aktuellen Betriebssysteme erkennen diese Änderung aber und richten die neu gefundene Hardware automatisch ein.

    Software

    Mehr über VirtualBox erfahren Sie hier: http://www.virtualbox.org/

    05. Feb 2010
    Teaser

    PHP: Unable to load dynamic library ‘/usr/lib/php5/extensions/mysql.so’

    Wenn im ErrorLog des Apache2 WebServers (“tail /var/log/apache2/error.log”) u.a. folgende Zeile zu finden ist, kann PHP die Extension (Erweiterung) nicht finden und laden:

    PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib/php5/extensions/mysql.so' - /usr/lib/php5/extensions/mysql.so: cannot open shared object file: No such file or directory in Unknown on line 0

    Häufig wird dann angefangen, wild an der Konfiguration zu ändern und basteln. Dabei wird meist das naheliegendste übersehen:

    Gibt es das angegebene Verzeichnis überhaupt ?
    Erst recht, wenn mehrere (oder gar viele) Extensions nicht geladen werden können.

    Wenn dann der Befehl

    dir -l /usr/lib/php5/extensions/

    die folgende Fehlermeldung anzeigt, sollte alles klar sein:

    dir: Zugriff auf /usr/lib/php5/extensions/ nicht möglich: Datei oder Verzeichnis nicht gefunden

    Lösung

    Den Pfad für die Extensions in der “php.ini” anpassen. Diese kann, falls der Pfad nicht bekannt ist, mithilfe des folgenden Befehls gefunden werden.

    find / -name php.ini

    Dieser Befehl zeigt Ihnen ggf. auch andere “php.ini” Dateien auf ihrem System an. Manchmal konfiguriert man ein einer “php.ini” und wundert sich, dass keine Änderung eintritt. Wenn man zufällig die falsche Datei in den Händen hat, dann kann man auch lange auf ein Ergebnis warten 😉

    Häufig fällt dieses Problem nach einer (Neu)Installation erst auf, wenn die mySQL / mySQLi Unterstützung fehlt. Grund ist dann (meist), dass die mysql.so Extension in PHP nicht geladen werden kann.

    05. Feb 2010
    Teaser

    Debian: Verbindung per SSH installieren / einrichten

    Nachdem Sie sich einen minimalen Linux Server (hier mit “Debian +lenny4”) installiert haben, sollten SIe sich für den Remotezugang den SSH-Server installieren:

    apt-get install openssh-server

    Danach mit folgendem Befehl starten:

    /etc/init.d/ssh start

    Ab jetzt können Sie sich per SSH mit Ihrem Server verbinden.

    Kostenloses & häufig eingesetztes Tool ist “PuTTY”.
    Auf der folgenden Webseite finden Sie dazu mehr Informationen:

    http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html