IOException.de

Icon

Ausgewählter Nerdkram von Informatikstudenten der Uni Ulm

Barrier points in Node.js

Node.js ist ein serverseitiges, hochskalierbares Framework für die Entwicklung von asynchronen Netzwerkanwendungen in JavaScript. Aufgrund der Asynchronität ist das Framework in der Lage, tausende Verbindung gleichzeitig offen zu halten und zu verarbeiten. Ein wesentliches Merkmal hier von ist, dass ausschließlich mit Callbacks gearbeitet wird, um auf Beendigungen von Operationen zu reagieren.

Im Normalfall führt das zu einem Chaining von Callback. Im folgenden Beispiel sollen zwei Dateien geöffnet werden und ihr kompletter Inhalt zurückgegeben werden:

var size = 0;

fs.readFile('/home/benjamin/file1', function(err, data)
{
	if (!err)
	{
		// first file read
		size += data.length;
		fs.readFile('/home/benjamin/file2', function(err, data)
		{
			if (!err)
			{
				// second file read
				size += data.length;
				fs.writeFile('/home/benjamin/size', size, function(err)
				{
					if (!err)
					{
							// both file read and content written to file
							sys.log('done');
						}
					});
			}
		});
	}
});

Das Problem hierbei ist, dass zwei Aktionen, die eigentlich parallel ablaufen könnten, nämlich das lesen beider Dateien, nacheinander ablaufen müssen. Für einen parallelen Ablauf ist eine zusätzliche Koordination notwendig, da die Resultate beider Aufrufe in Verbindung stehen. Hierfür habe ich mich an den CyclicBarrier Klassen von Java orientiert und eine einfache Klasse für die Koordination von asynchronen Callbacks geschrieben. Eine Barriere wird erzeugt unter Angabe der Anzahl von teilnehmenden Parties. Desweiteren können optional ein Callback für die Beendigung sowie ein optionaler Callback im Abbruchsfall registriert werden. Anschließend können die einzelnen Aufgaben der Parties angestoßen werden. Im Erfolgsfall müssen diese an der Barriere mit submit() anzeigen, dass sie beendet sind. Durch abort() kann auch ebenfalls ein Abbruch signalisiert werden. Eine Propagation der Ergebnisdaten lässt am besten durch eine externe Variable realisieren, auf den die Funktionen ebenfalls Zugriff haben.

Der Code des Beispielszenarios ändert sich dann wie folgt:

var size = 0;

var b = new Barrier(2, function()
{
	//Success callback
	fs.writeFile('/home/benjamin/size', size, function(err)
	{
		sys.log('done');
	});
}, function()
{
	//Aborted callback
	sys.log("aborted");
});

fs.readFile('/home/benjamin/file1', function(err, data)
{
	if (err)
	{
		b.abort();
	}
	else
	{
		size += data.length;
		b.submit();
	}
});

fs.readFile('/home/benjamin/file2', function(err, data)
{
	if (err)
	{
		b.abort();
	}
	else
	{
		size += data.length;
		b.submit();
	}
});

Wie im Vergleich zu erkennen ist, lässt sich die Ausführung deutlich beschleunigen. Ein paar Rahmenbedingungen gibt es jedoch. Zunächst dürfen die Teilaufgaben keine Abhängigkeiten untereinander besitzen. Dann darf ein Abbruch einer Teilaufgabe keine Auswirkung auf noch laufende Teilaufgaben besitzen, dessen Ergebnis später verworfen wird. Schließlich muss bei der Programmierung darauf geachtet werden, dass in jedem Fall eine Teilaufgabe mit submit() oder abort() terminiert, da ansonsten ein Lock entsteht.

Die Klasse ist relativ einfach:

/**
 * @class
 *
 * Creates a new barrier for the given amount of parties.
 * @param parties
 * @param barrierCallback
 * @param abortCallback
 * @return
 */
var Barrier =  function(parties, barrierCallback, abortCallback)
{
	this.parties = parties;
	this.barrierCallback = barrierCallback;
	this.abortCallback = abortCallback;

	this.running = true;
	this.count = 0;
};

