12. Januar 2012

just more incredible - the incredible Blog

Die Unglaublichkeit scheint kein Ende zu nehmen xD

Nach the incredible Machine und the incredible Staggers, (zuvor kurz The Staggers) bin ich nun auf einen weiteren incredible Blog gestoßen :-o

www.incredibleblog.co.za aber nicht von dem incredible Leitman :-/

Wie es aussieht ein Blog über aktuelle Technologien,
Apple, Gaming, Tablets, Laptops, Cameras, Cellulas und "Specials" kann man den Topics entnehmen.

Gehostet wird dieser incredibleBlog scheinbar von Whitespace, die vermarktende Firma nennt sich Incredible Connection.


Tja, was es so alles gibt :)
- der RICHTIGE incredible Leitman xD

NACHTRAG zu wt - Installation on windows

Eigentlich wollte ich den ursprünglichen Beitrag "wt - Installation on windows" editieren und erweitern, bzw. mit Kommentaren weitere Informationen ergänzen...
aber dann hatte ich ein schlechtes Gefühl, wenn ich auf einen eigenen Beitrag selber kommentiere :-/
(Das ist ungefähr so, wie auf Facebook seinen eigenen Status zu liken xD)

Darum hier, ein eigener Beitrag mit einigen zusätzlichen Informationen:


Starten von wt Beispielen

Wie bereits in der Dokumentation beschrieben
[copy - paste]
In the MSVC IDE Right-click on the example project you want to run, and select 'Properties'. In Configuration Properties->Debugging, set the Command Arguments to

--http-address=0.0.0.0 --http-port=8080 --deploy-path=/hello --docroot=.

Wt builds static versions of all libraries by default and links against static boost libraries by default. If you would choose to build dynamic libraries in the future (see remarks at the bottom of this page), the easiest way to locate the dependency dlls, is to append their location to the PATH variable. In order to do so, change the Environment field to contain a PATH directive:
PATH=c:/libraries/lib;c:/Boost/lib;;

Right-click on the example project you want to run and select 'Set as Startup Project'. Press F5 (Run). This will start a httpd server listening on all local interfaces, on port 8080, and you may browse the example at http://127.0.0.1:8080/hello

Examples that need extra files to run, should be executed from their source directory in order to find their dependency files (icons, css files, etc. Watch for 404 errors in Wt's output). To do so, set the 'Working directory' for the example to wt-2.x.x/examples/ExampleName. Some examples (e.g. the wt home page) need the 'resources' directory to work correctly. Copy the wt-2.x.x/resources to the example's source directory to solve this problem. Other examples (such as the Charts example) may require the installation of ExtJs. See the Wt reference manual for more information on how to obtain and install ExtJs.

These are all the command-line options that are available (run the wt application with --help to see the newer options available in your version):
General options:
  -h [ --help ]              produce help message
  -t [ --threads ] arg (=10) number of threads
  --docroot arg              document root for static files
  --no-compression           do not compress dynamic text/html and text/plain 
                             responses
  --deploy-path arg (=/)     location for deployment


HTTP server options:
  --http-address arg    IPv4 (e.g. 0.0.0.0) or IPv6 Address (e.g. 0::0)
  --http-port arg (=80) HTTP port (e.g. 80)


HTTPS server options:
  --https-address arg     IPv4 (e.g. 0.0.0.0) or IPv6 Address (e.g. 0::0)
  --https-port arg (=443) HTTPS port (e.g. 443)
  --ssl-certificate arg   SSL server certificate chain file
                          e.g. "/etc/ssl/certs/vsign1.pem" 
  --ssl-private-key arg   SSL server private key file
                          e.g. "/etc/ssl/private/company.pem" 
  --ssl-tmp-dh arg        File for temporary Diffie-Hellman parameters
                          e.g. "/etc/ssl/dh512.pem" 
[/copy - paste]



Möglicherweise auftretende Probleme


  • CMake Error: file cannot create directory

Ich erhielt seltsamerweise die folgende Fehlermeldung von cmake, als ich, wie in der Installationsanleitung beschrieben, versucht habe, das "INSTALL" Projekt zu bauen:
"Install the project... -- Install configuration: "Debug" CMake Error at cmake_install.cmake:33 (FILE): file cannot create directory: C:\WT C:\Programme\cmake. Maybe need administrative privileges."

Was auch verständlich ist, denn wieso sollte ein directory aus zwei Pfadangaben bestehen? o.O
Jedenfalls, wirklich in meinem cmake file (cmake_install.cmake, befindet sich im build Verzeichnis von wt, welches lt. Installationsanleitung mit cmake erstellt wurde) steht in Zeile 33
"FILE(INSTALL DESTINATION "C:/Programme/WT/C:/Programme/cmake/share/cmake-version/Modules" TYPE FILE FILES "WT_ROOT/cmake/FindWt.cmake")"

Keine Ahnung, woher das gekommen ist,
aber selbstverständlich funktioniert das Ganze, wenn lediglich EIN Zielverzeichnis angegeben wird
"FILE(INSTALL DESTINATION "C:/Programme/WT" TYPE FILE FILES "WT_ROOT/cmake/FindWt.cmake")"



  • default_token is not a static member of class boost::random::random_device

Beim kompilieren erhielt ich einige Fehlermeldungen im Stil von:
" t-3.1.11\src\web\random_device.cpp:125: error: 'const char* const boost::random::random_device::default_token' is not a static member of 'class boost::random::random_device'
wt-3.1.11\src\web\random_device.cpp: In constructor 'boost::random::random_device::random_device(const std::string&)':wt-3.1.11\src\web\random_device.cpp:165: error: 'max_value' was not declared in this scope "

Nach einigem Suchen, bin ich auf ein Ticket in der boost library gestoßen das besagt, das dies passiert wenn das flag WT_NO_BOOST_RANDOM nicht korrekt gesetzt ist.
Die Lösung war, mittels cmake die Konfiguration nochmals zu laden, das flag auf FALSE zu stellen und nochmals zu generieren :)



  • _SCL_SECURE_NO_WARNINGS macro redefinition in Boost.Move

