backgroundimage

marbetschar - Coldfusion, Klettern, Freizeit

Joint Venture von Apple und Ersatzgeräte: Das geht doch besser?!

0

Das Joint Venture Programm von Apple an und für sich ist ja ganz nett, aber man merkt deutlich das dieser sogenannte "Business Support" noch in den Kinderschuhen steckt:

  • Wenn gefordert sind immer zuwenig ausgebildete Fachkräfte vor Ort
  • Die Wartezeiten sind trotz Versprechungen einer bevorzugten Behandlung seitens Apple viel zu lang
  • Ersatzgeräte sind zwar prinzipiell vorhanden, werden aber mit veralteten Betriebssystem Versionen ausgeliefert

Ich hab für mein Macbook Air ein Ersatzgerät bekommen, dieses aber noch mit Snow Leopard - Resultat: Ich konnte zwar mein Time Machine Backup wiederherstellen, aber die Programme funktionieren nicht da diese für Lion konzipiert wurden.

Extrem ärgerlich dabei: Der Mac App Store wurde ebenfalls wiederhergestellt und lässt sich nicht starten, ein Upgrade auf Lion ist unter diesen Bedingungen unmöglich!! Vielen Dank Apple - ich muss nun Stunden damit verbraten das Ersatzgerät komplett neu zu installieren, nur weil ihr ein einfaches Update nicht ausführen konntet!

Ganz ehrlich, ein funktionierender Business Support der was taugt schaut anders aus!!

Kundendienst: Swisscom vs. Sunrise

1

Kundendienst à la Swisscom

Gerade eben hatte ich ein Telefonat mit dem Swisscom Kundendienst. Ich bin zurzeit stolzer Besitzer eines Nadel & DSL Pro Kombiangebots. Aufgrund meines Umzugs von St. Gallen nach Zürich, musste ich aber meinen DSL Vertrag kündigen.

Vertraglich bin ich leider bis Ende Februar an das DSL gebunden, die Nachmieterin zieht allerdings bereits Ende Januar in meine alte Wohnung ein und mich muss zusätzlich bis dahin doppelt Miete zahlen.

Nach Erklärung der Situation und einer kurzen Rücksprache der Kundendienstmitarbeiterin war die Situation nach nicht einmal 10 Minuten zu meiner vollsten Zufriedenstellung geklärt:

Abschaltung des DSL am Ende des Januars und Verzicht auf die 59.- Ende Februar! Das nenne ich einen super Kundenservice!!

"Kundendienst" à la Sunrise

Letztes Jahr bin ich (zum Glück) zu Swisscom gewechselt. Aus Kulanz und weil ich damals ebenfalls noch zwei Monate an den Vertrag gebunden war, hatte ich in den zwei Folgemonaten die Kosten ebenfalls doppelt bezahlen müssen (Sunrise und Swisscom). Ist zwar ärgerlich, aber ok. Im dritten Monat habe ich aber von Sunrise noch zusätzlich eine Rechnung erhalten, mit einem erneuten Monatsbetrag - dies obwohl ich die Nr bereits seit drei Monaten nicht mehr verwendet hatte!

Mehrere Telefonate, Blogeinträge und Mails später ist die Situation noch immer nicht geklärt und die Sunrise beauftragt doch tatsächlich wegen 20.- noch ein Inkasso Unternehmen! Geht's noch?!

SBB: Kein GA - automatisch Verbrecher?!

0

Wieder einmal eine nervenaufreibende Geschichte über die Schweizerische Bundesbahnen (SBB):

Wie in meinem letzten Eintrag berichtet, bin ich zurzeit im Wiederholungskurs der Armee. Stationiert bin ich in Monte Ceneri im Tessin. Das bedeutet ich darf zweimal wöchentlich eine Strecke von jeweils vier Stunden mit der ÖV bewältigen. Wie ihr wisst, besitzt die SBB das Monopol auf die öffentlichen Verkehrsmittel in der Schweiz.

Ich habe also letzten Montag den Zug (mit Vollpackung und im Tarnanzug wohlgemerkt!) von Schaffhausen Richtung Zürich betreten. Abfahrtszeit war um 06:07 in der Früh.