/**
 * Signals a completion of one of the parties.
 * @return
 */
Barrier.prototype.submit = function()
{
	if (++this.count === this.parties && this.running)
	{
		this.barrierCallback();
	}
};

/**
 * Signals an abort by one of the parties. If not callback is passed, the default abort callback will be executed.
 * @param customAbortCallback Optional callback that should be executed due to the abort.
 * @return
 */
Barrier.prototype.abort = function(customAbortCallback)
{
	if (this.running && customAbortCallback)
	{
		customAbortCallback();
	}
	else if (this.running && this.abortCallback)
	{
		this.abortCallback();
	}
	this.running = false;
};

Klasse auf github: http://gist.github.com/464179

Atom Feeds in Java mit ROME direkt lesen

Für die Interaktion mit Feeds gibt es in Java die weit verbreitete ROME-Library. Diese Library unterstützt sowohl RSS als auch ATOM in den verschiedenen Versionen. Außerdem bietet es eine Abstraktion an, die den Umgang mit den verschiedenen Feedarten vereinfachen soll. Ihre sogenannten Syndication Feeds bieten eine einheitliche Schnittstelle an, und sind unabhängig vom darunter liegenden Format. Dies mag allgemein sehr hilfreich sein und für viele Fälle auch ausreichen. Typische Operationen sind somit entkoppelt vom Format und können wiederverwendet werden, oder das konkrete Format kann problemlos ausgetauscht werden.

Der Nachteil hierbei ist, dass bei dieser Abstraktion Besonderheiten der einzelnen Formate verborgen werden. Problematisch wird es zum Beispiel, wenn man explizit ein bestimmtes Format lesen möchte, um auf bestimmte Elemente zuzugreifen. So muss in Atom jeder Feed und Einträg ein ID Element besitzen, in RSS existiert dies jedoch nicht. Leider existiert nun auch keine Methode, ein solches Feld in einem Syndication Feed direkt abzufragen.

Nach einigem Suchen bin ich nun auf die Lösung gestoßen. Beim Einlesen des Feeds muss explizit ein Flag aktiviert werden, dass das zugrunde liegende Format ebenfalls mitgespeichert werden soll. Erst wenn dieses Flag gesetzt ist, lässt sich später der Feed im Originalformat (WireFeed) abrufen:

InputSource source = new InputSource(...);
SyndFeedInput feedInput = new SyndFeedInput();
feedInput.setPreserveWireFeed(true);
SyndFeed feed = feedInput.build(source);

Später bietet dann der Syndication Feed Zugriff auf den konkreten Feed:

WireFeed wireFeed = (WireFeed) feed.originalWireFeed();
if(wireFeed instanceof com.sun.syndication.feed.atom.Feed)
{
   String feedId = ((Feed) wireFeed).getId()
}

Kurzpräsentation – Node.js

Auf dem gestrigen Webmontag in Ulm habe ich Node.js vorgestellt, ein Framework für serverseitiges JavaScript für skalierbare Netzwerkanwendungen. Dabei hat es sich um eine eher kurze und oberflächliche Präesentation gehandelt, die die Grundidee des asynchroner I/O Operationen betonen sollte. Detailliertere Beiträge zu Node.js wird es aber hier in Kürze geben.

AF Ubiquitous Computing – Projektskizze ‘diretto’

Heutige Mobilgeräte wie Smartphones, Netbooks oder PDAs stellen zu einem großen Teil drahtlosen Zugriff auf das Internet bereit. Zugleich bieten diese Geräte häufig auch die Möglichkeit, multimediale Inhalte wie Bilder, Videos oder Tonmitschnitte überall zu produzieren. Alternativ können sie zumindest als Brücke ins Internet fungieren und dedizierte Geräte wie Digitalkameras anbinden.