Zu guter Letzt erhielt ich noch ungefähr 1900 Warnungen dass ein Macro erneut definiert wurde xD
Dies scheint jedoch auch ein bug in der boost library version 1.48 zu sein (Ticket) und ist über ein wenig Patcharbeit schnell ausgebügelt:
[copy - paste]
In the "boost/move/move.hpp" (line 28) header file _SCL_SECURE_NO_WARNINGmacro is defined without checking whether previous definition exists:
#ifdef BOOST_MSVC
   #ifndef _CRT_SECURE_NO_DEPRECATE
   #define  BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE
   #define _CRT_SECURE_NO_DEPRECATE
   #define _SCL_SECURE_NO_WARNINGS
   #endif
   #pragma warning (push)
   #pragma warning(disable:4996)
#endif
Correct code:
#ifdef BOOST_MSVC
   #ifndef _CRT_SECURE_NO_DEPRECATE
   #define  BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE
   #define _CRT_SECURE_NO_DEPRECATE
   #endif
   #ifndef _SCL_SECURE_NO_WARNINGS
   #define _SCL_SECURE_NO_WARNINGS
   #endif
   #pragma warning (push)
   #pragma warning(disable:4996)
#endif
[/copy - paste]


Sooooo.... puh,  ist doch ein wenig mehr als gedacht :-o
War also doch die richtige Entscheidung, das in einen extra Post zu verfrachten ;)


Ich hoffe, hiermit jemandem mit einem eventuell auftretendem selben Problem vielleicht geholfen zu haben,
doch wenn nicht habe ich immer noch die Genugtuung, das alles zusammengeschrieben zu haben falls ich wieder mal in die Versuchung komme diesen ganzen Framework-aufsetzen-Durchgang zu wiederholen ^^

mit freundlichen Grüßen,
happy coding :)
- the incredible Leitman 

11. Januar 2012

wt - Installation on windows

Endlich ist es so weit :))))
Neues Projekt, neue Technologie, neues Framework ^.^

Für unser neues Projekt werden wir in Zukunft auf wt von emweb setzen.

Ich bin eigentlich, rein vom anschauen und anfänglichen einlesen bereits ziemlich begeistert von diesem Framework,
es ist schnell, wirkt robust und weist weiter eine rasche Updatepolitik auf.


Doch, wie das so ist, am Anfang eines jeden Projektes steht der erste Schritt:
Die Installation und Konfiguration der neuen Technologie


Hierbei sei zu sagen, dass wt auf die boost C++ libaries setzt, welche ebenfalls heruntergeladen und installiert werden müssen,
des Weiteren benötigt man cmake.

Hier eine einfache Installationsanleitung unter windows (wer sich ein wenig umsieht, findet auf der Seite natürlich für alle anderen OS ebenfalls Informationen, sogar für Android :-o! )




Anhand dieser gut ausgeführten Installationszusammenfassung kann ich demnächst loslegen und bereits anfangen ein wenig damit zu spielen ;)

happy coding
- the incredible Leitman


UPDATE: 
Ich bin bei der Installation und kompilierung (OBWOHL ich mich strikt an die Anleitung gehalten habe :p) auf ein paar Probleme gestoßen, welche ich in folgendem Beitrag erörtert habe.

21. Dezember 2011

Korrektes Event Handling (registrieren und deregistrieren) in dotnet

Auf der Suche nach einer Möglichkeit um zu überprüfen ob ein Object einen EventHandler registriert hat,
bin ich auf folgendern überaus gut erklärten Post von herbivore auf myCSharp.de gestoßen, den ich im Folgenden einfach übernehmen werde:


Machmal sagt Code mehr als tausend Worte. So definiert man einen eigenen Event
(folgt nicht den Microsoft-Empfehlungen, dazu später mehr):

C#-Code:
using System;

public delegate void MyHandler (string str_nick, string str_channel);

public class Test
{
   public event MyHandler MyEvent;

