353 Tage zuvor: Restore erfolgreich

Heute ist es 303 Tage her, dass diese Webseite offline ging. Eine ziemlich lange Zeit, selbst f├╝r mich. Allerdings habe ich nur bedingt zu dieser beachtlichen Wiederherstellungszeit beigetragen. Gut einen Tag habe ich f├╝r die eigentliche Wiederherstellung auf einem anderen Webserver gebraucht. Allerdings hat es gut zehn Monate gedauert, bis ich wieder auf meine Daten zugreifen konnte.

Am 5. November waren meine Webseiten nicht mehr erreichbar. Ein Zugriff auf den Server war nicht mehr m├Âglich, und auch ein Fern-Reboot brachte leider keine Abhilfe. Ein freundliches Nachfragen beim Hoster hat allerdings auch keine L├Âsung gebracht – bis zur Antwort waren bereits einige Wochen verstrichen. Da es sich bei dem Server um einen RaspberryPi in einem gratis-Hosting Programm handelte, kann man sich auch nur bedingt ueber Antwortzeiten beschweren. Jedenfalls wurden mir zwei Optionen angeboten:

  1. Die SD-Karte zum booten neu aufsetzen lassen, was eine Neukonfiguration erfordert.
  2. Den RasPi zur├╝ck schicken lassen, womit der Platz im Rechenzentrum wegfallen w├╝rde.

Das Hosting-Programm wurde in der Zwischenzeit eingestellt. Option 2 hie├č daher auch, dass ein Umzug auf einen neuen Server anstehen w├╝rde. Da ich jedoch zu diesem Zeitpunkt (Dezember) bereits einige Zeit mit warten verbracht hatte, entschloss ich mich f├╝r Option 2. In Vorbereitung auf den Umzug der Webseiten erstellte ich schon einmal einen neuen Server, diesmal in der Amazon-Cloud.

Nach einigen Tagen lieft der Server in der Cloud, samt verteilter Ressourcen und Nutzung von etlichen AWS Diensten. Die Performance-Unterschiede sind gewaltig – und nebenbei habe ich noch das Know-How f├╝r Cloud-basierte Webseiten aufgebaut. Alles in allem eine sehr positive Erfahrung! Jedenfalls bis die erste Rechnung kam und das Aufr├Ąumen und das Zusammenstreichen der Dienste auf das wirklich Notwendige anfing. Am Ende kostete mich der Server samt aller Ressourcen knapp $5.50 pro Monat. Ein akzeptabler Preis.

Was nun noch fehlte, waren meine Daten. Einige Webseiten konnte ich von Backups wiederherstellen. Das Blog jedoch basiert auf einer Datenbank – und f├╝r die hatte ich kein Offsite-Backup eingerichtet. Es hie├č also warten bis der RasPi eintrifft. Und das war, nach etlichen Tickets, Emails und Tweets, gestern dann endlich der Fall. 303 Tage nachdem die Webseite offline ging.

Nun also ist das Blog wieder verf├╝gbar. Wenn ich mir anschaue wie viele Artikel ich in den letzten Jahren ├╝ber diesen Zeitraum geschrieben habe, hat das Internet sie sicherlich nicht vermisst. Allerdings hatte ich durchaus ab und an das Bed├╝rfnis einige Tricks nieder zu schreiben. Wollen wir hoffen, dass derlei auch in n├Ąchster Zukunft weiterhin der Fall sein wird.

673 Tage zuvor: Twitter-Home als Feed mit Javascript

Vor gut zwei Jahren hat Twitter einen wichtigen Schritt zur Datensicherheit gemacht. Mit Einf├╝hrung ihrer API 1.1 wurde zum Ausf├╝hren vieler Funktionen eine OAuth Authentifizierung n├Âtig. Und bei der Implementierung in (Web-) Applikationen ist dies auch meistens kein Problem. Anders sieht es da schon mit JavaScript aus.