Es dauerte keine 15 Minuten da kam ein weiterer Mann in Uniform auf mich zu: Der Kondikteur. Der überfleissige Herr wollte meinen Marschbefehl sehen. Ein normaler Mensch fährt natürlich nicht in Uniform und das schon gar nicht mit Vollpackung an einem Montagmorgen in der Früh!

“Er tut doch nur seinen Job.”

Na gut, ich krahme also in meinem Portemonnaie. Da merke ich, dass ich den Marschbefehl zuhause vergessen habe und mein GA seit zwei Tagen abgelaufen ist. Kaum habe ich das dem Kondikteur mitgeteilt, beginnt dieser meine Personalien aufzunehmen.

Der gute Mann möchte also einen Ausweis sehen und drückt mir kurz darauf eine Quittung in die Hand: Innert 10 Tagen ist der Marschbefehl auf einer SBB Station vorzuweisen, ansonsten sind CHF 101.- zu bezahlen?!

“Er tut doch nur seinen Job.”

Vielen Dank liebe SBB - jetzt darf ich an meinem ansonsten schon kurzen Wochenende noch auf eine SBB Station rennen.

Die SBB täte gut daran, ein wenig mehr gesunden Menschenverstand walten zu lassen!

Mein Sunrise: Kündigung übers Web?

0

Heute hab ich mich durch die Weboberfläche meines Kontos des Mobilfunkanbieters Sunrise gehangelt. Die Anforderung: Kündigung meines Abonnements. Der Grund: Wechsel zu Swisscom. Was simpel klingt ist gar nicht so einfach, zumal Sunrise Vertragsänderungen mit Vertragsverlängerung gleichsetzt.

Zum Glück gibt es noch den (in mattem Grau gehaltenen und somit fast unsichtbaren) Hilfebutton mit der freundlichen Aufschrift “Kontakt”. Ich starte also den Assistenten um meine Kontaktanfrage zu Kategorisieren. Auf der zweiten Seite lächelt mich ein vertrauenserweckender Radiobutton an: “Vertragsänderungen”. Ratet mal welche Option sich dahinter verbirgt. Logisch: Vertragsverlängerung - nichts was mir das Kündigen auch nur im Ansatz auf einfache Art und Weise ermöglichen würde.

Liebe Sunrise, nennt ihr das Dienst am Kunden?

HQL Queries und ORM Properties: Kompromiss

0

Wie bereits in einem vorherigen Beitrag erwähnt, handhabt Hibernate HQL Queries unter Berücksichtigung der Gross/Kleinschreibung. Der Nachteil dieses Fakts bekahm ich gestern zu spüren als ich einige Funktionen programmierte, die Blogeinträge auslesen sollten.

Die Funktionalität die umgesetzt werden sollte, war ein guter alter Pageturner: Es werden maximal 10 Eintäge auf der Startseite angezeigt werden und durch Links kann man vor- und zurückblättern.

<cfif local.offset>
	<p><a href="#buildURL('blog.entries#local.queryString#&offset=#local.offsetNewer#')#" title="neuere">neuere</a></p>
</cfif>

<cfif local.entryCount GT local.offsetOlder>
	<p><a href="#buildURL('blog.entries#local.queryString#&offset=#local.offsetOlder#')#" title="ältere">ältere</a></p>
</cfif>

Um die Links korrekt ein- und ausblenden zu können, soll die komplette Anzahl Links (der local.entryCount) anhand der übergebenen Parameter ermittelt werden. Es gibt also zwei Funktionen im Service: Eine list und eine count Funktion - beide machen eigentlich dasselbe:

<cffunction name="count" returntype="numeric" access="public" output="false" hint="Zählt die Anzahl Einträge">

	<cfset local.ormResult = executeQuery(executionMode='count',argumentCollection=arguments) />

	<cfset local.result = 0 />
	<cfif arrayLen(local.ormResult)>
		<cfset local.result = local.ormResult[1] />
	</cfif>

	<cfreturn local.result />
</cffunction>

<cffunction name="list" returntype="array" access="public" output="false" hint="Liest Einträge aus">
	<cfreturn executeQuery(executionMode='default',argumentCollection=arguments) />
</cffunction>

Die Magie geschieht in den executeQuery und prepareHQL Methoden. Diese parsen als erstes die argumentCollection und führen das HQL - Query aus.

