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

1. November 2011

CINEMA 4D - Workshop-DVD für 0,00 Euro!


tutorials.de Verschenkaktion

Hallo liebe tutorials.de-Mitglieder,

unsere Partner-Website PSD-Tutorials.de hat zusammen mit 3D-Profi Uli Staiger eine Lern-DVD für CINEMA 4D aufgenommen, die über 16,5 Stunden Video-Training enthält. Diese DVD gibt es nun für 0,00 Euro (Originalpreis: 29,95 €). Einziger Haken: 3,95 Euro Porto im Shop (ab 30,00 Euro portofrei). Und nur solange der Vorrat reicht.

Meisterwerke in Cinema 4D


Der Inhalt der Lern-DVD:
  • 11,5 Stunden Video-Training zu den Grundlagen in CINEMA 4D
  • 5 Stunden Video-Training: ein Praxisprojekt von A-Z
  • alle Arbeitsmaterialien aus den Video-Trainings
Als Extra der Lern-DVD gibt es 1.700 Texturen zur freien Verwendung in CINEMA 4D.

Eine Meinung auf Amazon, die es auf den Punkt bringt: 

Von Barbara Vogler-Hemzal aus Wien:

„Herzlichen Dank an Uli Staiger für diese DVD! Charmant und kompetent erklärt er mittels immer komplexer werdender Arbeitsbeispiele die Handhabung der umfangreichen Tools in Cinema4D. Und mit ihm "gemeinsam" einen flugtüchtigen Zeppelin zu bauen, hat wirklich Spaß bereitet ;o) Durch die dadurch erworbenen Kenntnisse fällt es einem leicht eigene neue Projekte umzusetzen. Der Kauf dieser DVD erspart es, einen teuren Kurs zu besuchen! Danke auch an das Team von PSD-Tutorials.de die das alles ermöglichen ;o) LG aus Wien!”

Cinema 4D-Workshop-DVD


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

Aktion gültig bis Sonntag, den 13.11.2011 bzw. solange der Vorrat reicht. Nur ein 0,- € Artikel pro Besteller.

Drupal Buch kostenlos, 10% billiger in der KategorieGrafik-CAD-Video bei buecherbillig.de



nur bis 21.11.2011 --- 0,00 EUR danach 7,95 EURDas Drupal 6 Praxisbuch
Alter preis: 34,95 EUR Jetzt nur: 0,00 EUR  weiter»
Neuheiten
Restposten
eBooks
bis 1,00 EUR
Nochmal reduziert

10% Rabatt für Kategorie:Grafik-CAD-Video
10% Rabatt für Kategorie: Grafik-CAD-Video von 31.10.11 bis 07.09.09 nur für Newsletterempfänger
Coupon Code:  graf31

29. Oktober 2011

C# Whitespace Tips - String Modifications


As part of the coverage of strings in the C# language, we focus on custom whitespacemethods, which help us modify space and newline characters in string data. Also, some of these methods can be used with non-whitespace characters, but typically are used with spaces and newlines.
Key points:Whitespace characters can be converted with the methods shown here. It is useful to convert from Windows and UNIX newlines in some situations.

Condense whitespace