Generell ist von einer Implementierung von OAuth in JavaScript auch deutlich abzuraten! Da die privaten Schl├╝ssel zur einer eindeutigen Identifizierung im Klartext dem Client vorliegen m├╝ssen, gibt es keine M├Âglichkeit diese ausreichend vor Fremdzugriff zu sch├╝tzen. F├╝r mein letzte Projekt, eine personalisierte Browser-Startseite, war jedoch eine Server-seitige Implementation nicht zielf├╝hrend.

kbo Startpage

Beim Herausarbeiten der Funktionalit├Ąt stie├č ich immer wieder auf Aussagen das dies generell nicht m├Âglich sei (sogar von Twitter-Mitarbeitern). Selbstredend ist dies nicht korrekt; wenn auch die Implementation, vor allem dank des faszinierenden Signatur-Prozesses, durchaus herausfordernd ist. Um meinen Teil zum aufr├Ąumen mit diesem Ger├╝cht beizutragen, hier jedenfalls die Fr├╝chte meiner Arbeit.

Um das Skript auszuf├╝hren ben├Âtigt man:

  1. Eine Twitter-App (zu erstellen)
  2. Authentifizierten Zugriff der App auf das eigene Profil
  3. Die CryptoJS library (hmac-sha1.js reicht)
  4. jQuery (zumindest in dem Beispiel)

F├╝llt man die Variablen f├╝r Consumer und Access Token aus, sollte der Aufruf von loadTwitter() das Array tweets[] mit den letzten Tweets der Twitter Home-Timeline bef├╝llen. Und die kann man dann, zum Beispiel, in einer personalisierten Startseite verwenden.

/*
 * Retrieve Tweets from your personal Twitter home via REST.
 * (c)2015 by Kai Boenke [code@boenke.info]
 * Requires CryptoJS (hmac-sha1.js): https://code.google.com/p/crypto-js/
 * Requires jQUery: https://jquery.com/
 */
var tweets = [];
function loadTwitter(){
	twitterURL =			"https://api.twitter.com/1.1/statuses/home_timeline.json";
	twitterURLmethod =		"GET",
	twitterKey =			"xxxxxxxxxxxxxxxxxxxxxxxxx"; //Consumer Key (User)
	twitterSecret =			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //Consumer Secret (User)
	twitterToken =			"99999999-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //Access Token (App)
	twitterTokenSecret =	"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //Access Token Secret (App)
	twitterNonce =			getNonce(32);
	twitterTimestamp =		Math.round(Date.now()/1000);
	
	// Generate oAuth Signature (https://dev.twitter.com/oauth/overview/creating-signatures)
	twitterParameter = [
		encodeURI('oauth_consumer_key='+twitterKey),
		encodeURI('oauth_nonce='+twitterNonce),
		encodeURI('oauth_signature_method='+"HMAC-SHA1"),
		encodeURI('oauth_timestamp='+twitterTimestamp),
		encodeURI('oauth_token='+twitterToken),
		encodeURI('oauth_version='+"1.0")
	];
	twitterParameter.sort();
	twitterSignatureBase =	twitterURLmethod +"&"+ encodeURIComponent(twitterURL) +"&"+ encodeURIComponent(twitterParameter.join("&"));
	twitterSignatureKey =	encodeURIComponent(twitterSecret) +"&"+ encodeURIComponent(twitterTokenSecret);
	twitterSignature =		encodeURIComponent(CryptoJS.HmacSHA1(twitterSignatureBase, twitterSignatureKey).toString(CryptoJS.enc.Base64));
	
	// Get tweets
	$.ajax({
		type:		twitterURLmethod,
		url:		twitterURL,
		headers:	{
			'Authorization': 'OAuth '+
				'oauth_consumer_key="'+ twitterKey +'", '+
				'oauth_nonce="'+ twitterNonce +'", '+
				'oauth_signature="'+ twitterSignature +'", '+
				'oauth_signature_method="HMAC-SHA1", '+
				'oauth_timestamp="'+ twitterTimestamp +'", '+
				'oauth_token="'+ twitterToken +'", '+
				'oauth_version="1.0"'
		}
	}).done(function(twitterData){
		// Retrieve tweets
		$.each(twitterData, function(i, tweet){
			tweets.push({
				timestamp: (new Date(tweet.created_at)).getTime(),
				link: "https://twitter.com/"+ tweet.user.screen_name +"/status/"+ tweet.id_str,
				value: tweet.text
			});
		});
	});
}