<cffunction name="executeQuery" returntype="array" access="private" output="false" hint="Führt ein HQL Query aufgrund der übergebenen Argumente aus">
	<cfargument name="executionMode" type="string" required="false" default="default"	hint="Welche Art von Query ausgeführt werden soll: count, default, search" />

	<cfset local.hql = prepareHQL(argumentCollection=arguments) />

	<cfreturn ormExecuteQuery(local.hql.statement,local.hql.args,false,local.hql.options) />
</cffunction>


<cffunction name="prepareHQL" returntype="struct" access="private" output="false" hint="Generiert das HQL Statement">
	<cfargument name="executionMode"		type="string"		required="false"	default="default"	hint="Welche Art von Query ausgeführt werden soll: count, default" />
	<cfargument name="search"						type="string"		required="false"	default=""	hint="Freitext nach dem gesucht werden soll" />
	<cfargument name="ident"						type="guid"			required="false"	hint="Schlüssel des Eintrags" />
	<cfargument name="isActive"					type="boolean"	required="false"	hint="Ob der Eintrag aktiv ist" />
	<cfargument name="Title"						type="string"		required="false"	hint="Titel des Eintrags" />
	<cfargument name="urlTitle"					type="string"		required="false"	hint="Url sicherer Titel" />
	<cfargument name="Teaser"						type="string"		required="false"	hint="Einleitung des Eintrags" />
	<cfargument name="Body"							type="string"		required="false"	hint="Inhalt des Eintrags" />
	<cfargument name="Download"					type="string"		required="false"	hint="Downloadlink" />
	<cfargument name="Website"					type="string"		required="false"	hint="URL zu einer Webseite" />
	<cfargument name="GeoLocation"			type="string"		required="false"	hint="Karten URL" />
	<cfargument name="postedAt"					type="any"			required="false"	hint="Veröffentlichungs-Zeitpunkt" />
	<cfargument name="postedFrom"				type="any"			required="false"	hint="Ab Veröffentlichungs-Zeitpunkt" />
	<cfargument name="postedTo"					type="any"			required="false"	hint="Bis Veröffentlichungs-Zeitpunkt" />
	<cfargument name="postedBy"					type="any"			required="false"	hint="Verfasser" />
	<cfargument name="joinCategoryArgs"	type="struct"		required="false"	default="#structNew()#"	hint="Bedingungen die auf die verknüpften Kategorien zutreffen müssen" />
	<cfargument name="orderBy"					type="string"		required="false"	default="postedAt DESC"	hint="Sortierreihenfolge der Resultate" />
	<cfargument name="offset"						type="numeric"	required="false"	default="0"	hint="Offset ab welchem Einträge geliefert werden sollen" />
	<cfargument name="maxResults" 			type="numeric" 	required="false"	hint="Maximale Anzahl an Einträgen die ausgelesen werden sollen" />

	<cfset local.hql.select			= arrayNew(1) />
	<cfset local.hql.joins			= arrayNew(1) />
	<cfset local.hql.group			= arrayNew(1) />
	<cfset local.hql.conditions	= arrayNew(1) />
	<cfset local.hql.sort				= arrayNew(1) />
	<cfset local.hql.args				= structNew() />
	<cfset local.hql.options		= structNew() />

	<cfset arrayAppend(local.hql.select,'SELECT') />
	<cfset arrayAppend(local.hql.conditions,'WHERE') />
	<cfset arrayAppend(local.hql.group,'GROUP BY') />
	<cfset arrayAppend(local.hql.sort,'ORDER BY') />

	<cfif arguments.executionMode EQ 'default'>
		<cfloop list="offset,maxResults" index="local.option">
			<cfif structKeyExists(arguments,local.option)>
				<cfset local.hql.options[local.option] = arguments[local.option] />
			</cfif>
		</cfloop>
	</cfif>

	<cfset arrayAppend(local.hql.group,'main') />

	<cfloop list="#arguments.orderBy#" index="local.sort">
		<cfset arrayAppend(local.hql.sort,lCase('main.#local.sort#')) />
	</cfloop>

	<cfloop collection="#arguments#" item="local.arg">
		<cfif isNull(arguments[local.arg])>
			<cfset structDelete(arguments,local.arg) />
		</cfif>
	</cfloop>

	<cfif arguments.executionMode EQ 'count'>
		<cfset arrayAppend(local.hql.select,'COUNT(main)') />
	<cfelse>
		<cfset arrayAppend(local.hql.select,'main') />
	</cfif>
	<cfset arrayAppend(local.hql.select,'FROM blog_main AS main') />

	<cfif len(arguments.search)>
		<cfset arrayAppend(local.hql.conditions,'1=1') />
		<cfif structKeyExists(arguments,'isActive')>
			<cfset arrayAppend(local.hql.conditions,'AND main.isactive = :isactive') />
			<cfset local.hql.args.isactive = arguments.isActive />
		</cfif>

		<cfset arrayAppend(local.hql.conditions,'AND ( 1=2') />
		<cfset local.hql.args.search = '%#arguments.search#%' />
		<cfloop list="Title,urlTitle,Teaser,Body,Download,Website,GeoLocation" index="local.local.property">
			<cfset arrayAppend(local.hql.conditions,'OR main.#lCase(local.property)# LIKE :search') />
		</cfloop>
		<cfset arrayAppend(local.hql.conditions,')') />

	<cfelse>
		<cfset arrayAppend(local.hql.conditions,'1=1') />

		<cfloop collection="#arguments#" item="local.arg">
			<cfset local.arg = lCase(local.arg) />
			<cfswitch expression="#local.arg#">
				<cfcase value="joincategoryargs">
					<cfif structCount(arguments.joinCategoryArgs)>
						<cfset arrayAppend(local.hql.joins,'LEFT JOIN main.categories AS cat') />
						<cfloop collection="#arguments.joinCategoryArgs#" item="local.joinArg">
							<cfset local.joinArg = lCase(local.joinArg) />
							<cfswitch expression="#local.joinArg#">
								<cfcase value="isactive">
									<cfset arrayAppend(local.hql.conditions,'AND cat.#local.joinArg# = :cat#local.joinArg#') />
									<cfset local.hql.args['cat#local.joinArg#'] = arguments.joinCategoryArgs[local.joinArg] />
								</cfcase>
								<cfcase value="urlboard">
									<cfset arrayAppend(local.hql.conditions,'AND cat.#local.joinArg# LIKE :cat#local.joinArg#') />
									<cfset local.hql.args['cat#local.joinArg#'] = '%#arguments.joinCategoryArgs[local.joinArg]#%' />
								</cfcase>
							</cfswitch>
						</cfloop>
					</cfif>
				</cfcase>

				<cfcase value="postedat">
					<cfif isDate(arguments.postedAt)>
						<cfset local.hql.args.postedat = arguments.postedAt />
					<cfelse>
						<cfset local.hql.args.postedat = lsParseDateTime(arguments.postedAt) />
					</cfif>
					<cfset arrayAppend(local.hql.conditions,'AND main.postedat = :postedat') />
				</cfcase>

				<cfcase value="postedfrom">
					<cfif isDate(arguments.postedFrom)>
						<cfset local.hql.args.postedfrom = arguments.postedFrom />
					<cfelse>
						<cfset local.hql.args.postedfrom = lsParseDateTime(arguments.postedFrom) />
					</cfif>
					<cfset arrayAppend(local.hql.conditions,'AND main.postedat >= :postedfrom') />
				</cfcase>

				<cfcase value="postedto">
					<cfif isDate(arguments.postedTo)>
						<cfset local.hql.args.postedto = arguments.postedTo />
					<cfelse>
						<cfset local.hql.args.postedto = lsParseDateTime(arguments.postedTo) />
					</cfif>
					<cfset arrayAppend(local.hql.conditions,'AND main.postedat <= :postedto') />
				</cfcase>

				<cfcase value="postedby">
					<cfset local.hql.args.postedby = arguments.postedBy />
					<cfif isSimpleValue(arguments.postedBy)>
						<cfset local.hql.args.postedby = entityLoadByPk('sys_user',arguments.postedBy) />
					</cfif>
					<cfset arrayAppend(local.hql.conditions,'AND main.postedby = :postedby') />
				</cfcase>

				<cfdefaultcase>
					<cfif listFindNoCase('Ident,isActive,Title,urlTitle,Teaser,Body,Download,Website,GeoLocation',local.arg)>
						<cfset arrayAppend(local.hql.conditions,'AND main.#local.arg# = :#local.arg#') />
						<cfset local.hql.args[local.arg] = arguments[local.arg] />
					</cfif>
				</cfdefaultcase>
			</cfswitch>
		</cfloop>
	</cfif>

	<cfset local.hql.statement = ' />
	<cfloop list="select,joins,conditions,group,sort" index="local.part">
		<cfset local.hql.statement = listAppend(local.hql.statement,arrayToList(local.hql[local.part],' '),' ') />
	</cfloop>

	<cfreturn local.hql />