   protected virtual void OnMyEvent (string str_nick, string str_channel)
   {
      MyHandler myEvent = MyEvent;
      if (myEvent != null) {
         myEvent (str_nick, str_channel);
      }
   }

   public void DoSomething ()
   {
      // ...
      OnMyEvent ("herbivore", "mycsharp");
      // ...
   }

}

abstract class App
{
   public static void Main (string [] astrArg)
   {
      Test test = new Test ();

      test.MyEvent += new MyHandler (ThisMyEvent);
      test.DoSomething ();
   }

   public static void ThisMyEvent (string str_nick, string str_channel)
   {
      Console.WriteLine ("ThisMyEvent (" + str_nick + ", "
                                         + str_channel + ")");
   }
}


PS: Dieser Code funktioniert zwar, folgt aber nicht der Empfehlung von MS, an die man sich bei Events wirklich besser halten sollte. Wie ein eigener Event nach der Empfehlung von MS aussehen sollte, steht im folgenden Beitrag.



Und so erstellt man einen eigenen Event von Typ EventHandler (wie es von MS empfohlen wird):

C#-Code:
using System;

public class Test
{
   // --- schnipp ---

   public event EventHandler MyEvent;

   protected virtual void OnMyEvent (EventArgs e)
   {
      EventHandler myEvent = MyEvent;
      if (myEvent != null) {
         myEvent (this, e);
      }
   }

   // --- schnapp ---

   public void DoSomething ()
   {
      // ...
      OnMyEvent (EventArgs.Empty);
      // ...
   }
}

static class App
{
   public static void Main (string [] astrArg)
   {
      Test myObject = new Test ();
      myObject.MyEvent += myObject_MyEvent;

      myObject.DoSomething ();
   }

   public static void myObject_MyEvent (Object objSender, EventArgs e)
   {
      Console.WriteLine ("myObject_MyEvent (" + objSender + ", " + e + ")");
   }
}

Wobei man natürlich auch eine eigene MyEventEventArgs-Klasse erstellen und verwenden könnte. Siehe dazu das Beispiel von Programmierhans weiter unten.

Hier noch ein Blick auf die wichtigen Bestandteile des Beispiels:


1. Den Event selbst:

C#-Code:
public event EventHandler MyEvent;

Ist in der Klasse definiert, die den Event zur Verfügung stellen will und im Wesentlichen eine Variable, in der die jeweils registrierten EventHandler gespeichert sind. Ist null, wenn kein EventHandler registriert ist. Namen von Events sollten nie mit On beginnen. "MyEvent" ist nur ein Platzhalter, den ihr durch euren Namen für den Event ersetzen solltet, z.B. TextChanged o.ä.


2. Die event-auslösende Methode:

C#-Code:
protected virtual void OnMyEvent (EventArgs a)

Deren Namen sollte immer mit On beginnen und danach sollte der Name des Events folgen. Ist natürlich in der gleichen Klasse definiert. Sie wird von dieser Klasse aufgerufen, um den Event zu feuern. Im Beispiel also in DoSomething in der Zeile OnMyEvent (EventArgs.Empty);

Die Implementierung der event-auslösenden Methode kann man durch die Raise-Erweiterungsmethode, die weiter  unten vorgestellt wird, vereinfachen.


3. Den/die EventHandler:

C#-Code:
public static void myObject_MyEvent (Object objSender, EventArgs e)

Der EventHandler ist in der Klasse definiert, die über das Event informiert werden will. Das ist typischerweise eine andere Klasse, als die, die das Event definiert. Namen von EventHandlern sollten nie mit On beginnen. VS benennt EventHandler nach dem auch hier verwendeten Muster: Variablenname Unterstrich EventName.


4a. Das Registrieren des EventHandler für den Event (auch Abonnieren des Events genannt):

EventHandler werden registriert mit +=

C#-Code:
myObject.MyEvent += myObject_MyEvent;

Unter .NET 1.x musste man noch schreiben:

C#-Code:
myObject.MyEvent += new EventHandler (myObject_MyEvent);

Ab .NET 2.0 ist die kürzere Schreibweise möglich, die man auch bevorzugen sollte.


4b. Das Deregistrieren des EventHandler für den Event (auch Entfernen oder Abhängen des EventHandlers genannt):

Zum Deregistrieren eines EventHandlers verwendet man -= statt +=.

Es ist nicht erforderlich, beim Deregistrieren exakt dieselbe Instanz des Delegaten zu verwenden, sondern es reicht, wenn der Delegat auf dieselbe Methode verweist.

C#-Code:
myObject.MyEvent += new EventHandler (myObject_MyEvent);
myObject.MyEvent -= new EventHandler (myObject_MyEvent);

Durch die zweite Zeile wird der EventHandler myObject_MyEvent wieder entfernt, obwohl an sich zwei separate Delegaten-Objekte verwendet werden (new), die aber eben beide auf dieselbe Methode verweisen. Schon deshalb ist die C#-2.0-Schreibweise ohne new vorzuziehen.

