<?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>hoech.net</title>
	<atom:link href="https://hoech.net/feed/" rel="self" type="application/rss+xml" />
	<link>https://hoech.net/</link>
	<description>Webdesign und -entwicklung, professionelle Bildbearbeitung, Reinzeichnung, DTP und Prepress in Stuttgart</description>
	<lastBuildDate>Thu, 30 Jul 2015 19:50:19 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.5</generator>
	<item>
		<title>Quo vadis, SourceForge</title>
		<link>https://hoech.net/2015/07/30/quo-vadis-sourceforge/</link>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Thu, 30 Jul 2015 19:44:23 +0000</pubDate>
				<category><![CDATA[Software development]]></category>
		<category><![CDATA[dispcalGUI]]></category>
		<category><![CDATA[SourceForge]]></category>
		<guid isPermaLink="false">http://hoech.net/?p=679</guid>

					<description><![CDATA[<p>As a software developer I&#8217;ve been using SourceForge for around six years now (I believe I joined in 2009). I&#8217;m using it to help develop and distribute dispcalGUI, an open source graphical user interface for Argyll CMS aimed at display [&#8230;] <a href="https://hoech.net/2015/07/30/quo-vadis-sourceforge/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2015/07/30/quo-vadis-sourceforge/">Quo vadis, SourceForge</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>As a software developer I&#8217;ve been using SourceForge for around six years now (I believe I joined in 2009). I&#8217;m using it to help develop and distribute <a href="http://dispcalgui.hoech.net/">dispcalGUI</a>, an open source graphical user interface for <a href="http://argyllcms.com/">Argyll CMS</a> aimed at display calibration and characterization, utilizing these free services:</p>
<p><img src="https://s.w.org/images/core/emoji/16.0.1/72x72/25aa.png" alt="▪" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Version control<br />
<img src="https://s.w.org/images/core/emoji/16.0.1/72x72/25aa.png" alt="▪" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Hosting of binary and source code downloads over a distributed network of mirrors<br />
<img src="https://s.w.org/images/core/emoji/16.0.1/72x72/25aa.png" alt="▪" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Support forums<br />
<img src="https://s.w.org/images/core/emoji/16.0.1/72x72/25aa.png" alt="▪" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Issue tracker<br />
<img src="https://s.w.org/images/core/emoji/16.0.1/72x72/25aa.png" alt="▪" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Mailing lists<br />
<img src="https://s.w.org/images/core/emoji/16.0.1/72x72/25aa.png" alt="▪" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Wiki</p>
<p>The latest development is that the current owners of SourceForge, DHI Group (the former Dice Holdings, which had acquired SourceForge from GeekNet in 2012), is looking to sell off its Slashdot Media assets, which includes SourceForge. It&#8217;s too early to really tell what this means for its future, but nevertheless, I&#8217;m keeping an eye out for alternatives, and if SourceForge should cease to be an option for one reason or the other, I will be forced to move elsewhere—even considering self-hosting everything I need if I really can&#8217;t avoid it.</p>
<p><span id="more-679"></span></p>
<p>I&#8217;ve never partaken, nor plan to partake, in the controversial opt-in DevShare program that&#8217;s been available since 2013 (which would, at the choice of a developer, bundle open source software with closed source ad-ware, and share ad revenues with developers). I&#8217;ve observed, with dismay, the project hijackings done by SourceForge of &#8222;abandoned&#8220; projects (which weren&#8217;t really abandoned, but just weren&#8217;t using SourceForge anymore, i.e. development, file hosting etc. continued elsewhere)—thankfully, SourceForge seems to have stopped this practice, but a bad aftertaste remains. I&#8217;ve lived with my concerns about the proliferation of sometimes misleading ads on project download pages that was going on for a while, where an ad could consist of only a big green &#8222;download&#8220; button, with no clear indication that it actually was an ad and not a download button for the project files (although the situation seems to have gotten better, and I&#8217;ve not run into any of those ads for a while now). I understand that Sourceforge needs to pay its bills somehow, but ads have in my opinion been placed and potentially picked strategically in such a way to make it more likely that visitors click them accidentally, or are mislead into clicking them.</p>
<p>Despite my concerns and in some cases disdain for some of the business practices employed by SourceForge, I still feel it provides me with valuable services that aren&#8217;t easily replaced (recent service outages notwithstanding)—and by easily, I mean without me having to spend a considerable amount of time setting up alternatives. The matter of fact is that no other free or paid service provider actually seems to provide all the services I currently use (see the list above)—e.g. GitHub is viable for version control, code hosting, wiki and issue tracker, but does not provide hosting of binary downloads over a distributed network of mirrors, forums or mailing lists, which all are important components to me.</p>
<p>That said though, a new owner might actually bring positive change. We will see.</p>
<p>Der Beitrag <a href="https://hoech.net/2015/07/30/quo-vadis-sourceforge/">Quo vadis, SourceForge</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Seven years of open source development—a recap</title>
		<link>https://hoech.net/2015/07/30/seven-years-open-source-development-recap/</link>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Thu, 30 Jul 2015 19:16:34 +0000</pubDate>
				<category><![CDATA[Software development]]></category>
		<category><![CDATA[dispcalGUI]]></category>
		<guid isPermaLink="false">http://hoech.net/?p=675</guid>

					<description><![CDATA[<p>It was around early 2008 when I started to embark on a journey that would turn out to add a lot of fulfillment, knowledge, and experience to my life (and also keep me busy during my free time). That was [&#8230;] <a href="https://hoech.net/2015/07/30/seven-years-open-source-development-recap/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2015/07/30/seven-years-open-source-development-recap/">Seven years of open source development—a recap</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>It was around early 2008 when I started to embark on a journey that would turn out to add a lot of fulfillment, knowledge, and experience to my life (and also keep me busy during my free time). That was when I started developing <a href="http://dispcalgui.hoech.net">dispcalGUI</a>, a graphical user interface aimed at display calibration and profiling using <a href="http://argyllcms.com/">Argyll CMS</a>, a command line driven color management system.</p>
<p><span id="more-675"></span></p>
<p>Until then, I had used Argyll CMS occasionally from time to time (I remember first discovering it in 2005), and around 2007/2008 started to use it as a tool to explore color and learn more in-depth about ICC color management from a software development perspective (I had prior knowledge as a user of ICC color management as part of my day job at an imaging and prepress house until 2006, before I became self-employed as a web developer).</p>
<p>I also began to grow dissatisfied with the display calibration and profiling software I was using privately, and realized that Argyll CMS did a much better job at generating a hue neutral calibration (an aging CRT that I used back then had a significant green cast in the shadows through midtones in its uncalibrated state that Argyll CMS managed to get completely rid of). I didn&#8217;t object to using Argyll CMS from the command line, but started to write a simple graphical user interface in <a href="http://python.org">Python</a> (which I already had some development experience with)—with <a href="http://wxpython.org/">wxPython</a> as the GUI toolkit—that would help me explore the various options without having to remember command line switches and their effects. I had no plans to make my work public at the time, in fact I didn&#8217;t even think it would be useful to anyone (it was really, really rudimentary UI-wise).</p>
<p>But in the same year, Argyll CMS hit its version 1.0 milestone, and subsequently I became increasingly aware (by reading forums and mailing lists) of users actually wishing for a graphical interface. I began to wonder if I should build upon what I had and release it publicly under an open source license. So I decided on the not very creative and near unpronounceable working title that would ultimately not change to this day, and began to work on this little project in my free time. I remember an ever-increasing drive and motivation coming along with this endeavor—several other people had announced their development of GUIs for Argyll CMS, and I wanted to be among the first to present something useful. In retrospect, I feel a little silly for worrying that somebody else might beat me to the punch the way I did back then—a few others managed to release their GUIs before mine was ready, but theirs seemed even more rudimentary.</p>
<p>The first version of dispcalGUI, numbered 0.1b, was publicly released on August 18, 2008 and still a bit rough UI-wise, but already fully cross-platform and had a few interesting features, like the automatic detection of measurement instruments. Back then I was definitely a little proud of what I had achieved in a relatively short amount of time. I received a good amount of really positive and encouraging feedback, which I remain thankful for (and keep getting) to this day.<br />
Since then, I continued working on the project whenever I had free time available, adding features, fixing bugs and testing, testing, testing.</p>
<p>Over the years, I increased my knowledge of the inner workings and structure of ICC profiles, and wrote a little parser library to that effect. I learned a lot about systems, packaging, general software development advances, and interesting color and (human) vision related topics. Through following my own internal roadmap, reacting to changes and advances in the supported platforms as well as Argyll CMS itself, and by incorporating user and developer feedback, I kept driving the project forward, even though there were occasions when I had little time to further its development.</p>
<p>In 2010, following users repeatedly asking for a possibility to donate money to the project, I started accepting donations to aid development expenses—beforehand I wasn&#8217;t too comfortable with the idea, because I didn&#8217;t want to pressure myself into having to work on a project where a main driving factor I felt was that I could work on it whenever I felt like it and had the time, but ultimately that turned out to be a non-issue.</p>
<p>Fast forward. In 2012, I finally hit version 1.0 (although that was never released in binary form, the binary release was actually 1.0.7.6—the last two numbers coincide with my birth year and the release was on my birthday). Since then, development pace has continually picked up, ultimately resulting in version 2.0 being released last year and 3.0 this year with significantly overhauled UI, following an Argyll CMS 1.7 release. This brought another change with it in the sense that I&#8217;m now actively asking for donations to compensate for time and resources spent, and because I want to support Argyll CMS itself in a more direct way (all donations received by me are currently split 50/50, after deduction of PayPal fees, with me using one half and donating the other to Argyll CMS each month), the latter being a factor that I previously didn&#8217;t give much attention to even though I probably should have (dispcalGUI isn&#8217;t really useful without Argyll CMS).</p>
<p>My hope is that I&#8217;ll be able to continue working on this project, interacting with users and developers, furthering and refining it as time goes by.</p>
<p>And finally, a few lessons learned during development that may be helpful to people looking to develop a cross-platform application using Python (this is not an exhaustive list by any stretch of the imagination, and I might come back and amend it once more things come to mind):</p>
<ul>
<li><strong>Cross-platform and general Unicode support in Python 2.x is not very good.</strong> It&#8217;s easy to introduce unforeseen issues even if coding carefully (some of the potential pitfalls are mentioned in the <a href="https://docs.python.org/2/howto/unicode.html">Python Unicode HOWTO</a>, but that&#8217;s really just the tip of the iceberg). You&#8217;ll likely run into unexpected Unicode-related problems depending on platform<em>, </em>when you&#8217;d expect such differences to be abstracted away by the module in question. For example this <a href="http://bugs.python.org/issue22862">os.walk bug</a>, or the subprocess module—the latter under Windows fails with anything not representable in 7 bit ASCII, under Linux/Mac OS X it works fine as long as the file system encoding can represent the Unicode characters. In such a case, the only solution is to restrict yourself to characters representable in the file system encoding, and hand byte strings over to problematic modules. Or exclusively develop for Python 3.x instead, where Unicode support is much better and consistent.</li>
<li><strong>Platform differences in GUI behavior can be very annoying and cause unforeseen problems</strong>. If you plan to support multiple platforms, think hard about which GUI toolkit you are going to use. If the toolkit you&#8217;re considering wraps another toolkit which is native to the respective platform, like wxPython/wxWidgets does, you are very likely to run into these platform related issues. Something like Qt seems a better choice in such a scenario.</li>
</ul>
<p>Der Beitrag <a href="https://hoech.net/2015/07/30/seven-years-open-source-development-recap/">Seven years of open source development—a recap</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Perspective</title>
		<link>https://hoech.net/2015/07/29/perspective/</link>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Wed, 29 Jul 2015 12:48:38 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<guid isPermaLink="false">http://hoech.net/?p=672</guid>

					<description><![CDATA[<p> <a href="https://hoech.net/2015/07/29/perspective/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2015/07/29/perspective/">Perspective</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><img fetchpriority="high" decoding="async" class="alignleft size-full wp-image-673" src="http://hoech.net/wp-content/uploads/2015/07/truth.png" alt="" width="580" height="480" srcset="https://hoech.net/wp-content/uploads/2015/07/truth.png 580w, https://hoech.net/wp-content/uploads/2015/07/truth-276x228.png 276w" sizes="(max-width: 580px) 100vw, 580px" /></p>
<p>Der Beitrag <a href="https://hoech.net/2015/07/29/perspective/">Perspective</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Von Gringos und Gummipuppen</title>
		<link>https://hoech.net/2015/06/28/von-gringos-und-gummipuppen/</link>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Sat, 27 Jun 2015 23:06:23 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<guid isPermaLink="false">http://hoech.net/?p=665</guid>

					<description><![CDATA[<p>Wie manch einer vielleicht weiss, entwickle ich seit ca. sieben Jahren eine Open-Source-Benutzoberfläche zur Anzeigegeräte-Kalibrierung mit Argyll CMS in meiner Freizeit. Gestern hinterliess jemand einen etwas ausfallenden Beitrag im Support-Forum, der erste dieser Art überhaupt (Premiere!): Natürlich anonym, denn mit [&#8230;] <a href="https://hoech.net/2015/06/28/von-gringos-und-gummipuppen/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2015/06/28/von-gringos-und-gummipuppen/">Von Gringos und Gummipuppen</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Wie manch einer vielleicht weiss, entwickle ich seit ca. sieben Jahren eine <a href="http://dispcalgui.hoech.net/">Open-Source-Benutzoberfläche zur Anzeigegeräte-Kalibrierung mit Argyll CMS</a> in meiner Freizeit.</p>
<p>Gestern hinterliess jemand einen etwas ausfallenden Beitrag im Support-Forum, der erste dieser Art überhaupt (Premiere!):<br />
<div class="cta" >
<pre>after waiting an hour the programm alerts: "no profile is set" or "couldn't open Argyll_V1.7.0/bin/dispread.exe". And this file IS there and i have set the right path to "Argyll_V1.7.0/bin"

That's very dirty! For what do i wait hours and hours? An no chance to correct anything. The measurment was futile.

There are 34 types of profiles, I can choose - NOBODY NEEDS IT! But at the end of measurement I can kiss the ass of that Programm. Why is open source always so dirty made for the users? I don't understand. Do you do programming to have a wank or to do sinfull things?</pre>
</div><div class="clear"></div>
Natürlich anonym, denn mit Name würde ja so etwas wie Rückgrat erfordern. Nach kurzem Überlegen löschte ich den Beitrag, und deaktivierte auch die Möglichkeit, anonyme Beiträge zu verfassen, immerhin dient dieses Forum ja dem Support legitimer Nutzer und ist kein Müllabladeplatz. Damit hielt ich diese Sache für erledigt, aber weit gefehlt&#8230;</p>
<p><span id="more-665"></span></p>
<p>Kurze Zeit später erreichte mich folgende Mail, interessanterweise über das geschäftliche Kontaktformular auf meiner Website, nicht über die Support-Mailadresse:<br />
<div class="cta" >
<pre>Von: Andy &lt;elgringo@...&gt;

Hallo Florian,

nachdem ich in dem zuständigen Forum auf sourceforg einen kritischen Beitrag zu DispcalGUI gepostet habe, bin ich doch umgehend gesperrt worden. Geht das auf deine Kappe? Sowas geht ja gar nicht. Wenn eine Software nicht funktioniert, wird man das wohl noch sagen dürfen. Oder seid Ihr Open-Sourcler alle so kleine Sensibelchen? Vor allem hatte ich auf reelle Hilfe gehofft, wenn es schon keine anständige Anleitung gibt. Mein Gott, ich bin Grafiker und kein Programmierer. Woher soll ich wissen, was ich mit dämlich-kryptischen Fehlermeldungen anfangen soll? Könnt Ihr Programmierer eigentlich nicht anders? Voll nerdy oder was? Da sitzen MENSCHEN am anderen Ende und versuchen verzweifelt, die mißratene Software zu benutzen!</pre>
</div><div class="clear"></div>
Kritischer Beitrag, aha. Hier die <a href="https://de.wiktionary.org/wiki/Kritik">Wiktionary-Definition von Kritik</a>, und hier die von <a href="https://de.wiktionary.org/wiki/p%C3%B6beln">Pöbelei</a>. Was passt wohl besser?<br />
Keine Anleitung (die Homepage der Software ist praktisch nichts anderes, und extrem umfangreich)? Ziemlich dreist (und nein, das elgringo@ ist kein Scherz! El Gringo heisst übersetzt soviel wie &#8222;Ein Typ&#8220;. Irgendwie passend. Übrigens gehen alle anonymen Beiträge erst in eine Moderations-Queue, er war also keineswegs gesperrt, aber anonyme Beiträge müssen halt erst von mir freigeschaltet werden). Meine Antwort entsprechend schroff:<br />
<div class="cta" >
<pre>Von: Florian Höch
An: Andy &lt;elgringo@...&gt;

Hallo Andy,

Am 26.06.2015 um 19:14 schrieb hoech.net Kontaktformular:
&gt; nachdem ich in dem zuständigen Forum auf sourceforg einen kritischen 
&gt; Beitrag zu DispcalGUI gepostet habe, bin ich doch umgehend gesperrt 
&gt; worden. Geht das auf deine Kappe? Sowas geht ja gar nicht.

Das war aber hoffentlich nicht dein Beitrag mit dem Spam?

&gt; Wenn eine Software nicht funktioniert, wird man das wohl noch sagen
&gt; dürfen.

Der Ton macht die Musik.

&gt; Oder seid Ihr Open-Sourcler alle so kleine Sensibelchen?

Was ist ein Open-Sourcler?

Und zum Thema Sensibelchen: Für jemanden, der bei einem Problem gleich
ausfallend wird, hast du eine interessante Vorstellung von "sensibel".

&gt; Vor allem hatte ich auf reelle Hilfe gehofft, wenn es schon keine
&gt; anständige Anleitung gibt. Mein Gott, ich bin Grafiker und kein
&gt; Programmierer.

Es gibt gewisse Mindeststandards in der Kommunikation, von der ich
bedingungslos erwarte, dass sie eingehalten werden. Ich bin was das
angeht übrigens in einer verdammt starken Position, denn _DU_ willst was
von mir, nicht umgekehrt...

&gt; Woher soll ich wissen, was ich mit dämlich-kryptischen 
&gt; Fehlermeldungen anfangen soll? Könnt Ihr Programmierer eigentlich 
&gt; nicht anders? Voll nerdy oder was? Da sitzen MENSCHEN am anderen
&gt; Ende und versuchen verzweifelt, die mißratene Software zu benutzen!

Wenn du dir echte Hilfe in dem Tonfall erhoffst, wünsche ich dir viel Glück.

Florian.</pre>
</div><div class="clear"></div>
Open-Source ist übrigens ein Lizensierungsmodell für Software. Das nur am Rande&#8230;<br />
<div class="cta" >
<pre>Von: Florian Höch
An: Andy &lt;elgringo@...&gt;

Eine Sache noch:

Am 26.06.2015 um 19:49 schrieb Florian Höch:
&gt;&gt; Woher soll ich wissen, was ich mit dämlich-kryptischen 
&gt;&gt; Fehlermeldungen anfangen soll? Könnt Ihr Programmierer eigentlich 
&gt;&gt; nicht anders? Voll nerdy oder was? Da sitzen MENSCHEN am anderen
&gt;&gt; Ende und versuchen verzweifelt, die mißratene Software zu benutzen!

Woher soll ich wissen, was ich mit dümmlich-beleidigenden Kommentaren
anfangen soll? Könnt ihr Grafiker eigentlich nicht anders? Voll assi
oder was? Da sitzen MENSCHEN am anderen Ende und versuchen verzweifelt,
euch trotz eurer mißratenen Manieren zu helfen!

Konnte ich mir dann doch nicht verkneifen...

Florian.</pre>
</div><div class="clear"></div>
Wer glaubt der Typ wer er ist? Im Internet wundert mich die Dreistigkeit mancher Leute eigentlich nicht mehr, aber die Blüten, die diese grenzenlose Anonymität treibt, sind manchmal schon skurril (zur Verteidigung von Andy muss man allerdings dazusagen, dass er wohl noch sehr jung ist, und keineswegs Grafiker wie er ursprünglich angab bzw. mich anlog. Ich schätze ihn im Teenager-Alter, wie auch die ziemlich, sagen wir mal, &#8222;farbenfrohe&#8220; Sprache in seinen Mails zeigen wird). Es entwickelte sich daraus folgender, meiner Meinung nach äußerst amüsanter, Mailverkehr (Originaltext, Kommentare dazu wo nötig):<br />
<div class="cta" >
<pre>An: Florian Höch
Von: Andy &lt;elgringo@...&gt;

ja holt euch mal weiterhin auf eure Bastelsoftware einen runter. Grad 
wieder ne Stunde auf ein Profil gewartet, um AM SCHLUSS(!) zu erfahren, 
daß mal wieder eines der nötigen Programme nicht gestartet werden 
konnte. Wie unprofessionell ist das denn? Im übrigen will ich nichts von 
dir. Da geb ich doch lieber 100,- € für BasICColor aus. Die Jungs 
wissen, was sie tun, statt dummblind auf ihre Progger-Tastaturen 
einzuhämmern. Die Software funktioniert, ist zehnmal so schnell und 
liefert anständige Profile. Und jetzt hol deine Gummipuppe raus und 
besorgs ihr, du rattenscharfer Kellernerd.</pre>
</div><div class="clear"></div>
Olla, mein Gesprächspartner ist also deutlich jünger als ich ursprünglich annahm, und Grafiker ist er garantiert auch nicht. Bei soviel Gerede von Gummipuppen und Onanie scheint er mächtig sexuell frustriert zu sein. Na sei&#8217;s drum.<br />
<div class="cta" >
<pre>Von: Florian Höch
An: Andy &lt;elgringo@...&gt;

Bitte keine Spam-Nachrichten mehr. Danke.</pre>
</div><div class="clear"></div>
<div class="cta" >
<pre>An: Florian Höch
Von: Andy &lt;elgringo@...&gt;

du wolltest dir doch grad einen auf deine "starke Position" runterholen 
- bitte nicht mit den klebrigen Fingern Mails tippen - danke.</pre>
</div><div class="clear"></div>
<div class="cta" >
<pre>Von: Florian Höch
An: Andy &lt;elgringo@...&gt;

Hmmm. Du bist noch ein bisschen jung oder? Aber ich habs mir überlegt,
deine Mails sind eigentlich ganz nett. Kannst mir gern mehr schicken.</pre>
</div><div class="clear"></div>
Hier war ich schon ordentlich am schmunzeln und gespannt, wie sehr auf die Palme ich den armen gebeutelten Jungen noch bringen konnte.<br />
<div class="cta" >
<pre>An: Florian Höch
Von: Andy &lt;elgringo@...&gt;

bitte keinen weiteren Spam. Nimm Stellung zu deinem unprofessionellen 
Machwerk oder reib einfach weiter - bist ja offensichtlich immer noch 
nicht fertig.</pre>
</div><div class="clear"></div>
Hmm. Plappert er mir jetzt einfach nach&#8230;? Das wäre langweilig&#8230; setzen wir einen drauf:<br />
<div class="cta" >
<pre>Von: Florian Höch
An: Andy &lt;elgringo@...&gt;

&gt; Da geb ich doch lieber 100,- € für BasICColor aus.

Btw, ich bin basICColor Reseller, bei mir gibts die Software 50 €
günstiger bei Interesse (149,- inkl. Squid3 Messgerät, 49,- ohne).</pre>
</div><div class="clear"></div>
Nein, ich bin kein basICColor-Reseller, aber ich dachte mir vielleicht fällt er drauf rein, der Hellste schien er mir jetzt nicht unbedingt zu sein <img src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br />
<div class="cta" >
<pre>Von: Florian Höch
An: Andy &lt;elgringo@...&gt;

Vergessen zu erwähnen, ich kann/darf nur an Geschäftskunden verkaufen.
Aber Gewerbe hast du wahrscheinlich eh als Graficker, sollte also kein
Problem sein.</pre>
</div><div class="clear"></div>
Das überflüssige &#8222;c&#8220; war übrigens kein Tippfehler <img src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br />
<div class="cta" >
<pre>An: Florian Höch
Von: Andy &lt;elgringo@...&gt;

das passt doch: Verkäuferschnösel für die Konkurrenz. Wohl nicht so 
überzeugt vom eigenen Machwerk.</pre>
</div><div class="clear"></div>
Fast erfolgreich.<br />
<div class="cta" >
<pre>Von: Florian Höch
An: Andy &lt;elgringo@...&gt;

Nein, du blickst es nicht :)

Das Angebot hab ich dir nur gemacht, weil du mir nicht unbedingt als der
Hellste erscheinst, und weil ich mir ziemlich sicher bin, dass du noch
nicht volljährig bist und kein Gewerbe hast.

Wenn du also so dämlich gewesen wärst, auf das Angebot einzugehen, hätt
ich dir ein Päckchen mit ausgedrucktem Trollface als einzigem Inhalt
geschickt und mich köstlich amüsiert, so wie über den ganzen Rest
unserer "Korrespondenz" 

Btw, wie alt bist du tatsächlich? Bin nur neugierig. Ich mein, dir ist
schon klar dass du es hier mit einem fast vierzigjährigen Erwachsenen zu
tun hast? Bin mir nicht sicher, weil wie gesagt sonderlich helle
scheinst du mir nicht zu sein :)</pre>
</div><div class="clear"></div>
<div class="cta" >
<pre>An: Florian Höch
Von: Andy &lt;elgringo@...&gt;

spar dir deine Ausreden. Wenn du "erwachsen" bist, kümmer dich wie ein 
Mann darum, deine eigenen Fehler auszumerzen, anstatt hier den 
Schlauberger zu geben. Der Versuch an meine Adresse zu kommen war allzu 
durchschaubar. Also hurtig jetzt deine mißratene Software wartet auf dich...</pre>
</div><div class="clear"></div>
Ja, unser Gringo ist Experte auf dem Gebiet der Männlichkeit, denn wie wir alle wissen, braucht man diese für anonyme Pöbeleien im Internet <img src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br />
Und ich hatte das Trollface bereits ausgedruckt! A3-Überformat, gefaltet wie ein Poster. Wär mir die paar Euro fuffzig fürs Päckchen wert gewesen. Egal.<br />
<div class="cta" >
<pre>Von: Florian Höch
An: Andy &lt;elgringo@...&gt;

Btw, dir ist schon klar, dass die Art und Weise, wie und was jemand
schreibt, ziemlich eindeutige Rückschlüsse auf das Alter der
betreffenden Person zulässt? Wissen deine Eltern, dass du ihr Internet
benutzt? :)</pre>
</div><div class="clear"></div>
<div class="cta" >
<pre>An: Florian Höch
Von: Andy &lt;elgringo@...&gt;

scheint ja sehr interssant für dich zu sein, mal mit einem Fachmann zu 
sprechen. Und jetzt kümmer dich um deine mißratene Schadsoftware - wird 
hier gerade deinstalliert. Profile mit Rotstich sind nicht so mein Fall...</pre>
</div><div class="clear"></div>
<div class="cta" >
<pre>Von: Florian Höch
An: Andy &lt;elgringo@...&gt;

Naja, ich brauch noch ein bisschen Material für mein Blog, und da kommt
mir sowas gerade Recht. Das wird Klasse Andy :D

&gt; Fachmann

Fachmann? Im Pöbeln? Da hab ich aber schon weitaus besseres gesehen :D

&gt; wird hier gerade deinstalliert

Jetzt erst?

&gt; Profile mit Rotstich sind nicht so mein Fall...

Interessant! Darf ich fragen, wie du es trotz des angeblichen "Fehlers"
geschafft hast, ein Profil zu erstellen? 

(Abgesehen von der Enttäuschung, die du erleben wirst, wenn du
feststellst, dass der Rotstich am Messgerät liegt und nicht an der
Software. Lass mich raten, du hast einen älteren Spyder oder einen ColorHug)
</pre>
</div><div class="clear"></div>
Es gibt Menschen, dumme Menschen, und strunzdumme Menschen, bei denen man bereits mehr Intelligenz erhält, wenn man sich in die hohle Hand rotzt. In welche Kategorie fällt wohl unser Gringo?<br />
<div class="cta" >
<pre>An: Florian Höch
Von: Andy &lt;elgringo@...&gt;

falsch geraten - und jetzt geh, dir einen runterholen. Darin bist du 
besser als in Farbmanagement. Sogar die Spydersoftware erstellt 
neutralere Profile als dein Bastelprogramm...
</pre>
</div><div class="clear"></div>
Also doch Spyder, was willste denn?<br />
Und die Frage nach der Intelligenz wäre damit auch eindeutig beantwortet <img src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Der Beitrag <a href="https://hoech.net/2015/06/28/von-gringos-und-gummipuppen/">Von Gringos und Gummipuppen</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Custom tumblr 404 error page</title>
		<link>https://hoech.net/2013/12/10/custom-tumblr-404-error-page/</link>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Tue, 10 Dec 2013 13:52:02 +0000</pubDate>
				<category><![CDATA[Web development]]></category>
		<category><![CDATA[Web-Entwicklung]]></category>
		<category><![CDATA[404]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[tumblr]]></category>
		<guid isPermaLink="false">http://hoech.net/?p=616</guid>

					<description><![CDATA[<p>I wanted to have a custom 404 page for a client project, but tumblr does not have the ability to define a custom style or even custom content for the 404 error page. There are some ways around this, but [&#8230;] <a href="https://hoech.net/2013/12/10/custom-tumblr-404-error-page/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2013/12/10/custom-tumblr-404-error-page/">Custom tumblr 404 error page</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I wanted to have a custom 404 page for a client project, but tumblr does not have the ability to define a custom style or even custom content for the 404 error page. There are <a href="https://gist.github.com/karteek/260200">some ways around this</a>, but solutions like that have the problem that they do not really always work because they look for a certain error text in the page, but that error text is actually translated according to a visitor&#8217;s language preference (as set in their browser). The solution I came up with is to do an AJAX HTTP HEAD request via <a href="http://jquery.com/">jQuery</a> to the current document URL, and if that returns a 404 status code, forward to the custom 404 page (which is an actual custom page on the tumblr blog in question—you could also replace or alter the page content via JavaScript instead if you were so inclined). <span id="more-616"></span> Here&#8217;s the code:</p>
<pre class="language-javascript"><code>// Make a request to ourself to figure out if this returns a 404,
// and if that is the case, show our custom 404 page
$.ajax(document.location.href, {type: 'HEAD'}).fail(function (jqXHR, textStatus, errorThrown) {
	if (jqXHR.status == 404)
		location.href = document.location.protocol + '//' + document.domain + '/not-found';
});</code></pre>
<p>This still has the problem that it will briefly show the error page in the blog&#8217;s normal layout before the redirection occurs, also if the user navigates back they will end up being redirected again (this could be solved by using <code>location.replace</code>).</p>
<p><a href="http://typostrate.com/this-page-does-not-exist">Here you can see the solution in action</a>.</p>
<p>Der Beitrag <a href="https://hoech.net/2013/12/10/custom-tumblr-404-error-page/">Custom tumblr 404 error page</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Show related posts on tumblr permalink pages</title>
		<link>https://hoech.net/2013/11/26/show-related-posts-on-tumblr-permalink-pages/</link>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Tue, 26 Nov 2013 21:41:56 +0000</pubDate>
				<category><![CDATA[Web development]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Related Posts]]></category>
		<category><![CDATA[tumblr]]></category>
		<guid isPermaLink="false">http://hoech.net/?p=573</guid>

					<description><![CDATA[<p>I just added a github repository for my tumblr related posts jQuery plugin, which is (very loosely) based on the tumblr-related-posts widget. From the README: Show related posts on tumblr permalink pages. Prerequisites: jQuery. Usage &#60;script&#62; $(container).relatedposts(options); &#60;/script&#62; container should [&#8230;] <a href="https://hoech.net/2013/11/26/show-related-posts-on-tumblr-permalink-pages/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2013/11/26/show-related-posts-on-tumblr-permalink-pages/">Show related posts on tumblr permalink pages</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I just added a <a href="https://github.com/fhoech/tumblr-relatedposts">github repository for my tumblr related posts jQuery plugin</a>, which is (very loosely) based on the <a href="http://code.google.com/p/tumblr-related-posts/">tumblr-related-posts widget</a>. <span id="more-573"></span> From the README:</p>
<p>Show related posts on tumblr permalink pages.<br />
Prerequisites: jQuery.</p>
<h2>Usage</h2>
<pre class="language-markup"><code>&lt;script&gt;
    $(container).relatedposts(options);
&lt;/script&gt;</code></pre>
<p><code>container</code> should be a valid jQuery selector. <code>options</code> should be an object with key/value pairs.</p>
<h2>Possible options</h2>
<p><code>domain</code>: Your tumblr domain name e.g. mytumblr.tumblr.com. Defaults to current document domain.<br />
<code>num</code>: Max. number of related posts to display.<br />
<code>len</code>: Excerpt text length (number of characters).<br />
<code>thumbwidth</code>: Preferred thumbnail width in px (height will scale accordingly).<br />
<code>tags</code>: Array of post tags to search for.<br />
<code>type</code>: Limit posts to type. Empty string (&#8220;) for all types.<br />
<code>titlehtml</code>: HTML for the title tag (will be inserted before the container).</p>
<p>The only required option is the <code>tags</code> option, which should be an array of post tags.</p>
<h2>Minimal example</h2>
<p>Assuming you have a container with ID <code>related</code> in which you want to display, insert this just before the closing <code>&lt;/body&gt;</code> of your theme (change your domain/path accordingly, and leave jQuery out if it is already included on the page):</p>
<pre class="language-markup line-numbers"><code>{block:PermalinkPage}
    &lt;script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"&gt;
    &lt;/script&gt;
    {block:Posts}
        {block:HasTags}
            &lt;script src="//yourdomain.com/js/related.js"&gt;&lt;/script&gt;
            &lt;script&gt;
                $('#related').relatedposts(
                    {tags: [{block:Tags}'{Tag}',{/block:Tags}]});
            &lt;/script&gt;
        {/block:HasTags}
    {/block:Posts}
{/block:PermalinkPage}
</code></pre>
<p>You could also pull the tags via jQuery (in the example assuming post tags are displayed as links in a container with the class <code>tags</code>):</p>
<pre class="language-markup line-numbers"><code>{block:PermalinkPage}
    &lt;script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"&gt;
    &lt;/script&gt;
    {block:Posts}
        {block:HasTags}
            &lt;script src="//yourdomain.com/js/related.js"&gt;&lt;/script&gt;
            &lt;script&gt;
                $('#related').relatedposts(
                    {tags: $('.tags a').map(function() {
                               return $(this).text().replace(/^#/, '');
                           }).get()});
            &lt;/script&gt;
        {/block:HasTags}
    {/block:Posts}
{/block:PermalinkPage}
</code></pre>
<p>Der Beitrag <a href="https://hoech.net/2013/11/26/show-related-posts-on-tumblr-permalink-pages/">Show related posts on tumblr permalink pages</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Caching in WordPress</title>
		<link>https://hoech.net/2012/06/20/caching-in-wordpress/</link>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Wed, 20 Jun 2012 12:55:41 +0000</pubDate>
				<category><![CDATA[Web-Entwicklung]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">http://wp.hoech.net/?p=357</guid>

					<description><![CDATA[<p>Es gibt viele Möglichkeiten, die Performance einer Website zu verbessern. Neben der Optimierung von Bildern, HTML, JavaScripts und StyleSheets sowie Kompression ist sowohl browser- wie auch serverseitiges Caching (das Vorhalten von Daten in einem Zwischenspeicher) eine gute Option. Auf dieser [&#8230;] <a href="https://hoech.net/2012/06/20/caching-in-wordpress/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/20/caching-in-wordpress/">Caching in WordPress</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div class="cta" >Hinweis: Die aktuelle Version 2.9.0.3 von HyperCache behebt die in diesem Artikel angesprochenen Kritikpunkte. Dank an den Autor des Plugins, <a href="http://satollo.net">Stefano Lissa</a>, für das prompte Einpflegen des Patches.</div><div class="clear"></div>
<p><img decoding="async" src="http://hoech.net/wp-content/uploads/2012/05/smbutton-grey.png" alt="" width="58" height="69" class="alignleft size-full wp-image-369" /> Es gibt viele Möglichkeiten, die Performance einer Website zu verbessern. Neben der Optimierung von Bildern, HTML, JavaScripts und StyleSheets sowie Kompression ist sowohl browser- wie auch serverseitiges Caching (das Vorhalten von Daten in einem Zwischenspeicher) eine gute Option. <span id="more-357"></span></p>
<p>Auf dieser Website setze ich eine modifizierte Version des <a href="http://wordpress.org/extend/plugins/hyper-cache/">Hyper Cache Plug-Ins für WordPress</a> ein. Für WordPress gibt es mehr als ein dutzend Caching-Plug-Ins, ich habe mich für dieses aufgrund seiner Einfachheit (es macht, was es soll, und nicht mehr) sowie der gefühlt guten Performance entschieden.</p>
<p>Ein paar kleinere und größere Kritikpunkte des Original-Plug-Ins (Version 2.8.9) gab es allerdings schon, die mich dazu veranlasst haben, das Plug-In leicht zu überarbeiten:</p>
<ul class="fancy">
<li>Das Browser-Caching wurde durch das Setzen von entsprechenden HTTP-Antwort-Headern deaktiviert. Meiner Meinung nach ein großes No-No. Eine bessere Option besteht darin, die maximale Browser-Cache-Verweildauer anhand der Differenz der in den Optionen des Plug-Ins festgelegten Ablaufzeitspanne und des Alters der serverseitig gecachten Datei festzulegen.</li>
<li>Bei Aktivierung der Kompression im Plug-in wurde nach der ersten Anfrage an eine Seite diese unkomprimiert ausgeliefert. Verschmerzbar, aber auch leicht zu ändern.</li>
<li>Der Last-Modified HTTP-Antwort-Header fehlte trotz Aktivierung in den Plug-In-Optionen bei jedem ersten ungecachten Seitenzugriff.</li>
<li>Und noch eine Kleinigkeit, die „304 Not Modified“ HTTP-Antwort sollte idealerweise so früh wie möglich im Code erfolgen, um nicht serverseitig unnötig Daten zu verarbeiten, die dann gar nicht gebraucht werden.
</ul>
<p>Zu guter Letzt hier die Code-Änderungen, welche die obigen Kritikpunkte beseitigen, im diff-Format gegen 2.8.9:</p>
<pre class="language-diff line-numbers"><code>--- cache-2.8.9.php	Mon Apr 02 17:33:19 2012
+++ cache.php	Mon May 21 18:08:21 2012
@@ -91,6 +91,15 @@
     return;
 }

+if (array_key_exists("HTTP_IF_MODIFIED_SINCE", $_SERVER)) {
+    $if_modified_since = strtotime(preg_replace('/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"]));
+    if ($if_modified_since &gt;= $hc_file_time) {
+        header("HTTP/1.0 304 Not Modified");
+        flush();
+        die();
+    }
+}
+
 // Load it and check is it's still valid
 $hyper_data = @unserialize(file_get_contents($hc_file));

@@ -117,21 +126,12 @@
 }

 // It's time to serve the cached page
-if (array_key_exists("HTTP_IF_MODIFIED_SINCE", $_SERVER)) {
-    $if_modified_since = strtotime(preg_replace('/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"]));
-    if ($if_modified_since &gt;= $hc_file_time) {
-        header("HTTP/1.0 304 Not Modified");
-        flush();
-        die();
-    }
-}

-// Now serve the real content
+$maxage = $hyper_cache_timeout - $hc_file_age;
+header('Cache-Control: max-age=' . $maxage);
+header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $maxage) . " GMT");

 // True if user ask to NOT send Last-Modified
-header('Cache-Control: no-cache, must-revalidate, max-age=0');
-header('Pragma: no-cache');
-header('Expires: Wed, 11 Jan 1984 05:00:00 GMT');
 if (!$hyper_cache_lastmodified) {
     header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $hc_file_time). " GMT");
 }
@@ -195,7 +195,7 @@
     if ($hyper_redirect) {
         if ($hyper_cache_redirects) {
             $data['location'] = $hyper_redirect;
-            hyper_cache_write($data);
+            $buffer = hyper_cache_write($data);
         }
         return $buffer;
     }
@@ -233,13 +233,13 @@

     if (is_404()) $data['status'] = 404;

-    hyper_cache_write($data);
+    $buffer = hyper_cache_write($data);

     return $buffer;
 }

 function hyper_cache_write(&amp;$data) {
-    global $hc_file, $hyper_cache_store_compressed;
+    global $hc_file, $hyper_cache_lastmodified, $hyper_cache_store_compressed, $hyper_cache_timeout;

     $data['uri'] = $_SERVER['REQUEST_URI'];

@@ -247,12 +247,21 @@
     if ($hyper_cache_store_compressed) {
         $data['gz'] = gzencode($data['html']);
         if ($data['gz']) unset($data['html']);
+        header('Content-Encoding: gzip');
     }
     $file = fopen($hc_file, 'w');
     fwrite($file, serialize($data));
     fclose($file);

-    header('Last-Modified: ' . date("r", @filemtime($hc_file)));
+    header('Cache-Control: max-age=' . $hyper_cache_timeout);
+    header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $hyper_cache_timeout) . " GMT");
+
+    // True if user ask to NOT send Last-Modified
+    if (!$hyper_cache_lastmodified) {
+        header('Last-Modified: ' . gmdate("D, d M Y H:i:s", @filemtime($hc_file)). " GMT");
+    }
+
+    return !empty($data['gz']) ? $data['gz'] : $data['html'];
 }

 function hyper_mobile_type() {</code></pre>
<p class="small"><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/de/" target="_blank" class="alignleft"><img decoding="async" alt="Creative Commons Lizenzvertrag" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/3.0/de/88x31.png" /></a> Dieser Beitrag wurde unter <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/de/" target="_blank">Creative Commons Namensnennung-Nicht-kommerziell-Weitergabe unter gleichen Bedingungen 3.0 Deutschland Lizenz</a> veröffentlicht.</p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/20/caching-in-wordpress/">Caching in WordPress</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>GZIP compression of static assets via mod_rewrite and PHP</title>
		<link>https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/</link>
					<comments>https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/#comments</comments>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Sun, 03 Jun 2012 17:05:16 +0000</pubDate>
				<category><![CDATA[Web development]]></category>
		<category><![CDATA[.htaccess]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Compression]]></category>
		<category><![CDATA[GZIP]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">http://hoech.net/?p=489</guid>

					<description><![CDATA[<p>Zur deutschen Version dieses Artikels To conserve bandwidth and speed up page loading, it pays off to also compress static files like stylesheets and scripts in addition to the page itself with GZIP and set meaningful cache retention times. With [&#8230;] <a href="https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/">GZIP compression of static assets via mod_rewrite and PHP</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div class="cta" >This PHP script has changed since its initial release. You can find the <a href="https://github.com/fhoech/gz.php">latest version of the GZIP compression script on github</a>.</div><div class="clear"></div>
<p><a href="/2012/06/03/gzip-kompression-fuer-statische-dateien-mit-mod_rewrite-und-php/"><img decoding="async" alt="" src="/wp-content/plugins/polylang/flags/de_DE.png" /> Zur deutschen Version dieses Artikels</a></p>
<p><img decoding="async" class="alignleft size-full wp-image-377" style="margin-left: -4px;" alt="" src="http://hoech.net/wp-content/uploads/2012/05/package-x-gz.png" width="66" height="73" /> To conserve bandwidth and speed up page loading, it pays off to also compress static files like stylesheets and scripts in addition to the page itself with GZIP and set meaningful cache retention times. With Apache, this process can be set up with a custom .htaccess file as dynamic on-the-fly compression with either mod_deflate, or alernatively via PHP. In my case I settled with a PHP solution which stores the compressed data on disk, so repeated requests don&#8217;t cause the files to be compressed over and over again, but only on first access (or if the file has changed). <span id="more-489"></span></p>
<p>The PHP script which takes care of the compression of requested files and stores the compressed data as .gz files on disk looks like this:</p>
<div class="list"><p class="trigger"><a href="#">PHP script</a></p><div class="toggle_container"><div class="block">
<pre class="language-php line-numbers"><code>&lt;?php

function get_content_type($file) {
    // Determine Content-Type based on file extension
    // Default to text/html
    $info = pathinfo($file);
    $content_types = array('css' =&gt; 'text/css; charset=UTF-8',
                           'html' =&gt; 'text/html; charset=UTF-8',
                           'gif' =&gt; 'image/gif',
                           'ico' =&gt; 'image/x-icon',
                           'jpg' =&gt; 'image/jpeg',
                           'jpeg' =&gt; 'image/jpeg',
                           'js' =&gt; 'application/javascript',
                           'json' =&gt; 'application/json',
                           'png' =&gt; 'image/png',
                           'txt' =&gt; 'text/plain',
                           'xml' =&gt; 'application/xml');
    if (empty($content_types[$info['extension']]))
        return 'text/html; charset=UTF-8';
    return $content_types[$info['extension']];
}

function main() {
    // Get file path by stripping query parameters from the request URI
    if (!empty($_SERVER['REQUEST_URI']))
        $path = preg_replace('/\/?(?:\?.*)?$/', '', $_SERVER['REQUEST_URI']);

    // If the path is empty, either use DEFAULT_FILENAME if defined, or exit
    if (empty($path)) {
        if (defined('DEFAULT_FILENAME')) $path = '/' . DEFAULT_FILENAME;
        else die();
    }

    $file = dirname(__FILE__) . $path;
    if (!file_exists($file)) die();

    $mtime = filemtime($file);

    // If the user agent sent a IF_MODIFIED_SINCE header, check if the file
    // has been modified. If it hasn't, send '304 Not Modified' header &amp; exit
    if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) &amp;&amp;
        $mtime &lt;= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
        header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304);
        exit;
    }
    
    // Determine Content-Type based on file extension
    $content_type = get_content_type($file);

    // If the user agent accepts GZIP encoding, store a compressed version of
    // the file (&lt;filename&gt;.gz)
    if (!empty($_SERVER['HTTP_ACCEPT_ENCODING']) &amp;&amp;
        in_array('gzip', preg_split('/\s*,\s*/',
                                    $_SERVER['HTTP_ACCEPT_ENCODING']))) {
        // Only write the compressed version if it does not yet exist or the
        // original file has changed
        $gzfile = $file . '.gz';
        if (!file_exists($gzfile) || filemtime($gzfile) &lt; $mtime)
            file_put_contents($gzfile, gzencode(file_get_contents($file)));
        // Send compression headers and use the .gz file instead of the
        // original filename
        header('Content-Encoding: gzip');
        $file = $file . '.gz';
    }

    // Vary max-age and expiration headers based on content type
    switch ($content_type) {
        case 'image/gif':
        case 'image/jpeg':
        case 'image/png':
            // Max-age for images: 31 days
            $maxage = 60 * 60 * 24 * 31;
            break;
        default:
            // Max-age for everything else: 7 days
            $maxage = 60 * 60 * 24 * 7;
    }

    // Send remaining headers
    header('Vary: Accept-Encoding');
    header('Cache-Control: max-age=' . $maxage);
    header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $maxage) . ' GMT');
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime) . ' GMT');
    header('Content-Type: ' . $content_type);
    header('Content-Length: ' . filesize($file));
    
    // If the request method isn't HEAD, send the file contents
    if ($_SERVER['REQUEST_METHOD'] != 'HEAD') readfile($file);
}

main();

?&gt;</code></pre>
</div></div></div>
<p>The script is stored as &#8218;gz.php&#8216; inside of the root directory of my WordPress installation. It detects if files have changed and recompresses them if needed. In addition it sends a &#8218;304 Not Modified&#8216; header if a file hasn&#8217;t changed since it was last requested. Furthermore we need to adjust the  .htaccess file. For my own WordPress installation it looks like this:</p>
<div class="list"><p class="trigger"><a href="#">.htaccess</a></p><div class="toggle_container"><div class="block">
<pre class="language-apache line-numbers"><code># Set 'Vary' response header for .gz files
&lt;FilesMatch "\.gz$"&gt;
&lt;IfModule mod_headers.c&gt;
Header always append Vary "Accept-Encoding"
&lt;/IfModule&gt;
&lt;/FilesMatch&gt;

&lt;IfModule mod_expires.c&gt;
ExpiresActive On
ExpiresByType application/json "access plus 1 week"
ExpiresByType application/x-javascript "access plus 1 week"
ExpiresByType application/xml "access plus 1 week"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 month"
ExpiresByType text/css "access plus 1 week"
ExpiresByType text/html "access plus 1 week"
ExpiresByType text/plain "access plus 1 week"
&lt;/IfModule&gt;

# BEGIN WordPress
&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
&lt;/IfModule&gt;
# END WordPress

# BEGIN GZIP
&lt;IfModule mod_rewrite.c&gt;
# If the user agent accepts gzip encoding...
RewriteCond %{HTTP:Accept-Encoding} gzip
# ...and the requested file exists...
RewriteCond %{REQUEST_FILENAME} -f
# ...then use a PHP script serve a compressed version. Done.
RewriteRule \.(css|html|ico|js|json|txt|xml)$ /gz.php [L]
&lt;/IfModule&gt;
# END GZIP</code></pre>
</div></div></div>
<p>For .gz file access, a &#8218;Vary&#8216; header is sent to enable correct caching over proxies. Following this directive are several directives for cache retention times (&#8218;Expires&#8216; and &#8218;Cache Control&#8216; header, users may change those as it suits them. In my case, CSS and JS files expire after one week and images after one month.</p>
<p>Alternatively, the mod_rewrite rule for the PHP script can be changed so only the first request calls upon the script, and subsequently the .gz files are accessed directly (which has the drawback that you need to remember to delete any .gz files manually if you make changes, but doesn&#8217;t need to call PHP for each file access):</p>
<pre class="language-apache line-numbers"><code>&lt;IfModule mod_rewrite.c&gt;
# If the user agent accepts gzip encoding...
RewriteCond %{HTTP:Accept-Encoding} gzip
# ...and if gzip-encoded version of the requested file exists (&lt;file&gt;.gz)...
RewriteCond %{REQUEST_FILENAME}.gz -f
# ...then serve the gzip-encoded file. Done.
RewriteRule ^(.+)$ $1.gz [L]
# Or if the user agent accepts gzip encoding...
RewriteCond %{HTTP:Accept-Encoding} gzip
# ...and the requested file exists...
RewriteCond %{REQUEST_FILENAME} -f
# ...then use a PHP script serve a compressed version. Done.
RewriteRule \.(css|html|ico|js|json|txt|xml)$ /gz.php [L]
&lt;/IfModule&gt;</code></pre>
<p class="small">Credits: .gz-Icon based on generic package icon from <a href="http://art.gnome.org/themes/icon/1352" target="_blank">GNOME 2.18 Icon Theme</a>, released under <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0">GNU GPL 2.0 Lizenz</a></p>
<p class="small"><a class="alignleft" href="http://creativecommons.org/licenses/by-nc-sa/3.0/de/" target="_blank" rel="license"><img decoding="async" style="border-width: 0;" alt="Creative Commons Lizenzvertrag" src="http://i.creativecommons.org/l/by-nc-sa/3.0/de/88x31.png" /></a> This article was published under <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/" target="_blank" rel="license">Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)</a>.</p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/">GZIP compression of static assets via mod_rewrite and PHP</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>GZIP-Kompression für statische Dateien mit mod_rewrite und PHP</title>
		<link>https://hoech.net/2012/06/03/gzip-kompression-fuer-statische-dateien-mit-mod_rewrite-und-php/</link>
					<comments>https://hoech.net/2012/06/03/gzip-kompression-fuer-statische-dateien-mit-mod_rewrite-und-php/#comments</comments>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Sun, 03 Jun 2012 17:05:10 +0000</pubDate>
				<category><![CDATA[Web-Entwicklung]]></category>
		<category><![CDATA[.htaccess]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[GZIP]]></category>
		<category><![CDATA[Kompression]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">http://wp.hoech.net/?p=333</guid>

					<description><![CDATA[<p>View english version of this article Um Bandbreite zu sparen und die Downloadgeschwindigkeit zu erhöhen, lohnt es sich, auch statische Dateien wie Stylesheets und JavaScripts mit GZIP zu komprimieren und eine sinnvolle Cache-Verweildauer festzulegen. Das lässt sich mit einer angepassten [&#8230;] <a href="https://hoech.net/2012/06/03/gzip-kompression-fuer-statische-dateien-mit-mod_rewrite-und-php/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/03/gzip-kompression-fuer-statische-dateien-mit-mod_rewrite-und-php/">GZIP-Kompression für statische Dateien mit mod_rewrite und PHP</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div class="cta" >Dieses PHP-Skript hat sich seit seiner Erstveröffentlichung geändert. <a href="https://github.com/fhoech/gz.php">Zur neuesten Version des GZIP-Komprimierungs-Skripts auf github</a>.</div><div class="clear"></div>
<p><a href="/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/"><img decoding="async" alt="" src="/wp-content/plugins/polylang/flags/en_US.png" /> View english version of this article</a></p>
<p><img loading="lazy" decoding="async" class="alignleft size-full wp-image-377" style="margin-left: -4px;" alt="" src="http://hoech.net/wp-content/uploads/2012/05/package-x-gz.png" width="66" height="73" /> Um Bandbreite zu sparen und die Downloadgeschwindigkeit zu erhöhen, lohnt es sich, auch statische Dateien wie Stylesheets und JavaScripts mit GZIP zu komprimieren und eine sinnvolle Cache-Verweildauer festzulegen. Das lässt sich mit einer angepassten .htacces-Datei gut automatisieren. Hierbei kann man entweder auf die dynamische Kompression mittels Apache mod_deflate oder aber eine Alternativlösung (in diesem Fall ein PHP-Skript) zurückgreifen. Ich habe mich für die PHP-Lösung entschieden, da ich die komprimierten Daten so im Dateisystem ablegen kann und etwas Prozessorleistung für die dynamische Kompression spare, die sonst mit mod_deflate bei jedem Dateizugriff erfolgt (und nicht nur beim ersten oder bei Änderungen, was den Vorteil der PHP-Lösung ausmacht). <span id="more-333"></span></p>
<p>Das PHP-Skript, das sich um die Kompression der angefragten Dateien kümmert und sie als statische .gz-Dateien auf dem Server ablegt, sieht wie folgt aus:</p>
<div class="list"><p class="trigger"><a href="#">PHP-Skript</a></p><div class="toggle_container"><div class="block">
<pre class="language-php line-numbers"><code>&lt;?php

function get_content_type($file) {
    // Determine Content-Type based on file extension
    // Default to text/html
    $info = pathinfo($file);
    $content_types = array('css' =&gt; 'text/css; charset=UTF-8',
                           'html' =&gt; 'text/html; charset=UTF-8',
                           'gif' =&gt; 'image/gif',
                           'ico' =&gt; 'image/x-icon',
                           'jpg' =&gt; 'image/jpeg',
                           'jpeg' =&gt; 'image/jpeg',
                           'js' =&gt; 'application/javascript',
                           'json' =&gt; 'application/json',
                           'png' =&gt; 'image/png',
                           'txt' =&gt; 'text/plain',
                           'xml' =&gt; 'application/xml');
    if (empty($content_types[$info['extension']]))
        return 'text/html; charset=UTF-8';
    return $content_types[$info['extension']];
}

function main() {
    // Get file path by stripping query parameters from the request URI
    if (!empty($_SERVER['REQUEST_URI']))
        $path = preg_replace('/\/?(?:\?.*)?$/', '', $_SERVER['REQUEST_URI']);

    // If the path is empty, either use DEFAULT_FILENAME if defined, or exit
    if (empty($path)) {
        if (defined('DEFAULT_FILENAME')) $path = '/' . DEFAULT_FILENAME;
        else die();
    }

    $file = dirname(__FILE__) . $path;
    if (!file_exists($file)) die();

    $mtime = filemtime($file);

    // If the user agent sent a IF_MODIFIED_SINCE header, check if the file
    // has been modified. If it hasn't, send '304 Not Modified' header &amp; exit
    if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) &amp;&amp;
        $mtime &lt;= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
        header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304);
        exit;
    }
    
    // Determine Content-Type based on file extension
    $content_type = get_content_type($file);

    // If the user agent accepts GZIP encoding, store a compressed version of
    // the file (&lt;filename&gt;.gz)
    if (!empty($_SERVER['HTTP_ACCEPT_ENCODING']) &amp;&amp;
        in_array('gzip', preg_split('/\s*,\s*/',
                                    $_SERVER['HTTP_ACCEPT_ENCODING']))) {
        // Only write the compressed version if it does not yet exist or the
        // original file has changed
        $gzfile = $file . '.gz';
        if (!file_exists($gzfile) || filemtime($gzfile) &lt; $mtime)
            file_put_contents($gzfile, gzencode(file_get_contents($file)));
        // Send compression headers and use the .gz file instead of the
        // original filename
        header('Content-Encoding: gzip');
        $file = $file . '.gz';
    }

    // Vary max-age and expiration headers based on content type
    switch ($content_type) {
        case 'image/gif':
        case 'image/jpeg':
        case 'image/png':
            // Max-age for images: 31 days
            $maxage = 60 * 60 * 24 * 31;
            break;
        default:
            // Max-age for everything else: 7 days
            $maxage = 60 * 60 * 24 * 7;
    }

    // Send remaining headers
    header('Vary: Accept-Encoding');
    header('Cache-Control: max-age=' . $maxage);
    header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $maxage) . ' GMT');
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime) . ' GMT');
    header('Content-Type: ' . $content_type);
    header('Content-Length: ' . filesize($file));
    
    // If the request method isn't HEAD, send the file contents
    if ($_SERVER['REQUEST_METHOD'] != 'HEAD') readfile($file);
}

main();

?&gt;</code></pre>
</div></div></div>
<p>Das Skript sollte als &#8218;gz.php&#8216; im Wurzelverzeichnis der WordPress-Installation liegen. Es erkennt, wann eine Datei geändert wurde und komprimiert diese nur dann erneut. Ausserdem sendet es eine &#8218;304 Not Modified&#8216;-Antwort, falls eine angefragte Datei seit der letzten Anfrage nicht verändert wurde.</p>
<p>Dann benötigen wir eine angepasste .htaccess-Datei. Für meine WordPress-Installation sieht diese wie folgt aus:</p>
<div class="list"><p class="trigger"><a href="#">.htaccess-Datei</a></p><div class="toggle_container"><div class="block">
<pre class="language-apache line-numbers"><code># Set 'Vary' response header for .gz files
&lt;FilesMatch "\.gz$"&gt;
&lt;IfModule mod_headers.c&gt;
Header always append Vary "Accept-Encoding"
&lt;/IfModule&gt;
&lt;/FilesMatch&gt;

&lt;IfModule mod_expires.c&gt;
ExpiresActive On
ExpiresByType application/json "access plus 1 week"
ExpiresByType application/x-javascript "access plus 1 week"
ExpiresByType application/xml "access plus 1 week"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 month"
ExpiresByType text/css "access plus 1 week"
ExpiresByType text/html "access plus 1 week"
ExpiresByType text/plain "access plus 1 week"
&lt;/IfModule&gt;

# BEGIN WordPress
&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
&lt;/IfModule&gt;
# END WordPress

# BEGIN GZIP
&lt;IfModule mod_rewrite.c&gt;
# If the user agent accepts gzip encoding...
RewriteCond %{HTTP:Accept-Encoding} gzip
# ...and the requested file exists...
RewriteCond %{REQUEST_FILENAME} -f
# ...then use a PHP script serve a compressed version. Done.
RewriteRule \.(css|html|ico|js|json|txt|xml)$ /gz.php [L]
&lt;/IfModule&gt;
# END GZIP</code></pre>
</div></div></div>
<p>Für .gz-Dateizugriffe wird der &#8218;Vary&#8216;-Header festgelegt, um korrektes Caching über Proxy-Server zu gewährleisten. Dann folgen einige Direktiven zur Cache-Verweildauer (&#8218;Expires&#8216;- bzw. &#8218;Cache-Control&#8216;-Header), diese lassen sich nach eigenem Gusto anpassen. Im Beispiel laufen CSS- und JS-Dateien nach einer Woche im Cache ab, Bilddateien nach einem Monat.</p>
<p>Alternativ lässt sich die mod_rewrite-Direktive für das PHP-Skript auch so ändern, dass nur der erste Zugriff einen Aufruf des Skripts erzeugt, und danach direkt die erstellte .gz-Datei abgerufen wird. Dazu die Zeilen zwischen # BEGIN GZIP und # END GZIP in dem .htaccess-Beispiel oben durch folgende Zeilen ersetzen:</p>
<pre class="language-apache line-numbers"><code>&lt;IfModule mod_rewrite.c&gt;
# If the user agent accepts gzip encoding...
RewriteCond %{HTTP:Accept-Encoding} gzip
# ...and if gzip-encoded version of the requested file exists (&lt;file&gt;.gz)...
RewriteCond %{REQUEST_FILENAME}.gz -f
# ...then serve the gzip-encoded file. Done.
RewriteRule ^(.+)$ $1.gz [L]
# Or if the user agent accepts gzip encoding...
RewriteCond %{HTTP:Accept-Encoding} gzip
# ...and the requested file exists...
RewriteCond %{REQUEST_FILENAME} -f
# ...then use a PHP script serve a compressed version. Done.
RewriteRule \.(css|html|ico|js|json|txt|xml)$ /gz.php [L]
&lt;/IfModule&gt;</code></pre>
<p class="small">Bildnachweis: .gz-Icon basierend auf generischem Paket-Icon aus <a href="http://art.gnome.org/themes/icon/1352" target="_blank">GNOME 2.18 Icon Theme</a>, veröffentlicht unter <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0">GNU GPL 2.0 Lizenz</a></p>
<p class="small"><a class="alignleft" href="http://creativecommons.org/licenses/by-nc-sa/3.0/de/" target="_blank" rel="license"><img decoding="async" style="border-width: 0;" alt="Creative Commons Lizenzvertrag" src="http://i.creativecommons.org/l/by-nc-sa/3.0/de/88x31.png" /></a> Dieser Beitrag wurde unter <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/de/" target="_blank" rel="license">Creative Commons Namensnennung-Nicht-kommerziell-Weitergabe unter gleichen Bedingungen 3.0 Deutschland Lizenz</a> veröffentlicht.</p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/03/gzip-kompression-fuer-statische-dateien-mit-mod_rewrite-und-php/">GZIP-Kompression für statische Dateien mit mod_rewrite und PHP</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://hoech.net/2012/06/03/gzip-kompression-fuer-statische-dateien-mit-mod_rewrite-und-php/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Neue Website ist online</title>
		<link>https://hoech.net/2012/06/03/neue-website-ist-online/</link>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Sun, 03 Jun 2012 17:00:07 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<guid isPermaLink="false">http://wp.hoech.net/?p=1</guid>

					<description><![CDATA[<p>&#8230;wurde auch Zeit, möchte man meinen, immerhin sind die Jahre der vorigen Web-Visitenkarte nun endlich passé. Herausgekommen ist dabei eine schlichte, hoffentlich funktionale und mobiltaugliche WordPress-Site mit ein paar kleinen Gimmicks (das Mini-Zahnrad im Footer führt bei modernen Browsern zu [&#8230;] <a href="https://hoech.net/2012/06/03/neue-website-ist-online/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/03/neue-website-ist-online/">Neue Website ist online</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>&#8230;wurde auch Zeit, möchte man meinen, immerhin sind die Jahre der vorigen Web-Visitenkarte nun endlich passé. Herausgekommen ist dabei eine schlichte, hoffentlich funktionale und mobiltaugliche WordPress-Site mit ein paar kleinen Gimmicks (das Mini-Zahnrad im Footer führt bei modernen Browsern zu einer Einstellungsseite). Die Site wurde auf möglichst geringe Ladezeiten optimiert (Google-Page-Speed-Score der Startseite ist 95/100, inkl. aller Abhängigkeiten ca. 200 KiB mit gzip-Kompression, worauf ich in Folgebeiträgen noch eingehen werde). Viel Spaß!</p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/03/neue-website-ist-online/">Neue Website ist online</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss><!-- hyper cache: hoech.net/feed/index.dat 26-06-08 10:05:05 -->