</cffunction>

Das Problem welches sich eingestellt hat, ist diese vermaledeite Gross/Kleinschreibung. ColdFusion übergibt Strukturen teilweise Uppercase - da ist natürlich mit camelCase Properties in den persistenten Komponenten Essig.

Die Moral von der Geschichte: lowercase für alle Properties - ausser jemand kennt da ne elegantere Lösung?!

ormExecuteQuery ist case sensitive

0

Bei meinen heutigen Experimenten hat folgender Code eine java.lang.NullPointerException geworfen:

<cfreturn ormExecuteQuery('FROM blog_main WHERE title LIKE :title',{ title='%arguments.title%' }) />

Die Ausführung folgender Zeile lieferte allerdings das gewünschte Array:

<cfreturn ormExecuteQuery('FROM blog_main WHERE Title LIKE :title',{ title='%arguments.title%' }) />

Der Unterschied besteht lediglich aus der Schreibweise des Title Attributs. Einfacher Lehrsatz: Hibernate basiert auf Java - Java ist case sensitive.

setPassword oder setUsername mit attributeCollection

0

Viele Dinge lassen sich sehr einfach mit dem neuen ORM von ColdFusion lösen und deshalb macht es richtig Spass damit zu arbeiten.

Da dieses Feature noch ziemlich neu in ColdFusion ist, muss man sich allerdings bei der Arbeit auf einige auf den ersten Blick willkürlich erscheinende Überaschungen gefasst machen.