Das rechtzeitige Deregistrieren von nicht mehr benötigten Events wird oft vergessen. Das kann allerdings negative Konsequenzen haben. Hat ein Objekt B einen Event von Objekt A registriert und wird das Objekt B nicht mehr benötigt, kann die Speicherfreigabe des Objekts B verzögert oder verhindert werden (memory leak). Der Grund ist, dass das Objekt A noch eine Referenz auf das Objekt B hält. Diese Referenz "versteckt" sich im Delegaten für den EventHandler (Delegate.Target). Deshalb sollte man rechtzeitig alle EventHandler die B registriert hat entfernen.

Noch schlimmer ist es, wenn das Objekt B zerstört wird (Dispose) und dabei die EventHandler nicht entfernt werden. Denn wird ein solches Event ausgelöst, wird der weiterhin registrierte EventHandler aufgerufen und dieser greift dann im schlimmsten Fall auf das bereits zerstörte Objekt zu.

+= und -= sind übrigens die einzigen beiden Operatoren, mit denen man auf Events einer Klasse von außen zugreifen kann. Man kann insbesondere nicht abfragen, ob ein EventHandler bereits registriert ist oder nicht. Das ist aber normalerweise gar nicht nötig. Möchte man einen EventHandler entfernen, obwohl man nicht weiß, ob er momentan registriert ist oder nicht, kann man trotzdem -= benutzen. Im Ergebnis ist der EventHandler deregistriert, egal ob er vorher registriert war oder nicht. Möchte man einen EventHandler hinzufügen, aber nur, wenn er nicht bereits registriert ist, benutzt man erst -= und dann +=. Im Ergebnis ist der EventHandler genau einmal registriert, egal ob er vorher registriert war oder nicht. Das gilt natürlich nur, wenn man konsequent ist und es an keiner Stelle zulässt, dass ein EventHandler mehr als einmal registriert wird.


Überlegungen zur Thread-Sicherheit

In vielen Büchern wird in der event-auslösende Methode direkt das Event auf null abgefragt, bevor es gefeuert wird, also so:

C#-Code:
      if (MyEvent != null) {
         MyEvent (this, e);
      }

Auch hier stand bisher der Code so. Dass diese Vorgehensweise nicht thread-sicher ist (zwischen Abfrage und Feuern könnte ein anderer Thread den letzten EventHandler deregistrieren und dann würde das Feuern eine NullReferenceException auslösen), wurde in Kauf genommen, weil viele Klassen sowieso nicht thread-sicher ausgelegt sind und Synchronisierung (z.B. durch lock) nur unnötig Zeit kostet, wenn die Klasse ohnehin nur single-threaded eingesetzt wird.

Es gibt aber eine so preiswerte Lösung, um Thread-Sicherheit zu erreichen, dass man diese grundsätzlich immer einsetzen kann und sollte. Man muss nur dafür sorgen, dass man bei Abfrage und Feuern eine Referenz auf dasselbe Objekt verwendet. Denn Delegaten - und mithin Events - sind immutable. Das Registrieren oder Deregistrieren eines EventHandlers erzeugt immer ein neues Objekt mit den Änderungen. Diesen Umstand kann man nun ausnutzen, denn MyEvent ruft bei jedem Zugriff das jeweils aktuelle Objekt und damit an beiden Stellen ggf. unterschiedliche Objekte ab, wogegen myEvent an beiden Stellen garantiert dasselbe (und da immutable auch unveränderte) Objekt liefert.

C#-Code:
      EventHandler myEvent = MyEvent;
      if (myEvent != null) {
         myEvent (this, e);
      }

Diese Lösung kostet nur eine zusätzlich Referenzzuweisung und spart dabei sogar noch einen Property-Zugriff.

Es sei jedoch darauf hingewiesen, dass trotz oder gerade wegen dieses Vorgehen ein EventHandler auch noch aufgerufen werden kann, *nachdem* er schon aus dem Event ausgetragen (deregistriert) wurde, wodurch sich die Notwendigkeit einer zusätzlichen Synchronisierung ergeben kann.

Dank geht an Golo Roden, der mich auf diese Lösung hingewiesen hat.


Vereinfachung der event-auslösenden Methode bei gleicher Thread-Sicherheit

Mit der Raise-Erweiterungsmethode, die weiter  unten vorgestellt wird, lässt sich die Implementierung der event-auslösenden Methode bei gleicher Thread-Sicherheit noch einfacher realisieren.

herbivore



Danke herbivore :)

Tomcat als Service unter Windows installieren UND für den Jazz Team Server konfigurieren

Weil ich es eben gemacht habe,
und falls ich es in Zukunft wieder brauche, mir ein wenig gegoogle erpare,
folgend eine kurze Zusammenfassung, wie man das Ganze zustande bringt:

Installation von Tomcat als Service / Dienst:

Nach dem download (hier) wird einfach der Installer wizard wie gewohnt ausgeführt.

Anschließend geht es darum, tomcat als Dienst festzulegen und automatisch zu starten.

Sehr geholfen hierbei hat mir das offizielle Windows service HOW-TO der Apache Foundation die unter anderem Folgendes beschreibt:


Installing services
The safest way to manually install the service is to use the provided service.bat script. Administrator privileges are required to run this script. If necessary, you can use the /user switch to specify a user to use for the installation of the service.
NOTE: On Windows Vista or any other operating system with User Account Control (UAC) you must either disable UAC or right-click on cmd.exe and select "Run as administrator" in order to run this script. If UAC is enabled neither being logged on with an Administrator account, nor using the /user switch is sufficient.

Install the service named 'Tomcat7'
C:\> service.bat install
Also begeben wir uns auf der Windows command line in den Ordner, in dem Tomcat liegt, wechseln ins bin Verzeichnis und installieren das service wie beschrieben.
Konfigurieren kann man den service anschließend über das Gui, wenn man Tomcat7w.exe startet.


Konfiguration für den Jazz Team Server:

Um nun dem Jazz Framework mitzuteilen, welchen tomcat es wie verwenden soll,
klärt uns die Hilfe von RTC direkt von IBM auf:

Vorbereitende Schritte

Das Stammverzeichnis Ihrer Implementierung von Jazz Team Server muss C:\jazz sein. Passen Sie Ihre Pfade ausgehend vom tatsächlichen Stammverzeichnis an.
Bei diesen Anweisungen wird davon ausgegangen, dass der Dienst nicht installiert ist. 
Falls er installiert ist, überspringen Sie Schritt 1!


  1. Öffnen Sie eine Eingabeaufforderung und führen Sie den folgenden Befehl aus, um den Tomcat-Dienst zu installieren.
    C:\jazz\server\tomcat\bin\service.bat install
  2. Wenn Sie Derby als Datenbank für Ihr Jazz-Repository verwenden, bearbeiten Sie C:\jazz\server\conf\jazz\teamserver.properties so, dass für die Datenbankposition ein absoluter Pfad angegeben ist. Ändern Sie beispielsweise den Wert von db.jdbc.location in C:/jazz/server/repositoryDB.
    Beachten Sie die Schrägstriche (/) im Pfad.
    Zusätzlich zur Bearbeitung von teamserver.properties muss die Datei log4j.properties hinzugefügt werden, um den Protokolldateipfad zu einem absoluten Pfad zu machen. Bearbeiten Sie für die JTS-Protokolldatei conf\jts\log4j.properties, um den Wert der Eigenschaft log4j.appender.file.File auf einen absoluten Pfad zu setzen, z. B. auf log4j.appender.file.File=C:/jazz/server/logs/jts.log.
    Beachten Sie die Schrägstriche (/) im Pfad. 
  3. Führen Sie C:\jazz\server\tomcat\bin\tomcat5w.exe aus, um den Dienst zu konfigurieren. 
  4. Klicken Sie auf das Register Java und löschen Sie die Markierung im Kontrollkästchen Use default.
  5. Fügen Sie unter Java Virtual Machine den folgenden Pfad hinzu. Sie können auch auf die Auslassungspunkte klicken, um nach der Datei jvm.dll zu suchen.
    C:\jazz\server\jre\bin\j9vm\jvm.dll
  6. Fügen Sie unten im Textfeld Java Options die folgenden Zeilen hinzu:
    -DJAZZ_HOME=file:///c:/jazz/server/conf
    -Djava.awt.headless=true 
    -Dorg.eclipse.emf.ecore.plugin.EcorePlugin.doNotLoadResourcesPlugin=true 
    -Dcom.ibm.team.repository.tempDir=%TEMP%
    -Djazz.connector.sslProtocol=SSL_TLS
    -Djazz.connector.algorithm=IbmX509
    -Dlog4j.configuration=file:///c:/jazz/server/conf/startup_log4j.properties
    
    Wenn Sie eine Oracle-Datenbank verwenden, fügen Sie folgende Zeile hinzu:
    -DORACLE_JDBC=[Pfad zur Oracle JDBC-Treiber-JAR]
    
    Falls Sie eine SQL-Server-Datenbank verwenden, fügen Sie auch die folgende Zeile hinzu:
    -DSQLSERVER_JDBC=[Pfad für die SQL Server JDBC-Treiber-JAR]
  7. Ändern Sie die Größe für Maximum memory pool in den Wert '1200'.
  8. Vergewissern Sie sich, dass auf den Registerseiten Startup und Shutdown für Mode die Einstellung jvm ausgewählt ist.
  9. Klicken Sie auf das Register General und setzen Sie den Starttyp unter Startup type auf Automatic, sofern der Dienst automatisch beim Start von Windows gestartet werden soll.

  10. Starten Sie den Dienst, um den Server zu testen.


Damit sollte nun tomcat als Dienst unter Windows laufen und von Jazz verwendet werden.


Um den Jazz Team Server in einer vorhandener Apache-Tomcat-Umgebung implementieren habe ich folgende Informationen hier von IBM gefunden:

Verwenden Sie die folgenden Anweisungen, um Jazz Team Server für die Zusammenarbeit mit Ihrem vorhandenen Apache Tomcat Server zu konfigurieren.