868 Tage zuvor: Intelligenz f├╝r das Intelligente Wohnen

So ein Smart-Home ist schon etwas feines: Lichter gehen von alleine aus, wenn die werten Familienmitglieder es mal wieder vergessen, der freundliche Hausgeist erinnert einen daran rechtzeitig die M├╝lltonnen an die Strasse zu stellen und wenn mal niemand zu Hause ist kann das Haus von ganz allein so tun als ob es doch so w├Ąre. Um das zu bewerkstelligen muss man zum einen selbstredend die entsprechende Hardware haben. Zum anderen braucht man auch noch eine Zentrale, die alles miteinander verbindet – und letztendlich steuert.

Soweit, so einfach. Doch es bringt auch eine Reihe neuer Herausforderungen mit sich. Zum Beispiel die neuartige Frage warum eine Lampe sich morgens partout nicht einschalten lassen will. Oder weshalb das Wohnzimmer auf einmal rot leuchtet. Oder warum morgens das Radio l├Ąuft. Oder warum allabendlich die Beleuchtung im Garten angeht. Oder, oder, oder…

Was daf├╝r bislang fehlte war ein Schaltplan f├╝r das Smarthome; denn zumindest meine Schaltzentrale bietet keine ad├Ąquate L├Âsung um derlei Zusammenh├Ąnge klar darzustellen. Aber daf├╝r gibt es eine API samt XML Export der Konfiguration. Was fehlt ist lediglich ein Konverter in eine anschaulichere Darstellungsweise, zum Beispiel ein UML Diagramm (mein pers├Ânlicher Favorit f├╝r derlei ist yUML). Und das sieht dann in etwa so aus:

Schaltbild eines Smarthome

Das Bild muss sich in seiner Komplexit├Ąt nicht unbedingt hinter klassischen Schaltpl├Ąnen verstecken, hilft aber ebenso gut um die Fehlerursache einzugrenzen.

Das Script zum konvertieren der XML Datei in ein PHP-Array gibt es in meinem github Repository. Viel Spa├č beim visualisieren!

978 Tage zuvor: Update mit noch mehr Updates

Scheinbar schreibe ich dieses Blog nur noch, um es mit Updates zu best├╝cken. Jedenfalls ist das in der Tat (schon wieder) der Grund aus dem ich einen Artikel schreibe. Aber man wei├č ja nie wie es weiter geht…

Dem geneigten Leser mag es vielleicht aufgefallen sein, dass dieses Blog eine Weile lang nicht erreichbar war. Grund ist, dass es in der Zwischenzeit von einem Professionellen Webhoster auf eine Self-Hosting Plattform umgezogen ist. Die netten Menschen bei edis.at bieten n├Ąmlich ein tolles Gratis-Hosting f├╝r Raspberry-PI Module an. Nachdem ich mir dort vor etliche Monaten einen Slot sichern konnte, wurden nach und nach Webseiten umgezogen.

Leider hat sich dabei heraus gestellt, dass dieses Blog nicht so ohne weiteres auf der neuen Plattform (lighttpd und MySQL unter Debian) lauff├Ąhig ist. Und mit der Zeit war es auch nicht so ├╝ppig bestellt, als das ich mich direkt dahinter h├Ąngen konnte. Im Endeffekt lag es dann an ein paar fehlenden PHP-Modulen. Kleiner Tip fuer alle, die Textpattern unter lighttpd laufen lassen wollen: Mit einem 404-Handler kann man saubere URL’s realisieren!

server.error-handler-404 = "/textpattern/index.php"

Wie dem auch sei, mittlerweile scheint wieder alles zu funktionieren – wenngleich auch weniger performant als zuvor. Und wo ich schonmal dabei war, wurde auch gleich eine aktuelle Version eingespielt.