Heute arbeitete ich mit einem User Model. Einfachheitshalber habe ich dieses auf den Benutzernamen und das Passwort reduziert.

<cfcomponent output="false" persistent="true" hint="Benutzer Model">

<cfproperty name="ident"			type="guid"			ormType="string"		notNull="true"	getter="true"	setter="false"	length="36"	generator="guid"	fieldType="id"	hint="Eindeutiger Schluessel" />
<cfproperty name="Username"		type="string"		ormType="string"		notNull="true"	getter="true"	setter="true" 	length="50"		validate="string"	validateParams="{minLength=1,maxLength=50}"	hint="Benutzername des Benutzers" />
<cfproperty name="Password"		type="string"		ormType="string"		notNull="true"	getter="true"	setter="true" 	length="50"		validate="string"	validateParams="{minLength=1,maxLength=50}"	hint="Passwort des Benutzers" />

</cfcomponent>

Die Formulardaten möchte ich automatisch in das Model übernehmen. Das bedeutet konkret, dass die dynamisch durch ColdFusion generierten Setter Methoden für die Attribute ‘username’ und ‘password’ automatisch ausgeführt werden sollen, sofern im Formular die entsprechenden Felder existieren.

Klingt nach einer einfachen Anforderung: Ein loop über die Funktionen des Models und sofern ein entsprechender Setter vorhanden ist wird dieser mit den Formulardaten gefüttert. Die Lösung zur dynamischen ausführung des Setters heisst cfinvoke:

<cfinvoke component="#arguments.entity#" method="#local.ormFunction.name#" attributeCollection="#local.args#" />

Dem Befehl übergebe ich eine Bereinigte Struktur mit dem getrimmten Formularwert.

Dabei wirft ColdFusion allerdings eine Exception:

The Password parameter to the SETPASSWORD function is required but was not passed in

Was auf den ersten Blick verwirrend aussieht, macht durchaus Sinn wenn man sich die Neuerungen seit CF 8 CFTags mit attributeCollection definieren und das Handbuch zu cfinvoke anschaut.