Here, we see how you can use the static Regex.Replace method to change any of a set of individual characters to a space. The square brackets [ ] in the parameter indicate a set of separate characters. To use this example, you will need to add "using System.Text.RegularExpressions;" to the top of your .cs file.
Regex.Replace Examples: MatchEvaluator
Method that uses Regex.Replace [C#]

/// 
/// Converts all whitespace in the string to spaces using Regex.
/// 
public static string ConvertWhitespaceToSpacesRegex(string value)
{
    value = Regex.Replace(value, "[\n\r\t]", " ");
    return value;
}

Replace line break chars

You can also replace all line breaks in your string using two string Replace calls. These receive a single character as the parameters. The first parameter is the character you need to replace, and the second character is the replacement. When using the char overload, you cannot replace a character with nothing.
Replace String Examples
Method that uses string Replace [C#]

/// 
/// Converts all whitespace in the string to spaces using string Replace.
/// 
public static string ConvertWhitespaceToSpacesString(string value)
{
    value = value.Replace('\r', ' ');
    value = value.Replace('\n', ' ');
    return value;
}

Convert whitespaces

Conversion or change
The method you see here uses the ToCharArray method on the string parameter, which converts the string to a char[] array. This allows us to modify the characters in-place. The result is that the performance of this method is far better than those that use Replace calls, on small strings.
ToCharArray Method, Convert String to Array
Method that uses ToCharArray and switch [C#]

/// 
/// Converts all the whitespace in the string to spaces using switch.
/// 3-4x faster than using string replace.
/// Faster than using a new empty array and filling it.
/// 
public static string ConvertWhitespaceToSpaces(string value)
{
    char[] arr = value.ToCharArray();
    for (int i = 0; i < arr.Length; i++)
    {
 switch (arr[i])
 {
     case '\t':
     case '\r':
     case '\n':
  {
      arr[i] = ' ';
      break;
  }
 }
    }
    return new string(arr);
}
Switch statement. Internally, this method uses a switch on the char, which is compiled to a jump table. Jump tables are low-level instructions that provide constant lookup time. Therefore, the switch is faster than if/else statements.
Switch Char, Conditional Character TestSwitch Enum

Newline to spaces

Here we see a method that converts all Windows newlines, which contain two characters, and all UNIX newlines, which contain one character. The newlines are all converted to single spaces. The clever part of this method is that it converts the Windows newlines first.
Method that replaces newlines [C#]

/// 
/// Converts all newlines in the string to single spaces.
/// 
public static string ConvertNewlinesToSingleSpaces(string value)
{
    value = value.Replace("\r\n", " ");
    value = value.Replace('\n', ' ');
    return value;
}
Question mark
Why convert Windows newlines first? The reason you must convert the two-character Windows line breaks first is that the UNIX newlines are half of the Windows ones. Therefore, if you replace UNIX newlines first, you will be left with '\r' characters you don't want.

UNIX newlines

It is very easy to convert all linebreaks in a string you read in from the disk. On the string, simply use Replace to change all Windows newlines to UNIX newlines. You do not need to change any existing UNIX newlines.
Method that converts to UNIX newlines [C#]

/// 
/// Converts Windows style newlines to UNIX-style newlines.
/// 
public static string ConvertToUnixNewlines(string value)
{
    return value.Replace("\r\n", "\n");
}

Windows newlines

You can also convert all the newlines in your string to Windows newlines, providing compatibility with many applications. The trick here is to convert all pre-existing Windows newlines to UNIX newlines first. Then, convert all UNIX newlines to Windows newlines.
Method that converts to Windows newlines [C#]

/// 
/// Converts all newlines in the file to Windows newlines.
/// 
public static string ConvertToWindowsNewlines(string value)
{
    value = ConvertToUnixNewlines(value);
    value = value.Replace("\n", "\r\n");
    return value;
}
Description. The code example uses the ConvertToUnixNewlines method in the section directly above. You could simply paste the Replace call instead of using that method.

Replace many whitespaces

Here we see a method that converts any number of whitespaces in a sequence into a single space. This is really useful for when you are reading in text data from a database or file and are not sure what kind of whitespaces are used in it.
Method that uses Regex.Replace [C#]

/// 
/// Convert all whitespaces to a single space.
/// 
public static string ConvertWhitespacesToSingleSpaces(string value)
{
    value = Regex.Replace(value, @"\s+", " ");
    return value;
}
Using this method with HTML. Sometimes, you can use this method on markup such as HTML to reduce the size of the file. My experience is that this can reduce the final size by 1%, even after compression. In HTML, two spaces are usually the same as one space.

Whitespace in file

This example uses the simple File.ReadAllText method and calls one of the above methods. Note that the example has the "using System.IO;" line near the top. It writes the modified file, TextFile1.txt, to the Console window. The NewlineTool class specified is a static class located in another file. You can create it by creating "NewlineTool.cs" and then looking at the next example and using the code there.
File.ReadAllText (TXT)
Method that uses File.ReadAllText [C#]

using System;
using System.IO;

class Program
{
    static void Main()
    {
 //
 // Read in text with File.ReadAllText.
 //
 string value = File.ReadAllText("TextFile1.txt");
 //
 // Call method and display result.
 //
 value = NewlineTool.ConvertWhitespacesToSingleSpaces(value);
 Console.WriteLine(value);
 //
 // You can now write it with File.WriteAllText.
 //
    }
}

Static whitespace class

I prefer to keep static methods, which do not require allocation or state, in a separate file. The file should have the name of its class as the filename. The class must also be public, as well as the individual methods.
Static Class
Example of static class [C#]

using System.Text.RegularExpressions;

/// 
/// Contains string methods for converting newlines.
/// 
public static class NewlineTool
{
    /// 
    /// Converts all whitespace in the string to spaces using Regex.
    /// 
    public static string ConvertWhitespaceToSpacesRegex(string value)
    {
 // ...
    }
}

Summary

We explored whitespace handling in the C# language. We saw ways to convert newlines, line breaks, spaces, tabs and all whitespace characters into single spaces or other characters; we also looked at UNIX newlines and Windows newlines, and how to Replace these strings.
String Type