Jetzt fehlen nur noch neue Artikel…

1426 Tage zuvor: Update mit Updates

Scheinbar habe ich mir weit ├╝ber ein halbes Jahr Zeit gelassen um das Update auf Textpattern 4.5.4 (dem CMS f├╝r dieses Blog) durchzuf├╝hren. Nicht, weil es so viel Arbeit ist; um genau zu sein hat es keine zehn Minuten gedauert. Eher weil es immer andere Dinge zu tun gab. Zeit raubend sind eher die Arbeiten an der Seite selbst, die im Laufe der Zeit liegen geblieben sind – aber auch die sind nunmehr abgearbeitet. Eine kleine ├ťbersicht der ├änderungen:

  • Kommentare erfordern keine Email-Adresse mehr
  • Die Suchfunktion liefert nun Ergebnisse
  • Tag-Suchen zeigen jetzt die gesamten Artikel an, nicht nur eine Ergebnisliste
  • Die Artikelnavigation am Ende der Seite wird wieder angezeigt
  • Sowohl Anderswo als auch Andere wurden repariert und aktualisiert (soweit m├Âglich)

Au├čerdem wurden diverse Anpassungen am Design durchgef├╝hrt.

Wie immer gilt: Wer Fehler findet bitte melden! Ich werde dazu die kommenden Wochen die Anzeige von Fehlermeldungen aktiviert lassen. Als kleinen Ansporn habe ich insgesamt f├╝nf Artikel freigeschaltet, die seit einiger Zeit auf Ver├Âffentlichung gewartet haben.

Weiterlesen?

1426 Tage zuvor: Sticky-Navigation in Prototype

Sticky-Navigationen sind ja irgendwie ein Trend: Die Navigationsleiste einer Webseite bleibt dabei am oberen Fensterrand kleben, wenn man nach unten scrollt. Ist ja auch eine praktische Sache, manchmal jedenfalls.

Die g├Ąngigen Implementierungen greifen jedoch auf jQuery zur├╝ck. Soweit nichts verwerfliches, ist es doch eine weit verbreitete Standard-Bibliothek. F├╝r die Implementierung auf diesem Blog wollte ich jedoch die ohnehin bereits verwendete Bibliothek Prototype nutzen. Doch leider gab es dazu keine L├Âsung. Oder zumindest konnte ich keine finden. F├╝r die nachfolgenden Leidensgenossen hier ein passende L├Âsung:


1436 Tage zuvor: Zigeuner-So├če

Dem geneigten Leser mag bekannt sein, dass mich haupts├Ąchlich der Hei├čhunger auf geliebte, heimische Gerichte zum Kochen gebracht hat. Kochen soll in diesem Zusammenhang, so traurig es auch sein mag darauf hinzuweisen, auf das Zubereiten von Gerichten von Grund auf hei├čen. Keine T├╝ten-So├čen, keine Dosen-Ravioli und ganz sicher auch keine Mikrowellen-Currywurst.

Eine letzte Bastion, die es zu erklimmen galt, war die Zigeuner-So├če. Einige erste Versuche sind leider nicht sehr erfolgreich geendet (zumindest was meine geschmackliche Erinnerung betraf), daher hatte ich mich zuletzt nicht mehr sehr h├Ąufig daran versucht. Heute jedoch wurden die Bem├╝hungen von Erfolg gekr├Ânt. Damit es beim n├Ąchsten Mal nicht wieder im Desaster endet, hier das (ziemlich einfache) Rezept:

  • Zwei Zwiebeln, in Halbkreise geschnitten
  • Eine Knoblauch-Zehe
  • Zwei Paprika (rot & gr├╝n), in kleine Streifen geschnitten
  • Circa f├╝nf p├╝rierte Tomaten

Die Zwiebeln scharf anbraten. Sobald die Kanten der Zwiebeln braun werden Knoblauch und Paprika dazugeben und ebenfalls mit scharf anbraten. Mit dem Tomaten-P├╝ree abl├Âschen und alles kurz aufkochen. Mit Salz, Pfeffer, Paprika, ein wenig Chilli und s├╝├čem Curry nach Belieben abschmecken. Anschlie├čend circa 30 Minuten k├Âcheln lassen.