Vielleicht ist in CF 9.0.1 das Problem ja behoben, die BugID 83671 sieht auf jedenfall vielversprechend aus.

UPDATE: Das Update von CF 9 auf CF 9.0.1 hat nichts gebracht - es ist halt ein Feature, kein Bug… Abhilfe schafft ein nicht ganz so schönes evaluate Statement:

<cfset evaluate("arguments.entity.#local.ormFunction.name#(#local.propertyName#='#local.propertyValue#')") />

Elegantere Lösungsvorschläge sind jederzeit willkommen…

UPDATE: Wenn man vor lauter Bäumen den Wald nicht sieht. cfinvokeargument heisst das Zauberwort:

<cfinvoke component="#arguments.entity#" method="#local.ormFunction.name#">
  <cfinvokeargument name="#local.propertyName#" value="#local.propertyValue#" />
</cfinvoke>

Damit klappts auch mit dynamischen Settern.

SHA1 und ColdFusion 6.1

0

Der SHA1 Algorithmus kann bei älteren ColdFusion Versionen nicht direkt verwendet werden um einen Hash String zu erzeugen. Deshalb verwendete ich bis anhin die SHA1 Implementierung von Rob Brooks-Bilson von CFlib.org.

Diese Implementierung basiert auf dem Custom Tag Code von Tim McCarthy. Heute bin ich über einen bemerkenswerten Fehler in dieser Implementierung gestolpert.

Lustigerweise wird bei einer Message Länge von 55 Zeichen ein falscher Hash String generiert.

Der folgende Code

<cfset str = "ABCDE1234567890abcdefghijklmnopqrstuvwxyz0987654321WXYZ" />
<cfoutput>#sha1(str)#</cfoutput>

erzeugt diese Ausgabe:

9C10E5A45AC5BEF4D0810E308CAE4514256A8521

Nutzt man unter ColdFusion 9 die hash - Funktion, so erscheint ein anderer Hashwert. Da erzeugt der Code

<cfset str = "ABCDE1234567890abcdefghijklmnopqrstuvwxyz0987654321WXYZ" />
<cfoutput>#hash(str,"SHA")#</cfoutput>

auf magische (aber korrekte) Art und Weise die folgende Ausgabe:

132D865A5630AAEE0BCFAA039B60A446DB675404

Unglücklicherweise kann bei zu alten ColdFusion Versionen nicht auf die hash - Funktion zurückgegriffen werden. Der optionale Parameter für den Algorithmus wurde erst in der Version 7 hinzugefügt. Für ColdFusion ab Version 6 schafft zumindest Railo abhilfe.

Von dort kann die korrekt arbeitende Java Klasse railo.runtime.crypt.SHA1 extrahiert und als Hotfix eingebunden werden. Innerhalb von ColdFusion kann dann ganz einfach auf die Java Klasse zurückgegriffen werden:

<cfset str = "ABCDE1234567890abcdefghijklmnopqrstuvwxyz0987654321WXYZ" />
<cfset jSHA1 = createObject("java","railo.runtime.crypt.SHA1") />
<cfset jSHA1.update(javaCast("string",str)) />
<cfset jSHA1.finalize() />
<cfoutput>#uCase(jSHA1.toString())#</cfoutput>

Ich bin auch ein Kino

0

Wer kennt das nicht: Man sitzt im Kino und knabbert genüsslich an seinem Popcorn.

Kaum ist der langweilige Werbeblock überstanden, wird die Vorfreude auf den Film auch schon durch zwei Tatsachen getrübt.

  1. Das Popcorn ist bereits leer.
  2. Der grösste Mensch der Welt hat sich direkt vor einen gesetzt.

Für das erste Problem gibt es eine Lösung, für das zweite Verschwörungstheorien.

Interessanterweise tauchen solche Phänomene nicht nur im Kino sondern auch im Alltag eines Pendlers auf.

Fensterplätze sind ja bekanntlich beliebt - so auch im öffentlichen Verkehr. Dennoch wundere ich mich immer wieder, wieso ein einem ansonsten leeren Abteil beide Fensterplätze besetzt werden.

Verschränkte Arme und Beine sind nicht nur ein Zeichen der Zurückhaltung, sondern in erster Linie vor allem eines: Unbequem!