Trotz dieser theoretischen Möglichkeiten existieren bisher kaum Anwendungen, die mithilfe dieser Technologien eine multimediale Berichterstattung in quasi Echtzeit ermöglichen. Das Ziel des diretto-Projektes ist es, eine solche Plattform zu entwickeln und Beispiellösungen für die Integration mobiler Geräte aufzuzeigen. Zusätzlich zu Sammlung der mutlimedialen Inhalte liegt ein weiter Fokus auf der Analyse, Bewertung und Verbesserung der erhaltenen Daten – sowohl durch das System als auch durch die Benutzer selbst. So kann zum Beispiel die Genauigkeit von Metadaten wie Orts- und Zeitangaben verbessert werden, Beiträge können mithilfe von Tags klassifiziert und verschiedene mutlimediale Inhalte untereinander sinnvoll verlinkt werden. Durch das System erzeugte Gruppierungen unterstützen den Benutzer zusätzlich bei der Auswertung der Inhalte.

Als Grundlage für das komplette Projekte werden zeitgemäße Web-Technologien eingesetzt. Somit ist die Plattform offen, sehr leicht erweiterbar und skaliert auch bei der Nutzung in größeren Szenarien. Die API steht in Form eines REST-konformen Webservices zur Verfügung. Metadaten werden im leichtgewichtigen JSON-Format kodiert. Ein spezieller PubSubHubbub-Endpunkt ermöglicht Benachrichtigungen über neue Inhalte in Echtzeit. Dezentrale Zusatzdientse steuern zusätzliche Funktionalitäten bei.

Eine mächtige Weboberfläche bietet Zugriff auf die Gesamtheit der erhobenen Daten – auch entfernt über das Internet. Sie bietet die Grundlage für komplexe Auswertungen der vorhandenen Multimediadaten und zugehörigen Metadaten. Im Vordergrund steht hierbei auch die Unterstützung des Benutzers beim Umgang mit den vieldimensionalen Daten.

Für die Integration mobiler Systeme werden verschiedene Clients entwickelt und erprobt. Ein Smartphone-Client erlaubt es dem Besitzer eines Smartphones direkt zum Reporter vor Ort zu werden und Inhalte beizusteuern. Für die Anbindung dedizierter Hardware wie einer digitalen Spiegelreflexkamera wird eine besondere Lösung erabreitet. Ein mobiler Rechner im Rucksack soll als Uplink-Gerät dienen und frisch geschossene Bilder ohne Verzögerung direkt auf die Plattform hochladen. Mithilfe einer solchen Lösung können Fotojournalisten als echte Live-Berichterstatter agieren und Pausen für den Upload entfallen.

Eine solche Plattform eignet sich je nach Ausrichtung für eine Vielzahl verschiedener Einsatzszenarien. So könnte es zur Live-Dokumentation großer Ereignisse dienen. In einem geschlossenen Kontext könnte es Einsatzkräfte bei Großschadenslagen dabei helfen, in kürzerer Zeit einen detaillierteren Überblick zu bekommen und unterstützende Kräfte zur Auswertung fernab einbinden.

Das Projekt wurde im Rahmen des Anwendungsfaches Ubiquitous Computing an der Universität Ulm von einem studentischen Team entworfen und nun in Zusammenarbeit mit einem Team für Interaktive Systeme als Prototyp realisiert. Nähere Informationen gibt es auf der Projektseite www.diretto.org

Anwendungsfachprojekte Ubiquitous Computing

Als Student im Diplomstudiengang Medieninformatik an der Uni Ulm ist es Bestandteil des Hauptstudiums, ein Anwendungsfach aus den Teilgebieten der Medien-Informatik zu belegen. Hierbei stehen unter anderem Vertiefungsrichtungen wie Computergrafik, Computer Vision, Ubiquitous Computing, Medienpädagogik, Interaktive Systeme, Interaktives Video oder Mensch-Maschine Dialogsysteme zur Auswahl.

Ubiquitous Computing steht für den Trend hin zum allgegenwärtigen Computer oder dem „Internet der Dinge“. Ob als intelligenter Kühlschrank, im vernetzten Auto oder in Form von intelligenten Smartphones, der Computer und mit ihm oft auch das Internet werden immer allgegenwärtiger und verschmelzen mit der Umgebung. Das Anwendungsfach besteht einerseits aus den Vorlesungen Multimediasysteme und Mobile & Ubiquitous Computing, und andererseits aus einer wissenschaftlichen Projektarbeit über zwei Semester in Gruppen.