Dazu passt nat├╝rlich nur eines: Schnitzel mit Pommes! Obwohl es auf einem Hotdog bestimmt auch ganz vorz├╝glich schmecken d├╝rfte. Zigeuner-Hotdog?

1439 Tage zuvor: Bubble-Sort in PHP

Da bin ich die Tage doch glatt dazu gekommen einige (Er-)Kenntnisse meines Algorithmus-Kurses vom letzten Jahr anzuwenden. Grund war die fehlende Funktion zur Sortierung eines Mehrdimensionalen Arrays basierend auf einem Sub-Key. Aber gut, so konnte ich mir wenigstens beweisen das ich das Konzept noch verstanden habe:

// (Bubble)Sort
do{
	$swapped = false;
	for($i=0; $i<(count($calendar)-1); $i++){
		if($calendar[$i]["stamp"] > $calendar[$i+1]["stamp"]){
			$swap = $calendar[$i];
			$calendar[$i] = $calendar[$i+1];
			$calendar[$i+1] = $swap;
			$swapped = true;
		}
	}
}while($swapped != false);

Mal schauen wann mir dann eine Anwendung f├╝r die Algorithmen zu Graphen in den Schoss f├Ąllt.

PS: Wieso gibt es in PHP eigentlich kein array_swap()?

1441 Tage zuvor: The Gathering

Ich bin jetzt schon seit zwei Tagen auf der Suche nach einem ganz bestimmtes Lied. Gothic war es wohl. Circa im Jahre 2001 – geh├Ârt wohlgemerkt. Trotz mannigfaltigen Anfragen konnte ich es bis dato nicht entdecken.

Aber immerhin habe ich dabei viel Musik zu h├Âren bekommen. Ein wirklicher Fund, wie ich finde, ist The Gathering’s if_then_else:

1553 Tage zuvor: Stadt des Winds

Nun also Chicago. Ganze f├╝nf Jahre hat es gedauert. Zumindest wurde eine Gesch├Ąftsreise mit freiem Wochenende daraus. Und das Fr├╝hst├╝cksbuffet im Hotel erinnerte doch arg an alte Zeiten. Nicht des Essens wegen (grausam). Vielmehr kennt man fast jeden, der im Esssaal sitzt – alles Kollegen. Zuletzt passierte mir dies in einem ├Ąhnlich g├╝nstig (was das berufliche betrifft) gelegenen Hotel im Stuttgarter Raum.

Aber zur├╝ck zu Chicago, den sub-urbanen Teil in dem mein Hotel gelegen ist. Es erinnert einen doch arg Wohnsiedlungen die aussehen wie im Film: Lang-gezogene, gr├╝ne Vorg├Ąrten mit Auffahrten f├╝r die diversen Autos. Wei├če Briefk├Ąsten am Stra├čenrand soweit die Strasse reicht. Chicago selbst hingegen ist anders. Anders als so vieles in diesem Land: Eine sp├╝rbar alte Stadt. Das wird einem nicht nur durch die tats├Ąchlich nennenswert alte Geschichte auf, sondern man sp├╝rt es auch. Die ├╝berall vorhandenen Industriegeb├Ąude erinnern an die Zeiten der Industrialisierung, allerdings weniger dreckig als der Ruhrpott.

CHicago

Doch auch die klassischen Touristen-Attraktionen sind durchaus sehenswert: The Art Institute of Chicago (Zeit mitbringen! Auch wenn Google einem hier die Gem├Ąlde erkl├Ąren kann), Grant Park , eine Boots-Tour ├╝ber den Chicago-River oder auch einfach nur durch die Stadt zu spazieren. Chicago ist definitiv eine Reise wert! Und es gibt immer noch so viel zu sehen… Einzig mit der typischen Chicago-style Pizza konnte ich mich nicht so recht anfreunden. Sei’s drum.