Richtig interessant schaut das dann aus, wenn einer der beiden Abteil-Genossen einen Laptop bedient. Die daraus resultierende Embryonen Stellung kann sich jeder bildlich vorstellen.

Also liebe Leute: Wenns schon Platz hat - nutzt denn auch!

Soziale Hölle

0

E-Mail, Instant Messaging, Blogs, Newsseiten, Facebook, Buzz, Twitter, Flickr. Alles Informationsquellen im Netz die mich auf dem Laufenden halten. Die Dienste für sich genommen sind Toll. In der Realität sieht es allerdings ganz schön düster aus.

  • Ich benötige ein E-Mail Programm oder logge mich online auf der Webseite ein
  • Ich benötige einen Feed Reader oder ich besuche die Blogs und Newsseiten manuell
  • Ich benötige ein Instant Messaging Programm um schnell und einfach Unterhalten zu können
  • Ich muss mich auf der Facebook Seite einloggen um mit meinem Freundeskreis in Kontakt bleiben zu können
  • Ich muss mich auf der Google Seite einloggen um mit meinen Geschäftskontakten in Verbindung bleiben zu können
  • Ich benötige ein Photo Verwaltungsprogramm um aktuelle Bilder auf Flickr posten zu können
  • Ich benötige ein Programm um meine Twitter Feeds abzurufen

Jeder Dienst für sich genommen hat definitiv seine Daseinsberechtigung. Für mich als Nutzer bringen die unterschiedlichen Dienste aber vor allem eines: Mehraufwand.

Vereinfacht kann eigentlich von folgendem Szenario ausgegangen werden: Ich habe zwei Freunde (ist nicht viel aber immerhin) und einen Geschäftskontakt. Nennen wir meine Freunde mal Hans und Susi, mein Geschäftskumpan ist der Luca. Die Sozialen Dienste die diese Drei nutzen sind natürlich unterschiedlich.

Hans

E-Mail, Blog, ICQ, Facebook

Susi

E-Mail, MSN, Facebook, Flickr

Luca

E-Mail, Webseite der Firma, Twitter, Google Talk, Google Buzz, Skype

Um mit allen in Kontakt bleiben zu können, muss ich also folgende Dienste unterstützen:

Ich

E-Mail, Feeds, ICQ, MSN, Skype, Facebook, Flickr, Twitter, Google Talk, Google Buzz

Ihr seht, bei nur drei Kontakten muss ich (um aktuell zu bleiben) mit zehn unterschiedlichen Medien Kommunizieren können. Das heisst, ich muss mir überall mein Profil zurechtlegen und wissen wie ich die jeweilige Applikation bedienen muss.

Gebt mir einen Multi - Social - Networking - Messenger!

cfexecute oder cfwaszumteufel

0

Ab und an kommt es vor das Bilder konvertiert werden müssen. Da ColdFusion dieses Feature vor der Version 8 nicht unterstützt, musste ich auf ImageMagick zurückgreifen. Ein gutes Tool, ein kurzer cfexecute und ein glücklicher Entwickler. So die Theorie, in der Realität sah das aber ganz anders aus.

Anfänglich funktionierte der erwähnte cfexecute ganz gut:

<cfexecute name="C:ImageMagickconvert.exe D:srcimage.png D:dstimage.gif" outputFile="D:ImageMagick.log" timeout="250" />

Als es aber darum ging viele Bilder in einem Batchprozess zu verarbeiten traten die ersten Fehler auf. Es wurden allerhand 0 Byte Bilder in den Zielordner unter D:dst verschoben.

Vielleicht löst eine einzelne Batch Datei, welche die Aufrufe tätigt, das Problem? Gesagt, getan, gescheitert.

Die Batchdatei wird zwar von cfexecute ausgeführt, bricht aber nach einiger Zeit aus unerfindlichen Gründen ab. Die knappe Aussage des ColdFusion Servers dazu:

... was terminated unexpected ...

Gefühlte 15 Liter Kaffee und einiger zermürbenden Batch-Bastelstunden später war immer noch kein cfexecute - Durchbruch zu verzeichnen.

Gott habe Kevan Stannard selig - er hat mich mit seinem System Command Projekt aus dieser Hölle befreit!