Verschiedene Autoren des Blogs arbeiten derzeit gemeinsam an solchen Projekten und werden diese hier genauer vorstellen.

LRU-Cache in Java

Caches dienen in der Informatik als Methode, Zugriffe auf bestimmte Daten zu beschleunigen, in dem diese vorgelagert/gepuffert werden. Sie sind in verschiedensten Bereichen zu finden, unter anderem auf Prozessoren, in Festplatten, aber auch in Technologien wie dem Web. Verschiedene Verdrängungsstrategien ermöglichen es, die beschränkte Kapazität eines Caches zu berücksichtigen, so dass nur wichtige Werte im Cache gelagert werden. Least Recently Used (LRU), ist eine solche Strategie, die häufig angewandt wird. Sie sortiert die Werte im Cache nach der letzten Nutzung. Wird auf ein Element über einen längeren Zeitraum nicht mehr zugegriffen, so wird es aus dem Cache verdrängt.

In Java lässt sich ein solcher LRU-Cache besonders einfach implementieren, da die Klasse java.util.LinkedHashMap bereits die wesentlichen Mechanismen unterstützt. Eine HashMap ist eine Hash-Tabelle, die Zugriffe auf Werte über ihre Schlüssel regelt. Zusätzlich verkettet die LinkedHashMap aber die Werte noch in einer Liste, womit auch eine Traversierung in Einfügereihenfolge ermöglicht wird. Mithilfe eines Flags in einem der Konstruktoren kann dieses Verhalten geändert werden, so dass bei jedem Zugriff das angesprochene Element neu in diese Liste eingereiht wird. Damit verwaltet die Liste die Zugriffe und ist Basis für die LRU-Strategie.

Die Methode removeEldestEntry() der LinkedHashMap wird bei jedem Schreibezugriff auf die Map, also nach Einfügeoperationen über put() oder putAll() automatisch aufgerufen und bietet die Möglichkeit, durch Überschreiben der Methode die Verdrängungsstrategie zu implementieren. Diese Methode gibt ein boolean zurück, ob der älteste Eintrag gelöscht werden soll. Es ist auch möglich, innerhalb der Methode selbst die Liste zu manipulieren, dann sollte allerdings die Methode immer false zurückgeben. Für den LRU-Cache reicht es aus, die Größe der Map mit dem gewünschten Maximum zu vergleichen. Ist der Inhalt der Map zu groß, so soll das letzte Element gelöscht werden.

Im Folgenden nun der Code dazu. Zu beachten ist noch, dass es sich um eine threadsichere Klasse handelt, da die Map explizit synchronisiert wird.

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * A thread-safe LRU cache implementation based on internal LinkedHashMap.
 *
 * @author Benjamin Erb
 *
 * @param <K> Entry Key Type
 * @param <V> Entry Value Type
 */
public class LRUCache<K, V>
{
	public static final int DEFAULT_MAX_SIZE = 1000;

	private final Map<K, V> internalMap;

	public LRUCache()
	{
		this(DEFAULT_MAX_SIZE);
	}

	public LRUCache(final int maxSize)
	{
		this.internalMap = (Map<K, V>) Collections.synchronizedMap(new LinkedHashMap<K, V>(maxSize + 1, .75F, true)
		{
			private static final long serialVersionUID = 5369285290965670135L;

			@Override
			protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
			{
				return size() > maxSize;
			}
		});
	}

	public V put(K key, V value)
	{
		return internalMap.put(key, value);
	}

	public V get(K key)
	{
		return internalMap.get(key);
	}

}

Streiflicht 2010

Am Mittwoch, den 10. Februar, stellen Studierende des Studiengangs Medieninformatik die Highlights ihrer Anwendungsfächer um 16 Uhr im H20 vor.