Vorgehensweise

  1. Kopieren Sie die Datei 'jts.war' aus dem Jazz-Installationsverzeichnis in das Verzeichnis tomcat\webapps.
  2. Öffnen Sie die Tomcat-Startdatei zur Bearbeitung und fügen Sie die folgenden Einstellungen für Systemeigenschaften hinzu:
    set CATALINA_OPTS=-Dcom.ibm.team.server.configURL=file:///"%cd%"/teamserver.properties -Dlog4j.configuration=file:///"%cd%"/log4j.properties 
    set JAVA_OPTS=-Djava.awt.headless=true -DORACLE_JDBC="%ORACLE_JDBC%" -DDB2I_JDBC="%DB2I_JDBC%" -DDB2Z_JDBC="%DB2Z_JDBC%" -Dorg.eclipse.emf.ecore.plugin.EcorePlugin.doNotLoadResourcesPlugin=true -Dcom.ibm.team.repository.provision.profile="%cd%"\provision_profiles -Dcom.ibm.team.repository.tempDir=%TEMP% -Xmx700M
    
  3. Speichern und schließen Sie die Startdatei.
  4. Öffnen Sie die Datei teamserver.properties und bearbeiten Sie sie so, dass sie auf Ihre Datenbank zeigt.
  5. Speichern und schließen Sie die Datei teamserver.properties.



Doch leider weiß ich nicht, ob man für Jazz unbedingt den mitgelieferten tomcat verwenden MUSS oder einfach einen bereits installierten (in einer anderen Version?) verwenden kann.


Falls jemand hierbei Erfahrungen hat, bitte lasst es mich wissen, nutzt die Kommentar Funktion ;)

5. Dezember 2011

[Buch-Verschenkaktion 12/11] - 33 (!) Bücher für 0,-€ + Gutschein

tutorials.de Buch-Verschenkaktion

Hallo liebe tutorials.de-Mitglieder,

zum Jahresende bedankt sich unser Partner Terrashop mit einer stattlichen Auswahl an kostenlosen Artikeln - es gilt diesmal das Motto: 33 für 0,-€! Ihr habt also wirklich die Qual der Wahl, zumal einige Top-Titel dabei sind.

Zusätzlich gibt es wieder einen 5-EUR-Gutschein (30,00 EUR Mindestbestellwert), dieser ist bis zum 18.12.2011 gültig. Der Gutschein-Code lautet tutor1112 und kann auf der Aktions-Seite (ganz unten) eingelöst werden.

Selbstverständlich ist unsere Buch-Verschenkaktion wie immer garantiert ohne Mindestbestellwert und ohne weitere Verpflichtungen. Die Versandkosten betragen 3,95€ (innerhalb Deutschlands).


PS: Auf tutorials.de gibt es, wie im letzten Jahr, einen Adventskalender. Täglich wird ein neues Türchen geöffnet: Es erwartet euch eine eine bunte Mischung an nützlichen Goodies. Sowohl für Grafiker, Fotografen, Webentwickler und Programmierer sollte etwas dabei sein. Schaut doch einfach mal bei uns rein!

Buch-Verschenkaktion 12/11

Viel Spaß mit deinem Gratis-Exemplar wünscht dir das Team von Tutorials.de!

Aktion gültig bis Montag, den 12. Dezember 2011 bzw. solange der Vorrat reicht. Nur ein 0,- € Artikel pro Besteller.

24. November 2011

Comparing Images using GDI+ - CodeProject

Comparing Images using GDI+ - CodeProject

Introduction

.NET provides some great methods for working with images and bitmaps using the managed GDI+ methods. However, I found myself a bit stuck even with GDI+ when I wanted to compare two images to see if they were identical. I was trying to run some automated tests on our charting component, SimpleChart, and I needed to know if the charts being produced were identical to those in the test specification. To do this, I needed to compare each image being generated by SimpleChart in the test with a reference image that was known to be good. If the two were identical then the test had passed.
Comparing Images

First Attempts

The first step in comparing two images to see if they were identical was to check the size of each. If they don't match then we know almost immediately that the images are not identical. Once that quick test was complete, we needed to look at the actual image content to see if it matched up. Initially, I decided to use GetPixel method of the GDI+ Bitmap class to compare each pixel in the first image with the corresponding pixel in the second image. If at any point, the two pixels did not match then we can safely say that the images are different. If, however, we got to the end of the comparison tests without any mismatches then we can conclude that the two images are indeed identical.

public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2) 
{     CompareResult cr = CompareResult.ciCompareOk;
//Test to see if we have the same size of image
      if (bmp1.Size != bmp2.Size)
{
cr = CompareResult.ciSizeMismatch;
}
 else
      {
//Sizes are the same so start comparing pixels
         for (int x = 0; x < bmp1.Width && cr == CompareResult.ciCompareOk; x++)
{
for (int y = 0; y < bmp1.Height && cr == CompareResult.ciCompareOk; y++)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
cr = CompareResult.ciPixelMismatch;
}
}
}
return cr;
}
 
