<?xml version="1.0" encoding="iso-8859-1"?><rss version="2.0"><channel><title>Procurios TechBlog RSS</title><link>http://techblog.procurios.nl/</link><description>The latest news articles</description><language>nl-NL</language><lastBuildDate>Thu, 11 Mar 2010 21:35:43 +0100</lastBuildDate><docs>http://blogs.law.harvard.edu/tech/rss</docs><generator>Procurios RSS2 Feed</generator><item><title>Locking multiple objects in MySQL</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/39224?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='locks' style='float:left;margin-right:1ex;' /&gt;I was looking for a way to lock several objects in a single transaction. It took me some time to figure it out, but it turned out to be very simple.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Subject&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;MySQL, using InnoDB tables, placing WRITE locks on (a distributed representation of) &quot;objects&quot;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;An object in a programming language usually needs to be stored in a database, for later retrieval. Most developers are using a relational database to do this. This means that an object is stored as a record in a table. And if it stays that simple, there is no problem. However, once an object gets more complex, it will span many more records, in several tables. And when two or more processes start editing the same object at the same time, data corruption may occur. The objects need to be locked explicitly for writing, so that the other process waits for the first one to finish. But how do you lock &quot;objects&quot;?&lt;br /&gt;&lt;br /&gt;I will give you an example of data corruption:&lt;br /&gt;&lt;br /&gt;A relation is represented by this main record (table: 'relation_main'):&lt;/p&gt;
&lt;pre&gt;[relation_id, lastname, firstname]&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;this relation has a single e-mail address in a separate table ('relation_address', because he can have many addresses)&lt;/p&gt;
&lt;pre&gt;[relation_id, e-mail]&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;This is an object that spans several (2) tables. At some point an extra e-mail address needs to be added to this relation and two processes (either people and or automated processes) enter the new address at the same time. The processes both check if the e-mail adres is present already, and if not, add it. But since both processes are doing this at the same time, the new address will have been entered twice.&lt;br /&gt;&lt;br /&gt;If your application has comparable situations, think of locking the objects: one of the processes acquires the lock first, the other process needs to wait until the other process is completely done with the object, before it can make its change.&lt;br /&gt;&lt;br /&gt;Now MySQL has a function for just this purpose: GET_LOCK(str, timeout). It enables you to acquire a single lock on any given identifier. It could be the relation_id of our example. RELEASE_LOCK(str) will release the lock again.&lt;br /&gt;&lt;br /&gt;If this was all there is to it I wouldn't be writing this article. The point is this: on the request of a second GET_LOCK(), MySQL will release the first lock. So the function does not allow you to acquire multiple locks. In a transaction it is often necessary to lock multiple objects at once. To be able to do that, we need another technique. I thought of some terribly hopeless alternatives that I will not expose here. In stead, let's look at the conclusion.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The Solution&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To lock an &quot;object&quot;, change a single special record that is part of the object, or that represents it, by updating it.&lt;br /&gt;&lt;br /&gt;How does that work? Well, remember the simple case where an object is represented by a single record? There is no need for an explicit object lock, because MySQL will place a write lock on the record automatically. You can use this principle to place a lock on an object with multiple records as well. All you need to do is to mark one of the object's records as special, and make sure that all processes that modify the object, modify this special record first. This way, by writing to a single record, a lock is acquired for the entire object.&lt;br /&gt;&lt;br /&gt;You can use a special &quot;locking&quot; table for this purpose, or use a special record inside of the object. It doesn't matter what update is made to the main record: update its last-modified time if you like. But writing the existing value of a field right back to it will do just fine:&lt;/p&gt;
&lt;pre&gt;UPDATE 'relation_main' SET 'firstname' = 'firstname' WHERE 'relation_id' = 1234;
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;No change is made to the data, but MySQL will still place a write lock on the record.&lt;br /&gt;&lt;br /&gt;When a process performs this update it may need to wait for another process to release this &quot;lock&quot;. Only after the UPDATE has completed, the process should read the object's current data from the database, because the other process have have changed it.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/39223/14863/Locking-multiple-objects-in-MySQL.html</link><pubDate>Sun, 17 Jan 2010 12:03:05 +0100</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/39223/14863</guid></item><item><title>Mark unread tabs in FireFox</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/38977?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='UnreadTab' style='float:left;margin-right:1ex;' /&gt;I&amp;#039;m a heavy FireFox user. When doing research these days my primary source of information is the web and the browser is my primary application. So I&amp;#039;m interested in everything that makes my FireFox life easier. I&amp;#039;d like to share the best tweak I know.&lt;/p&gt;&lt;p&gt;When reading a page I open a lot of tabs. Search results to be checked out later. Interesting topics I stumble upon by serendipity. References an article links to. A simple ctrl-click and they're being loaded in the background for later reading. The following tweak marks an unread tab with any style you like.&lt;/p&gt;
&lt;p&gt;Open the file chrome/userChrome.css in your FireFox &lt;a href='http://www.gemal.dk/mozilla/profile.html'&gt;profile directory&lt;/a&gt;. If this file does not exist you can create an empty one.&lt;/p&gt;
&lt;p&gt;Put the following simple css rule in it, restart FireFox and you're done.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;#content tab:not([selected]) {
	color:red !important;
}
&lt;/pre&gt;
&lt;p&gt;See the &lt;a href='http://www.mozilla.org/unix/customizing.html'&gt;Customizing Mozilla&lt;/a&gt; page on mozilla.org for more information about the chrome css files and lots of other tweaks.&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/38979/14863/Mark-unread-tabs-in-FireFox.html</link><pubDate>Sun, 03 Jan 2010 14:19:38 +0100</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/38979/14863</guid></item><item><title>Upgrade to PHP5.3 using dotdeb debian packages</title><description>&lt;p&gt;Currently we are testing PHP 5.3 on some of our production servers.&amp;nbsp;It has a quite stable feel to it.&lt;/p&gt;
&lt;p&gt;I expected much more problems. Although we had to modify our sources a bit, (To avoid &lt;a href='http://bugs.php.net/bug.php?id=46614'&gt;this bug&lt;/a&gt;&amp;nbsp;for example. Using empty() within our own database class extending mysqli) the effort into getting it to work wasn't too big.&lt;/p&gt;
&lt;p&gt;In the past years we've always used the &lt;a href='http://www.dotdeb.org/'&gt;dotdeb.org&lt;/a&gt; repository for php packages. Guillaume is doing a terrific job in keeping his packages updated with the last PHP source version. Typically it takes about 2-3 days for packages tot pop up on dotdeb after a new PHP release. Because 5.3 is such a big change, Guillaume has setup a &lt;a href='http://www.dotdeb.org/2009/07/03/php-5-3-0-final-preview-packages-available-for-debian-lenny/'&gt;separate repository&lt;/a&gt;&amp;nbsp;for it.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The dotdeb php 5.3 repository is still lacking some packages, so we had to build a few packages ourselves. The packages php5-apc, php5-ffmpeg and php5-mailparse built &lt;a href='http://www.dotdeb.org/2008/09/25/how-to-package-php-extensions-by-yourself/'&gt;the dh-make-pecl way&lt;/a&gt;&amp;nbsp;without problems.&lt;/p&gt;
&lt;p&gt;Building php5-imagick gave us some troubles. I don't recall if that was because we wanted them running on ubuntu too. The ImageMagick package is in transition from libimagick to -core and -wand packages. Also debian and ubuntu packages names are different. I eventually decided to build ImageMagick ourselves too. That way I have the same setup on production and my ubuntu development laptop.&lt;/p&gt;
&lt;p&gt;We are using the &lt;a href='http://pecl.php.net/package/syck'&gt;syck pecl package&lt;/a&gt;, that one built as a charm too. We use the &lt;a href='http://packages.debian.org/sid/libsyck0-dev'&gt;libsyck0-dev&lt;/a&gt; package from debian unstable&amp;nbsp;to build it.&lt;/p&gt;
&lt;p&gt;We also used the dbase functions that were available by default in PHP 5.2. From 5.3 on they have been moved to a pecl package, but it is still without maintainer. Currently it lives in SVN only at &lt;a href='http://svn.php.net/repository/pecl/dbase/'&gt;http://svn.php.net/repository/pecl/dbase/&lt;/a&gt;. This one wasn't easy to build. You have to make a file structure that complies with pecl packages, before you can use dh-make-pecl on it.&amp;nbsp;If you want I could provide you a debian source package for this one.&lt;/p&gt;
&lt;p&gt;Now the only thing missing is the Suhosin patch for PHP 5.3. Good news on that front: Arnold Daniels ported the patch&amp;nbsp;&lt;a href='http://blog.adaniels.nl/articles/suhosin-patch-for-php-53/'&gt;http://blog.adaniels.nl/articles/suhosin-patch-for-php-53/&lt;/a&gt;. Although it is not done by Stefan Esser of the &lt;a href='http://www.suhosin.org/'&gt;Suhosin&lt;/a&gt; team himself.&lt;/p&gt;
&lt;p&gt;Did you switch to PHP 5.3 already? Did you run into any problems?&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/35542/14863/Upgrade-to-PHP53-using-dotdeb-debian-packages.html</link><pubDate>Wed, 12 Aug 2009 16:02:56 +0200</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/35542/14863</guid></item><item><title>Cache a large array: JSON, serialize or var_export?</title><description>&lt;p&gt;While developing software like our framework you will need to cache a large data array to a file at some point sooner or later. At such a point you need to choose what caching method you will be using. In this article I will compare three methods: JSON, serialization and var_export() combined with include().&lt;/p&gt;&lt;p&gt;&lt;em&gt;Too curious? &lt;a href='http://techblog.procurios.nl#results'&gt;Jump right to the results!&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;JSON&lt;/h3&gt;
&lt;p&gt;The JSON method uses the &lt;a href='http://php.net/json_encode'&gt;json_encode&lt;/a&gt; and &lt;a href='http://php.net/json_decode'&gt;json_decode&lt;/a&gt; functions. The JSON-encoded data is stored as is into a plain text file.&lt;/p&gt;
&lt;h4&gt;Code example&lt;/h4&gt;
&lt;pre class='php' name='code'&gt;// Store cache&lt;br /&gt;file_put_contents($cachePath, json_encode($myDataArray));&lt;br /&gt;// Retrieve cache&lt;br /&gt;$myDataArray = json_decode(file_get_contents($cachePath));&lt;/pre&gt;
&lt;h4&gt;pros&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Pretty easy to read when encoded&lt;/li&gt;
&lt;li&gt;Can easily be used outside a PHP application&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;cons&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Only works with UTF-8 encoded data&lt;/li&gt;
&lt;li&gt;Will not work with objects other than instances of the stdClass class.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Serialization&lt;/h3&gt;
&lt;p&gt;The serialization method uses the &lt;a href='http://php.net/serialize'&gt;serialize&lt;/a&gt; and &lt;a href='http://php.net/unserialize'&gt;unserialize&lt;/a&gt; functions. The serialized data is, just like the JSON data, stored as is into a plain text file.&lt;/p&gt;
&lt;h4&gt;Code example&lt;/h4&gt;
&lt;pre class='php' name='code'&gt;// Store cache&lt;br /&gt;file_put_contents($cachePath, serialize($myDataArray));&lt;br /&gt;// Retrieve cache&lt;br /&gt;$myDataArray = unserialize(file_get_contents($cachePath));&lt;/pre&gt;
&lt;h4&gt;pros&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Does not need the data to be UTF-8 encoded&lt;/li&gt;
&lt;li&gt;Works with instances of classes other than the stdClass class.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;cons&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Nearly impossible to read when encoded&lt;/li&gt;
&lt;li&gt;Can not be used outside of a PHP application, without having to write custom functions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Var_export&lt;/h3&gt;
&lt;p&gt;This method 'encodes' the data using &lt;a href='http://php.net/var_export'&gt;var_export&lt;/a&gt; and loads the data using the &lt;a href='http://php.net/include'&gt;include&lt;/a&gt; statement (no need for file_get_contents!). The encoded data needs to be in a valid PHP file so we wrap the encoded data in the following PHP code:&lt;/p&gt;
&lt;pre class='php' name='code'&gt;&amp;lt;?php&lt;br /&gt;return /*var_export output goes here*/;&lt;/pre&gt;
&lt;h4&gt;Code example&lt;/h4&gt;
&lt;pre class='php' name='code'&gt;// Store cache&lt;br /&gt;file_put_contents($cachePath, &quot;&amp;lt;?php\nreturn &quot; . var_export($myDataArray, true) . &quot;;&quot;);&lt;br /&gt;// Retrieve cache&lt;br /&gt;$myDataArray = include($cachePath);&lt;/pre&gt;
&lt;h4&gt;pros&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;No need for UTF-8 encoding&lt;/li&gt;
&lt;li&gt;Is &lt;strong&gt;very&lt;/strong&gt; readable (assuming you can read PHP code)&lt;/li&gt;
&lt;li&gt;Retrieving the cache uses one language construct instead of two functions&lt;/li&gt;
&lt;li&gt;When using an opcode cache your cache file will be stored in the opcode cache. (This is actually a disadvantage, see the cons list).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;cons&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Needs PHP wrapper code.&lt;/li&gt;
&lt;li&gt;Can not encode Objects of classes missing the __set_state method.&lt;/li&gt;
&lt;li&gt;When using an opcode cache your cache file will be stored in the opcode cache. If you do not need a persistant cache this is useless, most opcode caches support storing values in the shared memory. If you don't mind storing the cache in memory, use the shared memory without writing the cache to disk first.&lt;/li&gt;
&lt;li&gt;Another disadvantage is that your stored file &lt;em&gt;has&lt;/em&gt; to be valid PHP. If it contains a parse error (which could happen when your script crashes while writing the cache) your application will not work anymore.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Benchmark&lt;/h3&gt;
&lt;p&gt;In my benchmark I used 5 different data sets with different sizes (measured in memory usage): 904B, ~18kB, ~250kB, ~4.5MB and ~72.5MB. For each of these data sets I did the following routine for each encoding method:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Encode the data 10 times&lt;/li&gt;
&lt;li&gt;Calculate the string length of the encoded data&lt;/li&gt;
&lt;li&gt;Decode the encoded data 10 times&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id='results'&gt;Results&lt;/h3&gt;
&lt;p&gt;Yay, results! In the result tables you see the length of the encoded string, the total time used for encoding and the total time used for decoding. The benchmark was done on my laptop: 2.53GHz, 4GB, Ubuntu linux, PHP 5.3.0RC4.&lt;/p&gt;
&lt;table border='0'&gt;
&lt;thead&gt; 
&lt;tr&gt;
&lt;th&gt;904 B array&lt;br /&gt;&lt;/th&gt; &lt;th&gt;JSON&lt;/th&gt; &lt;th&gt;Serialization&lt;/th&gt; &lt;th&gt;var_export / include&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt; 
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;td&gt;151&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encoding&lt;/td&gt;
&lt;td&gt;0.0000660419464111&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;0.00004696846008301&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;0.00014996528625488&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decoding&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;0.0011160373687744&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;0.00092697143554688&lt;/td&gt;
&lt;td&gt;0.0010221004486084&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table border='0'&gt;
&lt;thead&gt; 
&lt;tr&gt;
&lt;th&gt;18.07 kB array&lt;/th&gt; &lt;th&gt;JSON&lt;/th&gt; &lt;th&gt;Serialization&lt;/th&gt; &lt;th&gt;var_export / include&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt; 
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;1965&lt;/td&gt;
&lt;td&gt;2790&lt;/td&gt;
&lt;td&gt;3103&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encoding&lt;/td&gt;
&lt;td&gt;0.0005040168762207&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;0.00035905838012695&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;0.001352071762085&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decoding&lt;/td&gt;
&lt;td&gt;0.0017290115356445&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;0.0011298656463623&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;0.0056741237640381&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table border='0'&gt;
&lt;thead&gt; 
&lt;tr&gt;
&lt;th&gt;290.59 kB array&lt;/th&gt; &lt;th&gt;JSON&lt;/th&gt; &lt;th&gt;Serialization&lt;/th&gt; &lt;th&gt;var_export / include&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt; 
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;31725&lt;/td&gt;
&lt;td&gt;45030&lt;/td&gt;
&lt;td&gt;58015&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encoding&lt;/td&gt;
&lt;td&gt;0.0076849460601807&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;0.0057480335235596&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;0.02099609375&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decoding&lt;/td&gt;
&lt;td&gt;0.014955997467041&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;0.010177850723267&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;0.030472993850708&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table border='0'&gt;
&lt;thead&gt; 
&lt;tr&gt;
&lt;th&gt;4.54 MB array&lt;/th&gt; &lt;th&gt;JSON&lt;/th&gt; &lt;th&gt;Serialization&lt;/th&gt; &lt;th&gt;var_export / include&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt; 
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;507885&lt;/td&gt;
&lt;td&gt;720870&lt;/td&gt;
&lt;td&gt;1059487&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encoding&lt;/td&gt;
&lt;td&gt;0.13873195648193&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;0.11841702461243&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;0.38376498222351&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decoding&lt;/td&gt;
&lt;td&gt;0.29870986938477&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;0.21590781211853&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;0.53850317001343&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table border='0'&gt;
&lt;thead&gt; 
&lt;tr&gt;
&lt;th&gt;72.67 MB array&lt;/th&gt; &lt;th&gt;JSON&lt;/th&gt; &lt;th&gt;Serialization&lt;/th&gt; &lt;th&gt;var_export / include&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt; 
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;8126445&lt;/td&gt;
&lt;td&gt;11534310&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;19049119&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encoding&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;2.3055040836334&lt;/td&gt;
&lt;td&gt;2.7609040737152&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;6.2211949825287&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decoding&lt;/td&gt;
&lt;td style='background-color:#61E361;'&gt;4.5191099643707&lt;/td&gt;
&lt;td&gt;8.351490020752&lt;/td&gt;
&lt;td style='background-color:#D85865;'&gt;8.7873070240021&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;We've done the same benchmark on eight other machines including Windows and Mac OS machines and some webservers running Debian. Some of these machines had PHP 5.2.9 installed, others already switched to 5.3.0. All had the same (relative) results, except for a macbook in which serialize was faster encoding the largest dataset.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;As you can see the var_export (without opcode cache!) method doesn't come out that well and serialize seems to be the overall winner. What bothered me though was the largest dataset in which JSON became faster than serialize. Wondering whether this was a glitch or a trend I fired up my OpenOffice spreadsheet and created some charts:&lt;/p&gt;
&lt;p&gt;&lt;img style='vertical-align:middle;' src='http://techblog.procurios.nl/l/library/download/34987?width=450&amp;amp;height=289&amp;amp;ext=.png' border='0' alt='' width='450' height='289' /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img style='vertical-align:middle;' src='http://techblog.procurios.nl/l/library/download/34985?width=450&amp;amp;height=289&amp;amp;ext=.png' border='0' alt='' width='450' height='289' /&gt;&lt;/p&gt;
&lt;p&gt;The charts show the relative speed of each method compared to the fastest method (so 100% is the best a method can do). As you can see both JSON and var_export become relatively faster when the data set gets big (arrays of 70MB and bigger? Maybe you should reconsider the structure of your data set :)). So when using a sane sized data array: use serialize. When you want to go crazy with large data sets: use anything you like, disk i/o will become your bottleneck.&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/34972/14863/Cache-a-large-array-JSON-serialize-or-var_export.html</link><pubDate>Thu, 09 Jul 2009 16:20:40 +0200</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/34972/14863</guid></item><item><title>ProtoFish: advanced hover menu based on Prototype</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/34554?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='protofish' style='float:left;margin-right:1ex;' /&gt;ProtoFish is an advanced hover menu based on Prototype. You can easily add a delay to your menu (on mouseout) and choose your own hover class. All ProtoFish menu&amp;#039;s are keyboard accessible conform ARIA best practices. On top of that: it&amp;#039;s fully customizable and free to use!&lt;/p&gt;&lt;div style='padding:10px;margin-bottom:1em;background-color:#FFF7D0;border:1px solid #43A52A;'&gt;
&lt;h2&gt;&lt;span style='color:#000000;'&gt;Quickstart&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;You've come here to implement ProtoFish into your website. Due to ProtoFish' popularity, we've decided to give ProtoFish it's own home at&lt;a href='http://protofish.procurios.nl/'&gt; http://protofish.procurios.nl/&lt;/a&gt;. All implementation details can be found there!&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Why ProtoFish?&lt;/h2&gt;
&lt;p&gt;Most people know the parent of all hover menu's: the &lt;a href='http://www.alistapart.com/articles/dropdowns/'&gt;SuckerFish dropdown&lt;/a&gt; menu published by A List Apart in 2003. Obviously, the name ProtoFish is a combination of the Prototype JS framework and the SuckerFish technique published by A List Apart. There are many enhanced versions of the SuckerFish dropdown around on the web, but none of them met the following, to me important, criteria:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The script should be based on Prototype,&lt;/li&gt;
&lt;li&gt;The script should be lightweight and&lt;/li&gt;
&lt;li&gt;The script should be easy to implement.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Finding a good menu-script based on criteria #1 is already hard enough, so I decided to write my own class and share it with the world!&lt;/p&gt;
&lt;h2&gt;Can I customize ProtoFish?&lt;/h2&gt;
&lt;p&gt;Sure! You're allowed to use ProtoFish without any constraints. Rip the code apart or add some features - use it the way you like! If you download the non-minified ProtoFish version, you can easily get a grip on the code, by reading the comments!&lt;/p&gt;
&lt;p&gt;You can also contribute to ProtoFish on github: &lt;a href='http://github.com/pesla/ProtoFish/'&gt;http://github.com/pesla/ProtoFish/&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Feedback&lt;/h2&gt;
&lt;p&gt;If you've found a bug, want to improve ProtoFish or just want to give some feedback, feel free to contact me &lt;a href='http://www.twitter.com/pesla'&gt;on Twitter (@pesla)&lt;/a&gt; or leave a comment below this post.&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/34556/14863/ProtoFish-advanced-hover-menu-based-on-Prototype.html</link><pubDate>Wed, 19 Aug 2009 12:22:33 +0200</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/34556/14863</guid></item><item><title>Semantic web marvels in a relational database - part II: Comparing alternatives</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/34453?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='organize' style='float:left;margin-right:1ex;' /&gt;In this article I will compare the basic technical details of current relational database alternatives. &lt;/p&gt;&lt;p class='first'&gt;In the &lt;a href='http://techblog.procurios.nl/k/618/news/view/34300/14863/Semantic-web-marvels-in-a-relational-database---part-I-Case-Study.html'&gt;first article in this series&lt;/a&gt; I explained the relational database mapping of our semantic web implementation. In this article I will place this work into perspective by exploring related techniques.&lt;/p&gt;
&lt;p&gt;The last few years developers are looking for ways to overcome certain shortcomings of relational database systems. RDBMSes are general purpose data stores that are flexible enough to store any type of data. However, these are several cases in which the &lt;a href='http://en.wikipedia.org/wiki/Relational_model'&gt;relational model&lt;/a&gt; proves inefficient:&lt;/p&gt;
&lt;ul class='first'&gt;
&lt;li&gt;An object has many attributes (100+), many of which are optional. It would be wasting space to store all these attributes in separate columns.&lt;/li&gt;
&lt;li&gt;Many attributes with multiple values. Since each of these attributes needs a separate table, the object data will be distributed over many tables. This is inefficient in terms of development time, maintenance, as well as query time.&lt;/li&gt;
&lt;li&gt;Class inheritance. Since most software is Object Oriented these days the objects in code will need to be mapped to the database structure. In the case of class inheritance, where attributes are inherited from superclasses, it is a big problem to store objects in, and query them from, an RDBMS efficiently.&lt;/li&gt;
&lt;li&gt;Types and attributes are not objects. In an RDBMS the data of a model is separate from the metadata (attribute names, datatypes, foreign key constraints, etc.). Types and attributes are not like normal objects. This is inefficient in areas where types and attributes need to be added, changed and removed regularly, just like any other data. It is inefficient to write separate code to manipulate and query types and attributes. In short, &lt;em&gt;first order predicate logic no longer suffices&lt;/em&gt; for many new applications. The &lt;a href='http://en.wikipedia.org/wiki/Second_order_predicate_calculus'&gt;second order&lt;/a&gt; is needed.&lt;/li&gt;
&lt;li&gt;Scalability. Is an aspect often named as the reason to leave RDBMS. However, since relational databases have been optimized for decades, they &lt;em&gt;do scale&lt;/em&gt;. Nevertheless, in this age of global, real-time webapplications, techniques provided by RDBMS manufacturers may prove to be inadequate, or simply too expensive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the following I will provide a simple understanding of the basic principles of alternative database techniques, along with some pointers to more in-depth information. &lt;em&gt;I hope you will forgive me my non-expert view on these subjects.&lt;/em&gt; For detailed information on any given subject, look elsewhere. This article is meant to be just a quick overview, aimed to waken some concepts provided by the examples.&lt;/p&gt;
&lt;h2 class='first'&gt;RDBMS, or Row-Oriented database&lt;/h2&gt;
&lt;p&gt;In a relational database management system, pieces of data are grouped together in a record. In this article I will consider the case where the data stored is meant to represent the attributes of an object. Seen this way, a record is a group of attributes of an object. Here's an example of such a table of objects:&lt;/p&gt;
&lt;table class='first' style='width:293px;height:76px;' border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;color&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;width&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;height&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;name&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;red&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;my box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;green&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;old beam&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;br /&gt;Metadata is shown in gray. Keys / foreign keys are shown in bold typeface.&lt;/p&gt;
&lt;p&gt;Need more attributes? Add more columns. Need an attribute with multiple values? Add a table and link it to the first. The RDBMS chooses speed over flexibility. Speed was a big deal 40 years ago, when this database type was designed. And it still is a big deal today. For large amounts of simple data, there is absolutely no need to leave this model.&lt;/p&gt;
&lt;h2 class='first'&gt;Semantic net&lt;/h2&gt;
&lt;p&gt;Storing semantic information as triples is an old idea in the field of Knowledge Representation. As early as 1956, &lt;a href='http://en.wikipedia.org/wiki/Semantic_net'&gt;semantic nets&lt;/a&gt; were used for this purpose. In this technique the relations between objects are represented by plain labels. Each &quot;record&quot; stores only a single attribute, or one element of an array-attribute. Most notable are the absense of metadata and the fact that object data is distributed over many records.&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;predicate&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;value&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;color&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;red&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;width&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;height&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;name&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class='first last'&gt;my box&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;color&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;green&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;width&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;height&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;name&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;old beam&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;br /&gt;Need more attributes? No need to change the table structure. Need an attribute with multiple values? Same thing.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style='text-align:center;'&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/34456?width=345&amp;amp;height=258' alt='' width='345' height='258' /&gt;&lt;/p&gt;
&lt;p class='first'&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 class='first'&gt;Entity-Attribute-Value&lt;/h2&gt;
&lt;p&gt;The &lt;a href='http://en.wikipedia.org/wiki/Entity-attribute-value_model'&gt;Entity-Attribute-Value&lt;/a&gt; model of knowledge representation uses some form of triples, just like the semantic web. Its primary use is described by Wikipedia as &quot;Entity-Attribute-Value model (EAV), also known as object-attribute-value model and open schema is a data model that is used in circumstances where the number of attributes (properties, parameters) that can be used to describe a thing (an &quot;entity&quot; or &quot;object&quot;) is potentially very vast, but the number that will actually apply to a given entity is relatively modest. In mathematics, this model is known as a sparse matrix.&quot;&lt;/p&gt;
&lt;p&gt;Attribute metadata is stored in separate attribute tables, which are not triples. EAV is a sort of middle between semantic nets and semantic web: attributes have explicit properties, but these are fixed in amount.&lt;/p&gt;
&lt;p&gt;EAV can be used to model classes and relationships as in &lt;a href='http://en.wikipedia.org/wiki/Entity-Attribute-Value_model#Representing_substructure:_EAV_with_classes_and_relationships_.28EAV.2FCR.29'&gt;EAV/CR&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;EAV is &lt;a href='http://en.wikipedia.org/wiki/Entity-attribute-value_model#EAV_and_Cloud_Computing'&gt;used in Cloud computing databases&lt;/a&gt; like Amazon's SimpleDB and Google's App Engine.&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#c0c0c0;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#c0c0c0;'&gt;attribute id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#c0c0c0;'&gt;value&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;1&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;red&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;2&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;3&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;100&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;3&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;4&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class='first last'&gt;&lt;span style='color:#000000;'&gt;my box&lt;/span&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;4&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;1&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;green&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;4&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;2&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;50&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;4&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;3&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#000000;'&gt;500&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;4&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span style='color:#000000;'&gt;4&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old beam&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#c0c0c0;'&gt;attribute id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#c0c0c0;'&gt;name&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#c0c0c0;'&gt;datatype&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#c0c0c0;'&gt;unique&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;color&lt;/td&gt;
&lt;td&gt;char(6)&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;width&lt;/td&gt;
&lt;td&gt;double&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;height&lt;/td&gt;
&lt;td&gt;double&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;br /&gt;Need more attributes? Add them in the attribute table. Attributes with multiple values? No extra work. The schema of the attributes is stored in the database explicitly, but attributes are treated different from the objects.&lt;/p&gt;
&lt;h2&gt;Column-Oriented databases&lt;/h2&gt;
&lt;p&gt;From &lt;a href='http://en.wikipedia.org/wiki/Column-oriented_DBMS'&gt;wikipedia&lt;/a&gt;: &quot;A column-oriented DBMS is a database management system (DBMS) which stores its content by column rather than by row.&quot;&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;color&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;red&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;green&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;width&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;height&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;name&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;my box&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old beam&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Google's BigTable is based, in part, on column-orientation. Their tables use reversed URI's as object and column identifiers, and have a &quot;third dimension&quot; in that older revisions of the data are stored in the same table.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href='http://marklogic.blogspot.com/2007/03/whats-column-oriented-dbms.html'&gt;What's a Column-Oriented DBMS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href='http://labs.google.com/papers/bigtable.html'&gt;Google's research paper on BigTable&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Correlation databases&lt;/h2&gt;
&lt;p&gt;A &lt;a href='http://en.wikipedia.org/wiki/Correlation_database'&gt;correlation database&lt;/a&gt; is &quot;value based&quot;: every constant value is stored only once. All these values are stored together, except that values are grouped by datatype. All values are indexed. &quot;In addition to typical data values, the data value store contains a special type of data for storing relationships between tables...but with a CDBMS, the relationship is known by the dictionary and stored as a data value.&quot;&lt;/p&gt;
&lt;p&gt;I have not found a clear example of what this datastructure looks like, but we can infer that the internal structure must look something like the following. &lt;em&gt;Note: I may be completely wrong here&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;The values-table (actually there is one table per major datatype; i.e. integers, strings, dates, etc.)&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;value id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;value&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;red&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;green&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;6&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;my box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;7&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old beam&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;object 1&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;object 2&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;relationship color&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;11&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;relationship width&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;relationship height&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;13&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;relationship name&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;and then there is at least a table containing the relationships (or: &quot;associations&quot;) between the values. The relationships are stored as values themselves:&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;value id 1&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;association&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;value id 2&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;13&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;13&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;br /&gt;References:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href='http://www.illuminateinc.com/VBS-ad-hoc-query-performance.html'&gt;Value-based storage (VBS) unleashes fast ad hoc query performance.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Hierarchical model, Network model, Navigational database&lt;/h2&gt;
&lt;p&gt;For the sake of completeness I have to name these models. The &lt;a href='http://en.wikipedia.org/wiki/Hierarchical_model'&gt;hierarchical model&lt;/a&gt; stores tree-like structures only, requiring each piece of data to have a single &quot;parent&quot;. The &lt;a href='http://en.wikipedia.org/wiki/Network_model'&gt;network model&lt;/a&gt; allows a piece of data to have multiple parents. Both models were superseded by the relational model, but they are still used for special-purpose applications. A &lt;a href='http://en.wikipedia.org/wiki/Navigational_database'&gt;navigational database&lt;/a&gt; allows to traverse such trees / DAGs by following paths.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style='text-align:center;'&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/34463?width=333&amp;amp;height=389' alt='' width='333' height='389' /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Object-Oriented databases&lt;/h2&gt;
&lt;p&gt;In an &lt;a href='http://en.wikipedia.org/wiki/Object_database'&gt;object-oriented database&lt;/a&gt; all attributes of a class are stored together. From what I've read on the internet I conclude that the actual storage structure of an OODBMS is sort of an implementation detail. This means that performance characteristics of the database will depend heavily on the type of implementation chosen. Development of this model was first in the hands of the &lt;a href='http://en.wikipedia.org/wiki/Object_Data_Management_Group'&gt;ODMG&lt;/a&gt;, but control was transferred to the Java Community Proces that build the &lt;a href='http://en.wikipedia.org/wiki/Java_Data_Objects'&gt;Java Data Objects&lt;/a&gt; specification. This specification names the conditions for such a database, but does not guide the implementation.&lt;/p&gt;
&lt;p&gt;Some special properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Class inheritance is supported in the data model.&lt;/li&gt;
&lt;li&gt;Object nesting: an object can contain (not just &lt;em&gt;link to&lt;/em&gt;) other objects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mapped to an RDBMS, a so called ORM (Object Relational Mapping), objects are commonly stored in a standard relational way: one column per (single valued) attribute. To implement inheritance, the columns of all base classes of an object are joined. This can be done at design-time (create a big table containing the columns of all parent classes) or at query-time (join parent class tables).&lt;/p&gt;
&lt;table style='width:293px;height:76px;' border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;class id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;color&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;width&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;height&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;name&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;101&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;red&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;my box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;101&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;green&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;old beam&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;class id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;class name&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;parent class&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;101&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;102&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bar&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;br /&gt;References:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href='http://www.jcp.org/en/jsr/detail?id=243'&gt;JSR 243: Java Data Objects 2.0 specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href='http://www.amazon.com/Building-Scalable-Database-Applications-Object-Oriented/dp/0201310139'&gt;Building Scalable Database Applications: Object-Oriented Design, Architectures and Implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href='http://www.acm.org/crossroads/xrds7-3/objects.html'&gt;Objects, objects everywhere&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Document based databases&lt;/h2&gt;
&lt;p&gt;A &lt;a href='http://en.wikipedia.org/wiki/Column-oriented_DBMS'&gt;document based database&lt;/a&gt; is a different beast altogether. It lacks a database schema completely, and a complete object is stored in a single cell. In the case of &lt;a href='http://en.wikipedia.org/wiki/CouchDB'&gt;CouchDB&lt;/a&gt;, this is done by encoding the object (or: document) in JSON. Real-time querying of the source table is thus impossible, one needs to create &lt;em&gt;views&lt;/em&gt; on the data.&lt;/p&gt;
&lt;table border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;document&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;{&quot;color&quot;:&quot;red&quot;,&quot;width&quot;:100,&quot;height&quot;:100,&quot;name&quot;:&quot;my box&quot;}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;{&quot;color&quot;:&quot;green&quot;,&quot;width&quot;:50,&quot;height&quot;:500,&quot;name&quot;:&quot;old beam&quot;}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;br /&gt;References:&lt;/p&gt;
&lt;ul class='last'&gt;
&lt;li&gt;&lt;a href='http://couchdb.apache.org/docs/overview.html'&gt;CouchDB: Technical Overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Triplestores&lt;/h2&gt;
&lt;p&gt;Some &lt;a href='http://en.wikipedia.org/wiki/Triplestore'&gt;triplestores&lt;/a&gt; are publicly available. Commonly they have an RDF interface. Their performance can be measured using the &lt;a href='http://swat.cse.lehigh.edu/projects/lubm/'&gt;Lehigh University Benchmark (LUBM)&lt;/a&gt;. The most advanced open source triplestores are &lt;a href='http://www.openrdf.org/'&gt;Sesame&lt;/a&gt;, and &lt;a href='http://arc.semsol.org/'&gt;ARC&lt;/a&gt;.&lt;/p&gt;
&lt;table class='last' border='1'&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;object id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;attribute id&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style='color:#888888;'&gt;value&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;101&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;red&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;102&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;103&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;104&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;my box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;101&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;green&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;102&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;103&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;104&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old beam&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;101&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;104&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;color&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;102&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;104&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;width&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;103&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;104&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;height&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;104&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;104&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Very little has been made public about the way triplestores are implemented in a relational database. A laudable exception to this is the &lt;a href='http://jena.sourceforge.net/DB/layout.html'&gt;Jena2 database schema&lt;/a&gt;. Unfortunately, the schema appears to be very inefficient, since the URIs are not indexed but are used literally.&lt;/p&gt;
&lt;p&gt;A charmingly simple implementation that seems resource intensive was made for &lt;a href='http://dev.isb-sib.ch/projects/expasy4j-webng/store.html'&gt;expasy4j&lt;/a&gt;: triples are stored in a single table, but for query speed, a single column is reserved for each separate datatype.&lt;/p&gt;
&lt;p&gt;Another, somewhat better implementation was made for &lt;a href='http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VOSRDFWP'&gt;OpenLink Virtuoso&lt;/a&gt;: it uses indexed uris, but all constants are placed in a single field datatyped &quot;ANY&quot;.&lt;/p&gt;
&lt;h2 class='last'&gt;Conclusion&lt;/h2&gt;
&lt;p class='last'&gt;I hope this article has shown you a little bit why developers are looking for alternatives for the familiar RDBMS and which forms these currently have taken. Currently the field is quite diverse and developments are being made by many different parties. It will be interesting to see how this evolves and which alternative(s) will eventually become the successor of the relational database.&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/34441/14863/Semantic-web-marvels-in-a-relational-database---part-II-Comparing-alternatives.html</link><pubDate>Sun, 13 Sep 2009 11:18:04 +0200</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/34441/14863</guid></item><item><title>Semantic web marvels in a relational database - part I: Case Study</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/34312?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='triplestore2' style='float:left;margin-right:1ex;' /&gt;You have heard about the semantic web. You know it is described as the future of the Web. But you are still wondering how this vision is going to make your applications better. Can it speed up application development? Can it help you to build complex datastructures? Can you use Object Oriented principles? This article shows how it can be done. And more.&lt;/p&gt;&lt;p&gt;The &lt;a href='http://en.wikipedia.org/wiki/Semantic_web'&gt;semantic web&lt;/a&gt; is framework developed by the &lt;a href='http://www.w3.org/2001/sw/'&gt;W3C&lt;/a&gt; under supervision of Tim Berners Lee. Its basic assumption is that data should be self-descriptive in a global way. That means that data does not just express numbers, dates and text, it also &lt;em&gt;explicitly expresses&lt;/em&gt; the types of relationship these fields have for their objects. Using this uniform datastructure, it will be easier to interchange data between different servers, and most of all, data can be made accessible to global search engines.&lt;/p&gt;
&lt;p&gt;That is a big thing. But is that all? Can't you just provide an RDF import / export tool for your data and be done? Are there any intrinsic reasons why you would base you entire datastructure on the semantic web?&lt;/p&gt;
&lt;p class='first'&gt;In a series of two articles I will try to explain how we at Procurios implemented semantic web concepts, what the theoretical background of our implementation is, and what benefits a semantic web has over a traditional relational database. In this first article I will explain how we implemented a semantic web in a relational database (we used MySQL), added an object oriented layer on top, and even created a data revision control system from it.&lt;/p&gt;
&lt;h2&gt;Triples&lt;/h2&gt;
&lt;p&gt;In a classic relational database, data is stored in records. Each record contains multiple fields. These fields contain data that may belong to some object. The relation between the field and the object it belongs to is not represented as data in the database. It is only available as metadata in the form of the column (name, datatype, collation, foreign keys). An object is not explictly modelled, but rather via a series of linked tables.&lt;/p&gt;
&lt;p&gt;A semantic web is a network of interrelated triples (&quot;subject-predicate-object&quot; triplets) whose predicates are part of the data themselves. Moreover, each object has an identifier that is not just an integer number that means only something inside the database only. It is a URI that may have a distinct meaning worldwide.&lt;/p&gt;
&lt;p&gt;A triple is a record containing three values: either &lt;strong&gt;(uri, uri, uri)&lt;/strong&gt; or&lt;strong&gt; (uri, uri, value)&lt;/strong&gt;. In the first form the triple relates one object to another, as in the fact &quot;Vox inc. is a supplier&quot; (Both &quot;Vox inc.&quot;, &quot;is a&quot;, and &quot;supplier&quot; are semantic subjects identified by a uri). In the second form the triple links a constant value to a subject, as in&amp;nbsp; &quot;Vox inc.'s phone number is 0842 020 9090&quot;. A naive implementation would look like this:&lt;/p&gt;
&lt;pre class='sql' name='code'&gt;CREATE TABLE 'triple' (&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'subject'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;varchar(255) NOT NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'predicate'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;  varchar(255) NOT NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'object'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;   longtext,&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;This table provides a complete implementation for the semantic web. However, it is too slow to be used in any serious application. Now, there are various ways in which this basic form can be optimized, but to my knowledge there is no best practise available. Several problems have to met:&lt;/p&gt;
&lt;ul class='first'&gt;
&lt;li&gt;How to identify a triple uniquely (If this is necessary for your application. The combination of subject, predicate, object itself is not unique)&lt;/li&gt;
&lt;li&gt;How to search fast, given a subject and predicate? (&quot;Give me the names of these set of people&quot;?)&lt;/li&gt;
&lt;li&gt;How to search fast, given a predicate and an object? (&quot;Give me the persons whose name begins with 'Moham'&quot;?)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To solve these problems we came up with the following changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a single triple index table that only stores triple ids.&lt;/li&gt;
&lt;li&gt;Create separate triple tables for each of the major datatypes needed (varchar(255), longtext, integer, double, datetime)&lt;/li&gt;
&lt;li&gt;The triple tables reference the index table by foreign key.&lt;/li&gt;
&lt;li&gt;Add two extra indexes for the two ways the tables are used: a subject-predicate combined key and a predicate-object combined key.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's the triple index table (we are using MySQL):&lt;/p&gt;
&lt;pre class='sql' name='code'&gt;CREATE TABLE 'triple' (&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'triple_id'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;int(11) NOT NULL auto_increment,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;PRIMARY KEY ('triple_id')&lt;br /&gt;) ENGINE=InnoDB DEFAULT CHARSET=latin1;&lt;/pre&gt;
&lt;p&gt;and here's the triple table for the datatype &quot;datetime&quot; (the other datatypes are handled similarly)&lt;/p&gt;
&lt;pre class='sql' name='code'&gt;CREATE TABLE 'triple_datetime' (&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'triple_id'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int(11) NOT NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'subject_id'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;  &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; int(11) NOT NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'predicate_id'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;    &amp;nbsp;&amp;nbsp; int(11) NOT NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'object'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; datetime NOT NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'active'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; tinyint(1) NOT NULL DEFAULT '1',&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;PRIMARY KEY ('triple_id'),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;KEY ('subject_id', 'predicate_id'),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;KEY ('predicate_id', 'object'),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;CONSTRAINT 'triple_datetime_ibfk_1' FOREIGN KEY ('triple_id') REFERENCES 'triple' ('triple_id') ON DELETE CASCADE&lt;br /&gt;) ENGINE=InnoDB DEFAULT CHARSET=latin1;&lt;/pre&gt;
&lt;p&gt;The table definition should speak for itself, except for the field &quot;active&quot;. This field is not necessary at this point, but I will need it in the next section.&lt;/p&gt;
&lt;p&gt;The predicate_id refers to a separate &quot;uri&quot; table where the full uris of these predicates are stored. However, this is not necessary and the uris may be stored in the triple_longtext table as well.&lt;/p&gt;
&lt;p&gt;The two combined keys have an interesting side-effect: the application developer never needs to be concerned again about using the right keys. Effective keys have been added by default.&lt;/p&gt;
&lt;p&gt;To query this triplestore building SQL queries by hand may be a daunting task. It requires a special query language to be effective. More about that below.&lt;/p&gt;
&lt;p&gt;All data of a given object can be queried by selecting all triples with a given subject id (one query per datatype triple table). That seems to be inefficient and it is: compared to the situation where an object can be stored in a single record, the triplestore is always slower. However, in a more complex situation a relational database requires you to join many tables to fetch all data. We use 5 separate queries (one per datatype table) to fetch all object data from the triplestore. This turned out faster than a single union query on the five queries. We use the same 5 queries to fetch all data of any desired number of objects. Here a the queries needed to fetch object data from three objects identified by the ids 12076, 12077, and 12078:&lt;/p&gt;
&lt;pre class='SQL' name='code'&gt;SELECT 'object' FROM 'triple_varchar' WHERE 'subject_id' IN (12076, 12077, 12078);&lt;br /&gt;SELECT 'object' FROM 'triple_longtext' WHERE 'subject_id' IN (12076, 12077, 12078);&lt;br /&gt;SELECT 'object' FROM 'triple_integer' WHERE 'subject_id' IN (12076, 12077, 12078);&lt;br /&gt;SELECT 'object' FROM 'triple_double' WHERE 'subject_id' IN (12076, 12077, 12078);&lt;br /&gt;SELECT 'object' FROM 'triple_datetime' WHERE 'subject_id' IN (12076, 12077, 12078);&lt;/pre&gt;
&lt;p&gt;You can see that the object-data is fetched from the database without having to provide explicit type or attribute information. The type of the object is stored in one of the triples. This is useful in case of inheritance where the exact type of an object can only be determined at runtime.&lt;/p&gt;
&lt;p style='text-align:center;'&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/34301?width=102&amp;amp;height=98&amp;amp;ext=.png' alt='' width='102' height='98' /&gt;&lt;/p&gt;
&lt;h2 class='last'&gt;Arrays and multilinguality&lt;/h2&gt;
&lt;p&gt;Many object attributes have an array datatype (an unordered set). To model these in a relational database you would need a separate table for each of these attributes. Querying all attributes of a series of objects including these array attributes is far from easy. In the triple store you can model an unordered set as a series of triples having the same subject and predicate and a different object. When you query all object data, you will get the array values the same way as you get the scalar values.&lt;/p&gt;
&lt;p&gt;Multilinguality is also a hassle in relational databases. For each of the attributes that need to be available in more than one language the table structure needs to be adjusted and it is hard to avoid data duplication. In a triplestore you can treat a multilingual attribute almost like an array element. The only thing is that the predicates are similar but not the same. We use the following uri's for the representation of different language variants of an attribute: http://our-business.com/supplier/description#nl, http://our-business.com/supplier/description#en, http://our-business.com/supplier/description#de (in the tables these predicates are replaced by their integer ids for faster querying).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style='text-align:center;'&gt;&lt;img style='border:0px solid;' src='http://techblog.procurios.nl/l/library/download/34307?width=500&amp;amp;height=40' alt='' width='500' height='40' /&gt;&lt;/p&gt;
&lt;p style='text-align:left;'&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Data revision control&lt;/h2&gt;
&lt;p&gt;Version control is pretty common for developers when it comes to storing previous versions of their code. It allows you to track the changes of the code, revert to a previous version, and to work on the same file together. Still, when it comes to data, version control is very uncommon. And I think that is mainly because the overhead to create such a system is huge in a traditional relational database.&lt;/p&gt;
&lt;p&gt;One of the requirements for our framework was that there should be some form of data-change history available. And when you think of it, it is actually really simple to keep track of all the changes that are made to the data if you use triples. And that's because from a version-control point of view, all that changes each revision is that &lt;em&gt;some triples are added, and others are removed&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So all that is needed is two more tables, one to keep track of the revision-data, like, who made the change, when, and a short description for future reference, and another to track all the added and removed triples in this revision:&lt;/p&gt;
&lt;pre class='sql' name='code'&gt;CREATE TABLE 'revision' (&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'revision_id'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;      int(11) not null auto_increment,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'user_id' &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;     int(11),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'revision_timestamp'      &amp;nbsp;&amp;nbsp; int(11) not null,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'revision_description' &amp;nbsp;&amp;nbsp;    varchar(255),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PRIMARY KEY&amp;nbsp; ('revision_id')&lt;br /&gt;) ENGINE=InnoDB DEFAULT CHARSET=latin1;&lt;br /&gt;&lt;br /&gt;CREATE TABLE IF NOT EXISTS 'mod_lime_revision_action' (&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'action_id'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; int(11) NOT NULL AUTO_INCREMENT,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'revision_id'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; int(11) NOT NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'triple_id'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; int(11) NOT NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'action'&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;  &amp;nbsp;   enum ('ACTIVATE', 'DEACTIVATE') NOT NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;'section_id' &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; int(11),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;PRIMARY KEY&amp;nbsp; ('action_id'),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;CONSTRAINT 'revision_triple_ibfk_1' FOREIGN KEY ('revision_id') REFERENCES 'revision' ('revision_id') ON DELETE CASCADE,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;CONSTRAINT 'revision_triple_ibfk_2' FOREIGN KEY ('triple_id') REFERENCES 'triple' ('triple_id') ON DELETE CASCADE&lt;br /&gt;) ENGINE=InnoDB DEFAULT CHARSET=latin1;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Each time a user changes the data, a new revision is stored in the database, along with a list of all triples that are added or deactivated, and a compact description of the change. A triple that was already available in an inactive state is made active. If no such triple was present, an active one is created. Triples are never really removed, they are only set to be inactive.&lt;/p&gt;
&lt;p&gt;If you query the triplestore (the set of all triples), you need to ensure that only the active triples are queried.&lt;/p&gt;
&lt;p&gt;With this information, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;List all revisions made to the data, showing who made the change and when, along with a small description of the change.&lt;/li&gt;
&lt;li&gt;Revert changes back to a previous revision, by performing the revisions backwards: activate the deactivated triples, deactivate the activated triples. It is also possible to undo a single revision, that is not even the last one. But beware that revisions following it may have dependencies on it.&lt;/li&gt;
&lt;li&gt;Work together on an object by merging the changes made by the two users using the difference in data between the start and end revisions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style='text-align:center;'&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/34309?width=500&amp;amp;height=153' alt='' width='500' height='153' /&gt;&lt;/p&gt;
&lt;p style='text-align:center;'&gt;&amp;copy; &lt;a href='http://www.artofadambetts.com/weblog/'&gt;Adam Betts&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Object database&lt;/h2&gt;
&lt;p&gt;Businesses are used to work with objects. A web of data needs to be structured first before it can be used for common business purposes. To this end we decided to build an object oriented layer on top of the triplestore. But even though the &lt;a href='http://en.wikipedia.org/wiki/Web_Ontology_Language'&gt;Web Ontology Language (OWL)&lt;/a&gt; was designed for this purpose, we did not use it, since we needed only a very small subset anyway and we wanted complete freedom for our modelling activities, because processing speed was very high on our priority list. I will not cover all the details here, since it is a very extensive project, but I want to mention the following features:&lt;/p&gt;
&lt;ul class='last'&gt;
&lt;li&gt;The database was set up as a repository: no direct database access is possible by the application developer. Object creation, modification, destruction, and querying is done via the repository API. This provided the OOP principles of information hiding, modularity.&lt;/li&gt;
&lt;li&gt;Object types could be associated with PHP classes. This is no requirement, but it proved really easy to generate object types from PHP classes. This provided us with the principle of &lt;a href='http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming'&gt;polymorphism&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Not only simple objects are modelled as objects (a set of triples, having the same subject), but &lt;em&gt;object types&lt;/em&gt; as well. Furthermore, the &lt;em&gt;attributes of the types&lt;/em&gt; are modelled as objects as well. Objects and their types can be used in the same query.&lt;/li&gt;
&lt;li&gt;Object types can be subtyped. The triplestore allows us to query objects of a &lt;em&gt;given type and all its subtypes&lt;/em&gt; in a straightforward way.&lt;/li&gt;
&lt;li&gt;The attributes of objects can be subtyped as well. This allows you to add datatype restrictions to the attributes of subtypes that were not applicable on a higher level up the type hierarchy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These features are very powerful. It is possible to build a real Object database using triples as a datastructure only. Types and attributes are treated the same as normal objects. This means that the same code can be used to manipulate normal data as wel as metadata. Also, to implement &lt;a href='http://en.wikipedia.org/wiki/Inheritance_(computer_science)'&gt;inheritance&lt;/a&gt; is relatively easy, since object data is not chunked in single rows any more.&lt;/p&gt;
&lt;h2 class='last'&gt;Query language&lt;/h2&gt;
&lt;p&gt;After some time we felt that the simple queries we were performing on the object database were too constraining. We wanted the same power that SQL provides. And on top of that, since we continue to use normal relation tables as well, the object queries needed to be able combine the object database with the relational tables. For these reasons, the semantic web query language of choice, &lt;a href='http://en.wikipedia.org/wiki/Sparql'&gt;SPARQL&lt;/a&gt;, was insufficient for our purposes. We now build SQL-like queries using &lt;a href='http://en.wikipedia.org/wiki/Method_chaining'&gt;method chaining&lt;/a&gt; on a query object. The object then creates the SQL query.&lt;/p&gt;
&lt;p&gt;I mention this because you really need to build or use a new query language when starting to work with either a triplestores or an object database. The underlying triple store is too Spartan for an application developer. The lower level SQL queries consist of many self-joins connecting the subject of one to the object of another. Very hard to understand.&lt;/p&gt;
&lt;h2 class='last'&gt;Afterword&lt;/h2&gt;
&lt;p class='last'&gt;I wrote this article because I think this sort of detailed information about emerging datastructures is lacking on the internet. It is also great to work for a company (Procurios!) that agrees with me that knowledge should be given back to the community if possible. Gerbert Kaandorp from Backbase once asked me very seriously what I had done to promote the semantic web, like it was some kind of holy mission. I hope this article has made a small contribution and that it inspires some of you to build your own semantic web based object datastore. Let me know what you think!&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/34300/14863/Semantic-web-marvels-in-a-relational-database---part-I-Case-Study.html</link><pubDate>Tue, 15 Sep 2009 09:09:39 +0200</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/34300/14863</guid></item><item><title>Syntactic Sugar for MySQLi Results using SPL Iterators</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/34074?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='sugar' style='float:left;margin-right:1ex;' /&gt;Ever wondered why you can&amp;#039;t use foreach() on MySQLi Results, and instead have to write less convenient while() loops with fetch_row? Actually, you can use foreach() on MySQLi Results. All it takes is some SPL Iterator magic.&lt;/p&gt;&lt;h2&gt;Why would we want foreach()?&lt;/h2&gt;
&lt;p&gt;Well, just take a look at the code examples below and judge for yourself.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;$DB = new mysqli('localhost', 'user', 'password', 'db');

// standard approach using a while() loop with fetch_row
$Result = $DB-&amp;gt;query($query);
while ($row = $Result-&amp;gt;fetch_row()) {
  // do something with $row
}
$Result-&amp;gt;free();

// same loop with foreach
foreach($DB-&amp;gt;query($query) as $row) {
  // do something with $row
}

// foreach loop on a query that selects 2 columns
foreach ($DB-&amp;gt;query($query) as $key =&amp;gt; $value) {
  // do something with $key and $value
}
&lt;/pre&gt;
&lt;p&gt;As you can see the foreach loops can be written in a more compact form. Another benefit is that we can't accidentally forget to free() our $Result objects this way, which could lead to unnecessary memory usage.&lt;/p&gt;
&lt;p&gt;Whereas the &lt;a href='http://nl3.php.net/pdo'&gt;PDO&lt;/a&gt; database interface does support foreach() on &lt;a href='http://php.net/manual/en/class.pdostatement.php'&gt;PDOStatements&lt;/a&gt; natively, &lt;a href='http://php.net/manual/en/class.mysqli.php'&gt;MySQLi&lt;/a&gt; doesn't support foreach() on it's &lt;a href='http://php.net/manual/en/class.mysqli-result.php'&gt;MySQLi_Results&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Keep reading to find out how we can add foreach() support to your MySQLi Results ourselves.&lt;/p&gt;
&lt;h2&gt;The Iterator Interface&lt;/h2&gt;
&lt;p&gt;The &lt;a href='http://www.php.net/~helly/php/ext/spl/'&gt;Standard PHP Library&lt;/a&gt; (SPL) contains a set of useful classes, among which we find the &lt;a href='http://php.net/manual/en/class.iterator.php'&gt;Iterator&lt;/a&gt; interface. Any class that implements the Iterator interface can be iterated using a foreach() loop.&lt;/p&gt;
&lt;p&gt;If we want to use a foreach() loop on our query results we need to write our own ResultIterator class that implements the Iterator interface.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;interface Iterator extends Traversable
{
  function rewind();
  function current();
  function key();
  function next();
  function valid();
}
&lt;/pre&gt;
&lt;p&gt;Implementing the Iterator interface means providing implementations for each of the 5 methods in the interface. A nice way to show what each of these methods should do, is using the iterator interface in a standard for() loop.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;for ($Iterator-&amp;gt;rewind(); $Iterator-&amp;gt;valid(); $Iterator-&amp;gt;next()) {
  $value = $Iterator-&amp;gt;current();
  $key = $Iterator-&amp;gt;key();
}
&lt;/pre&gt;
&lt;p&gt;As you can see the loop will start with rewind() and will then continue to call next() untill valid() returns false. The Iterator needs to maintain an internal pointer for the current position and return false from the valid() method as soon as the position has reached the end. Inside each iteration the key() and current() methods are called to get the $key and $value for the current position.&lt;/p&gt;
&lt;h2&gt;An Iterator for MySQLi_Result objects&lt;/h2&gt;
&lt;p&gt;The next example shows how you can create an Iterator for MySQLi results.&lt;/p&gt;
&lt;p&gt;Once you know what each of the functions should do, implementing them for a MySQLi result is really straightforward. The only tricky part is that the mysqli_fetch_* methods advance the MySQLi_Results' internal pointer, while the current() method on our Iterator shouldn't. We can solve this by calling $Result-&amp;gt;fetch_array() in rewind() and next() instead and prefetching the current row.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;class ResultIterator implements Iterator
{
  protected $Result;
  protected $fetchMode;
  protected $position;
  protected $currentRow;

  /**
   * Constructor
   * @param MySQLi_Result $Result
   * @param constant $fetchMode (MYSQLI_ASSOC, MYSQLI_NUM, MYSQLI_BOTH)
   */
  public function __construct($Result, $fetchMode = MYSQLI_ASSOC)
  {
    $this-&amp;gt;Result = $Result;
    $this-&amp;gt;fetchMode = $fetchMode;
  }

  /**
   * Destructor
   * Frees the Result object
   */
  public function __destruct()
  {
    $this-&amp;gt;Result-&amp;gt;free();
  }

  /**
   * Rewinds the internal pointer
   */
  public function rewind()
  {
    // data_seek moves the Results internal pointer
    $this-&amp;gt;Result-&amp;gt;data_seek($this-&amp;gt;position = 0);

    // prefetch the current row
    // note that this advances the Results internal pointer.
    $this-&amp;gt;currentRow = $this-&amp;gt;Result-&amp;gt;fetch_array($this-&amp;gt;fetchMode);
  }

  /**
   * Moves the internal pointer one step forward
   */
  public function next()
  {
    // prefetch the current row
    $this-&amp;gt;currentRow = $this-&amp;gt;Result-&amp;gt;fetch_array($this-&amp;gt;fetchMode);

    // and increment internal pointer
    ++$this-&amp;gt;position;
  }

  /**
   * Returns true if the current position is valid, false otherwise.
   * @return bool
   */
  public function valid()
  {
    return $this-&amp;gt;position &amp;lt; $this-&amp;gt;Result-&amp;gt;num_rows;
  }

  /**
   * Returns the row that matches the current position
   * @return array
   */
  public function current()
  {
    return $this-&amp;gt;currentRow;
  }

  /**
   * Returns the current position
   * @return int
   */
  public function key()
  {
    return $this-&amp;gt;position;
  }
}
&lt;/pre&gt;
&lt;p&gt;At this point we have a fully functional ResultIterator that can be used like this:&lt;/p&gt;
&lt;pre class='php' name='code'&gt;foreach (new ResultIterator($DB-&amp;gt;query($query) as $row)) {
  // do something with $row
}
&lt;/pre&gt;
&lt;p&gt;While this is already quite nice it isn't perfect. We still need to create our own ResultIterator object, which - as i will show in the next part - isn't really necessary.&lt;/p&gt;
&lt;h2&gt;Extending MySQLi and MySQLi_Result&lt;/h2&gt;
&lt;p&gt;To avoid having to create our own ResultIterator object we can use the simple &lt;a href='http://nl.php.net/manual/en/class.iteratoraggregate.php'&gt;IteratorAggregate&lt;/a&gt; interface.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;IteratorAggregate extends Traversable
{
  function getIterator();
}
&lt;/pre&gt;
&lt;p&gt;As soon as foreach() is called on an object that implements this interface the &lt;a href='http://nl.php.net/manual/en/iteratoraggregate.getiterator.php'&gt;getIterator()&lt;/a&gt; method is called and can then create a new Iterator for the object. We can apply this interface to our MySQLi_Result objects.&lt;/p&gt;
&lt;p&gt;To do so, we will have to extend both MySQLi_Result and MySQLi. Let's start by showing how to extend the MySQLi_Result class for this purpose.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;class QueryResult extends MySQLi_Result implements IteratorAggregate
{
  public function getIterator()
  {
    return new ResultIterator($this);
  }
}
&lt;/pre&gt;
&lt;p&gt;As you can see this is really simple.&lt;/p&gt;
&lt;p&gt;There is just one small problem. Even though we provided an extension for the MySQLi_Result class, the MySQLi::query() method still returns a standard MySQLi_Result object. To solve this problem we need to override the query() method, which can be done like this:&lt;/p&gt;
&lt;pre class='php' name='code'&gt;class DB extends MySQLi
{
  public function query($query)
  {
    // query succeeded
    if ($this-&amp;gt;real_query($query)) {

      if ($this-&amp;gt;field_count) {

        // SELECT, SHOW, DESCRIBE
        return new QueryResult($this)

      } else {

        // INSERT, UPDATE, DELETE
        return true;

      }
    }
  }
&lt;/pre&gt;
&lt;p&gt;This one is a bit tricky. First we use the &lt;a href='http://nl.php.net/manual/en/mysqli.real-query.php'&gt;real_query()&lt;/a&gt; method to run the query. Then if there was no error in the query, we use &lt;a href='http://nl.php.net/manual/en/mysqli.field-count.php'&gt;field_count&lt;/a&gt; to find out if we just did a select query. If so we create our own QueryResult object and return it, otherwise we just return true to indicate the query was succesful. The trick here is that by creating our own QueryResult after calling real_query() we are basically doing the same as the &lt;a href='http://nl.php.net/manual/en/mysqli.store-result.php'&gt;store_result&lt;/a&gt; method does.&lt;/p&gt;
&lt;p&gt;At this point we can finally enjoy the results of our work&lt;/p&gt;
&lt;pre class='php' name='code'&gt;$DB = new DB('localhost', 'root', '', 'test');
$query = 'SELECT ... ';

foreach ($DB-&amp;gt;query($query) as $row) {
  // do something with $row
}
&lt;/pre&gt;
&lt;h2&gt;Taking it one step further&lt;/h2&gt;
&lt;p&gt;At the beginning of this article i showed the following example:&lt;/p&gt;
&lt;pre class='php' name='code'&gt;// foreach loop on a query that selects 2 columns
foreach ($DB-&amp;gt;query($query) as $key =&amp;gt; $value) {
  // do something with $key and $value
}
&lt;/pre&gt;
&lt;p&gt;If we select 2 columns and want the first column as $key and the second as $value all we need is a specialized version of our ResultIterator.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;class KeyValueResultIterator extends ResultIterator
{
  public function __construct($Result)
  {
    $this-&amp;gt;Result = $Result;
    $this-&amp;gt;fetchMode = MYSQLI_NUM;
  }

  public function current()
  {
    return $this-&amp;gt;currentRow[1];
  }

  public function key()
  {
    return $this-&amp;gt;currentRow[0];
  }
}
&lt;/pre&gt;
&lt;p&gt;Likewise, when we are selecting only 1 column we don't need to return an array from the current method(). For this case we can create a third version of our ResultIterator.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;class SingleColumnResultIterator extends ResultIterator
{
  public function __construct($Result)
  {
    $this-&amp;gt;Result = $Result;
    $this-&amp;gt;fetchMode = MYSQLI_NUM;
  }

  public function current()
  {
    return $this-&amp;gt;currentRow[0];
  }
}
&lt;/pre&gt;
&lt;p&gt;The downside of these 2 specialized ResultIterators is that we would have to create them manually again if we wanted to use them. Unless ofcourse, we alter our getIterator() method like so:&lt;/p&gt;
&lt;pre class='php' name='code'&gt;public function getIterator()
{
  switch ($this-&amp;gt;field_count) {
    case 1:    return new SingleColumnResultIterator($this);
    case 2:    return new KeyValueResultIterator($this);
    default:   return new ResultIterator($this);
  }
}
&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By creating our own Iterator for MySQLi_Results we can now easily iterate over them using foreach(). We also solved the special cases when selecting only 1 or 2 columns. In the process we saw some of the new things we can do with the SPL.&lt;/p&gt;
&lt;h3&gt;But what about the performance?&lt;/h3&gt;
&lt;p&gt;Well, as was to be expected, it's a bit slower than a while() loop using fetch_row() directly. As we saw in the example for() loop, the Iterator interface has the overhead of 3 or 4 functions calls per iteration (depending on whether key() is called or not).&lt;br /&gt; I included some source code with a few benchmarks at the bottom of this article if you need more specifics.&lt;/p&gt;
&lt;h3&gt;Further improvements&lt;/h3&gt;
&lt;p&gt;If you want to further improve the QueryResult class or try some other SPL interfaces, you could take a look at the &lt;a href='http://nl.php.net/manual/en/class.seekableiterator.php'&gt;SeekableIterator&lt;/a&gt; and &lt;a href='http://nl.php.net/manual/en/class.countable.php'&gt;Countable&lt;/a&gt; interfaces.&lt;/p&gt;
&lt;p&gt;Or download the [&lt;a href='http://extranet.procurios.nl/l/nl/library/download/34071?format=save_to_disk'&gt;source code&lt;/a&gt;] used for this article to play around with.&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/33914/14863/Syntactic-Sugar-for-MySQLi-Results-using-SPL-Iterators.html</link><pubDate>Fri, 15 May 2009 21:12:26 +0200</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/33914/14863</guid></item><item><title>Calculate ISO 8601 week and year in javascript</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/33797?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='calendar' style='float:left;margin-right:1ex;' /&gt;For one of our projects I needed to be able to calculate the current weeknumber and corresponding year of a given date... in javascript. Not really a big deal, just calculate the number of weeks between the requested date and the 1st of January that year and you&amp;#039;re done, right? Wrong!&lt;/p&gt;&lt;h2&gt;Why do we use ISO week numbering?&lt;br /&gt;&lt;/h2&gt;
&lt;p&gt;In our framework (including modules) we use the &lt;a href='http://en.wikipedia.org/wiki/ISO_8601#Week_dates'&gt;ISO 8601&lt;/a&gt; standard for week numbering. We've chosen this standard because it is very related to western european workweeks: weeks start on monday and the first week of the year is the first week with a workday in it. Our clients are mostly businesses operating in western europe and therefore this standard is the most obvious choice.&lt;/p&gt;
&lt;h2&gt;Why this article?&lt;br /&gt;&lt;/h2&gt;
&lt;p&gt;Our framework is built using PHP. In PHP requesting the week and / or year number according to this standard is easy:&lt;/p&gt;
&lt;pre class='php' name='code'&gt;// Week and year number using date()&lt;br /&gt;$w = date('W');&lt;br /&gt;$y = date('o');&lt;br /&gt;&lt;br /&gt;// Week and year number using strftime()&lt;br /&gt;$w = strftime('%V');&lt;br /&gt;$y = strftime('%G');&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;But in javascript no built-in methods are available to calculate these values.&lt;/p&gt;
&lt;h2&gt;ISO 8601 week numbering&lt;/h2&gt;
&lt;p&gt;This (part of the) standard primarily defines two rules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Weeks start on monday&lt;/li&gt;
&lt;li&gt;The first week of the year is the week with the first thursday of that year&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;An alternative to the second rule is that the first week of the year is the week with the 4th of January in it. This rule is mostly more convenient in coding.&lt;/p&gt;
&lt;p&gt;As a result of this second rule the week with the 1st of January isn't always week number 1. Another result is that some years have 53 weeks instead of 52.&lt;/p&gt;
&lt;h2&gt;Extending the javascript Date class&lt;/h2&gt;
&lt;p&gt;To be able to get the week and year numbers in javascript we extend the Date class with two methods: getWeek() and getWeekYear().&lt;/p&gt;
&lt;p&gt;Extending a class in javascript can be done by adding properties to the prototype object of that class. In the code below we define Date.prototype.getWeek() and Date.prototype.getYearWeek(), these new methods can be called directly on instances of the Date class:&lt;/p&gt;
&lt;pre class='javascript' name='code'&gt;var today = new Date();&lt;br /&gt;alert(&quot;The current week number is: &quot; + today.getWeek());&lt;br /&gt;&lt;/pre&gt;
&lt;h3&gt;Date.getWeek()&lt;/h3&gt;
&lt;p&gt;First, take a look at the code below:&lt;/p&gt;
&lt;pre class='javascript' name='code'&gt;/**&lt;br /&gt; * Get the ISO week date week number&lt;br /&gt; */&lt;br /&gt;Date.prototype.getWeek = function () {&lt;br /&gt;	// Create a copy of this date object&lt;br /&gt;	var target  = new Date(this.valueOf());&lt;br /&gt;&lt;br /&gt;	// ISO week date weeks start on monday&lt;br /&gt;	// so correct the day number&lt;br /&gt;	var dayNr   = (this.getDay() + 6) % 7;&lt;br /&gt;&lt;br /&gt;	// Set the target to the thursday of this week so the&lt;br /&gt;	// target date is in the right year&lt;br /&gt;	target.setDate(target.getDate() - dayNr + 3);&lt;br /&gt;&lt;br /&gt;	// ISO 8601 states that week 1 is the week&lt;br /&gt;	// with january 4th in it&lt;br /&gt;	var jan4    = new Date(target.getFullYear(), 0, 4);&lt;br /&gt;&lt;br /&gt;	// Number of days between target date and january 4th&lt;br /&gt;	var dayDiff = (target - jan4) / 86400000;  &lt;br /&gt;&lt;br /&gt;	// Calculate week number: Week 1 (january 4th) plus the  &lt;br /&gt;	// number of weeks between target date and january 4th  &lt;br /&gt;	var weekNr = 1 + Math.ceil(dayDiff / 7);  &lt;br /&gt;&lt;br /&gt;	return weekNr;  &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;The first thing we do is find out the difference in days between the requested date and the 4th of January that same (calendar) year. We subtract the two Date objects, which will result in a number of milliseconds, and divide that by the number of milliseconds in a day: 86400000. Since weeks always start on monday (rule #1) we are more interested in the difference in days between January 4th and the monday of the target week, so we correct this day difference. Next we convert this amount of days to weeks and add one (since it was the difference between week #1 and the target date).&lt;/p&gt;
&lt;p&gt;This was the general part of the method, next we need to correct for the exceptions (remember that the 1st of January might be in a week of the previous year?). If the result of our method is less than 1, we know this date belongs to the last week of the previous year, simply return the result of the getWeek() method for December 31st of the previous year.&lt;/p&gt;
&lt;p&gt;On the other hand the last few days of the year might belong to a week of the next year. Since at most 3 days can belong to the next year (remember that the first week is the week with January 4th) we only need to check this exception when the date is after December 28th. We return 1 when the monday of the requested week is after the 28th of December.&lt;/p&gt;
&lt;h3&gt;Date.getWeekYear()&lt;/h3&gt;
&lt;p&gt;That was the getWeek method, the most important one of the two. The getWeekYear() method uses getWeek() to determine what year to return.&lt;/p&gt;
&lt;p&gt;This method is very simple, just return the calendar year except when:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The requested date is in January but the getWeek() method returns 52 or 53&lt;/li&gt;
&lt;li&gt;The requested date is in December but the getWeek() method returns 1&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The code below (and it's comments) speak for itself ;)&lt;/p&gt;
&lt;pre class='javascript' name='code'&gt;/**&lt;br /&gt;* Get the ISO week date year number&lt;br /&gt;*/&lt;br /&gt;Date.prototype.getWeekYear = function () &lt;br /&gt;{&lt;br /&gt;	// Create a new date object for the thursday of this week&lt;br /&gt;	var target	= new Date(this.valueOf());&lt;br /&gt;	target.setDate(target.getDate() - ((this.getDay() + 6) % 7) + 3);&lt;br /&gt;	&lt;br /&gt;	return target.getFullYear();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;So that's about all you'll need to calculate ISO 8601 year and week numbers in javascript, happy coding!&lt;/p&gt;
&lt;h2&gt;
&lt;hr /&gt;
Optimisation&lt;/h2&gt;
&lt;p&gt;After reading the site from &lt;a href='http://www.merlyn.demon.co.uk/js-date8.htm#YWD'&gt;Dr J R Stockton&lt;/a&gt; that &lt;a href='http://techblog.procurios.nl#p681'&gt;Rick&lt;/a&gt; recommended in his post I stole a simple trick to make the code a little shorter. Instead of handling the edge cases I first change the date to the thursday of the requested week so the week year number equals the calendar year. I did keep the code more verbose than Stockton did though, just so you understand what exactly happens.&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/33796/14863/Calculate-ISO-8601-week-and-year-in-javascript.html</link><pubDate>Mon, 27 Apr 2009 14:58:55 +0200</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/33796/14863</guid></item><item><title>CSS Rendering problems in IE8? Fix your conditional comments!</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/33504?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='ie8-hello' style='float:left;margin-right:1ex;' /&gt;Are your existing websites incorrectly rendered by IE8? Do you have a hard time getting IE8 to render your CSS correctly? The core problem may be incorrect usage of conditional comments... Ofcourse, a fix is available in this article!&lt;/p&gt;&lt;p&gt;Today, I talked to some friends &amp;amp; colleague front-end developers, who had trouble with the way IE8 renders their existing websites and websites under development. We all know that developing for IE7 (and lower versions) can be a pain. Using &lt;a href='http://www.quirksmode.org/css/condcom.html'&gt;conditional comments&lt;/a&gt; is a commonly used method to fix IE proprietary bugs. Please note that the point of this article is not to discuss the usage of conditional comments. My opinion on this comes close to &lt;a href='http://meiert.com/en/blog/20080824/to-be-clear/'&gt;what Jens Meiert said about this subject&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Conditional comments are conditional statements interpreted by IE only. They first appeared in IE5 and are supported through at least IE8. An example of a conditional comment:&lt;/p&gt;
&lt;pre class='css' name='code'&gt;&lt;!-- [if IE]&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt; link rel='stylesheet' type='text/css' href='http://techblog.procurios.nlie.css'/&amp;gt;&lt;br /&gt;&lt;!  [endif] --&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, the conditional comment is interpreted only by IE, which loads the ie.css file with IE-specific fixes. The idea is simple and effective. So what's any of this got to do with IE8 rendering problems?&lt;/p&gt;
&lt;h2&gt;&quot;Fix&quot; IE8 rendering&lt;/h2&gt;
&lt;p&gt;The most common way the conditional comments were used when IE7 was the latest IE version, was as following:&lt;/p&gt;
&lt;pre class='css' name='code'&gt;&lt;!-- [if IE] --&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt; link rel='stylesheet' type='text/css' href='http://techblog.procurios.nlie.css'/&amp;gt;&lt;br /&gt;&lt;!-- [endif] --&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- [if lt IE 7]&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt; link rel='stylesheet' type='text/css' href='http://techblog.procurios.nlie6.css'/&amp;gt;&lt;br /&gt;&lt;! [endif] --&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;The idea was to return a CSS-file for all versions of IE to fix the most common version-wide IE bugs, and another CSS-file for IE6 and lower. Since IE8 supports conditional comments, the first comment in the above example affects IE8 as well.&lt;/p&gt;
&lt;p&gt;IE8 renders CSS2.1 fine, and doesn't behave nearly as buggy as the previous versions. This means that the fixes in your ie.css probably conflict with IE8's rendering. The solution is to change the first conditional comment into the following:&lt;/p&gt;
&lt;pre class='css' name='code'&gt;&lt;!-- [if lt IE 8]&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt; link rel='stylesheet' type='text/css' href='http://techblog.procurios.nlie.css'/&amp;gt;&lt;br /&gt;&lt;!  [endif] --&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;You'll see that most of the rendering problems in IE8 will disappear. Being aware of this could save you time and prevents you ending up with &lt;a href='http://davidwalsh.name/ie8-emulate-ie7'&gt;adding a meta-tag&lt;/a&gt; to make IE8 render in IE7 compatability mode. Have fun developing!&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/33506/14863/CSS-Rendering-problems-in-IE8-Fix-your-conditional-comments.html</link><pubDate>Wed, 19 Aug 2009 12:22:42 +0200</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/33506/14863</guid></item><item><title>Testing Internet Explorer 8: CSS3 for Web Design</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/33225?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='ie-css' style='float:left;margin-right:1ex;' /&gt;CSS3 introduces many exciting new features for webdesigners and webdevelopers. These features can help you create some common webdesign techniques like rounded corners, opacity and dropshadows just by typing out some CSS rules. Let&amp;#039;s find out whether Microsofts newly born baby, Internet Explorer 8, supports these CSS3 features or not.&lt;/p&gt;&lt;h2&gt;Internet Explorer 8 Final released&lt;/h2&gt;
&lt;p&gt;It was thursday the 19th of March when Microsoft released &lt;a href='http://www.microsoft.com/windows/internet-explorer/default.aspx'&gt;Internet Explorer 8&lt;/a&gt;. Microsoft said the following about IE8:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get where you want to go faster with real world performance.&lt;/li&gt;
&lt;li&gt;Use more of the web, easier.&lt;/li&gt;
&lt;li&gt;Stay safer from real world threats.&lt;/li&gt;
&lt;li&gt;Build on real world interoperability, standards, and compatibility. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nice. A safe, fast and up-to-date browser, released by Microsoft. But how modern is it? Does it support any of the new features CSS3 introduces?&lt;/p&gt;
&lt;h2&gt;An introduction to CSS3&lt;/h2&gt;
&lt;p&gt;CSS3 is the new CSS-standard, which is set to take over from CSS2.1.&amp;nbsp;CSS3 introduces a huge variety of ways to create flexible and attractive designs. Even though &lt;a href='http://www.w3.org/Style/CSS/current-work'&gt;the CSS3 specification&lt;/a&gt; is still in development, there are some &lt;a href='http://www.css3.info/preview/'&gt;very exciting new features for webdesigners&lt;/a&gt; to be implemented in the specifications. These features can help you create some common Web design techniques like rounded corners, transparent boxes and dropshadows just by typing out some CSS rules.&lt;/p&gt;
&lt;p&gt;I'm aware of the fact that in reality we can't use any of these CSS rules yet, because not every browser fully supports them. Some of the CSS3 features are already implemented in modern browsers like Firefox 3, Safari 3, Google Chrome 1 and Opera 9.6. Does Internet Explorer 8 join this list of modern browsers, supporting the new features CSS3 is going to introduce?&lt;/p&gt;
&lt;h2&gt;Testing the CSS3 implementation&lt;/h2&gt;
&lt;h3&gt;Transparency using RGBA and opacity&lt;/h3&gt;
&lt;p&gt;The use of &lt;a href='http://en.wikipedia.org/wiki/Portable_Network_Graphics'&gt;PNG files&lt;/a&gt; with alpha-transparency is a modern and common design feature. CSS3 enables you to directly specify an alpha-value or opacity setting in your CSS. A simple test case in which we test the support of the &lt;a href='http://www.w3.org/TR/css3-color/#opacity'&gt;opacity&lt;/a&gt; and &lt;a href='http://www.w3.org/TR/css3-color/#rgba-color'&gt;rgba&lt;/a&gt; properties:&lt;/p&gt;
&lt;p&gt;&lt;iframe style='border:0pt none;width:450px;height:155px;' src='http://techblog.procurios.nl/l/nl/library/download/33216'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href='http://techblog.procurios.nl/l/nl/library/download/33189'&gt;This is how it looks in compatible browsers.&lt;/a&gt;&lt;br /&gt;Full support in: Firefox 3, Safari 3, Chrome 1.&lt;br /&gt;Partial support in: Firefox 2, Opera 9.6 (no support for rgba).&lt;br /&gt;No support in: &lt;strong&gt;Internet Explorer 8&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Rounded corners&lt;/h3&gt;
&lt;p&gt;Another commonly used webdesign feature is rounded corners, which are usually made by placing background-images or using empty elements. If you need some examples of current techniques, check out &lt;a href='http://www.cssjuice.com/25-rounded-corners-techniques-with-css/'&gt;this list of 25 rounded corner techniques&lt;/a&gt;. CSS3 allows rounded corners to be set in your CSS files, which would eliminate every of the existing techniques. Let's see if your browser supports the &lt;a href='http://www.w3.org/TR/2002/WD-css3-border-20021107/#the-border-radius'&gt;border-radius&lt;/a&gt; property:&lt;/p&gt;
&lt;p&gt;&lt;iframe style='border:0pt none;width:450px;height:150px;' src='http://techblog.procurios.nl/l/nl/library/download/33218'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href='http://techblog.procurios.nl/l/nl/library/download/33191'&gt;This is how it looks in compatible browsers.&lt;/a&gt;&lt;br /&gt;Full support in: Firefox 2 &amp;amp; 3, Safari 3, Chrome 1.&lt;br /&gt;No support in: &lt;strong&gt;Internet Explorer 8&lt;/strong&gt;, Opera 9.6.&lt;/p&gt;
&lt;h3&gt;Border Image&lt;/h3&gt;
&lt;p&gt;A new border feature CSS3 introduces, is the &lt;a href='http://www.w3.org/TR/2002/WD-css3-border-20021107/#the-border-image'&gt;border-image&lt;/a&gt; property. With this feature you can set an image to be used as a border instead of the normal border of an element. This feature is split up into border-edge-images and border-corner-images. If your browser supports this CSS3 feature, a colorfull border should be displayed in the following test case:&lt;/p&gt;
&lt;p&gt;&lt;iframe style='border:0pt none;width:450px;height:170px;' src='http://techblog.procurios.nl/l/nl/library/download/33222'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href='http://techblog.procurios.nl/l/nl/library/download/33195'&gt;This is how it looks in compatible browsers.&lt;/a&gt;&lt;br /&gt;Full support in: Firefox &lt;strong&gt;3.1&lt;/strong&gt; (upcoming), Safari 3, Chrome 1.&lt;br /&gt;No support in: &lt;strong&gt;Internet Explorer 8&lt;/strong&gt;, Opera 9.6.&lt;/p&gt;
&lt;h3&gt;Box Shadow&lt;/h3&gt;
&lt;p&gt;CSS3 has a nice new feature called &lt;a href='http://www.w3.org/TR/css3-background/#box-shadow'&gt;box-shadow&lt;/a&gt;, to create dropshadows with CSS instead of using images. The property takes four values: three lenghts (the shadow offsets &amp;amp; shadow blur) and the color of the shadow:&lt;/p&gt;
&lt;p&gt;&lt;iframe style='border:0pt none;width:450px;height:150px;' src='http://techblog.procurios.nl/l/nl/library/download/33206'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href='http://techblog.procurios.nl/l/nl/library/download/33197'&gt;This is how it looks in compatible browsers.&lt;/a&gt;&lt;br /&gt;Full support in: Firefox &lt;strong&gt;3.1&lt;/strong&gt; (upcoming), Safari 3, Chrome 1.&lt;br /&gt;No support in: &lt;strong&gt;Internet Explorer 8&lt;/strong&gt;, Opera 9.6.&lt;/p&gt;
&lt;h3&gt;Text Shadow&lt;/h3&gt;
&lt;p&gt;Even though i'm not a fan of heavy usage of dropshadows, CSS3 also introduces a &lt;a href='http://www.w3.org/TR/2003/CR-css3-text-20030514/#text-shadows'&gt;text-shadow&lt;/a&gt; feature. Who needs Photoshop? ;) The property text-shadow takes the same four values as box-shadow:&lt;/p&gt;
&lt;p&gt;&lt;iframe style='border:0pt none;width:450px;height:150px;' src='http://techblog.procurios.nl/l/nl/library/download/33220'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href='http://techblog.procurios.nl/l/nl/library/download/33193'&gt;This is how it looks in compatible browsers.&lt;/a&gt;&lt;br /&gt;Full support in: Firefox &lt;strong&gt;3.1&lt;/strong&gt; (upcoming), Safari 3, Opera 9.6.&lt;br /&gt;No support in: &lt;strong&gt;Internet Explorer 8&lt;/strong&gt;, Chrome 1.&lt;/p&gt;
&lt;h3&gt;@font-face (custom fonts)&lt;/h3&gt;
&lt;p&gt;One of the coolest new features of CSS3, is enabling the developer to use his/her own fonts with the &lt;a href='http://www.w3.org/TR/css3-webfonts/#introduction'&gt;Web Fonts module&lt;/a&gt;. The &lt;a href='http://www.w3.org/TR/css3-webfonts/#font-descriptions'&gt;@font-face rule&lt;/a&gt; provides the bridge between an author's font specification and the font data, which is the data needed to format text and to render the abstract glyphs to which the characters map - the actual scalable outlines or bitmaps. Fonts are referenced by style sheet properties. The @font-face rule takes two properties: the definition of the font-family and the source (url) of the font:&lt;/p&gt;
&lt;p&gt;&lt;iframe style='border:0pt none;width:450px;height:150px;' src='http://techblog.procurios.nl/l/nl/library/download/33208'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href='http://techblog.procurios.nl/l/nl/library/download/33199'&gt;This is how it looks in compatible browsers.&lt;/a&gt;&lt;br /&gt;Full support in: Safari 3, Opera &lt;strong&gt;10&lt;/strong&gt; (upcoming), Firefox &lt;strong&gt;3.1&lt;/strong&gt; (upcoming).&lt;br /&gt; No support in: Firefox 3.0, &lt;strong&gt;Internet Explorer 8&lt;/strong&gt;, Chrome 1.&lt;/p&gt;
&lt;h3&gt;HSL &amp;amp; HSLA Colors&lt;/h3&gt;
&lt;p&gt;CSS3 adds numerical &lt;a href='http://en.wikipedia.org/wiki/HSL_color_space'&gt;hue-saturation-lightness&lt;/a&gt; (HSL) colors as a complement to numerical &lt;a href='http://en.wikipedia.org/wiki/RGB'&gt;RGB&lt;/a&gt; colors. According to the W3C, the RGB color model has two limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RGB is hardware-oriented: it reflects the use of CRTs.&lt;/li&gt;
&lt;li&gt;RGB is non-intuitive. People can learn how to use RGB, but actually by internalizing how to translate hue, saturation and lightness, or something similar, to RGB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HSL is far more intuitive to use. You can guess the colors you want to use, and if needed, tweak them a little. Besides, you can easily create a set of matching colors by setting the hue to a constant and varying the lightness and saturation. The A in &quot;HSLA&quot; stands for alpha, and allows you to add an alpha-value (as in rgba). If your browser supports HSLA colors, you should see three red blocks, each with a different alpha setting:&lt;/p&gt;
&lt;p&gt;&lt;iframe style='border:0pt none;width:480px;height:150px;' src='http://techblog.procurios.nl/l/nl/library/download/33210'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href='http://techblog.procurios.nl/l/nl/library/download/33201'&gt;This is how it looks in compatible browsers.&lt;/a&gt;&lt;br /&gt;Full support in: Safari 3, Firefox 3, Opera 9.6, Chrome 1.&lt;br /&gt; No support in: &lt;strong&gt;Internet Explorer 8&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Multiple Backgrounds&lt;/h3&gt;
&lt;p&gt;Another very cool feature CSS3 Background &amp;amp; Borders Module introduces is the ability to add &lt;a href='http://www.w3.org/TR/css3-background/#layering'&gt;multiple background images&lt;/a&gt; to one box. The 'background' property may have multiple values, separated with comma's:&lt;/p&gt;
&lt;p&gt;&lt;iframe style='border:0pt none;width:480px;height:135px;' src='http://techblog.procurios.nl/l/nl/library/download/33214'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href='http://techblog.procurios.nl/l/nl/library/download/33203'&gt;This is how it looks in compatible browsers.&lt;/a&gt;&lt;br /&gt;Full support in: Safari 3, Chrome 1.&lt;br /&gt; No support in:  Firefox 3, Opera 9.6, &lt;strong&gt;Internet Explorer 8&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;CSS3 selector test&lt;/h2&gt;
&lt;p&gt;From &lt;a href='http://www.w3.org/TR/CSS2/selector.html#q2'&gt;w3.org&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In CSS, pattern matching rules determine which style rules apply to elements in the document tree. These patterns, called selectors, may range from simple element names to rich contextual patterns. If all conditions in the pattern are true for a certain element, the selector matches the element.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CSS3 also introduces an enhanced selector-model, which we can test easily using the CSS3 selector test provided by &lt;a href='http://www.css3.info/selectors-test/'&gt;CSS3.info&lt;/a&gt;. I've saved the testresult of Internet Explorer 8 (if your browser has scaled the image down: click to zoom in):&lt;/p&gt;
&lt;p&gt;&lt;iframe style='border:0pt none;width:480px;height:250px;' src='http://techblog.procurios.nl/l/nl/library/download/33212'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Based on the test cases in this article, we can conclude the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Internet Explorer 8 supports none of the exciting new features CSS3 introduces to webdesigners and front-end developers.&lt;/li&gt;
&lt;li&gt;Internet Explorer 8 only supports 22 of the 43 available CSS3 selectors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Comparing the CSS3 implementations of IE8 to its modern competitors, we'll sadly notice that IE8 comes last across the finish line. Microsoft did a huge step forward with the release of Internet Explorer 8 where it comes to support of CSS2.1 and rendering speed, but it's still far behind it's competitors.&lt;/p&gt;
&lt;p&gt;Thumbs up to Safari, which supports every tested CSS3 features.&lt;/p&gt;
&lt;h2&gt;Finally&lt;/h2&gt;
&lt;p&gt;Did you spot a mistake? Please send your feedback and you'll be rewarded with your nickname next to the corrected phrase ;). Feel free to comment or use the contact form on the &lt;a href='http://techblog.procurios.nl/'&gt;homepage&lt;/a&gt;.&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/33224/14863/Testing-Internet-Explorer-8-CSS3-for-Web-Design.html</link><pubDate>Wed, 19 Aug 2009 12:22:52 +0200</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/33224/14863</guid></item><item><title>Protection against SYN Floods</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/33046?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='2005-dos4' style='float:left;margin-right:1ex;' /&gt;Just after lunch our office is a calm and peaceful place. The only sound comes from a handful of developers discussing possible solutions for a challenging problem in a project...&lt;/p&gt;&lt;p&gt;Suddenly our &lt;a href='http://www.nagios.org/'&gt;nagios&lt;/a&gt; IRC bot politely informs us that the HTTP service is down for one of the servers. Fortunately SSH still works like a charm. A quick inspection reveals no peculiarities, except for an amazing number of Apache clients doing nothing. A quick glance in the logs learns us that Apache has reached its MaxClients setting. An Apache restart doesn't help, it reaches its MaxClients setting again within the minute.&lt;/p&gt;
&lt;pre&gt;# tail /var/log/apache2/error.log&lt;br /&gt;&lt;br /&gt;[Fri Dec 05 14:31:30 2008] [error] server reached MaxClients setting, consider raising the MaxClients setting&lt;br /&gt;[Fri Dec 05 14:50:54 2008] [notice] caught SIGTERM, shutting down&lt;br /&gt;[Fri Dec 05 14:50:56 2008] [notice] Apache/2.2.x (Debian) configured -- resuming normal operations&lt;br /&gt;[Fri Dec 05 14:51:35 2008] [error] server reached MaxClients setting, consider raising the MaxClients setting&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Could be a (D)DoS attack. However, the server doesn't show typical signs of a DoS attack like high load or network traffic. Next stop is netstat which shows us a huge number of tcp connections in SYN_RECV state:&lt;/p&gt;
&lt;pre&gt;# netstat -n -p TCP&lt;br /&gt;&lt;br /&gt;tcp        0      0 10.1.1.1:80       91.64.4.146:64979       SYN_RECV   -&lt;br /&gt;tcp        0      0 10.1.1.1:80       84.24.103.112:4005      SYN_RECV   -&lt;br /&gt;tcp        0      0 10.1.1.1:80       79.223.69.239:61510     SYN_RECV   -&lt;br /&gt;tcp        0      0 10.1.1.1:80       67.86.135.44:43312      SYN_RECV   -&lt;br /&gt;tcp        0      0 10.1.1.1:80       86.88.67.226:50600      SYN_RECV   -&lt;br /&gt;tcp        0      0 10.1.1.1:80       173.20.137.110:3813     SYN_RECV   -&lt;br /&gt;tcp        0      0 10.1.1.1:80       84.58.10.121:4878       SYN_RECV   -&lt;br /&gt;tcp        0      0 10.1.1.1:80       91.37.40.151:2408       SYN_RECV   -&lt;br /&gt;tcp        0      0 10.1.1.1:80       173.20.137.110:3441     SYN_RECV   -&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Lots of half-open connections are a good indication of a &lt;a href='http://en.wikipedia.org/wiki/SYN_flood'&gt;SYN Flood&lt;/a&gt; attack. So we need to do two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Harden the TCP/IP stack&lt;/li&gt;
&lt;li&gt;Block attackers&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Harden the TCP/IP stack&lt;/h3&gt;
&lt;p&gt;If you're not familiar to SYN Floods or other TCP-based resource starvation attacks, read &lt;a href='http://www.securityfocus.com/infocus/1729'&gt;this SecurityFocus article&lt;/a&gt;. It also covers hardening your TCP/IP stack against SYN Flooding and SYN Spoofing. Most important is enabling &lt;a href='http://en.wikipedia.org/wiki/SYN_cookies'&gt;SYN Cookies&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Block attackers&lt;/h3&gt;
&lt;p&gt;Now we've hardened the TCP/IP stack, spoofing has been eliminated. The attacking source address is really the attacker, so it makes sense to block it. However, these days it's not very hard to create, buy or rent a large &lt;a href='http://en.wikipedia.org/wiki/Botnet'&gt;botnet&lt;/a&gt; consisting of thousands of hacked computers ready to be engaged in massive DDoS attacks. So manually block IP's won't work.&lt;/p&gt;
&lt;p&gt;We'll have to write a script to automatically block attacking IP's. The script consists of three parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find out which IP's to block&lt;/li&gt;
&lt;li&gt;Block IP&lt;/li&gt;
&lt;li&gt;Unblock IP after 24 hours&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first part is the hardest part. In our case, we could just take all IP's having too many connections in SYN_RECV state. In your case you might need to use another condition, e.g. count requests to a specific URI.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;$netstat = shell_exec('/bin/netstat -apn | grep SYN_RECV');&lt;br /&gt;$lines = preg_split('/[\r\n]+/', $netstat);&lt;br /&gt;&lt;br /&gt;$ips = array();&lt;br /&gt;foreach ($lines as $line) {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;$fields = preg_split('/\s+/', $line);&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;if(preg_match('/[\d\.]+/is', $fields[4], $match)) {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$key = $match[0];&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$ips[$key] = empty($curr[$key]) ? 1 : &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;($ips[$key] + 1);&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Now we have all IP's and number of concurrent connections in SYN_RECV state. Next step is block IP's with more than 50 connections. This number is quite random, any sane treshold will do.&lt;/p&gt;
&lt;pre class='php' name='code'&gt;foreach ($ips as $key =&amp;gt; $val) {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;if ($val &amp;gt; 50) {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exec(&quot;sbin/iptables -A INPUT -s &quot; . &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;escapeshellarg($key) . &quot; -j DROP&quot;);&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;For the last step you need to create your own administration of blocked IP's and timestamps. Check out the full script [&lt;a href='http://extranet.procurios.nl/l/nl/library/download/33043?format=save_to_disk'&gt;Download&lt;/a&gt;] for this and some other features like a whitelist and simple logging.&lt;/p&gt;
&lt;h3&gt;Reinventing the wheel?&lt;/h3&gt;
&lt;p&gt;You might wonder why we try to reinvent the wheel. Though avoiding to reinvent the proverbial wheel is a good practice and key principle in software development, it's useful to rethink the wheel concept from time to time. Or to quote Jeff Atwood: &lt;a href='http://www.codinghorror.com/blog/archives/001145.html'&gt;Don't Reinvent The Wheel, Unless You Plan on Learning More About Wheels&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most high profile websites will probably have a dedicated intrusion detection or prevention system (&lt;a href='http://en.wikipedia.org/wiki/Intrusion-detection_system'&gt;IDS&lt;/a&gt;/&lt;a href='http://en.wikipedia.org/wiki/Intrusion_prevention_system'&gt;IPS&lt;/a&gt;) in place. IT security companies can implement a commercial solution, e.g. Cisco, IBM or Juniper systems. You could also try to build one yourself. &lt;a href='http://en.wikipedia.org/wiki/Snort_(software)'&gt;Snort&lt;/a&gt; is a free and open source IDS/IPS. It's the de facto standard and used by many commercial solutions as well.&lt;/p&gt;
&lt;p&gt;However, for most websites or web applications an IDS/IPS is overkill. Start with good server configuration, hardened OS and server software and a good router and firewall. And add an IDS or custom IP blocking script if necessary.&lt;/p&gt;
&lt;h3&gt;Finally&lt;/h3&gt;
&lt;p&gt;In this case we controlled the attack within 5 minutes after we launched the block-ips script. The websites came back online and the attack stopped after three days.&lt;/p&gt;
&lt;h3&gt;Further reading:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href='http://en.wikipedia.org/wiki/Denial-of-service_attack'&gt;Wikipedia: Denial-of-service attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href='http://www.cert.org/advisories/CA-1996-21.html'&gt;CERT Advisory: TCP SYN Flooding and IP Spoofing Attacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href='http://www.securityfocus.com/infocus/1729'&gt;SecurityFocus article: Hardening the TCP/IP stack to SYN attacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href='http://cr.yp.to/syncookies.html'&gt;D.J. Bernstein: SYN cookies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/33045/14863/Protection-against-SYN-Floods.html</link><pubDate>Mon, 16 Mar 2009 10:34:27 +0100</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/33045/14863</guid></item><item><title>Transforming the button element with sliding doors and image sprites</title><description>&lt;p&gt;&lt;img src='http://techblog.procurios.nl/l/library/download/33013?width=100&amp;amp;height=100&amp;amp;scaleType=1&amp;amp;' alt='my-button' style='float:left;margin-right:1ex;' /&gt;One of the elements lacking a standardized look is the button element. In this article, we&amp;#039;re going to transform the buttons image from fixed to flexible and good looking using HTML and CSS. Let&amp;#039;s get styling!&lt;/p&gt;&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;In the past years, webdesign and webdevelopment have become mature. The user is the center of development, and deserves an user interface which supports and leads users to accomplish the goal of the website. Building consistent, attractive &lt;strong&gt;and cross-browser compatible&lt;/strong&gt; user interfaces can be a tough job. This especially becomes apparent when you're busy giving your forms the desired look and feel. One of &lt;a href='http://www.w3.org/TR/html401/interact/forms.html'&gt;the form-elements&lt;/a&gt; lacking a standardized look is the button element. Let's go tame that button, so it fits into any design.&lt;/p&gt;
&lt;h3&gt;Introducing the button element&lt;/h3&gt;
&lt;p&gt;First, let's get to know the button element. The &lt;a href='http://www.w3.org/TR/html401/'&gt;HTML 4.01 specification&lt;/a&gt; provides the following information about &lt;a href='http://www.w3.org/TR/html401/interact/forms.html#h-17.5'&gt;the button element&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;Buttons created with the BUTTON element function just like buttons created with the INPUT element, &lt;span style='color:#9e053b;'&gt;but they offer richer rendering possibilities&lt;/span&gt;: the BUTTON element may have content. For example, a BUTTON element that contains an image functions like and may resemble an INPUT element whose type is set to &quot;image&quot;, but the BUTTON element type allows content.&lt;br /&gt;&lt;br /&gt; Visual user agents may render BUTTON buttons with relief and an up/down motion when clicked, while they may render INPUT buttons as &quot;flat&quot; images.&lt;/blockquote&gt;
&lt;p&gt;That sounds great. Even though the W3C recommendations states two advantages of using the button element, it seems that many developers forgot about it, or aren't even aware of its existence.&lt;/p&gt;
&lt;p&gt;With that in mind, let's find out the possibilities of the button element. User Interfaces are often heavily dependent on background images, icons and other fancy layout-elements. We want our buttons to blend into that perfectly as well, and accomplish the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use the most &lt;a href='http://www.thefutureoftheweb.com/blog/writing-semantic-html'&gt;semantic&lt;/a&gt; element HTML4 offers us to submit a form: the (submit) button element.&lt;/li&gt;
&lt;li&gt;Create a flexible, attractive button using: 		                                                                     
&lt;ul&gt;
&lt;li&gt;The &lt;a href='http://www.alistapart.com/articles/slidingdoors/'&gt;sliding doors technique&lt;/a&gt;, introduced by &lt;a href='http://www.alistapart.com/'&gt;A List Apart&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use an image sprite (&lt;a href='http://www.alistapart.com/articles/sprites/'&gt;there's plenty&lt;/a&gt; of &lt;a href='http://websitetips.com/articles/css/sprites/'&gt;information&lt;/a&gt; about &lt;a href='http://www.fiftyfoureleven.com/weblog/web-development/css/css-sprites-images-optimization'&gt;image sprites&lt;/a&gt; on the web) for fast hover changes and less HTTP requests (faster page loading).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create a cross-browser, consistent look.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Our goal&lt;/h3&gt;
&lt;p&gt;Before we get into technical information and details, let's take a look at what we are going to build. I've created three buttons, two with basic terms, and another one with some more text. The buttons look great, have round corners, a &lt;a href='http://www.w3.org/TR/CSS2/selector.html#dynamic-pseudo-classes'&gt;hover&lt;/a&gt; state and a &lt;a href='http://www.w3.org/TR/CSS2/selector.html#dynamic-pseudo-classes'&gt;focus&lt;/a&gt; state. Feel free to move your mouse over the buttons, or even click them ;) (Chrome users will see a minor bug, we'll come to that later):&lt;/p&gt;
&lt;p&gt;&lt;iframe style='width:450px;height:60px;' src='http://extranet.procurios.nl/l/nl/library/download/33021'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h3&gt;The markup and images&lt;/h3&gt;
&lt;p&gt;Let's have a closer look at one of the buttons markup. We'll inspect the following button:&lt;/p&gt;
&lt;p&gt;&lt;iframe style='width:450px;height:60px;' src='http://extranet.procurios.nl/l/nl/library/download/33019'&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;pre class='css' name='code'&gt;&lt;button type='submit'&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;This is my button&lt;/span&gt;&lt;br /&gt;&lt;/button&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the markup is really basic. For flexibility reasons, we wrapped the inner text into a span element. This makes it possible for us to use the sliding doors technique, which enables us to blend the button into any user interface. Without the span element inside the button, we wouldn't be able to create a button with round edges and a flexible width.&lt;/p&gt;
&lt;p&gt;To give the button it's look, I used an image sprite containing the three states our button has (the hover and focus state are the same):&lt;/p&gt;
&lt;p&gt;&lt;img src='http://extranet.procurios.nl/l/library/download/33017?' alt='Background sprite of a button' /&gt;&lt;/p&gt;
&lt;h3&gt;The CSS&lt;/h3&gt;
&lt;p&gt;Now, its time to style our buttons. Let's start with the button element:&lt;/p&gt;
&lt;pre class='css' name='code'&gt;	button {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;float: left;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;padding: 0 15px 0 0;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;height: 25px;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;border: 0;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;cursor: pointer;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;text-align: center;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;color: #f9f9f9;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;background: transparent url(images/button-sprite.png) no-repeat right top;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;font: bold 14px &quot;Myriad Pro&quot;, arial, sans-serif;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;overflow: visible;&lt;br /&gt;	}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Some of the properties and values (padding, background and font) are written with &lt;a href='http://www.456bereastreet.com/archive/200502/efficient_css_with_shorthand_properties/'&gt;shorthand properties and values&lt;/a&gt;. I want to address three values and explain why they'r used:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;float: left;&lt;/strong&gt;&lt;br /&gt;I wanted to point out that you should, logically, only apply this value if you want your button to float. In my example, I got three buttons floating next to eachother, hence the value is present.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;padding: 0 20px 0 0;&lt;/strong&gt;&lt;br /&gt;The padding-right is used to show the top-right image in our sprite. If you remove the padding, the span element will overlap the button completely, hiding the right edge of the button.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;overflow: visible;&lt;/strong&gt;&lt;br /&gt;For some reason Internet Explorer decides to stack padding depending on the width of the content inside the element. This value eliminates the stacking. More information &lt;a href='http://www.viget.com/inspire/styling-the-button-element-in-internet-explorer/'&gt;here&lt;/a&gt; and &lt;a href='http://jehiah.cz/archive/button-width-in-ie'&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Secondly, the span element inside our button needs some CSS to get the job done.&lt;/p&gt;
&lt;pre class='css' name='code'&gt;button span {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;display: block;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;padding: 0 0 0 15px;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;height: 25px;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;line-height: 25px;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;white-space: nowrap;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;background: transparent url(images/button-sprite.png) no-repeat left -25px;&lt;br /&gt;	}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Again, i'd like to address three values in our &lt;a href='http://dabrook.org/cc/Basic-Anatomy-of-a-CSS-Rule.png'&gt;CSS rule.&lt;/a&gt; Even though it may sound really basic, questioning &lt;em&gt;why &lt;/em&gt;certain values are present, is a good habit.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;display: block;&lt;/strong&gt;&lt;br /&gt; By default, a span element is &lt;a href='http://htmlhelp.com/reference/html40/inline.html'&gt;an inline element&lt;/a&gt;. We need to be able to add &lt;a href='http://www.pageresource.com/dhtml/csstut6.htm'&gt;box properties&lt;/a&gt; like height and padding to our element, so we need to change its display setting to block.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;line-height: 23px;&lt;/strong&gt;&lt;br /&gt; To vertically align our text in the middle of our button element, we'll have to set the line-height to a value within the 20-25px range. I chose 23px.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;white-space: nowrap&lt;/strong&gt;&lt;br /&gt; This settings makes sure that all of the words you want to show on your button are visible in Internet Explorer. If you forget this setting, you'll notice that '&lt;em&gt;This is my sentence&lt;/em&gt;' will display as '&lt;em&gt;This&lt;/em&gt;'.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thirdly we'll add the CSS necessary to add effects on the hover- and focusevents. Please note that Internet Explorer 7 lacks the implementation of the :focus pseudoclass and Internet Explorer 6 and lower lack the :hover pseudoclass as well. Both can be simulated / fixed using javascript. For example, &lt;a href='http://dean.edwards.name/IE7/'&gt;Dean Edwards javascript library&lt;/a&gt; fixes the most common IE6 and IE7 problems.&lt;/p&gt;
&lt;pre class='css' name='code'&gt;button:hover,&lt;br /&gt;button:focus {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;background-position: right -56px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;button:hover span,&lt;br /&gt;button:focus span {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;background-position: left -84px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;button:focus {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;margin-top: 1px;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;We've come to the point that we're ready to view the buttons in a couple of browsers. Let's see:&lt;/p&gt;
&lt;p&gt;&lt;img src='http://extranet.procurios.nl/l/library/download/33015?' alt='Image showing the look of a button in different browsers' /&gt;&lt;/p&gt;
&lt;p&gt;You'll notice that there's still a little bug in Firefox and Google Chrome. The differences in browser implementations become really apparent now. Let's find out whats happening, and &lt;span class='dict_text2' ondblclick=&quot;dL.f.action=&amp;#039;/lwu.exe/lwu/d&amp;#039;;dL.f.slang.name=&amp;#039;lang&amp;#039;&quot;&gt;additionally how to fix the problem&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;If you inspect our CSS closely, you'll notice that there isn't a conflicting value that causes the extra padding in our button. So where does it come from? Every browser has implemented User Agent stylesheets. If a browser gets a HTML document served without styling information attached to it, it will still show some basic formatting: the User Agent stylesheets. Jens Meiert has written a &lt;a href='http://meiert.com/en/blog/20070922/user-agent-style-sheets/'&gt;good article on User Agent stylesheets&lt;/a&gt;, there's even a list with CSS files you can download.&lt;/p&gt;
&lt;p&gt;If you open Firefox' forms.css, you'll see the following code:&lt;/p&gt;
&lt;pre class='css' name='code'&gt;button::-moz-focus-inner,&lt;br /&gt;input[type=&quot;reset&quot;]::-moz-focus-inner,&lt;br /&gt;input[type=&quot;button&quot;]::-moz-focus-inner,&lt;br /&gt;input[type=&quot;submit&quot;]::-moz-focus-inner,&lt;br /&gt;input[type=&quot;file&quot;] &amp;gt; input[type=&quot;button&quot;]::-moz-focus-inner {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;padding: 0px 2px 0px 2px;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;border: 1px dotted transparent;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Mozilla supports a number of extensions to CSS that are prefixed with '-moz'. These include a number of capabilities, including rounded borders, and the ability to specify different box width and height calculations to more easily support browers that perform such calculations in a non-standard way. &lt;a href='http://techblog.procurios.nlhttps://developer.mozilla.org/en/CSS_Reference/Mozilla_Extensions#Properties'&gt;An overview of all available settings can be found here&lt;/a&gt;.&lt;br /&gt;So apparently the Mozilla extensions are conflicting with our CSS. The first selector is the one we need to fix:&lt;/p&gt;
&lt;pre class='css' name='code'&gt;button::-moz-focus-inner /* fixing evil default firefox padding */ {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;padding:0;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;border:none;&lt;br /&gt;}&lt;/pre&gt;
&lt;p&gt;There we go, the button we created will show correctly in Firefox as well. So what happens in Google Chrome?&lt;/p&gt;
&lt;p&gt;Google's goal with Chrome form implementation, is to behave exactly the same as Firefox. Obviously and unfortunately, they introduced the same bug, which in Chrome can't be fixed. I'm still searching for a way to get around it, but I'm sure Google will fix it sooner or later. The bug has been reported to the Google Headquarters.&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;We've looked at the button element and discovered it's possibilities and limits. We've seen that its possible to create flexible and good looking button elements, with cross-browser support.&lt;/p&gt;
&lt;h4&gt;Pros&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Semantic HTML;&lt;/li&gt;
&lt;li&gt;Fast :hover changes;&lt;/li&gt;
&lt;li&gt;Less HTTP requests;&lt;/li&gt;
&lt;li&gt;Good looking, flexible buttons.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Cons&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Needs a 'hack' to disable the native User Agent CSS in Firefox.&lt;/li&gt;
&lt;li&gt;Google Chromes similar bug can't be fixed at the moment (I dont worry too much about Google Chrome yet, though).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The method described in this article, covers the usage of image sprites. It's possible to get this working in Chrome aswell, but you will have to make separated images instead of using a sprite. If there's demand for an article which explains how to get this done, I'll write a follow up.&lt;/p&gt;
&lt;h3&gt;The code&lt;/h3&gt;
&lt;pre class='css' name='code'&gt;&lt;button type='submit'&gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;This is my button&lt;/span&gt;&lt;br /&gt;&lt;/button&gt;&lt;/pre&gt;
&lt;pre class='css' name='code'&gt;button {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;float: left;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;padding: 0 15px 0 0;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;height: 25px;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;border: 0;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;cursor: pointer;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;text-align: center;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;color: #f9f9f9;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;background: transparent url(images/button-sprite.png) no-repeat right top;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;font: bold 14px &quot;Myriad Pro&quot;, arial, sans-serif;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;overflow: visible;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;button span {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;display: block;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;padding: 0 0 0 15px;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;height: 25px;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;line-height: 25px;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;white-space: nowrap;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;background: transparent url(images/button-sprite.png) no-repeat left -25px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;button:hover,&lt;br /&gt;button:focus {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;background-position: right -56px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;button:hover span,&lt;br /&gt;button:focus span {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;background-position: left -84px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;button:focus {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;margin-top: 1px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;button::-moz-focus-inner /* fixing evil default firefox padding */ {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;padding:0;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;border:none;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;If you feel something is missed out here, or needs further explanation, feel free to post your comment!&lt;/p&gt;</description><link>http://techblog.procurios.nl/k/n618/news/view/33023/14863/Transforming-the-button-element-with-sliding-doors-and-image-sprites.html</link><pubDate>Fri, 13 Mar 2009 20:05:20 +0100</pubDate><guid isPermaLink='true'>http://techblog.procurios.nl/k/n618/news/view/33023/14863</guid></item></channel></rss>