Vorgestellte Projekte:

  • Echtzeitgrafik (Praktikum Computergrafik)
  • Visuelle Wahrnehmung (Praktikum Computer Vision)
  • awarenia, iNet, w3i (Anwendungsfach Interaktive Systeme)
  • pocketU (Anwendungsfach Medienpädagogik)
  • newsmachine (Anwendungsfach Interaktives Video)
  • TTable (Anwendungsfach Ubiquitous Computing)
  • Anwendungsfach Dialogsysteme

Weitere Informationen gibt es unter: http://www.uni-ulm.de/in/mi/streiflicht.html

Von uns ist dieses Mal noch niemand dabei, allerdings werden wir in Kürze über unsere eigenen Anwendungsfachprojekte berichten, an denen wir derzeit arbeiten.

SSH-Tunnel und SOCKS Proxy Forwarding als Alternative zum Surfen über (Web)VPN

An meiner Uni sind einige Webressourcen nur aus dem Intranet zugreifbar, das heißt man braucht als Client eine IP aus dem Uni-Netz. Um von extern darauf zuzugreifen, ist die Einwahl über ein VPN notwendig. Neben der klassischen “schwergewichtigen” Einwahl über einen VPN-Client gibt es noch die Möglichkeit, einen Web-VPN zu nutzen. Hier werden nach der Authentifizierung alle HTTP-Anfragen über eine spezielle Seite der Rechenzentrums getunnelt. Leider lässt nicht nur die Verfügbarkeit des Dienstes manchmal zu wünschen übrig, sondern auch die verfügbaren Bandbreiten machen es uninteressant für den Download größerer Paper.

Als Alternative hierzu ist mir die Möglichkeit begegnet, mithilfe des Application Level Port Forwardings von SSH Zugriffe zu tunneln. Durch den Flag “-D portnummer” erzeugt der SSH-Client beim Verbinden einen lokalen SOCKS-Proxy auf diesem Port, der über den SSH-Tunnel Requests weiterleitet. Endpunkt stellt der SSH-Server da. Mithilfe zusätzlicher Flags lässt sich außerdem ein Timeout unterdrücken.

Im Falle der Uni Ulm und einer Einwahl auf den Server des Rechenzentrums (KIZ) sieht der Aufruf so aus:

ssh -D 8800 -o ServerAliveInterval=60 s_login@login.rz.uni-ulm.de

Nach erfolgreichem Verbindungsaufbau steht dann lokal unter dem Port 8800 der SOCKS-Proxy zur Verfügung und kann im Browser eingetragen werden. Für eine dynamische Nutzung bieten sich unter Firefox Plugins wie FoxyProxy an. Hier lassen sich Regelsätze definieren, wann dieser Proxy benutzt werden soll, zum Beispiel für alle Uni-Seiten.

Mehrere Werte in Java-Methoden typsicher zurückgeben

Anders als manch andere imperative Programmiersprachen, unterstützt Java nur die Rückgabe eines Wertes bei einem Methodenaufruf. Jedoch ist es häufig interessant, mehrere Werte zurückzugeben. Grundsätzlich lassen sich hier zwei Szenarien unterscheiden. Bei der Rückgabe von mehreren gleichartigen Typen wird meist eine Klasse des Collections-Frameworks verwendet, wie zum Beispiel List oder ein Array. Manchmal will man aber auch völlig verschiedene Typen gemeinsam zurückgeben. Gängige Praxis ist es hier, ein Object-Array zurückzugeben und dann quasi beim Implementieren festzulegen, von welchem Typ die einzelnen Werte sind und entsprechen zurückzucasten. Dies ist leider weder typsicher, noch lässt sich die vorherige Festlegung im Code erzwingen. Abhilfe schafft hier eine generische Holder-Klasse, die einzelnen Werte typsicher kapselt und als einziger Rückgabewert verwendet werden kann.

Hier ein Beispiel für die Rückgabe über ein Object-Array:

private Object[] doItUnchecked()
{
	String s = "foo";
	Date d = new Date();

	return new Object[] { s, d };
}

Aufruf:

// unchecked variant: dangerous!
Object[] returnValues = t.doItUnchecked();
String s = (String) returnValues[0];
Date d = (Date) returnValues[1];

Eine generische Holderklasse (hier: immutable):

/**
 * Immutable holder type for two values.
 *
 * @author Benjamin Erb
 *
 * @param <F> type of first value
 * @param <S> type of second value
 */
public class PairHolder<F, S>
{
	private final F first;
	private final S second;

	public PairHolder(F first, S second)
	{
		this.first = first;
		this.second = second;
	}

	public F getFirst()
	{
		return first;
	}

	public S getSecond()
	{
		return second;
	}
}

Verwendung in Methode:

private PairHolder<String, Date> doItChecked()
{
	String s = "foo";
	Date d = new Date();

	return new PairHolder<String, Date>(s, d);
}

Aufruf:

// check variant: safe already at compile-time
PairHolder<String, Date> h = t.doItChecked();
String s = h.getFirst();
Date d = h.getSecond();

Die Holderklasse lässt sich auch noch beliebig erweitern, um Tripel, Quadrupel etc. zu halten. Wer für 2-Tupel keine eigene Klasse implementieren möchte, kann übrigens auf AbstractMap.SimpleEntry oder AbstractMap.SimpleImmutableEntry zurückgreifen.

Twitterbot in Perl

Perl war schon immer eine polarisierende Sprache. Die einen lieben sie, die anderen hassen sie. Die einen sind Fan der flexiblen Syntax, die anderen verfluchen die mangelnde Lesbarkeit. Sätze wie “Perl: Write once – never understand again” oder “Perl is the only language that looks the same before and after RSA encryption.” zielen genau hierauf ab.

Dennoch ist Perl eine beliebte Skriptsprache, insbesondere im Unix/Linux-Bereich (dank erkennbarer Verwandschaft zu Unix-Tools/Sprachen wie C, awk oder Shell-Builtins) zur Systemadministration oder allgemein zur schnellen Problemlösung. Aber auch im Web und in vielen speziellen Einsatzgebieten wie zum Beispiel der (DNA-)Sequenzanalyse ist Perl weiterhin eine bedeutende Sprache. Aufgrund ihrer Mächtigkeit gilt Perl mancherorts als “Swiss Army Chainsaw of Programming Languages”.
Natürlich sind mit Ruby, Python und diversen Java-Derivaten viele neue Skriptsprachen auf den Markt gekommen, und Perl 6 lässt (leider) weiterhin auf sich warten.

Trotzdem bin ich weiterhin ein großer Freund dieser Sprache. Allerdings muss ich zugeben, dass ich etwas voreingenommen bin – Perl war mit die erste “richtige” Programmiersprache, mit der ich in Kontakt kam (dann kam die damals weniger richtige Sprache PHP).

Die Vorlesung Skriptsprachen und Anwendungen bei den Mathematikern hat dafür gesorgt, mein Interesse für Perl wieder etwas zu beleben und ein kleines Projekt in Angriff zu nehmen. Als Resultat entstand ein kleiner Bot, der täglich den Mensaplan der Uni Ulm abgrast und die Ergebnisse bei Twitter veröffentlicht. So besteht nicht nur die Möglichkeit, durch das Folgen des Bots bei Twitter täglich über die Tageskarte informiert zu werden, sondern es entsteht quasi als “Abfallprodukt” ein bisher nicht existenter RSS-Feed.

Das kleine Projekt zeigt sehr schön, wie man mithilfe der mächtigen CPAN-Module in Perl alltägliche Aufgabe sehr effizient und straight forward lösen kann. Zum Parsen der HTML-Seite, die als Quelle benutzt wird, wird das Paket XML::LibXML benötigt. Hiermit lassen sich per XPath direkt die interessanten Inhalte extrahieren. Die leichtgewichtige Twitter-Library Net::Twitter::Lite sorgt zudem für eine einfach Twitter-Anbindung:

#!/usr/bin/perl
use strict;
use DateTime;
use Net::Twitter::Lite;
use XML::LibXML;