This method worked fine but with one major drawback, speed, or rather the lack of it. Comparing two 2000 x 1500 pixel images using this method took over 17 seconds! With over 200 images to compare, this meant that my tests would take nearly an hour to complete and I wasn't prepared to wait that long.

Hash in a Flash

What I needed was a faster method to compare the images to allow the tests to complete in a timely manner. Rather than comparing the individual pixels in each image using GetPixel, I decided that it would be quicker if I could some how compare a 'hash' of each image to see if they were identical. As we know, a hash is a unique value of a fixed size representing a large amount of data, in this case our image data. Hashes of two images should match if and only if the corresponding images also match. Small changes to the image result in large unpredictable changes in the hash.
There are many different hashing algorithms provided by .NET in the System.Security.Cryptography namespace such as SHA1 and MD5 but I decided to use the SHA256Managed class. The ComputeHash method of this class takes a byte array of data as an input parameter and produces a 256 bit hash of that data. By computing and then comparing the hash of each image, I would be quickly able to tell if the images were identical or not.
The only problem now remaining was how to convert the image data stored in the GDI+ Bitmap objects to a suitable form for passing to the ComputeHash method, namely a byte array. Initially, I looked at the LockBits method of the Bitmap class which allowed me access to the individual pixel bytes but it would have meant a journey into the land of unmanaged code and that was somewhere I really didn't want to visit. Instead, GDI+ kindly provides an ImageConvertor class to allow us to convert Image (or Bitmap) objects from one data type to another, such as a byte array.
The final step to see if the images are identical is to compare the two hash values (also stored in byte arrays) to see if they match. Here is the final code:

using System;
using System.Drawing;  
using System.Drawing.Imaging;  
using System.Security.Cryptography; 
 
namespace Imagio 
{
public class ComparingImages
{
public enum CompareResult
{
ciCompareOk,
ciPixelMismatch,
ciSizeMismatch
};
 
         public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
{
CompareResult cr = CompareResult.ciCompareOk;
//Test to see if we have the same size of image
             if (bmp1.Size != bmp2.Size)
{
cr = CompareResult.ciSizeMismatch;
}
else
             {
//Convert each image to a byte array
                 System.Drawing.ImageConverter ic =
new System.Drawing.ImageConverter();
byte[] btImage1 = new byte[1];
btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
byte[] btImage2 = new byte[1];
btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());
//Compute a hash for each image
                 SHA256Managed shaM = new SHA256Managed();
byte[] hash1 = shaM.ComputeHash(btImage1);
byte[] hash2 = shaM.ComputeHash(btImage2);
//Compare the hash values
                 for (int i = 0; i < hash1.Length && i < hash2.Length && cr == CompareResult.ciCompareOk; i++)
{
if (hash1[i] != hash2[i])
cr = CompareResult.ciPixelMismatch;
}
}
return cr;
}
}
}

Conclusion

Running this new compare method on a 2000 x 1500 pixel bitmap resulted in a comparison time of 0.28 seconds which meant that my automated testing of 200 SimpleChart images now takes only 56 seconds to complete.
Hashes are normally used as a security tool to see if credentials such as passwords match. Using the same hashing approach, we can also quickly compare two images to see if they too are identical.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.
A list of licenses authors might use can be found here

About the Author

markrouse




Web Developer

United Kingdom United Kingdom

Member
Mark Rouse works as a software developer for Imagio Technology in Yorkshire, UK

When not working on his favourite charting component, SimpleChart, Mark is providing custom application development for his clients using ASP.NET, C# and SQL Server and in particular Web Services.

11. November 2011

just more incredible - the incredible Staggers

Wie unglaublich :-o
Nach the incredible Machine weiteres zum Thema (und diesmal auch aus Österreich ;) )

the incredible Staggers(zuvor kurz The Staggers)

ist eine österreichische 60's-Garage-Trash-Rock'n'Roll-Band.

Mit ca. 500 Auftritten (in Österreich, Deutschland, Schweiz, Frankreich, Spanien, Italien, Belgien, Niederlande, England, Slowenien, Kroatien, Ungarn, Schweden, Norwegen und den USA) seit Anfang 2004 zählen The Staggers zu den am häufigsten live spielenden Bands in Österreich.


Diskografie:

  • Zombies of Love (2010, Wohnzimmer Records & Soundflat Records)
  • Go Go Gorilla 7" (2010, Squoodge Records)
  • No como tu 7" (2008, Hey Girl! Records)
  • The Staggers Live 7" (2007, Bachelor Records)
  • Teenage Trash Insanity (2006, Wohnzimmer Records & Soundflat Records)
  • Be My Queen 7" (2005, Copase Disques)
  • Split LP with Skeptic Eleptic (2005, Broken Heart Records)
  • The Stranded 7" (2005, G.R.A.M.)
  • Wild Teens 7" (2004, Eigenvertrieb)

Mehr Infos gibts unter der offiziellen website der incredible staggers http://www.thestaggers.at/
ihrer myspace Seite http://www.myspace.com/staggers
sowie im Youtube channel http://www.youtube.com/thestaggers

