<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>IOException.de &#187; web</title>
	<atom:link href="http://www.ioexception.de/category/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ioexception.de</link>
	<description>Ausgewählter Nerdkram von Informatikstudenten der Uni Ulm</description>
	<lastBuildDate>Fri, 13 Jan 2012 07:38:26 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Benachrichtigungen für die Piratenpads skripten</title>
		<link>http://www.ioexception.de/2011/12/27/benachrichtigungen-fur-die-piratenpads-skripten/</link>
		<comments>http://www.ioexception.de/2011/12/27/benachrichtigungen-fur-die-piratenpads-skripten/#comments</comments>
		<pubDate>Tue, 27 Dec 2011 12:51:43 +0000</pubDate>
		<dc:creator>Michael Müller</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[programmieren]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[etherpad]]></category>
		<category><![CDATA[node.js]]></category>
		<category><![CDATA[notifications]]></category>
		<category><![CDATA[piratenpad]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=1371</guid>
		<description><![CDATA[Ich habe einen Notificationservice für die Piratenpads geschrieben. Bei Änderungen wird eine Benachrichtigung per E-Mail versendet.]]></description>
			<content:encoded><![CDATA[<p>Die <a href="http://piratenpad.de">Piratenpads</a> sind eine bequeme, kostenfreie Möglichkeit um kollaborativ an Texten zu arbeiten oder etwa Ideen zu sammeln. In letzter Zeit nutze ich den Service mit einigen anderen Leuten sehr exzessiv. Über die verschiedenen Pads in verschiedenen Teams habe ich aber inzwischen einfach den Überblick verloren. Um herauszufinden, ob es irgendwo Neuerungen gibt muss ich alles manuell abklappern und mich bei jedem einzelnen Team einloggen. Ich bin der Ansicht, dass man genau solche Aufgaben nach Möglichkeit immer automatisieren sollte. </p>
<p>Deswegen habe ich einen Notificationservice für die Piratenpads geschrieben. Das Skript loggt sich ein, fragt die aktuelle Version des Dokuments ab und speichert diese lokal zwischen. Beim nächsten Überprüfen (idealerweise als Cronjob) wird die lokale Kopie mit dem online-Original verglichen. Gibt es eine Differenz wird eine E-Mailbenachrichtigung mit dem <code>diff</code> versandt.</p>
<p>Um das Ganze zu Skripten habe ich node.js mit der Bibliothek <a href="https://github.com/mikeal/request">request</a> verwendet:</p>
<blockquote><p>Request is designed to be the simplest way possible to make HTTP calls. It support HTTPS and follows redirects by default.</p></blockquote>
<p>Tolle Sache! Ohne HTTPS-Support kommen wir eh nicht weit, bei einigen Pads ist der Zugriff auf HTTPS eingeschränkt. Außerdem muss man sich dank der Bibliothek nicht um das mühsame Parsen von &#8220;Set-Cookie&#8221; Feldern kümmern. request übernimmt die Cookies standardmäßig einfach global für zukünftige Requests.</p>
<p>Um die Session zu initialisieren, also sich vor dem Login einen Cookie zu holen, sieht der Code etwa so aus:</p>
<pre class="brush: jscript;">
var request = require('request');
var base = 'https://foo.piratenpad.de';

(function initiateSession() {
	request.get(base, function (error, response, body) {
		if (!error &amp;&amp; response.statusCode == 200) {
			login();
		}
	});
})();
</pre>
<p>Die Loginfunktion habe ich zusammengebaut, nachdem ich den kompletten Skriptablauf im Firefox durchgespielt habe und alle Requests mittels des (unheimlich praktischen) <a href="https://addons.mozilla.org/de/firefox/addon/live-http-headers/">Live HTTP Headers</a> Add-ons aufgezeichnet habe. </p>
<pre class="brush: jscript;">
function login() {
	var options = {
			url: base + '/ep/account/sign-in',
			form: {'email': 'john@doe.de', 'password' : 'mypw'}
	};

	request.post(options, function (err, res, body) {
			request.get(base + '/' + acc.padId, function (err, resp, body) {
				// get the latest version of the pad document
				var linkToLatestVersion = body.match(/[\w\d\/\-\.]*(latest')/gi);
				linkToLatestVersion = linkToLatestVersion[0].replace(&quot;'&quot;, '');

				getLatestDocument(linkToLatestVersion);
			});
		}
	);
}
</pre>
<p>Die aktuelle Version des Dokuments lässt sich dann mit einem einfachen GET-Request abfragen:</p>
<pre class="brush: jscript;">
function getLatestDocument(linkToLatestVersion) {
	request.get(base + linkToLatestVersion, function (err, resp, body) {
		var start = body.search('id=&quot;padcontent&quot;&gt;') + 'id=&quot;padcontent&quot;&gt;'.length;
		var end = body.search(&quot;&lt;!-- /padeditor --&gt;&quot;);
		var padContent = body.substring(start, end);

		// strip all tags and entities
		padContent = padContent.replace(/(&lt;[^&gt;]+&gt;)|(&amp;[#\w]+;)/gi, '');

		console.log(padContent.trim());
	});
}
</pre>
<p>Das Ganze zusammengefasst als ordentliches, sauber konfigurierbares, Projekt gibt es <a href="https://github.com/ioexception-de/website-changes-notifications">hier auf GitHub</a>. Das Skript kann sehr einfach für ähnliche Aufgaben wiederverwendet werden. Als Anregung: Beispielsweise wäre es möglich das Uni Hochschulportal anzuzapfen um E-Mailbenachrichtigungen zu versenden, wenn neue Prüfungsergebnisse eingetragen sind. </p>
<p><strong>Update:</strong> Ich habe noch die Möglichkeit hinzugefügt, Benachrichtigungen für Änderungen an dem Inhalt hinter einer URL zu konfigurieren (im Ordner <code>simple-webpage/</code>). Ich benutze das als simple Lösung für Seiten, die keinen RSS-Feed bereitstellen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2011/12/27/benachrichtigungen-fur-die-piratenpads-skripten/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sopra-Projekt: Routenplaner für das Gelände der Uni Ulm</title>
		<link>http://www.ioexception.de/2011/09/01/sopra-uulm/</link>
		<comments>http://www.ioexception.de/2011/09/01/sopra-uulm/#comments</comments>
		<pubDate>Thu, 01 Sep 2011 13:46:12 +0000</pubDate>
		<dc:creator>Michael Müller</dc:creator>
				<category><![CDATA[datenbanken]]></category>
		<category><![CDATA[uulm]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[Neo4J]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[Sopra]]></category>
		<category><![CDATA[vaadin]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=1162</guid>
		<description><![CDATA[An der Uni Ulm muss jeder Bachelorstudent in einem Informatik / Informatik verwandten Studiengang ein Softwareprojekt absolvieren. Dieses Jahr war die Aufgabe einen Routenplaner für das Universitätsgelände zur erstellen. ]]></description>
			<content:encoded><![CDATA[<p>An der Uni Ulm muss jeder Bachelorstudent in einem Informatik / Informatik verwandten Studiengang das Sopra absolvieren. Das ist ein umfangreiches Softwareprojekt, das sich über zwei Semester erstreckt. Im ersten Semester steht dabei die Erfassung von Anforderungen, die Planung und das Pflichtenheft im Vordergrund. Das passiert in einem Team aus drei Studenten. Im zweiten Semester werden zwei Teams zusammengelegt, so dass fortan sechs Leute an der Implementierung arbeiten.</p>
<p>Alle Teams, die am Sopra teilnehmen, müssen dasselbe Projekt implementieren, wobei die Projekte jedes Jahr wechseln. Dieses Jahr war die Aufgabe von Grund auf einen Routenplaner für die Universität zur erstellen. Die Ausgangsbasis waren die Baupläne der Uni, die vom Bauamt zur Verfügung gestellt wurden. </p>
<p>Einige Problemstellungen des Projekts waren eine besondere Herausforderungen. Beispielsweise müssen handelsübliche Straßen-Routenplaner nicht mit fünf Stockwerken die übereinander liegen zurecht kommen.</p>
<p>Zum Routing: Algorithmen für Routingprobleme (Dijkstra, Bellman-Ford, etc.) verwenden üblicherweise einen gewichteten Graphen. Unser Team hat sich dafür entschieden eine graphenbasierte NoSQL-Datenbank zu verwenden: <a target="_blank" href="http://neo4j.org/">Neo4J</a>. Da wir vorhatten einen Routeplaner zu entwickeln bot es sich einfach an eine Datenbank zu verwenden die inhärent schon auf einer Graphenstruktur aufbaut und somit viele Probleme &#8212; wie das Routing zwischen Knoten &#8212; schon im Vornherein löst.</p>
<p>Routingalgorithmen auf relationalen Datenbanken können recht hässlich werden. Für einige andere Teams war das eines der Kernprobleme.</p>
<p><em>Man sollte Technologien nie deswegen auswählen, weil es eben die einzige Technologie ist die man kennt.<br />
Stattdessen sollte eine Technologie, ein Werkzeug, gewählt werden, weil es sich am Besten für die Aufgabe eignet.</em></p>
<p>Der Routenplaner sollte webbasiert realisiert werden. Wir haben uns für <a target="_blank" href="http://vaadin.com/">Vaadin</a> als Web-Framework entschieden. Vaadin setzt auf GWT auf und ermöglicht es Web-Applikationen in Java zu schreiben, als würde man eine Swing-Applikation entwickeln. Java Code wird durch einen Cross-Compiler in JavaScript, HTML &#038; CSS übersetzt.  Die Arbeit mit dem Framework hat ziemlich gut funktioniert, es lassen sich sehr schnell vorzeigbare Ergebnisse erstellen.</p>
<p>Wir haben außerdem eine Desktop-Applikation für das Bearbeiten und Hochladen von Kartenmaterial geschrieben. Da wir die Aufgaben im Vornherein aufgeteilt hatten war ich hier aber nur beteiligt als es um die Synchronisation mit der Webapp ging. Dafür haben wir Git verwendet (siehe auch den Blogbeitrag &#8220;<a href="/2011/03/15/git-als-update-mechanismus/">Git als Update-Mechanismus</a>&#8220;).</p>
<p>Weitere erwähnenswerte Technologien: Für den PDF-Druck haben wir LaTeX verwendet. Aus einer generierten *.tex Datei wird eine PDF erstellt und an den Browser zurückgegeben. Wir haben mittels node.js das Uni-Adressbuch gescraped um so vernünftig einen vollständigen Datensatz in die Datenbank zu bekommen.</p>
<p>Die erstellen Projekte werden nicht produktiv eingesetzt werden, es wird aber an einer Musterimplementierung gearbeitet. Diese wird später eventuell auch auf den Terminals, die auf dem Unigelände verteilt sind, laufen.<br />
Allgemein war es ziemlich interessant mal in einem größeren Team an einem umfrangreicheren Projekt zu arbeiten. Man lernt einige Dinge über die Arbeit im Team und verschiedene Technologien. Insbesondere lernet man aber wo die eigenen Stärken liegen.</p>
<div style="float:left;margin:0px 0px 0px 0px;">
<a href="/wp-content/uploads/2011/09/sopra-0-large.jpg"><img width="310" class="size-full wp-image-189 alignnone" title="Screenshot der Web-Applikation" src="/wp-content/uploads/2011/09/sopra-0.png" alt="" align="right" /></a>
</div>
<div style="float:left;margin:0px 0px 0px 5px;">
<a href="/wp-content/uploads/2011/09/sopra-1-large.jpg"><img width="310" class="size-full wp-image-189 alignnone" title="Screenshot der Datenbank Neo4J, aus dem Tool Neoclipse" src="/wp-content/uploads/2011/09/sopra-1.png" alt="" align="right" /></a>
</div>
<div style="clear:both; width:690px; float:left;">&nbsp;</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2011/09/01/sopra-uulm/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Einfache Visualisierung von Geodaten – Teil 2: Leaflet &amp; jquery.couch.js</title>
		<link>http://www.ioexception.de/2011/08/30/einfache-visualisierung-von-geodaten-%e2%80%93-teil-2-leaflet-jquery-couch-js/</link>
		<comments>http://www.ioexception.de/2011/08/30/einfache-visualisierung-von-geodaten-%e2%80%93-teil-2-leaflet-jquery-couch-js/#comments</comments>
		<pubDate>Tue, 30 Aug 2011 09:48:49 +0000</pubDate>
		<dc:creator>Benjamin Erb</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[gis]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[visualisierung]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=1119</guid>
		<description><![CDATA[Im vorherigen Teil haben wir gesehen, wie man Geodaten mithilfe von CouchDB abspeichern kann. Da diese Datenbank zugleich ein Webserver ist und die Daten im JSON-Format gespeichert werden, eignet sie CouchDB auch gut für AJAX-Abfragen. Hierfür gibt es eine auf jQuery aufbauende Library namens jquery.couch.js, die von den AJAX-Requests abstrahiert und direkt browser-seitige Interaktionen mit [...]]]></description>
			<content:encoded><![CDATA[<p>Im <a href="http://www.ioexception.de/2011/08/09/einfache-visualisierung-von-geodaten-%E2%80%93-teil-1-couchdbgeocouch/">vorherigen Teil</a> haben wir gesehen, wie man Geodaten mithilfe von CouchDB abspeichern kann. Da diese Datenbank zugleich ein Webserver ist und die Daten im JSON-Format gespeichert werden, eignet sie CouchDB auch gut für AJAX-Abfragen. Hierfür gibt es eine auf jQuery aufbauende Library namens <a href="http://daleharvey.github.com/jquery.couch.js-docs/symbols/%24.couch.html">jquery.couch.js</a>, die von den AJAX-Requests abstrahiert und direkt browser-seitige Interaktionen mit der Datenbank ermöglicht.</p>
<p>Im diesem Beitrag soll gezeigt werden, wie man mit der offenen Karten-Library <a href="http://leaflet.cloudmade.com/">Leaflet</a> und jquery.couch.js geographische Daten aus CouchDB heraus auf einer Karten anzeigen kann.</p>
<div id="attachment_1153" class="wp-caption alignleft" style="width: 310px"><a href="http://www.ioexception.de/wp-content/uploads/2011/08/couchdb-leaflet.png"><img class="size-medium wp-image-1153 " title="couchdb-leaflet" src="http://www.ioexception.de/wp-content/uploads/2011/08/couchdb-leaflet-300x203.png" alt="" width="300" height="203" /></a><p class="wp-caption-text">Beispiel-Visualisierung von ulmapi.de, ebenfalls basierend auf CouchDB und Leaflet.</p></div>
<p>Wir verwenden die CouchApp aus dem ersten Teil weiter, und fügen zu den bisherigen Map/Reduce Views noch statische HTML- und Javascript-Dateien hinzu (im <code>_attachments</code> Ordner), die dann im Browser abgerufen werden können. Beim Aufruf dieser Webseite wird ein HTML-Grundgerüst übertragen, sowie eine JavaScript-Datei, die beim Aufruf die eigentlichen Datensätze via jquery.couch.js aus der CouchDB nachlädt.</p>
<p>Als Mapping-Library verwenden wir Leaflet, eine Open-Source Bibliothek für Kartendarstellungen im Browser. Leaflet abstrahiert von verschiedenen Kartenprovidern und erlaubt es somit, unterschiedliche Datenquellen zu verwenden, wie zum Beispiel auch Bing Maps oder <a href="http://cloudmade.com/">Cloudmade</a>. Letzteres ist ein Service, der auf Basis der Open Street Map Daten Kartenkacheln mit individuellen Stilen rendert und hostet – für Visualisierungen oft sehr hilfreich, da reguläre Karten meist zu viele Karteninformationen enthalten oder farblich überladen sind. In unserem Fall haben wir einen einfach Graustufenkarte gewählt. Leaflet selbst lässt sich relativ leicht verwenden, es muss eine CSS-Datei sowie eine JavaScript-Datei importiert werden, und ein div-Block im HTML enthalten sein, worin später die Karte gerendert werden soll. Somit sieht unser HTML-Gerüst zu Beginn so aus:</p>
<pre class="brush: xml;">
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;style/leaflet.css&quot; /&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.min.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.couch.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;js/leaflet.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;js/maploader.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
	&lt;div id=&quot;map&quot;&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Es werden jQuery, jquery.couch.js und die Leaflet-Libs geladen, und die letzte importierte JavaScript-Datei soll nun unseren Code zum initialisieren der Karte und dem Laden der Daten aus der CouchDB enthalten. Zunächst erstellen wir eine Karte und rendern sie, sobald die Seite vollständig geladen wurde (jQuery Callback für document.ready):</p>
<pre class="brush: jscript;">
$(document).ready(function(){

		var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/[YOUR_API_KEY]/33481/256/{z}/{x}/{y}.png';
		var cloudmadeAttribution = 'UlmApi.de / Shape Files: Stadt Ulm (cc-by-sa), Map data &amp;copy; 2011 OpenStreetMap contributors, Imagery &amp;copy; 2011 CloudMade';
		var cloudmade = new L.TileLayer(
			cloudmadeUrl, {
				maxZoom : 18,
				attribution : cloudmadeAttribution
		});

		var map = new L.Map('map', {
			center : new L.LatLng(48.399976,9.995399),
			zoom : 12,
			layers : [ cloudmade ],
			zoomControl : false
		});
});
</pre>
<p>In der <code>cloudmadeUrl</code> muss für Cloudmade Karte ein korrekter API-Key angegeben werden, der nächste Parameter im Pfad identifiziert den Kartentyp. Beim Initialisieren der Karte wird dann die ID des <code>div</code>s angeben, bei uns &#8216;map&#8217;. Nun sollte unsere Karte bereits dargestellt werden, nachdem wir die CouchApp neu deployen (außerhalb des Fokus dieses Artikels, mehr dazu auf <a href="http://couchapp.org/">couchapp.org</a>).</p>
<p>Was nun noch fehlt, ist das Nachladen der Geodaten aus der CouchDB und die Anzeige auf der Karte. Hierfür verwenden wir jquery.couch.js als Wrapper für die AJAX-Requests gegen CouchDB und die GeoJSON-Funktionalität von Leaflet:</p>
<pre class="brush: jscript;">
$.couch.db('database_name').view('design_doc_name/view_name', {

	success: function(data){
		if(data &amp;&amp; data.rows &amp;&amp; data.rows.length){

			var geoJsonLayer = new L.GeoJSON();

			for(var i = 0;i&lt;data.rows.length;i++){
				geoJsonLayer.addGeoJSON(data.rows[i].value.geometry);
			}

			map.addLayer(geoJsonLayer);
		}
	}
});
</pre>
<p>Das obige Snippet sollte im vorherigen Code hinter der Erzeugung der Karte eingefügt werden. Es ruft von der Datenbank &#8216;database_name&#8217; den View &#8216;view_name&#8217; des Design-Dokuments &#8216;design_doc_name&#8217; auf, und iteriert bei erfolgreicher Abfrage über alle Zeilen. Von jeder Zeile wird dabei die geometry-Property zu einem GeoJSON-Layer hinzugefügt, der am Ende an die Karte übergeben wird. Da unser View aus Teil 1 bereits GeoJSON generiert, und Leaflet nativ GeoJSON lesen und darstellen kann, ist das Hinzufügen von Geodaten auf die Karte sehr einfach.</p>
<p>Hier noch ein paar weiterführende Links mit vertiefenden Inhalten zu den einzelnen Themen:</p>
<ul>
<li><a href="http://leaflet.cloudmade.com/reference.html">Leaflet Reference</a></li>
<li><a href="http://couchapp.org/">CouchApp</a></li>
<li><a href="http://www.scribd.com/doc/40221773/Umsetzung-einer-verteilten-Anwendung-mit-der-dokumentenorientierten-Datenbank-CouchDB">Diplomarbeit von Lena Herrmann</a> über Webanwendungen mit CouchDB und CouchApp</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2011/08/30/einfache-visualisierung-von-geodaten-%e2%80%93-teil-2-leaflet-jquery-couch-js/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Einfache Visualisierung von Geodaten – Teil 1: CouchDB/GeoCouch</title>
		<link>http://www.ioexception.de/2011/08/09/einfache-visualisierung-von-geodaten-%e2%80%93-teil-1-couchdbgeocouch/</link>
		<comments>http://www.ioexception.de/2011/08/09/einfache-visualisierung-von-geodaten-%e2%80%93-teil-1-couchdbgeocouch/#comments</comments>
		<pubDate>Tue, 09 Aug 2011 15:43:01 +0000</pubDate>
		<dc:creator>Benjamin Erb</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[geo]]></category>
		<category><![CDATA[gis]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nosql]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=1103</guid>
		<description><![CDATA[Die Hochschulgruppe Open Data Ulm hat es sich zur Aufgabe gemacht, offene und öffentliche Daten rund um die Region Ulm zu aggregieren, aufzuarbeiten und zu visualisieren. Näheres zu diesem Projekt sowie bereits gesammelte Datensätze gibt es unter UlmApi.de 
Für unser Vorhaben habe ich als Persistenzlösung die dokumentenorientierte Datenbank CouchDB gewählt, da sie für uns mehrere [...]]]></description>
			<content:encoded><![CDATA[<p>Die Hochschulgruppe Open Data Ulm hat es sich zur Aufgabe gemacht, offene und öffentliche Daten rund um die Region Ulm zu aggregieren, aufzuarbeiten und zu visualisieren. Näheres zu diesem Projekt sowie bereits gesammelte Datensätze gibt es unter <a href="http://ulmapi.de">UlmApi.de</a> </p>
<p>Für unser Vorhaben habe ich als Persistenzlösung die dokumentenorientierte Datenbank <a href="http://couchdb.apache.org/">CouchDB</a> gewählt, da sie für uns mehrere interessante Features bietet:</p>
<ul>
<li><strong>schemalos</strong>: Anders als relationale Datenbanken benötigen schemalose Datenbanken keine im Voraus fest definierte Struktur der Einträge. Für unsere Geodaten ist dies sehr hilfreich, da außer einer ID und den Geodaten noch beliebige zusätzliche Daten pro Eintrag mitgespeichert werden können.</li>
<li><strong>JSON</strong>: Für die Speicherung strukturierter Daten stellt dieses Format eine leichtgewichtige Alternative zu XML dar.</li>
<li><strong>webbasiert</strong>: Die Datenbank ist zugleich ein Webserver und der Zugriff auf die Daten läuft somit über HTTP.</li>
<li><strong>verteilt/replizierend:</strong> Ein wichtiges Konzept von CouchDB ist die einfache aber mächtige Replikation zwischen verschiedenen Instanzen. Im Kontext unserer offenen Datensammlungen ermöglicht dies, dezentralte Kopien der Daten anzulegen, diese lokal zu editieren oder erweitern und wieder auf unsere Hauptdatenbank zu laden.</li>
<li><strong>Attachments</strong>: Neben strukturierten Daten lassen sich auch ganze Dateien speichern. Dies ist vor allem für archivierte Rohdaten in proprietären Formaten interessant.</li>
<li><strong>CouchApps</strong>: Neben der Speicherung der Daten sind vor allem einfache Anwendungen interessant, die diese visualisieren oder aufbereiten. Das Konzept der <a href="http://couchapp.org/">CouchApps</a> ermöglicht es uns, simple Webanwendungen direkt auf der Datenbank zu deployen und verfügbar zu machen.</li>
<li><strong>räumliche Indizes</strong>: Dank <a href="http://vmx.cx/">Volker Mische</a> besitzt CouchDB einen zusätzlichen Index (<a href="https://github.com/couchbase/geocouch">GeoCouch</a>), der statt eindimensionaler B-Bäume zweidimensionale R-Bäume benutzt. Damit lassen sich Dokumente mit räumlichen Daten abspeichern, indizieren und effizient abfragen.</li>
</ul>
<p>Von der Stadt Ulm haben wir als ersten Datensatz Shapefiles der Ulmer Stadtteile und Stadtviertel bekommen. Diese wurden zunächst vom Ausgangsformat (Gauss-Krueger-Shapefiles) in das GeoJSON-Format mit WGS84-Koordinaten konvertiert. Mithilfe eines kleinen node.js Skriptes wurden die einzelnen Shapes dann als Dokumente auf die Couch geladen. </p>
<p>Ein Dokument hat hierbei folgende Form (<a href="http://ulmapi.de/v1/geodaten/ul-st14">Originaldokument</a>):</p>
<pre class="brush: jscript;">
{
   &quot;_id&quot;: &quot;ul-st14&quot;,
   &quot;_rev&quot;: &quot;1-797187e292d93b6d661ca8f7fec3f6c9&quot;,
   &quot;type&quot;: &quot;stadtteil&quot;,
   &quot;name&quot;: &quot;Weststadt&quot;
   &quot;geometry&quot;: {
       &quot;type&quot;: &quot;Feature&quot;,
       &quot;properties&quot;: {
           &quot;identifier&quot;: &quot;ST 14&quot;,
           &quot;name&quot;: &quot;Weststadt&quot;
       },
       &quot;geometry&quot;: {
           &quot;type&quot;: &quot;Polygon&quot;,
           &quot;coordinates&quot;: [
               [
                   [
                       9.981459,
                       48.395751
                   ],
                   …
              ]
           ]
       }
   },
   &quot;creator&quot;: &quot;Stadt Ulm&quot;,
   &quot;license&quot;: {
       &quot;name&quot;: &quot;Creative Commons - Namensnennung-Weitergabe unter gleichen Bedingungen 3.0 Deutschland (CC BY-SA 3.0)&quot;,
       &quot;link&quot;: &quot;http://creativecommons.org/licenses/by-sa/3.0/de/&quot;
   },
}
</pre>
<p>Die <code>_id</code> bestimmt das Dokument eindeutig, das <code>_rev</code> Feld ist für die Versionskontrolle verantwortlich. Als ID haben wir einen internen Identifier der Stadt genommen und noch mit einem &#8220;ul&#8221; Präfix versehen. Der Rest des Dokuments kann frei strukturiert werden. In unserem Fall verwenden wir noch ein <code>type</code> Feld, durch das wir später Dokumente unterschiedlichen Typs unterscheiden können (z.B. <code>stadtteil</code> oder <code>stadtviertel</code>). Das geometry Feld (hier gekürzt) enthält die geografischen Daten im <a href="http://geojson.org/geojson-spec.html">GeoJSON</a>-Format. Die sonstigen Felder beschreiben noch den Urheber und die Lizenz der Daten sowie den Namen des Eintrags.</p>
<p>Nun ist die Datenbank gefüllt, später sollen aber die Daten auch wieder abgefragt werden können. Als &#8220;NoSQL&#8221; Datenbank bietet CouchDB hierfür aber keine SQL-Statements an, stattdessen muss man mithilfe von <a href="http://de.wikipedia.org/wiki/MapReduce">MapReduce</a> beschreiben, wie aus den Daten Indizes gebildet werden sollen:</p>
<pre class="brush: jscript;">function(doc) {
	if (doc.type) {
		if(doc.type === 'stadtviertel'){
		    emit(['stadtviertel', doc._id], {
		    	'geometry' : doc.geometry,
		    	'label' : &quot;&lt;b&gt;Stadtviertel &quot;+doc.name+&quot;&lt;/b&gt;&lt;br/&gt;ID: &quot;+doc._id+&quot;&lt;br/&gt;(Stadteil &quot;+doc.stadtteil+&quot;)&quot;
		    });
		}
		else if(doc.type === 'stadtteil'){
		    emit(['stadtteil', doc._id], {
		    	'geometry' : doc.geometry,
		    	'label' : &quot;&lt;b&gt;Stadtteil &quot;+doc.name+&quot;&lt;/b&gt;&lt;br/&gt;ID: &quot;+doc._id
		    });
		}
	}
};
</pre>
<p>Damit erzeugen wir eine sortiere Liste von Schlüssel-Wert-Paaren. Der Schlüssel ist selbst wieder komplex und besteht aus zwei Teilen. Der erste Teil ist der Typ, der zweite Teil die ID des Dokuments. Damit kann man später durch die sogenannte <a href="http://wiki.apache.org/couchdb/View_collation">View Collation</a> Abfragen durchführen, die sich auf einen bestimmtem Typ beschränken (zur Wiederholung: ohne SQL gibt es hier auch kein WHERE Statement). In diesem Fall werden bisher nur Dokumente des Typs <code>stadtteil</code> oder <code>stadtviertel</code> eingetragen, und als Wert eines Eintrages wird bereits die spätere Nutzung auf einer Karte vorbereitet – es werden die Geodaten sowie ein Label indiziert. Damit lassen sich nun schon Stadtteile/Stadtviertel abfragen.</p>
<p>Ergänzt man dies noch um einen räumlichen Index, so werden auch räumliche Abfragen ermöglicht. Hierfür werden in den Index als Schlüssel die Geodaten (unverändert im GeoJSON Format) eingetragen, den Wert selbst bliebt leer, da das Feld <code>_id</code> sowieso eingetragen wird und vorest keine weiteren Daten mehr benötigt werden:</p>
<pre class="brush: jscript;">
function(doc){
	if(doc.geometry &amp;&amp; doc.geometry.geometry){
		emit(doc.geometry.geometry, null);
	}
};
</pre>
<p>(Das etwas merkwürdig anmutende <code>doc.geometry.geometry</code> entstand einerseits dadruch, dass unser Feld mit dem GeoJSON-Objekt <code>geometry</code> heißt, das GeoJSON-Objekt selbst aber komplex ist und nur in einem Teil davon die eigentlichen Geodaten hinterlegt sind.)</p>
<p>Mithilfe dieses Index lässt sich nun bei einem gegebenen geografischen Raum überprüfen, welche Objekte darin enthalten sind. Also zum Beispiel ausgehend von einer Koordinate, ob sie sich in Ulm befindet und wenn ja, in welchem Stadtteil/Stadtviertel.</p>
<p>Im nächsten Teil wird näher betrachtet, wie die nun abgespeicherten und indizierten Geodaten im Browser auf einer Karte dargestellt werden können, und zwar direkt aus CouchDB heraus.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2011/08/09/einfache-visualisierung-von-geodaten-%e2%80%93-teil-1-couchdbgeocouch/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Präsentieren mit HTML5-Foliensätzen</title>
		<link>http://www.ioexception.de/2011/08/05/prasentieren-mit-html5-foliensatzen/</link>
		<comments>http://www.ioexception.de/2011/08/05/prasentieren-mit-html5-foliensatzen/#comments</comments>
		<pubDate>Fri, 05 Aug 2011 11:48:24 +0000</pubDate>
		<dc:creator>Benjamin Erb</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[uni ulm]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=1057</guid>
		<description><![CDATA[Kurzversion: HTML5 Foliensatz, basierend auf einem Google Template, das zusätzlich Notizen und einen Presenter Mode bietet: Demo / Code
Nicht nur die Frage, wie man richtig präsentiert (Stichwort Zen vs. Death by PowerPoint), sondern auch die Frage, mit welchen Anwendungen man präsentiert, ist oft umstritten. Ich persönlich konnte mich bisher mit Powerpoint und Konsorten eher wenig [...]]]></description>
			<content:encoded><![CDATA[<p><em>Kurzversion: HTML5 Foliensatz, basierend auf einem Google Template, das zusätzlich Notizen und einen Presenter Mode bietet: <a href="http://www.benjamin-erb.de/tmp/html5slides-uulm-presenter/template/index.html#1">Demo</a> / <a href="https://github.com/berb/html5slides-uulm">Code</a></em></p>
<p>Nicht nur die Frage, wie man richtig präsentiert (Stichwort <a href="http://www.presentationzen.com/">Zen</a> vs. <a href="http://en.wikipedia.org/wiki/Death_by_PowerPoint">Death by PowerPoint</a>), sondern auch die Frage, mit welchen Anwendungen man präsentiert, ist oft umstritten. Ich persönlich konnte mich bisher mit Powerpoint und Konsorten eher wenig anfreunden – vor allem Typografie und Einschränkungen bei der Gestaltung waren problematisch. Als Alternative habe ich bisher oft LaTeX Beamer verwendet, was allerdings je nach visueller Komplexität auch oft relativ zeitaufwendig ist, sich aber zumindest bei Grafiken in Vektorformaten und mathematischen Inhalten auch schnell auszahlt.</p>
<p><strong>HTML5-basierte Foliensätze</strong></p>
<p>Mit dem Aufkommen von HTML5 entstand eine zusätzliche Möglichkeit. Dank der neuen Multimedia-Tags wie &lt;audio&gt; und &lt;video&gt; sowie mächtigeren CSS Stilen bietet HTML nun die Grundlagen für browser-basierte Präsentationen. Mittlerweile gibt es hierfür auch schon mehrere Templates:</p>
<ul>
<li><a href="http://paulrouget.com/dzslides/">DZSlides</a></li>
<li><a href="http://code.google.com/p/html5slides/">html5slides</a></li>
<li><a href="http://meyerweb.com/eric/tools/s5/">S5: A Simple Standards-Based Slide Show System</a></li>
</ul>
<p>Noch mehr Alternativen gibt es in dieser <a href="http://en.wikipedia.org/wiki/Web-based_slideshow">Auflistung</a>. Ein weiteres sehr schönes Beispiel ist ein Foliensatz zu HTML5, der selbst quasi eine Technologiedemonstration enthält: <a href="http://slides.html5rocks.com">http://slides.html5rocks.com</a></p>
<p>Der Vorteil von HTML-basierten Präsentationen ist die hohe Anzahl von Medien (u.a. auch SVG, Flash Videos oder ganze Webseiten als IFrames), die man einbetten kann. Ein einfaches, weitläufig bekanntes Markup ermöglicht das schnelle Erstellen von Folien, und mit einer Kombination aus HTML, CSS und JavaScript lassen sich dennoch auch komplexe Spezialfunktionen realisieren.</p>
<p>Mir persönlich hat das html5slides Template ganz gut gefallen, das Google entwickelt und für die Google I/O Slides eingesetzt hat. Da das Template unter einer Apache License veröffentlicht wurde, habe ich zunächst damit begonnen, es an das Uni Ulm Corporate Design anzupassen. Außerdem hatte ich ein paar kleine Änderungen am Code vorgenommen, um zum Beispiel eine Nummerierung der Folien zu ermöglichen.</p>
<p><strong>Presenter Mode?</strong></p>
<p>Prinzipiell war das Ergebnis schon mal akzeptabel, allerdings wurden die oft genannten Probleme bei solchen HTML-Foliensätzen schnell offensichtlich – fehlende Notizen für den Vortragenden und nur eine Ausgabe.</p>
<p>Eher durch Zufall bin ich auf ein anderes Konstrukt gestoßen, dass seit HTML5 Cross-Frame-Communication erlaubt, also den Austausch von Nachrichten zwischen zwei verschiedenen Frames (mit einigen Einschränkungen): <a href="https://developer.mozilla.org/en/DOM/window.postMessage"><code>window.postMessage()</code></a></p>
<p>Die Möglichkeit, zwischen Frames zu kommunizieren, ist natürlich auch ideal dafür, Daten zwischen Frames zu synchronisieren. Übertragen auf zwei verschiedene Präsenationsframes ermöglicht dies beim Weiterschalten der Folien in einem Frame, den zweiten Frame zu aktualisieren. Schematisch sieht das so aus:</p>
<div id="attachment_1084" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.ioexception.de/wp-content/uploads/2011/08/html5slides.png"><img src="http://www.ioexception.de/wp-content/uploads/2011/08/html5slides-300x200.png" alt="" title="html5slides" width="300" height="200" class="size-medium wp-image-1084" /></a><p class="wp-caption-text">(CC-BY-NC) Icons by picol.org / w3.org</p></div>
<p>Im Hauptfenster kann per Tastendruck ein zusätzliches Popup geöffnet werden (1). Das neue Popup öffnet die gleiche URI der Präsentation und wird auf dem Bildschirm des Vortragenden platziert. Schaltet der Vortragende nun im Hauptfenster weiter zu nächsten Folie, so erzeugt dies ein Nachricht an das zweite Frame (2), das dann ebenfalls weiterschaltet.</p>
<p>Eine weitere Ergänzung war die Unterstützung von Notizen als Overlay über die Folien. Kombiniert mit dem Dual-Screen-Ansatz ermöglicht dies, dem Publikum die Folien zu zeigen, dem Vortragenden auf einem zweiten Bildschirm die Folien plus den verfügbaren Notizen.</p>
<p>Ausführliche Beispiele mit Code gibt es in einer <a href="http://www.benjamin-erb.de/tmp/html5slides-uulm-presenter/template/index.html#1">Beispielpräsentation</a>, den kompletten Code auf github: <a href="https://github.com/berb/html5slides-uulm">https://github.com/berb/html5slides-uulm</a></p>
<p>Auf der Feature Wishlist steht noch ein alternativer CSS-Stylesheet für den Druckexport. Außerdem ein Tool, dass externe Daten wie Bilder per Base64 encoding als Data URI integriert und JavaScript sowie Stylesheets inline einbindet, sodass die Präsentation als einzelne HTML5 Datei ohne externe Abhängigkeiten abgespeichert werden kann. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2011/08/05/prasentieren-mit-html5-foliensatzen/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Warum wir eine Wave brauchen</title>
		<link>http://www.ioexception.de/2011/03/14/warum-wir-eine-wave-brauchen/</link>
		<comments>http://www.ioexception.de/2011/03/14/warum-wir-eine-wave-brauchen/#comments</comments>
		<pubDate>Mon, 14 Mar 2011 02:02:29 +0000</pubDate>
		<dc:creator>matou</dc:creator>
				<category><![CDATA[security]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[xmpp]]></category>
		<category><![CDATA[chat]]></category>
		<category><![CDATA[kommunikation]]></category>
		<category><![CDATA[multimedia]]></category>
		<category><![CDATA[otr]]></category>
		<category><![CDATA[wave]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=905</guid>
		<description><![CDATA[Das Problem
E-Mail ist alt und kaputt. Es gehört durch modernere Kommunikationsarten ersetzt. Warum? Was erwarten wir von Kommunikation über das Internet?

Confidentiality, Integrity, Authentication
Perfect Forward Secrecy (PFS)
Plausible Deniability (PD)
Asynchrone und synchrone Kommunikationsmöglichkeit
Gruppenkommunikation
Kollaboration
Multimediale Kommunikation
Dezentrale Struktur

Wenn wir von Verschlüsselung sprechen, dann ist damit Ende-zu-Ende-Verschlüsselung gemeint und nicht die Verschlüsselung der Transportwege. Das Gleiche gilt für Integrity und Authentication.
Wir [...]]]></description>
			<content:encoded><![CDATA[<h2>Das Problem</h2>
<p>E-Mail ist alt und kaputt. Es gehört durch modernere Kommunikationsarten ersetzt. Warum? Was erwarten wir von Kommunikation über das Internet?</p>
<ul>
<li>Confidentiality, Integrity, Authentication</li>
<li>Perfect Forward Secrecy (PFS)</li>
<li>Plausible Deniability (PD)</li>
<li>Asynchrone und synchrone Kommunikationsmöglichkeit</li>
<li>Gruppenkommunikation</li>
<li>Kollaboration</li>
<li>Multimediale Kommunikation</li>
<li>Dezentrale Struktur</li>
</ul>
<p>Wenn wir von Verschlüsselung sprechen, dann ist damit Ende-zu-Ende-Verschlüsselung gemeint und nicht die Verschlüsselung der Transportwege. Das Gleiche gilt für Integrity und Authentication.</p>
<p>Wir können E-Mails verschlüsseln und digital signieren (z. B. durch Verwendung von OpenPGP). Leider kann dann für immer und von jedem bewiesen werden, dass wir diese Nachricht geschrieben haben. Ein weiteres Problem entsteht, wenn einer der Keys in falsche Hände gerät. Dann sind <em>sämtliche</em> bisher für ihn verschlüsselten Daten kompromittiert.</p>
<p>E-Mail ist langsam und immer asynchron. E-Mail-Verkehr kostet unnötig Zeit.[0] </p>
<p>E-Mail ist nicht kollaborativ.</p>
<p>E-Mail-Anhänge ermöglichen zwar die Übertragung multimedialer Inhalte, sind aber unglaublich ineffizient und ressourcenfressend.</p>
<p>Was gibt es also für Alternativen? Wie kann besser kommuniziert werden?</p>
<p>Soziale Netzwerke sind Privacy-Desaster.</p>
<p>Instant Messaging erfüllt die meisten Zwecke. Bei vielen Protokollen ist sowohl asynchrone als auch synchrone Kommunikation möglich. Confidentiality, Integrity, Authentication, Perfect Forward Secrecy und Plausible Deniability wird durch Verwendung von OTR[1] erreicht (allerdings nur bei Kommunikation mit <em>einem</em> Partner). Einige Protokolle erlauben Gruppenkommunikation durch Chaträume oder multimediale Kommunikation, wie das Übertragen von Dateien oder Video-/Audio-Telefonie.</p>
<p>Warum reichen bestehende Instant-Messaging-Systeme nicht aus? Was fehlt uns?</p>
<ul>
<li>Unterhaltungen in Echtzeit</li>
<li>Flexibles Hinzufügen von Teilnehmern zur Gruppenkommunikation</li>
<li>Verbessertes Sharing und Darstellung von Multimediainhalten</li>
<li>Verschlüsselte, möglicherweise asynchrone, Gruppenkommunikation<br />
    (mit PD und PFS)</li>
</ul>
<p>Die ersten drei Punkte kann Googles Wave[2,3]. Das Problem der verschlüsselten Gruppenkommunikation mit den beschriebenen Bedingungen ist leider darin bisher nicht gelöst worden. Zudem existieren keine zufriedenstellenden Clients für Wave. </p>
<p>Wir wollen, dass die Infrastruktur nicht von einem einzigen Knotenpunkt abhängig ist. Dezentrale Struktur wird von den Protokollen, die E-Mail bzw. Wave zugrunde liegen, unterstützt. Fast alle IM-Dienste erlauben diese nicht.</p>
<h2>Die Lösung</h2>
<p>Wir sehen mehrere Lösungsansätze. </p>
<h3>Komplett neues Protokoll mit Implementierung und Infrastruktur</h3>
<p>Auch bekannt als: „Das Rad neu erfinden“. Machen wir nicht. Das Rad gibt es schon. Dieser Ansatz wäre sehr aufwändig und würde sich schwer etablieren. </p>
<h3>Verwendung bestehender Protokolle</h3>
<p>Bedingung ist, dass das Protokoll offen und leicht erweiterbar ist. Hier halten wir nur XMPP für sinnvoll. Der Vorteil dieser Lösung ist, dass genau die gewünschten Features implementiert werden können und keine Kompromisse notwendig sind. Voraussichtlich wird bereits bestehende Infrastruktur verwendet werden können.</p>
<h3>Erweiterung von Wave</h3>
<p>Wave hat bereits die meisten Features, welche wir uns wünschen. Verschlüsselung fehlt aber und es existieren keine guten Clients.</p>
<h2>Der Plan</h2>
<p>Wir evaluieren die letzten beiden Lösungsansätze und implementieren dann die sinnvollste Lösung. Dazu müssen wir zunächst XMPP und das Google Wave Federation Protocol verstehen. </p>
<p>Auf jeden Fall werden wir einen Client schreiben, der im Vergleich zu bestehenden Clients besser bedienbar ist und unsere beschriebenen Anforderungen erfüllt. Für Legacy-Clients ist eine (teilweise) Umsetzung der Features, beispielsweise durch Plugins, denkbar. </p>
<p>Die Unzufriedenheit mit vorhandenen Kommunikationsmöglichkeiten und die Idee diese zu verbessern schlummert schon seit einiger Zeit in uns. Hiermit möchten wir die Sache ins Rollen bringen. Stay tuned!</p>
<p>–nico, phil, matou</p>
<p>[0] <a href="http://www.heise.de/newsticker/meldung/Unternehmen-will-Mitarbeitern-die-E-Mail-abgewoehnen-1184596.html">http://www.heise.de/newsticker/meldung/Unternehmen-will-Mitarbeitern-die-E-Mail-abgewoehnen-1184596.html</a><br />
[1] <a href="http://www.cypherpunks.ca/otr/">http://www.cypherpunks.ca/otr/</a><br />
[2] <a href="http://wave.google.com/">http://wave.google.com/</a><br />
[3] <a href="http://www.waveprotocol.org/">http://www.waveprotocol.org/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2011/03/14/warum-wir-eine-wave-brauchen/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>XMPP Multiuser Chat Bot</title>
		<link>http://www.ioexception.de/2011/03/05/xmpp-multiuser-chat-bot/</link>
		<comments>http://www.ioexception.de/2011/03/05/xmpp-multiuser-chat-bot/#comments</comments>
		<pubDate>Sat, 05 Mar 2011 16:10:05 +0000</pubDate>
		<dc:creator>matou</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[xmpp]]></category>
		<category><![CDATA[bot]]></category>
		<category><![CDATA[chat]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=880</guid>
		<description><![CDATA[Multiuser Chats stellen eine gute Möglichkeit dar mit vielen Leuten gleichzeitig zu kommunizieren. Ich selbst nehme regelmäßig über MUCs an Entwicklermeetings teil oder bespreche mit Freunden, was es so zu besprechen gibt. Und natürlich macht chatten auch viel Spaß :-)
Neulich hatten wir während eines solchen Chats die Idee, dass wir doch unseren WG-Server am Chat [...]]]></description>
			<content:encoded><![CDATA[<p>Multiuser Chats stellen eine gute Möglichkeit dar mit vielen Leuten gleichzeitig zu kommunizieren. Ich selbst nehme regelmäßig über MUCs an Entwicklermeetings teil oder bespreche mit Freunden, was es so zu besprechen gibt. Und natürlich macht chatten auch viel Spaß :-)</p>
<p>Neulich hatten wir während eines solchen Chats die Idee, dass wir doch unseren WG-Server am Chat teilnehmen lassen könnten, damit dieser uns z.B. mit Zitaten aus Fernsehsendungen unterhält oder wir über ihn die Musik in der Wohnung steuern können. Seit wir begonnen haben den ersten MUC-Bot zu implementieren, kommen immer wieder neue Ideen auf, was ein Bot so alles tun könnte. Zum Beispiel als Wörterbuch fungieren oder Kochrezepte fürs Abendessen vorschlagen. </p>
<p>Damit grundlegende Funktionalität nicht für jeden Bot neu geschrieben werden muss, habe ich begonnen ein kleines Framework zu entwickeln, dass sich um den XMPP-Teil des Bots kümmert und häufig benötigte Funktionen realisiert.  Das Framework ist in python geschrieben.</p>
<p>Im Folgenden beschreibe ich die Mucbot-Klasse, die einen einfachen Bot darstellt. Um den Eintrag übersichtlich zu halten lasse ich einige Dinge weg, die nicht wesentlich sind. Daher wird der hier gepostete Code nicht lauffähig sein. Für die komplette Version schaut einfach auf github vorbei.</p>
<pre class="brush: python;">
# Der Bot verwendet xmpppy (&lt;http://xmpppy.sourceforge.net/&gt;) um mit einem
# Jabber-Server zu kommunizieren.
import xmpp

# Wir brauchen Regular Expressions um in empfangenen Nachrichten nach Keywords
# zu suchen, auf die reagiert werden soll.
import re

# Das time Modul wird verwendet um Verzögerungen einzubauen. Z.B. falls der Bot
# nach einer bestimmten Zeit etwas sagen soll.
import time

# Der Bot erbt von Thread. Er kann also im Hintergrund gestartet werden, während
# das Programm noch etwas anderes tut.
from threading import Thread

class Mucbot(Thread):

# Es ist einiges an Initialisierung notwendig. Der Bot braucht eine Jabber-ID und
# ein dazu gehörendes Passwort, um sich damit am Server anmelden zu können. Da
# es ja ein MUC-Bot ist, braucht er außerdem einen Raum, dem er sich anschließen
# wird. Optional kann man ihm noch einen Namen geben, eine Liste von Zitaten,
# die er gelegentlich zitiert und ein Dictionary mit Keywords auf die er
# reagieren soll mit dazugehörenden Reaktionen. Die Keywords sind dabei als
# Reguläre Ausdrücke gegeben.
    def __init__(self, jid, pwd, room, botname='', roompwd='', quotes=[],
            minwait=-1, maxwait=-1, reactions={}, delay=3):

        # Kein expliziter Botname? -&gt; Verwende die Node der Jabber-ID
        if botname == '':
            botname = jid.getNode()

        # […]
        # hier werden alle übergebenen Parameter in der Mucbot-Instanz
        # gespeichert, um diese später noch verwenden zu können

        # Um Nachrichten schnell nach Schlüsselwörtern durchsuchen zu können
        # werden alle Regulären Ausdrücke compiliert.
        for key in self.reactions.keys():
            self.reactions[re.compile(key)] = self.reactions.pop(key)

        # Jetzt kommt die Verbindung zum Server. Zuerst erstellen wir ein
        # xmpp.Client Objekt und verbinden uns mit dem angegebenen Server.
        self.client = xmpp.Client(jid.getDomain(), debug=[])
        self.client.connect()

        # Um auf ankommende Nachrichten reagieren zu können, müssen wir
        # entsprechende Handler registrieren.
        self.client.RegisterHandler('message', self.msg_rcv)
        self.client.RegisterHandler('presence', self.pres_rcv)

        # Die Authentifizierung am Server:
        self.client.auth(jid.getNode(), pwd, resource=jid.getResource())

        # Und schlussendlich das Betreten des Raums:
        p = xmpp.Presence(to='%s/%s' % (room, botname))
        p.setTag('x', namespace=xmpp.NS_MUC).setTagData('password', roompwd)
        p.getTag('x').addChild('history', {'maxchars':'0', 'maxstanzas':'0'})
        self.client.send(p)

# Möchte der Bot etwas sagen, wird vom xmpp-Modul die xmpp Stanza zusammengebaut
# und an den Chatraum gesendet.
    def say(self, msg):
        m = xmpp.Message(to=self.room, body=msg, typ='groupchat')
        self.client.send(m)

# Wenn der Bot eine Nachricht empfängt, wird folgende Methode aufgerufen:
    def msg_rcv(self, sess, msg):

        # Wir ignorieren Nachrichten, die wir selbst verschickt haben.
        sender = str(msg.getFrom())
        if len(sender.split('/')) &gt; 1:
            sender = sender.split('/')[1]
        if sender.lower().find(self.botname) &gt;= 0:
            return

        self.react(msg.getBody())

# In der folgenden Methode wird für jedes Keyword, dass wir gespeichert haben
# geschaut, ob dieses in der empfangenen Nachricht gefunden werden kann. Falls
# ja, antwortet der Bot mit einer zufällig ausgewählten Antwort aus der Menge
# aller passenden Antworten.
    def react(self, msg):
        time.sleep(self.delay)
        for pattern in self.reactions.keys():
            print &quot;trying to find %s in %s&quot; % (pattern, msg)
            if pattern.search(msg):
                self.say(self.reactions[pattern]
                        [randint(0,len(self.reactions[pattern])-1)])
                return

# Die folgende Endlosschleife wird aufgerufen, wenn der Bot im Chat bleiben und
# auf ankommende Nachrichten warten soll.
    def processing(self):
        while True:
            self.client.Process(1)

# Wenn der Bot gestartet wird, beginnt er mit dem Warten auf Nachrichten. Falls
# er bei der Initialisierung eine Liste von Zitaten übergeben bekommen hat,
# zitiert er aus dieser Liste in zufälligen Abständen zufällige Zitate.
    def run(self):
        processor = Thread()
        processor.run = self.processing
        processor.start()
        if self.minwait==-1 or self.maxwait==-1:
            return
        while True:
            r = randint(self.minwait, self.maxwait)
            time.sleep(r)
            self.say(self.quotes[randint(0,len(self.quotes)-1)])
</pre>
<p>Das mucbot-Projekt ist frei auf <a href="https://github.com/matou/mucbot/">github</a> verfügbar. Es steht unter einer GNU General Public License. Eigentlich bin ich eher ein Fan von BSD und ähnlichen Lizenzen, aber die Verwendung von xmpppy macht dies notwendig. </p>
<p>Vielleicht kann ja der eine oder andere Teile des Mucbots verwenden oder findet hier Anregungen für neue Projekte. Ich grüße mit diesem meinem ersten Blogeintrag alle Leser von IOException.de und freue mich schon darauf bald weitere spannende Dinge mit der Welt zu teilen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2011/03/05/xmpp-multiuser-chat-bot/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GoogleMap Vaadin Widget (Google Maps JavaScript API V3)</title>
		<link>http://www.ioexception.de/2010/10/08/googlemap-vaadin-widget/</link>
		<comments>http://www.ioexception.de/2010/10/08/googlemap-vaadin-widget/#comments</comments>
		<pubDate>Fri, 08 Oct 2010 14:59:04 +0000</pubDate>
		<dc:creator>Tobias Schlecht</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[google maps]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[vaadin]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=628</guid>
		<description><![CDATA[Wer gerade dabei ist, eine Anwendung mit dem Web Application Framework Vaadin zu realisieren und darüber hinaus beabsichtigt, Google Maps in sein User Interface zu integrieren, hat mehrere Möglichkeiten.
Am naheliegendsten ist es zweifellos, einfach das fertige Vaadin Add-on GoogleMapWidget von Henri Muurimaa dafür zu nutzen, welches die Google Maps JavaScript API V2 einsetzt. Wenn man [...]]]></description>
			<content:encoded><![CDATA[<p>Wer gerade dabei ist, eine Anwendung mit dem Web Application Framework <a href="http://vaadin.com/">Vaadin</a> zu realisieren und darüber hinaus beabsichtigt, Google Maps in sein User Interface zu integrieren, hat mehrere Möglichkeiten.</p>
<p>Am naheliegendsten ist es zweifellos, einfach das fertige Vaadin Add-on <a href="http://vaadin.com/directory#addon/googlemapwidget">GoogleMapWidget</a> von Henri Muurimaa dafür zu nutzen, welches die <a href="http://code.google.com/intl/de-DE/apis/maps/documentation/javascript/v2/reference.html">Google Maps JavaScript API V2</a> einsetzt. Wenn man nun allerdings nicht nur die grundlegenden Funktionalitäten benötigt, kommt die Frage auf, ob man Anpassungen an diesem Widget vornehmen oder ein komplett neues Widget implementieren will.</p>
<p>Für den Fall, dass man sich dazu entschieden hat, ein eigenes Widget zu entwickeln, wäre es natürlich unsinnig, dafür noch die alte API Version und nicht die aktuelle Version, nämlich die <a href="http://code.google.com/intl/de-DE/apis/maps/documentation/javascript/reference.html">Google Maps JavaScript API V3</a>, zu verwenden.</p>
<div id="attachment_636" class="wp-caption alignright" style="width: 374px"><a href="http://www.ioexception.de/wp-content/uploads/2010/10/vaadin_googlemap.png"><img src="http://www.ioexception.de/wp-content/uploads/2010/10/vaadin_googlemap.png" alt="" title="Projektstruktur des Beispielprojekts IOException" width="364" height="528" class="size-full wp-image-636" /></a><p class="wp-caption-text">Projektstruktur des Beispielprojekts <strong><em>IOException</em></strong></p></div>
<p>Die meisten Entwickler möchten an dieser Stelle jedoch vermutlich kein JavaScript benutzen, da es ja einer der großen Vorteile von Vaadin ist, dass man die gesamte Anwendung in Java implementieren kann.</p>
<p>Also begibt man sich auf die Suche nach einer passenden GWT Library, welche Java Wrapper für die JavaScript API bereitstellt. Auf einer der <a href="http://code.google.com/p/gwt-google-apis/">offiziellen Seiten</a> über die GWT APIs wird man dann aber schnell durch folgende Aussage enttäuscht: &#8220;<em>At the present time, the gwt-maps API only supports Google Maps API version 2.</em>&#8221;</p>
<p>Jetzt hat man zwei Möglichkeiten: Entweder man wartet bis Google offiziell eine Library für die Version 3 zur Verfügung stellt, wozu es allerdings keine genauen Angaben gibt, wann das geschehen soll, oder aber man verwendet einfach die Alpha-Version der besagten GWT Library, die auf einer <a href="http://code.google.com/p/gwt-google-maps-v3/">inoffiziellen Seite</a> von Google zu finden ist.</p>
<p>Wer genug Zeit zum Warten und sich aus diesem Grund für die erste Möglichkeit ent- schlossen hat, braucht nun eigentlich nicht mehr weiterzulesen ;-) Allen Anderen soll nachstehend am Beispielprojekt <strong><em>IOException</em></strong> gezeigt werden, wie man das Grundgerüst für sein eigenes GoogleMap Vaadin Widget mit Hilfe der GWT Library <em>gwt-google-maps-v3</em> (Alpha-Version) erstellt.</p>
<p>Anmerkung: Im Folgenden werden lediglich die essenziellen Schritte aufgeführt. Für die Grundlagen zur Erstellung eines Vaadin Projekts wird auf das <a href="http://vaadin.com/book">Book of Vaadin</a> verwiesen, das vor allem für Anfänger sehr empfehlenswert ist.</p>
<p>Zuerst erzeugt man ein gewöhnliches Vaadin Projekt und legt daraufhin die im Screenshot dargestellte Projektstruktur an. Die JAR-Datei <em>gwt-maps3-0.2b.jar</em> (GWT Library) kann in der Rubrik <a href="http://code.google.com/p/gwt-google-maps-v3/downloads/list">Downloads</a> der bereits erwähnten inoffiziellen Seite von Google heruntergeladen werden.</p>
<p><strong>MANIFEST.MF</strong></p>
<pre class="brush: plain;">

Manifest-Version: 1.0
Vaadin-Widgetsets: de.ioexception.widgets.MainWidgetset.gwt.xml
</pre>
<p>In der Manifest-Datei muss durch das Attribut <code>Vaadin-Widgetsets</code> angegeben werden, wo sich der oberste GWT Modul Descriptor befindet, welcher das zentrale Widget Set definiert und auch als Einstiegspunkt zum Kompilieren dient.</p>
<p><strong>web.xml</strong> (Ausschnitt)</p>
<pre class="brush: xml;">

&lt;init-param&gt;
    &lt;param-name&gt;widgetset&lt;/param-name&gt;
    &lt;param-value&gt;de.ioexception.widgets.MainWidgetset&lt;/param-value&gt;
&lt;/init-param&gt;
</pre>
<p>Dies muss zusätzlich im Deployment Descriptor als <code>&lt;init-param&gt;</code> innerhalb der <code>&lt;servlet&gt;</code>-Tags aufgeführt werden.</p>
<p><strong>MainWidgetset.gwt.xml</strong> (Ausschnitt)</p>
<pre class="brush: xml;">

&lt;module&gt;
    &lt;inherits name=&quot;com.vaadin.terminal.gwt.DefaultWidgetSet&quot; /&gt;
    &lt;inherits name=&quot;de.ioexception.widgets.googlemap.GoogleMapWidgetset&quot; /&gt;
&lt;/module&gt;
</pre>
<p>Wie bereits erwähnt, wird in der Datei <em>MainWidgetset.gwt.xml</em> das zentrale Widget Set definiert. Dazu wird erst einmal vom Default Widget Set und anschließend von den GWT Modul Descriptoren der einzelnen Widget Sets geerbt. Da<br />
das gezeigte Beispielprojekt jedoch nur das GoogleMap Widget beinhaltet, ist dies hier auch die einzige Angabe.</p>
<p><strong>GoogleMapWidgetset.gwt.xml</strong> (Ausschnitt)</p>
<pre class="brush: xml;">

&lt;module&gt;
    &lt;inherits name=&quot;com.vaadin.terminal.gwt.DefaultWidgetSet&quot; /&gt;
    &lt;inherits name=&quot;com.google.gwt.maps.Maps&quot; /&gt;
    &lt;script src=&quot;http://maps.google.com/maps/api/js?sensor=false&quot; /&gt;
    &lt;source path=&quot;client&quot; /&gt;
&lt;/module&gt;
</pre>
<p>Um die JAR-Datei <em>gwt-maps3-0.2b.jar</em> (GWT Library) einzubeziehen, muss von deren GWT Modul Descriptor geerbt werden. Dies geschieht durch <code>&lt;inherits name="com.google.gwt.maps.Maps" /&gt;</code>. Durch den <code>&lt;script&gt;</code>-Tag erhält man Zugriff auf die Google Maps JavaScript API. Anschließend wird noch der Pfad, an dem sich die clientseitigen Dateien befinden, definiert.</p>
<p><strong>GoogleMap.java</strong></p>
<pre class="brush: java;">

package de.ioexception.widgets.googlemap.server;

import java.util.Map;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.ClientWidget;
import de.ioexception.widgets.googlemap.client.VGoogleMap;

@ClientWidget(VGoogleMap.class)
public class GoogleMap extends AbstractComponent
{
    @Override
    public void paintContent(PaintTarget target) throws PaintException
    {
        super.paintContent(target);
    }

    @Override
    public void changeVariables(Object source, Map&lt;String, Object&gt; variables)
    {
        super.changeVariables(source, variables);
    }
}
</pre>
<p>Die Klasse <em>GoogleMap.java</em> ist an dieser Stelle nur der Vollständigkeit halber aufgeführt und bedarf eigentlich keiner weiteren Erklärung, da dies der gewöhnliche Aufbau einer serverseitigen Widget-Klasse ist und erst einmal nicht erweitert werden muss.</p>
<p><strong>VGoogleMap.java</strong></p>
<pre class="brush: java;">

package de.ioexception.widgets.googlemap.client;

import com.google.gwt.maps.client.base.LatLng;
import com.google.gwt.maps.client.MapOptions;
import com.google.gwt.maps.client.MapTypeId;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.SimplePanel;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;

public class VGoogleMap extends Composite implements Paintable
{
    private SimplePanel wrapperPanel = null;
    private MapWidget mapWidget = null;
    private MapOptions mapOptions = null;

    public VGoogleMap()
    {
        wrapperPanel = new SimplePanel();

        initWidget(wrapperPanel);
    }

    @Override
    public void updateFromUIDL(UIDL uidl, ApplicationConnection client)
    {
        if(mapWidget == null)
        {
            initMap();
        }
    }

    private void initMap()
    {
        mapOptions = new MapOptions();

        mapOptions.setZoom(17);
        mapOptions.setCenter(new LatLng(48.42285529218286, 9.957287907600403));
        mapOptions.setMapTypeId(new MapTypeId().getSatellite());
        mapOptions.setScrollwheel(true);
        mapOptions.setDraggable(true);
        mapOptions.setNavigationControl(true);
        mapOptions.setMapTypeControl(true);

        mapWidget = new MapWidget(mapOptions);

        mapWidget.setWidth(&quot;800px&quot;);
        mapWidget.setHeight(&quot;500px&quot;);

        wrapperPanel.add(mapWidget);
    }
}
</pre>
<p>In der clientseitigen Widget-Klasse ist zu sehen, dass ein <code>MapWidget</code> nur mit <code>MapOptions</code> als Parameter initialisiert werden kann. Verpflichtend sind Werte zu den Eigenschaften <em>center</em>, <em>mapTypeId</em> und <em>zoom</em>. Im Absatz <a href="http://code.google.com/intl/de-DE/apis/maps/documentation/javascript/reference.html#MapOptions">MapOptions</a> der Google Maps JavaScript API V3 kann dies nachgelesen werden.</p>
<p><strong>IOException.java</strong></p>
<pre class="brush: java;">

package de.ioexception;

import com.vaadin.Application;
import com.vaadin.ui.Window;
import de.ioexception.widgets.googlemap.server.GoogleMap;

public class IOException extends Application
{
    @Override
    public void init()
    {
        Window mainWindow = new Window(&quot;IOException&quot;);
        GoogleMap googleMap = new GoogleMap();
        mainWindow.addComponent(googleMap);
        setMainWindow(mainWindow);
    }
}
</pre>
<p>Wie hier zu sehen ist, kann das GoogleMap Widget nun völlig unkompliziert verwendet werden. Als Beispiel dient dafür die Anwendungsklasse <code>IOException</code>, in der das initialisierte Widget einfach zum Main Window hinzugefügt wird.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2010/10/08/googlemap-vaadin-widget/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Effiziente Bereichs-Queries mit CouchDB/GeoCouch</title>
		<link>http://www.ioexception.de/2010/08/16/effiziente-bereichs-queries-mit-couchdbgeocouch/</link>
		<comments>http://www.ioexception.de/2010/08/16/effiziente-bereichs-queries-mit-couchdbgeocouch/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 17:45:12 +0000</pubDate>
		<dc:creator>Benjamin Erb</dc:creator>
				<category><![CDATA[datenbanken]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nosql]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=615</guid>
		<description><![CDATA[Im Vergleich zu klassischen SQL-Datenbank erfordern NoSQL-Datenbank vor allem bei der Datenabfrage ein Umdenken. Im Falle von CouchDB lässt sich zwar mit View Collation schon einiges erreichen, allerdings bei weitem nicht alles. Auf eine solche Grenze bin ich gestoßen, als ich Zeiträume speichern und abfragen wollte, also Einträge die ein Start- und Enddatum besitzen. Anfragen [...]]]></description>
			<content:encoded><![CDATA[<p>Im Vergleich zu klassischen SQL-Datenbank erfordern NoSQL-Datenbank vor allem bei der Datenabfrage ein Umdenken. Im Falle von <a href="http://couchdb.apache.org/">CouchDB</a> lässt sich zwar mit <a href="http://wiki.apache.org/couchdb/View_collation">View Collation</a> schon einiges erreichen, allerdings bei weitem nicht alles. Auf eine solche Grenze bin ich gestoßen, als ich Zeiträume speichern und abfragen wollte, also Einträge die ein Start- und Enddatum besitzen. Anfragen auf diese Daten könnten nun zu einem fixen Zeitpunkt alle darin ablaufenden Einträge erfragen, oder ausgeweitet auf einen Zeitraum auflisten, welche Einträge innerhalb eines Zeitfensters liegen. All dies ist mit CouchDB nicht wirklich lösbar. </p>
<p>Einen kleinen Workaround bietet die Idee, die Zeitleiste zu segmentieren und immer dann für einen Eintrag einen Key zu emitten, wenn der Zeitraum des Eintrages innerhalb dieses Bereichs liegt. Eine solche Map-Funktion könnte wie folgt aussehen. Hierbei wird für einen Eintrag jeweils ab dem Beginn für alle 5 Minuten ein Schlüssel in den Index emittiert.</p>
<p>Dokumentaufbau:</p>
<pre class="brush: jscript;">
{
   &quot;_id&quot;: &quot;s-ffc0b6b0-59d4-4a3b-ad36-7ec05e7db1de&quot;,
   &quot;begin&quot;: &quot;2010-08-05T09:11:52.156Z&quot;,
   &quot;end&quot;: &quot;2010-08-05T09:23:13.457Z&quot;
}
</pre>
<p>Map-Funktion:</p>
<pre class="brush: jscript;">
//length of time segment (here 5 min)
var periodLength = (60*5);

function(doc)
{
        if(doc.begin &amp;&amp; doc.end)
        {
                //start and end time as UNIX timestamps (seconds, not milliseconds)
                var begin =  Math.round(new Date(doc.begin).getTime()/1000);
                var end =  Math.round(new Date(doc.end).getTime()/1000);

                //calculate first matching segment of period
                var p = (begin - (begin%periodLength));

                //emit key for each matching period
                while(p&lt;=end)
                {
                        emit([p, doc._id], null);
                        p = p + periodLength;
                }
        }
}
</pre>
<p>Der resultierende View sieht dann in etwa so aus:<br />
<a href="http://www.ioexception.de/wp-content/uploads/2010/08/btree_periodical.png"><img src="http://www.ioexception.de/wp-content/uploads/2010/08/btree_periodical.png" alt="" title="btree_periodical" width="600" height="282" class="alignnone size-full wp-image-614" /></a><br />
Oder als Abfrage:<br />
<code>http://localhost:5984/entries/_design/entries/_view/docsByPeriodList?startkey=[1280998800]&#038;endkey=[1281000193,{}]</code></p>
<pre class="brush: jscript;">
{&quot;total_rows&quot;:3,&quot;update_seq&quot;:2,&quot;offset&quot;:0,&quot;rows&quot;:[
{&quot;id&quot;:&quot;s-ffc0b6b0-59d4-4a3b-ad36-7ec05e7db1de&quot;,&quot;key&quot;:[1280999400,&quot;s-ffc0b6b0-59d4-4a3b-ad36-7ec05e7db1de&quot;]15,&quot;value&quot;:null},
{&quot;id&quot;:&quot;s-ffc0b6b0-59d4-4a3b-ad36-7ec05e7db1de&quot;,&quot;key&quot;:[1280999700,&quot;s-ffc0b6b0-59d4-4a3b-ad36-7ec05e7db1de&quot;],&quot;value&quot;:null},
{&quot;id&quot;:&quot;s-ffc0b6b0-59d4-4a3b-ad36-7ec05e7db1de&quot;,&quot;key&quot;:[1281000000,&quot;s-ffc0b6b0-59d4-4a3b-ad36-7ec05e7db1de&quot;],&quot;value&quot;:null}
]}
</pre>
<p>Eine viel bessere Lösung bietet jedoch die CouchDB-Erweiterung <a href="http://github.com/vmx/couchdb">GeoCouch</a>. Dank des R-Trees lassen sich Bereichtsabfragen effizient durchführen. Da GeoCouch eigentlich für zweidimensionale Geokoordinaten gedacht, muss sie und die GeoJSON-Syntax etwas missbraucht werden. Anstatt einer WGS84-Koordinate emittieren wir einfach einen UNIX-Zeitstempel und lassen den anderen Grad leer:</p>
<pre class="brush: jscript;">
function(doc)
{
        if(doc.begin &amp;&amp; doc.end)
        {
                //start and end time as UNIX timestamps (seconds, not milliseconds)
                var begin =  Math.round(new Date(doc.begin).getTime()/1000);
                var end =  Math.round(new Date(doc.end).getTime()/1000);

                emit(
                        {
                                type: &quot;Point&quot;,
                                bbox : [0,start,0,end]
                        }, null
                );
        }
}
</pre>
<p>So lassen sich nun effiziente Bereichsabfragen durchführen:<br />
<code>http://localhost:5984/entries/_design/entries/_spatial/entriesByPeriod?bbox=0,1280998800,0,1281000600</code></p>
<pre class="brush: jscript;">
{&quot;update_seq&quot;:16,&quot;rows&quot;:[
{&quot;id&quot;:&quot;s-ffc0b6b0-59d4-4a3b-ad36-7ec05e7db1de&quot;,&quot;bbox&quot;:[0,1280999512,0,1281000193],&quot;value&quot;:null}
]}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2010/08/16/effiziente-bereichs-queries-mit-couchdbgeocouch/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Atom Feeds in Java mit ROME direkt lesen</title>
		<link>http://www.ioexception.de/2010/06/13/atom-feeds-in-java-mit-rome-direkt-lesen/</link>
		<comments>http://www.ioexception.de/2010/06/13/atom-feeds-in-java-mit-rome-direkt-lesen/#comments</comments>
		<pubDate>Sun, 13 Jun 2010 10:18:47 +0000</pubDate>
		<dc:creator>Benjamin Erb</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[atom]]></category>
		<category><![CDATA[rss]]></category>

		<guid isPermaLink="false">http://www.ioexception.de/?p=577</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>Für die Interaktion mit Feeds gibt es in Java die weit verbreitete <a href="http://rome.dev.java.net/">ROME-Library</a>. Diese Library unterstützt sowohl <a href="http://de.wikipedia.org/wiki/RSS">RSS</a> als auch <a href="http://de.wikipedia.org/wiki/Atom_%28Format%29">ATOM</a> 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.</p>
<p>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 <a href="http://tools.ietf.org/html/rfc4287">muss in Atom</a> 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. </p>
<p>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 <a href="http://rome.dev.java.net/apidocs/1_0/com/sun/syndication/io/SyndFeedInput.html#setPreserveWireFeed%28boolean%29">dieses Flag</a> gesetzt ist, lässt sich später der Feed im Originalformat (<a href="http://rome.dev.java.net/apidocs/1_0/com/sun/syndication/feed/WireFeed.html">WireFeed</a>) abrufen:</p>
<pre class="brush: java;">
InputSource source = new InputSource(...);
SyndFeedInput feedInput = new SyndFeedInput();
feedInput.setPreserveWireFeed(true);
SyndFeed feed = feedInput.build(source);
</pre>
<p>Später bietet dann der Syndication Feed Zugriff auf den  konkreten Feed:</p>
<pre class="brush: java;">
WireFeed wireFeed = (WireFeed) feed.originalWireFeed();
if(wireFeed instanceof com.sun.syndication.feed.atom.Feed)
{
   String feedId = ((Feed) wireFeed).getId()
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ioexception.de/2010/06/13/atom-feeds-in-java-mit-rome-direkt-lesen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