#Get date
my $today = DateTime->today();
die "No working day!\n" if($today->day_of_week()>5);

#Fetch url and load document as DOM tree
my $url = sprintf("http://www.uni-ulm.de/mensaplan/%04d-%02d-%02d.html",$today->year, $today->month,$today->day);
my $doc = XML::LibXML->new()->parse_html_file($url) or die "Error while fetching/parsing document!\n";

#Gather all list entries and extract mealtype and actual meal
my @meals = $doc->findnodes('//div[@class="meal"]');
my @tweets;
foreach (@meals)
{
	my ($mealtype, $meal) = ($_->find('./div[@class="mealtype"]'),$_->find('./div[@class="item"]'));
	$meal =	(length($meal)+length($mealtype) > 138 ? substr($meal,0,136-length($mealtype)).".." : $meal);
	push(@tweets, $mealtype.": ".$meal);
}
die "Error while fetching meals!\n" if(length(@tweets) == 0);

#Login to twitter and post entries in reverse order
my $nt = Net::Twitter::Lite->new(username => 'username', password => '...', clientname => "MensaBot",source => "web") or die "Error during twitter login procedure!\n";
$nt->update("="x 40);
foreach (reverse(@tweets))
{
	my $result = $nt->update($_);
}
$nt->update("Mensaplan Uni Ulm am ".$today->day.".".$today->month.".".$today->year.":   #uni #ulm #uulm #mensa #mensaplan");
exit;

Zugehöriger Crontab-Eintrag, wobei 1-5 für Werktage steht und 0 10 für 10:00 Uhr:

0 10 * * 1-5 /path/to/script.pl

Hiermit wird das Skript regelmäßig zu den gewünschten Zeiten ausgeführt.

ioexception.de

Benjamin Erb [] studiert seit 2006 Medieninformatik und interessiert sich insbesondere für Java, Web-Technologien, Ubiquitous Computing, Cloud Computing, verteilte Systeme und Informationsdesign.


Raimar Wagner studiert seit 2005 Informatik mit Anwendungsfach Medizin und interessiert sich für C++ stl, boost & Qt Programmierung, Scientific Visualization, Computer Vision und parallele Rechenkonzepte.


David Langer studiert seit 2006 Medieninformatik und interessiert sich für Web-Entwicklung, jQuery, Business Process Management und Java.


Sebastian Schimmel studiert seit 2006 Informatik mit Anwendungsfach Medizin und interessiert sich für hardwarenahe Aspekte, Robotik, webOs, C/C++ und UNIX/Linux.


Timo Müller studiert seit 2006 Medieninformatik. Er interessiert sich allen voran für Mobile and Ubiquitous Computing, systemnahe Enwticklung und verteilte Systeme, sowie Computer Vision.


Achim Strauß studiert seit 2006 Medieninformatik. Seine Interessen liegen in Themen der Mensch-Computer Interaktion sowie Webentwicklung und UNIX/Linux.


Tobias Schlecht studiert seit 2006 Medieninformatik und interessiert sich vor allem für Software Engineering, Model Driven Architecture, Requirements Engineering, Usability Engineering, Web-Technologien, UML2 und Java.


Fabian Groh studiert seit 2006 Medieninformatik. Seine Interessengebiete sind Computer Graphics, Computer Vision, Computational Photography sowie Ubiquitos Computing.


Matthias Matousek studiert seit 2007 Medieninformatik und interessiert sich besonders für Skriptsprachen, Echtzeitsysteme und Kommunikation.


Michael Müller [] studiert seit 2009 Medieninformatik. Er interessiert sich vor allem für Web-Technologien, Ubiquitous Computing, User-Interfaces, UNIX und Creative Coding.


Falco Nogatz [] studiert seit 2010 Informatik mit Anwendungsfach Mathematik. Er interessiert sich für Web-Technologien, Programmierparadigmen und theoretische Grundlagen.

Archiv

Februar 2012
M D M D F S S
« Dez    
 12345
6789101112
13141516171819
20212223242526
272829