10. November 2011

Google App Inventor eingestampft :-s

Und wie es scheint bald neu auferstanden,
wenn man folgendem newsletter Glauben schenken darf:


clickable image
Dear App Inventor User,

As we announced on the App Inventor Announcement Forum, Google will end support for App Inventor on December 31, 2011, after which data in appinventorbeta.com will not be accessible and will be deleted from Google servers.  You can preserve your App Inventor projects by simply clicking on the Download All Projects button on your My Projects page.  This will download to your computer a zipped archive of all your projects.  We recommend you retrieve your projects well before December 31st.


By the end of 2011 Google will also be making the complete App Inventor source code publicly available under an open source license, so that anyone can study the code and modify it as they desire.

In order to ensure the future success of App Inventor, Google has funded the establishment of a Center for Mobile Learning at the MIT Media Lab.  Sometime in the first quarter of 2012, the Center plans to provide an App Inventor service for general public access, similar to the one Google is currently running.

In order for you to continue working with your projects in an open source instance (MIT or otherwise) of App Inventor you will need to download your data from appinventorbeta.combefore December 31st and later upload them to an open source instance as it becomes available.

Please visit the App Inventor user forums to get future updates on App Inventor.  You can also visit http://mobilelearning.mit.edu/ for updates on what is being done with App Inventor at MIT.  

The App Inventor Team 


Was meint ihr dazu?
Habt ihr den AppInventor verwendet?
Interessiert ihr euch für mobile App Entwicklung? Habt ihr bereits etwas gemacht?

Ich bin gespannt auf eure Kommentare :)

- the incredible Leitman

3. November 2011

Blogger United verlost Bannerplätze, Blogrollplätze und Gutscheine

Wie ich eben von drewjosh erfahren habe,
startet Blogger United eine Megaverlosung :-o

Verlost werden 5 Bannerplätze für 1 Jahr, 3 Blogrollplätze und 3 Gutscheine (für getdigital.de <3 )!

Mehr Informationen:

(http://bloggerunited.de/blogger-united-verlost-5-bannerplatze-fur-ein-ganzes-jahr/)

Du suchst nach noch mehr Aufmerksamkeit für deinen Blog? Dann solltest du an unserer bisher größten Verlosung teilnehmen und dir die Chance auf einen von 5 Bannerplätzen in unserer Sidebar (auf jeder Seite sichtbar), einen von 3 Plätzen in unserer Blogroll und die Chance auf einen von 3 tollen Gutscheinen sichern!

Was wird verlost?

Außer dem Banner vom Chaosweib (unten rechts) sollten alle anderen ab dem 1.12.2011 so langsam aber sicher gegen neue Banner im Format 125*125 ausgetauscht werden.
Also zu gewinnen gibt es:
  • Einen von 5 Bannerplätzen für ein halbes Jahr
  • Einen von 3 Blogrollplätzen für ein halbes Jahr
  • Und einen Amazon-Gutschein im Wert von 30 € von Blogger United!

Wer darf an der Verlosung teilnehmen?

Mitmachen darf jeder der im Besitz eines Blogs ist!

Und wie kann ich teilnehmen?

Achtung:
Eure Teilnahme ist erst dann gültig, wenn ihr unter diesen Beitrag einen Kommentar mit den jeweiligen Links hinterlassen habt, denn danach richtet sich die Verlosung am Ende!
Auch bei dieser Verlosung setzen wir auf das Losverfahren, das heißt für jede Aktion die ihr durchführt bekommt ihr Lose und umso mehr Lose ihr habt, desto größer sind natürlich auch eure Chancen. Am Ende der Verlosung teilen wir jedem Teilnehmer so viele Nummern zu, wie er Lose hat und lassen dann per Zufallsgenerator 5 Zahlen bestimmen. Teilnehmen könnt ihr bis zum 30.11.11 um 23:59 Uhr!
1 Los bekommt ihr wenn ihr diesen Beitrag retweeted oder einen eigenen Tweet über die Verlosung mit Titel, Link und @BloggerUnited im Inhalt postet.
2 Lose bekommt ihr wenn ihr auf eurer Facebookseite oder euren Facebookprofil auf unsere Verlosung per Pinnwandbeitrag hinweist. Dieser Beitrag sollte einmal auf den Verlosungsartikel hier und auf unsere Facebookseite (erreichbar unter http://facebook.com/BloggerUnited) verlinken.
3 Lose bekommt ihr wenn ihr einen Artikel über die Verlosung auf euren Blog veröffentlicht. Dieser Artikel muss den Link zur Verlosung beinhalten.
Ein Extralos gibt es, wenn ihr alle 3 Varianten vollzogen habt.
Zwei Extralose gibt es wenn ihr bis zum 8.11. um 23:59 Uhr den Artikel in eurem Blog veröffentlicht habt.
An dieser Stelle bleibt uns nur noch euch viel Glück zu wünschen und wir hoffen das viele von euch sich alle 9 möglichen Lose sichern! :-D