<?xml version="1.0" encoding="ISO-8859-1" ?> 
<rss version="2.0">
<channel>
<title>ferdychristant.com :: article feed</title> 
<link>http://www.ferdychristant.com</link> 
<description>Article Feed: ferdychristant.com</description> 
<language>en</language> 
<item>
<title>Tagonomy: Taxonomy meets folksonomy</title> 
<pubDate>Sat, 12 Jun 2010 09:54:06 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-86CCFU</link>
<description><![CDATA[ <p>
<a href="http://www.ferdychristant.com/blog/resources/Article/$FILE/Tagonomy%"><img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/article_tagonomy.jpg" class="frame" border="0" height="318" width="500" /></a>
</p>
<p>
For my JungleDragon project I was facing an enormous information architecture challenge. Starting out with a classic tagging model for content classification, I had strong desires to overcome some of the drawbacks of such a folksonomy:
</p>
<ul>
	<li>Tags have no/weak relationships with each other since they are just user-invented text labels. This means that it is not possible to use tags to position content in a hierarchical tree</li>
	<li>Tags have no meaning or rich context other than the label itself. If I tag something as &quot;Africa&quot; the system does not know that this is a continent. If it would know this it could for example display Africa on a globe.&nbsp;</li>
	<li>Due to the flexible nature of tagging, they introduce data quality problems: tags not used or not used correctly, misspellings, synonyms, etc.</li>
</ul>
<p>
I needed to bring the worlds of folksonomy and taxonomy together. To combine the strengths of both, whilst minimizing their cons. If this is not difficult enough already, I needed the added strength of a taxonomy structure to be loosely coupled to the community software (ImageDragon). 
</p>
<p>
A challenge so it is. <b>But I managed to do all of the above, and in this article I am explaining you how</b>. Given the length of the article, I have published it as a PDF:
</p>
<p>
<a href="http://www.ferdychristant.com/blog/resources/Article/$FILE/Tagonomy%20meets%20Folksonomy.pdf">Download Tagonomy: Taxonomy meets Folksonomy</a>
</p>
<p>
Solving this challenge and writing this article has been a lot of work. I hope you will find the interest and patience to absorb it. I am convinced that the solution beholds a lot of power as I will show you over time. For now, enjoy, and don't forget to rate and comment back here. It keeps me going in writing more articles.
</p>
<p>
&nbsp;
</p>
]]></description>
</item>, <item>
<title>Strategizing online communities</title> 
<pubDate>Wed, 5 May 2010 02:35:50 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-856B4M</link>
<description><![CDATA[ <p>
&nbsp;
</p>
<p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/community-01.png" height="260" width="313" />
</p>
<p>
<b>Creating a community site does not create a community...<br />
</b>
</p>
<p>
I don't recall where I heard that statement, but it feels like an absolute truth to me. It has led me to think of the composition of existing communities, why they work or do not work, and how to grow them. I am in no way an authority on this subject, but in this post I want to simply structure some thoughts around this.
</p>
<p>
<b>Community composition</b>
</p>
<p>
The layer of circles above in some way or another is commonly used to visualize the composition of communities. Although the exact sizing and naming of inner circles may vary, the key message of the visualization is that there are different types of groups or potential groups within a community, and that their sizing and added value varies greatly. The closer to the inner of the circle, the greater the value, so it appears.
</p>
<p>
Let's have a look at each of these circles, and see what one can do to influence their size.
</p>
<p>
<b>Reach</b>
</p>
<p>
Reach is the most outward circle. It is your <b>potential</b> audience. You could assume this to be any internet user but that hardly ever is true. There are many factors that could exclude internet users from your potential audience:
</p>
<ul>
	<li>System requirements. What is required of your users for them to participate in your community? Which browsers are supported? Does Flash or Silverlight need to be installed? What is the minimum resolution their display device should support? This is not only about being able to run the community software, it is also about being able to use it <b>effectively</b>. If your web community requires a minimal resolution of 1024x768 pixels, you are possible excluding a large group of mobile only users. </li>
	<li>Internationalization and localization (I18N/L10N). Probably the most important factor determining your reach. If you offer single language support, you are locking out a huge audience who does not speak it. Besides language, there are other local factors commonly referred to as &quot;culture&quot;: timezones, date and number formatting, DST, etc. </li>
	<li>Accessibility. Is the community usable by people with visual, hearing or other impairments? What about people with color blindness?</li>
	<li>Culture. The topics and content of your community may not be appropriate for all cultures or even be actively blocked by governments. </li>
</ul>
<p>
This is not the end of it. Your reach may not only be limited by the characteristics of your users. It may also be restricted by your own limitations, your ability to scale the community, typically based on resource limitations.
</p>
<p>
What ammo do we have to grow our reach? Here are a few:
</p>
<ul>
	<li>Make your community usable on common clients. Think web standards and low performing clients and network connections.</li>
	<li>Consider implementing optimized interfaces for the most popular mobile clients</li>
	<li>Extend the experience to additional languages, most popular ones first (i.e. Chinese or Spanish)&nbsp;</li>
	<li>Comply with at least basic accessibility guidelines</li>
	<li>Make sure your system is able to scale to an increased reach (easier said than done)&nbsp; </li>
</ul>
<p>
<b>Community</b>
</p>
<p>
Circle 2 is the community. These are the actual users of your community, including inactive readers and hardcore contributors. A common term used here is &quot;eyeballs&quot;.The size of your community is restricted or influenced by many factors, of which the following are key:
</p>
<ul>
	<li>Content. Content is king. Without original, useful content, there is no foundation for a community. If your content is user generated, an additional challenge appears: seperating good content from poor content. More content does not mean a bigger community in all cases, but it often helps.</li>
	<li>Findability. This is not a proper English word, but I keep using it anyway. If your community or content cannot be found easily, you are limiting the size of your community. You do not exist. The obvious weapon here is to apply Search Engine Optimization. SEO, however, is only one part of Information Architecture, which is key for findability.&nbsp; </li>
	<li>Marketing. Marketing relates strongly to findability; it is about telling people that you exist and what you have to offer. The marketing approach may vary based on your resources, but common ways are online ads, social networking, magazines and speaking events. If you have a truly healthy community, your&nbsp; community members will market the community themselves.&nbsp; </li>
	<li>Experience. So your content is great, is easy to find and people know about it. If the actual experience of being in the community sucks, people will quickly stop participating. There are many aspects to experience, and UI is only one of them. For example, if trolls and spammers are not moderated well, that hurts the experience and people will leave. If people contributing to your community are not recognized and rewarded as such, they might leave. Invade on the user's sense of privacy? They will leave.</li>
</ul>
Given the nesting of circles, everything mentioned in the &quot;Reach&quot; section also applies to the Community section. The size of your community is naturally limited by your reach as well.<br />
<p>
<b>Contributors</b>
</p>
<p>
Circle 3 are the contributors, in many communities only a fraction of the total community. These are the people that are actively contributing content, commenting, rating, etc. It is of the greatest importance that there is a certain mass to this group, because they are the prime source of activity in your community. Without them, it would feel like nothing ever happens. Without them, good content does not get promoted over poor content. Without them, there is no community. 
</p>
<p>
So, what determines the amount of contributors? As before, there has to be a base of good content to lure them into contributing more content. The experience has to be good too. These aspects apply to the entire community, so what is it that specifically appeals to contributors?
</p>
<p>
Recognition. People doing completely voluntary work for you want to be recognized. They want to be rewarded. Hence, the birth of reward/reputation management systems. These systems are as old as games are. Typically, reputation management systems hand out rewards with a real value of zero, and an emotional value that is substantial. For example, a system may reward contributors with credits, badges or karma. In simple reputation systems, that's it really. The credits act like a badge of honour and recognition. More advanced systems may go further, and actually raise the influence of succesful contributors and give them access to exclusive features. Important to remember is that the rewards assigned should be based on community recognition, not on system recognition. An important difference. 
</p>
<p>
Reward systems as such fuel user engagement and perhaps even addiction. Ideally, contributors enjoy contributing, helping themselves and the community. However, reward systems can be destructive too. Without proper anti-gaming mechanics, real contributors and cheaters are impossible to differentiate. If recognition is for the taking, everybody stops caring. A secondary problem is in the reward hierarchy. If only top contributors run the show, the larger group of incidental contributors stop being engaged. 
</p>
<p>
<b>Core</b>
</p>
<p>
The 4th and final circle is the community core. This is the hardcore of the community, a small subset of the contributor circle. These are the people that go beyond just contributing; they may be community leaders or recognized as such, they may be early adapters or people actively marketing your community. They may even think constructively about the future direction of the community and have close contact with the community owner. In a way, they are partners or co owners, even though they are not legally so.
</p>
<p>
Unlike the other circles, there is no clear formula to recruit or grow this important group. Still, the following comes to mind:
</p>
<ul>
	<li>Treat them with the respect they deserve, they are an important reason for the success of your community. Consider asking them for strategic feedback or even make them part of decision making. Consider giving them extra rights, rewards and visibility. Make them feel proud.</li>
	<li>Match their interests. Typically, the core community is in the community because they are fanatics in a certain niche. Do not lose sight of that reason for existence.</li>
</ul>
<p>
As with the Community circle, the core circle can be supported through a well balanced reward system. However, the reward system should not position these users as community dictators. <br />
<br />
</p>
<p>
<b>The perfect community</b>
</p>
<p>
It may be tempting to conclude that every community should try to grow each of the circles at all times, up to the theoretical situation where all circles are maxed out and of equal size. In practice, this hardly ever makes sense as can be seen from the following examples:
</p>
<ul>
	<li>There is no point for a local Oklahoma fishing community to grow its' reach or community to a global level.</li>
	<li>It would be ineffective for Wikipedia to max out on the number of contributors, instead, a small set of high quality contributors is more effective. </li>
	<li> There is no core when everybody is part of the core. A core should be small and effective, as it is about leadership and the future. </li>
</ul>
In other words, pick your fights and choose wisely which circles you want to focus on. Which circle(s) bring you and the community the most value?
<p>
&nbsp;
</p>
<p>
<b>Relationship strategy</b>
</p>
<p>
In online communities, it is the core and contributor group who run your
community. In essence, they are doing work for you, completely 
voluntary, mostly for free. It is a mistake, however, to treat this 
relationship like a work relationship. In a work relationship, the owner
is there to minimize the cost of people and to maximize their value. 
Human needs are only secondary. In a community relationship, you have 
already minimized the costs, because their participation is voluntary 
and without pay. You are economically powerless to force community 
members to do anything. Therefore, the only way to maximize their value 
is by asking them nicely. By being friendly. By being supportive. By 
making them visible and rewarding them. The human approach.
</p>
<p>
<b>The community of communities</b>
</p>
<p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/community-02.png" height="230" width="313" /> 
</p>
<p>
Many communities allow for the creation of sub communities. This can be by design, for example a Flickr photo group. Flickr has purposely designed this feature to allow for specialized communities within the larger community. Sub communities can also occur spontaneously, for example a group of like-minded Twitter users following each other. They may not be recognized by Twitter as a designed sub community, but they are a community nevertheless.
</p>
<p>
The interesting thing about sub communities is that their composition (think of the circles) is often dramatically different from the larger community. There is a smaller total size, yet the core and contributor circles are much bigger. However, there is strong relationship with size. A wildlife photo group may have a large community with few contributors, yet a lion photo group may have a small community with many contributors. The more specialized the community, the more likely fanatics form the majority of it.
</p>
<p>
If you own or run a community where the creation of sub communities is within your control, a strong aspect to consider is ownership. Sub community leaders should have the feeling that they own and control it, so give them plenty of ways to tune and customize it.
</p>
<p>
<b>Community pitfalls</b>
</p>
<p>
There are many reasons why some communities never really take of, but here are two popular syndromes:
</p>
<ul>
	<li>The empty restaurant syndrome. Nobody walks into an empty restaurant. It must not be good if it is empty. This is why new restaurant owners invite family and strategically seat them next to the window. People walking by will see that the restaurant is not empty and may consider going in. The same is true for communities. You need to have a solid base of materials and users to work with before you launch anything. </li>
	<li>The &quot;now what?&quot; syndrome. You have lured new members to your community and they have completed the registration process. Now what? You should offer users something to do. Easy ways to get in touch with like minded people, find fresh content and discover features.&nbsp; </li>
</ul>
<p>
<b>In closing, community commonalities</b>
</p>
<p>
When using the circles to analyze communities and figuring out where the value and growth is, we see that a strategy depends on many factors. However, I would like to believe that some things are important for any community:
</p>
<ul>
	<li>Being accessible and findable (information architecture, accessibility,SEO, I18N)</li>
	<li>Being friendly and inviting (human approach, the community runs the community) </li>
	<li>Being rewarding to those who contribute (reputation management, cherishing key contributors)</li>
	<li>Being interesting. Content is king. Without it, all else fails.</li>
</ul>
The end. I look forward to your comments below.
]]></description>
</item>, <item>
<title>When to use or not use RIA technology</title> 
<pubDate>Wed, 31 Mar 2010 11:10:42 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-843BE2</link>
<description><![CDATA[ <p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/ria_03.jpg" height="221" width="250" /> 
</p>
<p>
At work we have been struggling with a specific question for a while now: When to use RIA technologies (Silverlight, Flash, etc) and when not to use them. It's a complex question and we approached it in a complex way. We made a comparison matrix comparing dozens of qualities of these technologies and the outcome was dissapointing. Instead of having a simple guideline the answer was &quot;it depends&quot;. It depends on many factors really. 
</p>
<p>
The reason why such an answer is dissapointing is that it does not help when you work in a very large organization and want to standardize your strategy and architecture. In my experience, any guideline or standard that you enforce has to be simple, not subject to interpretation or preference. And of course it has to make sense and be smart, so that the people following the standard feel like they are doing the right thing.
</p>
<p>
I was not satisfied with the &quot;it depends&quot; answer so I stepped away from it and let it sink in for a while. To make a long story short, I eventually concluded on a guideline that can be summarized as follow:
</p>
<p>
<b>You should use RIA technology when the interaction requires it or when the audience expects it</b>
</p>
<p>
This rule still leaves room for interpretation, so I will be using the rest of this article to discuss a few specific cases and how this rule applies to it. 
</p>
<p>
<b>First, our starting point</b> 
</p>
<p>
Before I do that, however, I first would like to address another consideration: our starting point. Why would we not always use RIA technology? There certainly are a few advantages to that approach:
</p>
<ul>
	<li>All applications and interactions will be rich</li>
	<li>Developing a rich application in RIA technology is much more productive than doing a similar thing in standard technology (DHTML)</li>
	<li>RIA applications tends to be pixel perfect, no browser quirks to deal with&nbsp;</li>
</ul>
<p>
Yet, there are also some important disadvantages:
</p>
<ul>
	<li>Users may not have your choice of RIA platform installed</li>
	<li>You will be locked into a vendor specific platform</li>
	<li>There is no guarantee for backwards-compatibility or your RIA platform surviving in the market</li>
	<li>There may be some addition technical disadvantages, such as bookmarking and broken back buttons that conflict with user's expectation of a web application </li>
</ul>
<p>
I'm a standards man, and the industry is on my side. I believe the future is in better web standards support, a neccessity because of the fragmentation of browsing devices. My starting point is therefore web standards, and to only add proprietary RIA technology where it adds value.
</p>
<p>
<b>You should use RIA technology when the interaction requires it</b>
</p>
<p>
This rule is best illustrated with a few examples. Here is a screenshot of my Flickr photo stream:
</p>
<p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/ria_01.jpg" height="419" width="500" /> 
</p>
<p>
Photo viewing at the largest photo site in the world. Other than perhaps some light Ajax tricks (such as inline editing), there is nothing rich about this interface. No RIA technology is used. You will find this to be true for allmost all big sites (Yahoo, MSN, Digg, Facebook, Craigslist) and the majority of all smaller sites. Do you follow web design blogs that showcase the latest RIA tricks but wonder why on earth no real site or application is implementing them? 
</p>
<p>
The answer is twofold:
</p>
<ul>
	<li>The interaction does not require it. You can browse and view photos, check on your online friends, read blogs and all those things without RIA technology because the interaction is simple and RIA technology will not add any value.</li>
	<li>Besides not adding any value for such interactions, RIA technology actually locks out users because of its proprietary nature. UI experts call this &quot;reach&quot;. When it comes to reach vs rich, reach allways wins for simple interactions.</li>
</ul>
<p>
Now, let's have a look at that same Flickr site for a richter interaction:
</p>
<p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/ria_02.jpg" height="340" width="500" /> 
</p>
<p>
Here I am editing one of my photos, like Photoshop in a web browser. This is an incredibly rich interaction for which RIA technology is not only justified, it is a neccessity. The target audience will also be smaller, as it only concerns signed in users that actually edit a photo in a web browser.&nbsp;
</p>
<p>
There are other examples of rich interactions in Flickr. Organizing your photos into sets using drag and drop for example. This would be possible, yet painful in standard technology. <b>The interaction requires it</b>. Sometimes RIAs can enrich basic interfaces too. You can upload a photo to Flickr using a class web upload form, but there is also a Flash-based multi file upload control and even a desktop RIA to upload files in batch. RIA technology provides a richer alternative here, a perfect mix of both rich and reach.
</p>
<p>
<b>Which interactions require a RIA?</b>
</p>
<p>
My claim is that RIA technology is justified when the interaction requires it. So which interactions require it? In short, all interactions where the usability of the application is improved by applying RIA technology. To make this more specific, here are a few examples that come to mind:
</p>
<ul>
	<li>Intense data administration. Applications that require a lot of data entry and maintenance benefit from RIA technology. These are the kind of applications that are not really suitable for the web anyway. </li>
	<li>Rich charting and other rich UI controls. Classic web technologies only offer limited input and visualization controls. An interactive chart with filtering and pivoting capabilities is probably best implemented using RIA technology. The same applies to a 3D product view control or a workflow process design control. </li>
	<li>Rich media, primarily video and games</li>
	<li>Offline usage</li>
	<li>Map technology</li>
	<li>Interactions that require some form of desktop integration</li>
	<li>Realtime systems</li>
</ul>
<p>
<b>Border cases</b>
</p>
<p>
There are always border cases, specifically when an interaction is semi-rich and can be implemented in both classic and RIA technology. Normally, I then recommend to stick with standard technology. However, there is also a practical consideration to make. Have a look at the following Silverlight scheduler control:
</p>
<p>
<a href="http://demos.telerik.com/silverlight/#Scheduler/FirstLook">http://demos.telerik.com/silverlight/#Scheduler/FirstLook</a>
</p>
<p>
This is a desktop-like experience for scheduling resources implemented in Silverlight. However, there is also an Ajax version:
</p>
<p>
<a href="http://demos.telerik.com/aspnet-ajax/scheduler/examples/outlook2007/defaultcs.aspx">http://demos.telerik.com/aspnet-ajax/scheduler/examples/outlook2007/defaultcs.aspx</a> 
</p>
<p>
Now, let us imagine that these 3rd party controls would not exist and we were to implement it from scratch. I can tell you that Ajax development for such a control is incredibly painful, error prone and expensive. The burden would be too large to go for classic web technologies in this case.&nbsp;
</p>
<p>
<b>Yet another border case</b>
</p>
<p>
Microsoft once visited us with a very slick Silverlight demo which involved a 3D web shop. Users could actually walk and navigate inside a virtual store and visit sections, have a look at products, and so on. An awesome technology showcase and of course many in the room were sold. I hate it when this happens. 
</p>
<p>
The problem here is that this is RIA for the sake of RIA. Guess why no web shop in the world has implemented this? Because it hurts their sales. It is an interaction that looks impressive but is less usable than a normal web shop experience. The interaction is richer, but the bottom line is not.
</p>
<p>
It takes some industry experience and usability insight to distinguish between RIA adding value or a supplier simply selling RIA technology using a sexy demo. Generally, when a supplier uses the term &quot;user engagement&quot; you should conclude that he does not know a thing about users.
</p>
<p>
Why? Because user engagement is a myth in allmost any context. Users do not want to be engaged or be in a relationship with your app. Users want to get a task done and get on with their life. Your app means nothing to them, all they want is for the app to be simple, fast, usable, intuitive. It helps when your app looks good, but when you push this to the point where it hurts usability, you are on the wrong track. If you don't believe me, again, look at any major website or application out there.&nbsp; 
</p>
<p>
A second example I would like to give is another recent demo I had the pleasure to attend. Upon making a filter decision in the application, a data grid rotated in 3D and then stopped into position. Next, it took 10 seconds for actual data to appear in the grid. And it gets better, it turns out users can click on some strange curvy arrow to flip the box in 3D once more and then on the &quot;backside&quot; choose some kind of sub filter. The application of RIA technology in this case clearly violates usability rule number one:
</p>
<p>
<b>&quot;Users spend most time on OTHER websites/applications&quot;</b>
</p>
<p>
In other words, do not break conventions and user expectations. Users want to get something done, not learn your application. Be wary of the &quot;cool&quot; factor, needless animations and eye candy.&nbsp;
</p>
<p>
You may get into heated debates about this. If so, take the emotional part out of it. Look at the bottom line. Measure usability statistics and conversions.&nbsp; 
</p>
<p>
<b>You should use RIA technology when the audience expects it</b>
</p>
<p>
I have just made a clear point against RIA just for the sake of RIA. However, there are some exceptions to be made. In certain niche areas and audiences, RIA is expected and entirely appropriate even when not technically required. Think of a movie site, an online game or a site about a console game, the portfolio of a designer, a ringtone site for teenagers. These are experiences where users really <b>are</b> looking to be engaged and entertained. Most of the time, this concerns consumer services in the entertainment and media industry.
</p>
<p>
<b>Summary</b>
</p>
<p>
As simple as my original guidelines was...
</p>
<p>
<b>You should use RIA technology when the interaction requires it or 
when the audience expects it</b>
</p>
<p>
...as lengthy this article became. I hope the examples explained my thinking, in that RIA should be applied where it truly adds value. Value should primarily be added to your user and your bottom line. Be wary of the &quot;coolness&quot; factor and the tension it creates between suppliers, decision makers and you. Have a look at what other websites and applications are doing. In the end, nothing beats common sense and real world figures. 
</p>
<p>
<b>The future of RIA </b>
</p>
<p>
There are some interesting developments going on in the web and RIA technology area:
</p>
<ul>
	<li>It is expected that within the next few years, the majority of the user population will access your site or application from a mobile device. These devices are not standardized and there is no guarantee that your RIA platform is even available. </li>
	<li>Powerful forces like Google and Apple are pushing forward web standards like HTML5, CSS3, faster Javascript and DOM2. Even Microsoft is getting on board with IE9. In a few years, it is likely that these standards are commoditized and available across pretty much all browsing devices. This will move web standards technology into the realm of RIA, that is, if their design tools are improved.</li>
</ul>
<p>
If the above is to become true, proprietary RIA technology is in for a lot of trouble and might be reduced to niche usage. I have always been in the web standards camp so I actually hope this is how it will plan out.
</p>
<p>
This is a highly opiniated piece on technology decisions, therefore I greatly appreciate your feedback. Please do rate and comment below. 
</p>
]]></description>
</item>, <item>
<title>PHP Mythbusting</title> 
<pubDate>Wed, 1 Apr 2009 01:40:59 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-7QNDHR</link>
<description><![CDATA[ <p>
<img width="300" src="http://www.ferdychristant.com/blog/resources/PHP/$FILE/mythbusters.gif" height="232" /> 
</p>
<p>
PHP is a technology that is often debunked as sloppy, inconsistent, immature and not enterprise-ready. I have used PHP for a few years now, for projects small to very large. I have seen it in the enterprise context, certified myself in PHP and am a loyal follower of the online communities. Through this article I want to bring forward my opinion on PHP and bust some myths at the same time. Let's get to it. 
</p>
<p>
<b>&quot;PHP does not scale&quot;</b> 
</p>
<p>
This is an easy one to bust. PHP does scale. In large scale web applications, the middleware, whether it is PHP, Java or anything else, hardly ever are the bottleneck. PHP typically ties into Apache, a world-class highly scalable web server. Considering that huge websites such as Digg.com and many others are built on PHP, there is little evidence to support this claim. 
</p>
<p>
What critics often mean with this statement is that PHP does not <b>perform</b>. Performance and scalability are two different things though. Considering PHP performance, the typical remark is that it is an interpreted language. This is true, PHP is compiled at the time of a page request, however I have little reason to believe that this is an issue with today's hardware. And if it is, don't worry, there are various PHP optimizers available on the market. these optimizers pre-compile PHP pages, speeding up page processing considerably. There is also a wealth of solutions for caching. PHP scales and performs just fine if you know what you're doing. 
</p>
<p>
<b>&quot;PHP is sloppy and inconsistent&quot;</b> 
</p>
<p>
There is a core of truth to this claim, the language itself is a bit inconsistent due to historical reasons. Particularly the function space suffers. Where a modern language provides namespaces with consistent function grouping and naming, PHP has no namespaces at all and the occasional weird function names. 
</p>
<p>
For example, in Java you might have a java.lang.String namespace with methods consistently named in it, PHP simply has a list of string functions without any namespace at all. Sometimes a string function starts with &quot;str&quot;, sometimes with &quot;str_&quot;. For people with a strong background in OO, this certainly does feel sloppy. Personally I hardly consider this a showstopper, if you do serious development in PHP, you will quickly get used to the weird function names. It's not a sign of elegance, but definitely workable.&nbsp; 
</p>
<p>
Another aspect of this claim is the runtime environment. There is a very good side to it: PHP can run on pretty much any platform and tie into all common web servers. However, in practice you may find that the large amount of PHP versions, compile-time directives and ini settings can lead to a large variety of runtime environments. PHP's flexibility comes at a cost, but not at all costs. In practice you will have hardly any issues if you're not doing anything uncommon. 
</p>
<p>
<b>&quot;PHP is for hobbyists and invites for sloppy programming&quot;</b> 
</p>
<p>
This argument is getting seriously outdated. Yes, PHP has little barriers for beginners and is the de facto choice for web hobbyists, given its low costs and wide availability. True, PHP without and training or experience invites for procedural programming. And finally, yes, you will find tons of poor examples online. 
</p>
<p>
However, during the last years a new movement has arrived. PHP 5 now has good OO support. There is a large audience of PHP professionals who use it in a serious context. There is a certification program. There are a number of world-class frameworks that promote and support good architecture and OO practices. There is Zend, a commercial entity pushing the product further by delivering enterprise support. 
</p>
<p>
It is possible to do sloppy programming in PHP and the language even hints the unknowing towards that path. Yet it does not differ much from any language: if you don't know what you're doing or what is possible, you will always end up with sloppy solutions. PHP has as much potential for proper application development as any other platform. 
</p>
<p>
<b>&quot;PHP is not ready for the enterprise&quot;</b> 
</p>
<p>
What does this even mean? Is the enterprise some magic place where common rules don't apply? Let's discuss some things that enterprises typically desire from their platforms: 
</p>
<ul>
	<li><b>Support.</b> PHP is open source and does not have it?&nbsp; Wrong, Zend supports PHP.</li>
	<li><b>Tooling.</b> All the tooling you need for PHP development are readily available, most open source, some commercial. Zend offers a great IDE and runtime platform with advanced monitoring facilities. With PHP development, you can also nicely integrate with off-the-shelf solutions for professional development, such as Subversion for source control and Ant for build management. </li>
	<li><b>Integration.</b> PHP speaks webservices, REST, SMTP, FTP, RSS and there are tons of additional libraries for the most common enterprise application integration scenarios. </li>
	<li><b>Documentation</b>. PHP is very well documented. It is documented for productivity, with lots of examples and user-contributed notes. Much easier than the typical library documentation where you have to find your way around namespaces, obscure parameters and lack of code examples.</li>
	<li><b>People.</b> The market of true PHP professionals is not as big as some other platforms, but it is definitely growing. In the enterprise where I work, we never had an issue sourcing PHP professionals in any part of the world.</li>
</ul>
<p>
I could go on, but I definitely think PHP is ready for the enterprise. It is a misconception to believe it is not. Major web companies would not bet their existence on it if it was not ready. I have personally seen enterprise PHP development for three years where I work, and it was a major success: low cost, highly productive, awesome performance, flexible, easy to learn and easy to automate and control. This is not to say that you should build everything in PHP, yet it is definitely suitable for most web applications, no matter how large or complex. 
</p>
<p>
To me, PHP's beauty is in it's simplicity. This in turns leads to a high reusability, low costs and high productivity...something every business needs. 
</p>
<p>
<b>&quot;PHP is insecure&quot;</b> 
</p>
<p>
This is an often-made claim but I am not sure what it means. I have never found any evidence to support the fact that PHP as a language is insecure. There is plenty of evidence though that some popular PHP applications, such as phpBB, are insecure, and since it is widely spread, the impact is large. PHP also offers some environment settings (such as register globals) that invite for security leaks in applications, but anybody who knows a thing about PHP knows not to use those features. I think PHP is partly to blame in offering the features (that intend to make building applications easier) or having them enabled by default in some cases, yet I can hardly blame the language itself for it. As a professional you need to be aware of the most common security risks and settings, just as in any platform. 
</p>
<p>
<b>Conclusion</b> 
</p>
<p>
I'll stop now. During the writing of this article I discovered another article called <a href="http://jaybill.com/2008/01/02/10-php-myths-dispelled/">10 PHP Myths Dispelled</a>. There you will find even more common myths about PHP. In closing, I would like to stress that I am not particularly biased or a fan of PHP. I've used multiple platforms in my career, obtained multiple certifications and continue to use multiple platforms. I hardly ever indulge in platform wars, but I do enjoy revealing the truth about them. My truth for PHP is that it is a very capable platform for many purposes, with a model that is attractive for many businesses and professionals. It has it flaws here and there, but no flaws that cannot be overcome with a bit of knowledge and experience. PHP's domination on the web is the living proof of that. 
</p>
<p>
<script type="text/javascript">
<!--
google_ad_client = "pub-8337087074568897";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_bg = "FFFFFF";
google_color_link = "FF6600";
google_color_text = "000000";
google_color_url = "6699CC";
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</p>
]]></description>
</item>, <item>
<title>Hierarchical data in MySQL: easy and fast</title> 
<pubDate>Fri, 27 Mar 2009 11:44:00 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-7QJPM7</link>
<description><![CDATA[ <p>
<img src="http://www.ferdychristant.com/blog/resources/PHP/$FILE/mysql_hierarchy.jpg" width="350" height="309" /> 
</p>
<p>
Storing hierarchical data in a relational database is a classic problem. Relational databases are not really designed for this purpose, because they store data in flat rows. Storage is actually the least of our problems. Imagine a commenting system with an unlimited level of nesting in replies. This is easy to store in a relational database:
</p>
<table border="1">
	<tbody>
		<tr>
			<td><b>comment_id</b> <br />
			</td>
			<td><b>body</b> <br />
			</td>
			<td><b>parent_id</b> <br />
			</td>
		</tr>
		<tr>
			<td>1</td>
			<td>JungleDragon rocks<br />
			</td>
			<td>&nbsp;</td>
		</tr>
		<tr>
			<td>2</td>
			<td>No it doesn't!<br />
			</td>
			<td>1 <br />
			</td>
		</tr>
		<tr>
			<td>3</td>
			<td>Oh yes it does!<br />
			</td>
			<td>2</td>
		</tr>
		<tr>
			<td>4</td>
			<td>The economy sucks<br />
			</td>
			<td>&nbsp;</td>
		</tr>
		<tr>
			<td>5</td>
			<td>True</td>
			<td>4</td>
		</tr>
	</tbody>
</table>
<p>
For the sake of simplicity, I have omitted other comment fields such as author, date, etc. The table shows that we can easily store unlimited levels of nesting by simply linking to the parent of the current comment. Comments that have no parent are the root comments, the others are leafs. If we would apply a foreign key to the parent_id column and link it to the id column we even get full referential integrity.&nbsp;
</p>
<p>
So far so good? Yes, but the real problems start when we want to query that table for useful stuff. Imagine the following tasks:
</p>
<ul>
	<li>Get the full comment tree sorted in the correct order. Hint: you cannot use date sorting, since replies can be made anywhere and must be positioned below their parent at all times.</li>
	<li>For each comment in the tree, we want to know how deep it is (how many levels deep), so we can use that for indenting the comment below its parent.</li>
	<li>For each comment we want to know how many replies there are, no matter how deep in the tree.</li>
</ul>
<p>
None of the above tasks can be queried efficiently using the table we started with. The problem is that since we do not know how many levels deep the hierarchy is, we need to make recursive calls, leading to many queries to the database, high memory usage in our scripts and generally a system that does not scale.
</p>
<p>
As said, this is a classic problem, and luckily there are existing solutions and patterns for this. <a href="http://www.evolt.org/article/Four_ways_to_work_with_hierarchical_data/17/4047/index.html">This article</a> explains four different approaches, I highly recommend it. In summary, these are the four methods:
</p>
<ul>
	<li><b>Recursive</b>. The approach we already discussed. This approach is inefficient and does not scale.</li>
	<li><b>Stack</b>. This one is not much different from the recursive approach. The idea is that you build a stack of hierarchical data by looping through the rows, typically inside a stored procedure. Once you have the stack built, it is very easy to use and query, however, it still requires a lot of database connections.</li>
	<li><b>Modified Preorder Tree Traversal</b>. This surely is the most sophisticated, but also most complex, of the methods to work with hierarchical data. I encourage you to read the full description to really understand it. The principle of this method is that we assign smart numbers (left and right) to each leaf in the tree, these numbers indicate the relative position of the node towards other nodes. With a tree preordered like this, querying the hierarchical data becomes very fast and easy. There is a major downfall though: as soon as you insert or change something in the tree, it has to be rebuild. This will lead to many update queries, and these are expensive. The larger the tree, the larger the time of inserting a new node.</li>
	<li><b>Flat table model.</b> Surely we know that if we could preprocess things like the level of the comment (how deep is it) and the rank (sort order), querying would become much easier. The author also admits that this does shift the performance problem to the writes: upon inserting a comment, all others ranks have to be recalculated. Anyways, the idea of this model is that you <b>store</b> essential attributes of the tree, instead of calculating them each time we retrieve the tree. Kind of like a tree cache.</li>
</ul>
<p>
Based on the options presented so far, it seems the flat table model looks promising, yet it does have a major limitation: a very expensive write operation. Luckily, one of the commenters of the article posted a way around this. I have taken his idea as a basis, and extended it somewhat. 
</p>
<p>
<b>The Flat Table Model done right</b>
</p>
<p>
Let's just get to it right away. Here's my(heavily inspired) solution:
</p>
<table border="1">
	<tbody>
		<tr>
			<td><b>comment_id</b> <br />
			</td>
			<td><b>body</b> <br />
			</td>
			<td><b>parent_id</b> <br />
			</td>
			<td><b>lineage</b></td>
			<td><b>deep</b></td>
		</tr>
		<tr>
			<td>1</td>
			<td>JungleDragon rocks<br />
			</td>
			<td>&nbsp;</td>
			<td>1<br />
			</td>
			<td>0</td>
		</tr>
		<tr>
			<td>2</td>
			<td>No it doesn't!<br />
			</td>
			<td>1 <br />
			</td>
			<td>1-2<br />
			</td>
			<td>1<br />
			</td>
		</tr>
		<tr>
			<td>3</td>
			<td>Oh yes it does!<br />
			</td>
			<td>2</td>
			<td>1-2-3<br />
			</td>
			<td>2</td>
		</tr>
		<tr>
			<td>4</td>
			<td>The economy sucks<br />
			</td>
			<td>&nbsp;</td>
			<td>4<br />
			</td>
			<td>0</td>
		</tr>
		<tr>
			<td>5</td>
			<td>True</td>
			<td>4</td>
			<td>4-5</td>
			<td>1</td>
		</tr>
	</tbody>
</table>
<p>
Instead of using a rank, we are using a lineage. They have the same purpose (correctly ordering the comments), it's just that a lineage has one major advantage: it never needs to be updated! As you can see, the lineage column displays the hierarchy ids in a flat column (from highest parent to lowest child). This field is calculated upon insertion, no other inserts need to take place. The deep column simply sets the nesting level of the comment, which is handy when we need this value for indentation later on. By storing it, we require no recursive queries at all.
</p>
<p>
Let's go into a little bit more detail concerning the insertion of a new comment. Here's how it works:
</p>
<ul>
	<li>in our save routine of a new comment, we check whether it came from a parent (is parent_id set?)</li>
	<li>if so, we do a query to retrieve the parent row</li>
	<li>next, we calculate the lineage and deepness of the new comment. For lineage, we use the parent's lineage. For deepness, we use the parent's deepness + 1.</li>
	<li>we now insert our new comment. next, we use the returned comment id of the new comment, add it to the lineage of the newly created comment, and save it again (update).</li>
</ul>
<p>
All in all, we are retrieving a row, inserting one, and updating one. Considering the other highly inefficient methods and knowing that most people will read comments and not write them, this is pretty awesome. We have no recursion, not even a regular loop.
</p>
<p>
Querying this structure is even better. It is super easy to get all comments in the right order, get the indentation, and even the replies per comment, no matter how many levels of nesting we have. This query kind of combines these three tasks:
</p>
<p>
<b>SELECT c.id, c.user_id, c.body, c.deep, c.lineage, c.parent_id, (SELECT COUNT(*) FROM comment where comment.lineage LIKE (CONCAT(c.lineage,'%')) AND comment.lineage!=c.lineage) as replies<br />
FROM comment as c<br />
order by c.lineage</b>
</p>
<p>
Careful readers will see that we are using a subquery to count the replies for each comment. This part does have some performance overhead, but not much. If you do not need to show the number of replies to <b>each</b> comment, leave it our for even faster results. Or, you could take this even further by storing the number of replies in the database. The downfall of that approach is that you will need to recursively update all parents of the current comment row. That's not as bad as it sounds, it is not likely that you will have more than a handful of nesting levels for a single comment, in fact, most will have none, one or two. 
</p>
<p>
<b>Referential integrity </b>
</p>
<p>
What about referential integrity? Since we have flattened the lineage and deep columns, we have lost some of that. No worries though, we are keeping our referential parent_id -&gt; id foreign key. We do have referential integrity at the foundation. Should anything go wrong with the lineage or deep columns, then we can easily use the parent_id -&gt; id relationship to &quot;rebuild&quot; those values.<br />
<br />
<b>Usage</b>
</p>
<p>
The advanced flat model is optimized for a comment system, it should not be used everywhere. Particularly it is suitable for wide trees (little nesting), not deep trees. The reason for this limitation is the lineage column, which flattens the hierarchy in a single column. When there are too many levels of nesting (let's say over 20), a different model may be more suitable. 
</p>
<p>
<b>Yet another way</b>
</p>
<p>
Throughout my online research, I found <a href="http://www.alandelevie.com/2008/07/12/recursion-less-storage-of-hierarchical-data-in-a-relational-database/">yet another way to work with hierarchical data</a>. This approach is again a flat model approach, but this time the author reserves one column per nesting level in the table to store the deepness. The problem is that this results in a hardcoded nesting level limit. The other problem is that it is patented. Go figure. That's like patenting breathing.
</p>
<p>
<b>Conclusion </b>
</p>
<p>
There are multiple approaches towards storing and retrieving hierarchical data in (my)SQL, but for comment systems and other wide tree hierarchies, I hope you like my tweaked flat model approach. It has no recursion, not even loops, fast retrieves, the least writes, and a solid foundation of referential integrity. Credits go out to the author of the article and the commenter that suggested the lineage method. I only extended those ideas a little bit. 
</p>
<p>
In closing, I like to end with a small tip. In many online examples, I see people looping through a depth counter to append things like spaces for indentation. This is not needed, almost every language has a function for this, here it is in PHP:
</p>
<p>
<b>str_repeat(&quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;,$row['deep']);</b> 
</p>
<p>
...where the first param is the indentation string, and the second param is the number of indentations.
</p>
<p>
Enjoy! 
</p>
<p>
<script type="text/javascript">
<!--
google_ad_client = "pub-8337087074568897";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_bg = "FFFFFF";
google_color_link = "FF6600";
google_color_text = "000000";
google_color_url = "6699CC";
//--></script>
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script>
</p>
]]></description>
</item>, <item>
<title>Coding a jQuery hotbox</title> 
<pubDate>Wed, 18 Feb 2009 04:09:20 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-7P9GF3</link>
<description><![CDATA[ <p>
I've always wanted to be good in 3D modeling. It is pure magic. It allows you to create anything you imagine in a photo realistic way. If you have the skills that is. I clearly don't, and I do not have the time to acquire them. Still, I like to occasionally play around in programs like Blender and Maya, just to see what it is like.
</p>
<p>
What is common about these programs is that their user interface is highly complex. Users want to have large views of their object, whilst also having a massive amount of controls on screen. Challenging. I've found out that most 3D programs use a so-called hotbox to make common options more accessible. Here's Maya's hotbox:
</p>
<p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/hotbox.jpg" width="399" height="393" /> 
</p>
<p>
A hotbox like this is launched when the user presses <b>and holds</b> the spacebar, and is automatically closed upon releasing the key. The shortcut is an overlay on the currently active screen, and provides quick shortcuts depending on the context. By associating it with a large key like the space bar, this is a very accessible way for power users to increase their productivity.
</p>
<p>
As I am building a <a href="http://www.s3maphor3.org/jungledragon/">rather complex web application</a> myself, I asked myself the question: <b>why do we not have hotboxes on the web?</b>
</p>
<p>
I've never seen one in a web application. Hence, I create one. Just because I can. Welcome to Coding a jQuery Hotbox.
</p>
<p>
<b>What we will be building</b>
</p>
<p>
We will be building a hotbox for the web using jQuery, some simple markup, and some clever CSS. We will use the spacebar as the key to activate it. When it is activated, we will dim the background of the page whilst preserving the opacity of the hotbox panel, much like the popular <a href="http://www.huddletogether.com/projects/lightbox2/">Lightbox</a> technique. We will not use the Lightbox library though. We want something simple and fast without bloat.
</p>
<p>
Time to point you to the demo: <a href="http://www.s3maphor3.org/demo/hotbox/">jQuery Hotbox online demo</a>
</p>
<p>
<a href="http://www.s3maphor3.org/demo/hotbox/"><img src="http://www.ferdychristant.com/blog/resources/Web/$FILE/hotbox.gif" border="0" /></a> 
</p>
<p>
Go ahead and tryout the effect: press <b>and hold</b> the spacebar key to launch the hotbox. If you want to know how this is done, please <a href="http://s3maphor3.org/download.php?get=hotbox.zip">download the Hotbox demo</a> and open the project files in your favorite IDE or text editor.
</p>
<p>
<b>Building the Hotbox demo - markup</b>
</p>
<p>
Ok. I am assuming that you have the source files of the demo open. If not, I will at least point you to the most important parts, starting with the markup. Most of the markup in the source file is needed only to layout the demo page. The only relevantt section occurs just before the body close tag (&lt;/body&gt;):
</p>
<div class="php" style="border: 1px solid #d0d0d0; font-family: monospace; color: #000066; background-color: #f0f0f0">
<ol>
	<li class="li1">
	<div class="de1">
	<span class="sy0">&lt;</span>div style<span class="sy0">=</span><span class="st0">&quot;display: none;&quot;</span> id<span class="sy0">=</span><span class="st0">&quot;darken&quot;</span><span class="sy0">&gt;&lt;/</span>div<span class="sy0">&gt;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	<span class="sy0">&lt;</span>div style<span class="sy0">=</span><span class="st0">&quot;display: none;&quot;</span> id<span class="sy0">=</span><span class="st0">&quot;qnav&quot;</span><span class="sy0">&gt;</span>Hotbox content comes here<span class="sy0">!&lt;/</span>div<span class="sy0">&gt;</span>
	</div>
	</li>
</ol>
</div>
<p>
This markup contains just what you might expect: a &quot;darken&quot; div that we will use the dim the background, and a &quot;qnav&quot; (quick navigation) div that will contain our hotbox menu. The &quot;darken&quot; div is empty and initially set to not be visible. The &quot;qnav&quot; div is not visible either, and contains a simple text. Note that you can place any markup inside the hotbox div, depending on your needs. The above fragment of markup you should typically place outside the &quot;flow&quot; of your page layout divs. 
</p>
<p>
<b>Building the Hotbox demo - CSS</b>
</p>
<p>
The demo HTML file has a head section that refers to two external stylesheets: main.css and reset-min.css. The latter is a CSS reset stylesheet. It is not really needed for this demo, but a good practice in general web development. The main.css file contains all styles used in the demo. Most of them are not relevant, they are needed to style the layout of the demo page. Let's have a look at the relevant parts:
</p>
<div class="php" style="border: 1px solid #d0d0d0; font-family: monospace; color: #000066; background-color: #f0f0f0">
<ol>
	<li class="li1">
	<div class="de1">
	<span class="co2">#darken { &nbsp;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	position<span class="sy0">:</span>fixed<span class="sy0">;</span> &nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	top<span class="sy0">:</span><span class="nu0">0</span><span class="sy0">;</span> &nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	left<span class="sy0">:</span><span class="nu0">0</span><span class="sy0">;</span> &nbsp;
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	width<span class="sy0">:</span><span class="nu0">100</span><span class="sy0">%;</span> &nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	height<span class="sy0">:</span><span class="nu0">100</span><span class="sy0">%;</span> &nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	display<span class="sy0">:</span>none<span class="sy0">;</span> &nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	z<span class="sy0">-</span>index<span class="sy0">:</span><span class="nu0">199</span><span class="sy0">;</span> &nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	background<span class="sy0">:</span>black<span class="sy0">;</span> &nbsp;
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	opacity<span class="sy0">:</span><span class="nu19">.7</span><span class="sy0">;</span> &nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	filter<span class="sy0">:</span>alpha<span class="br0">(</span>opacity<span class="sy0">=</span><span class="nu0">70</span><span class="br0">)</span><span class="sy0">;</span> <span class="coMULTI">/* Transparency in IE */</span> &nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	<span class="br0">}</span> &nbsp;
	</div>
	</li>
</ol>
</div>
<p>
The darken div is supposed to dim the entire screen, except for the hotbox panel. From the CSS you can see that we are declaring a layer of 100% width and height. There are a few specific things thata require our attention here:
</p>
<ul>
	<li>Line 2. By default, setting a width and height to 100% means a 100% of the <b>visible screen</b>, not the page. This is clearly visible when we have a page that scrolls, the dim effect would stop dimming below the scrolling area. To overcome this, we need to set the position to &quot;fixed&quot;, not &quot;absolute&quot;.</li>
	<li>Line 8. The z-index value is important, since we want to overlay the current screen. This value needs to be higher than the z-index of all other screen elements, yet at least 1 lower than the hotbox's z-index.</li>
	<li>Line 9-11. These rules set the color and opacity of the dim effect, feel free to adjust these to your own needs.</li>
</ul>
<p>
That was fairly easy. Now on to the styles for the hotbox. I have eliminated some irrelevant styles for brevity:
</p>
<div class="php" style="border: 1px solid #d0d0d0; font-family: monospace; color: #000066; background-color: #f0f0f0">
<ol>
	<li class="li1">
	<div class="de1">
	<span class="co2">#qnav {</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	display<span class="sy0">:</span>none<span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	background<span class="sy0">:</span><span class="co2">#fff;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	position<span class="sy0">:</span> fixed<span class="sy0">;</span>
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	top<span class="sy0">:</span><span class="nu0">40</span><span class="sy0">%;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	left<span class="sy0">:</span> <span class="nu0">50</span><span class="sy0">%;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	margin<span class="sy0">-</span>left<span class="sy0">:</span> <span class="sy0">-</span>100px<span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	height<span class="sy0">:</span>200px<span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	width<span class="sy0">:</span>200px<span class="sy0">;</span>
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	z<span class="sy0">-</span>index<span class="sy0">:</span><span class="nu0">200</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	<span class="br0">}</span>
	</div>
	</li>
</ol>
</div>
<p>
The most important lines for the Hotbox rules:
</p>
<ul>
	<li>Line 2. Hide the Hotbox by default.</li>
	<li>Line 4. We are again using the position:fixed rule to prevent scrolling issues</li>
	<li>Lines 5-9. Positioning and sizing the Hotbox. The margin-left rule is half of the width, this will center it.</li>
	<li>Line 10: The z-index of the Hotbox, this value needs to be higher than everything else</li>
</ul>
<p>
That is all the styling we need. On to the jQuery!
</p>
<p>
<b>Building the Hotbox demo - jQuery</b>
</p>
<p>
The HTML of the demo page has a reference to two external js files: jquery.js, and main.js. The jQuery file is obviously jQuery itself, version 1.3.1. The main.js file contains our logic for the Hotbox:
</p>
<div class="php" style="border: 1px solid #d0d0d0; font-family: monospace; color: #000066; background-color: #f0f0f0">
<ol>
	<li class="li1">
	<div class="de1">
	<span class="kw2">function</span> isFormEvent<span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp;<span class="co1">// this function checks if the supplied event came from a form element</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp;es <span class="sy0">=</span> e<span class="sy0">.</span>target<span class="sy0">.</span>nodeName<span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp;<span class="kw1">return</span> <span class="br0">(</span>es <span class="sy0">==</span> <span class="st_h">'HTML'</span> <span class="sy0">||</span> es <span class="sy0">==</span> <span class="st_h">'BODY'</span> <span class="sy0">||</span> es <span class="sy0">==</span> <span class="st_h">'DIV'</span> <span class="sy0">||</span> es <span class="sy0">==</span> <span class="st_h">'A'</span> <span class="sy0">||</span> es <span class="sy0">==</span> <span class="st_h">'FIELDSET'</span> ? <span class="kw2">false</span><span class="sy0">:</span> <span class="kw2">true</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	<span class="br0">}</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	$<span class="br0">(</span>document<span class="br0">)</span><span class="sy0">.</span>ready<span class="br0">(</span><span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp;
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp;<span class="co1">// when the user presses and holds the space key outside a form, launch the quicknav panel</span>
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	&nbsp; &nbsp;$<span class="br0">(</span><span class="br0">)</span><span class="sy0">.</span>keydown<span class="br0">(</span><span class="kw2">function</span> <span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp;<span class="co1">// key pressed</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">(</span>e<span class="sy0">.</span>which <span class="sy0">==</span> <span class="nu0">32</span><span class="br0">)</span> <span class="br0">{</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp;<span class="co1">// space key pressed</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span>isFormEvent<span class="br0">(</span>e<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span>
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	&nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// space key pressed outside form (so not in an input element)</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// darken background and show the navigation panel.</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp;$<span class="br0">(</span><span class="st_h">'#darken'</span><span class="br0">)</span><span class="sy0">.</span>show<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp;$<span class="br0">(</span><span class="st_h">'#qnav'</span><span class="br0">)</span><span class="sy0">.</span>show<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// stop the default behavior (space is usually used as extra pagedown key)</span>
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	&nbsp; &nbsp; &nbsp; &nbsp;e<span class="sy0">.</span>preventDefault<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; <span class="br0">}</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; <span class="br0">}</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp;<span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp;
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	&nbsp; &nbsp;<span class="co1">// when the user releases the space key outside a form, hide the quicknav panel</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp;$<span class="br0">(</span><span class="br0">)</span><span class="sy0">.</span>keyup<span class="br0">(</span><span class="kw2">function</span> <span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp;<span class="co1">// key pressed</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">(</span>e<span class="sy0">.</span>which <span class="sy0">==</span> <span class="nu0">32</span><span class="br0">)</span> <span class="br0">{</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// space key pressed</span>
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span>isFormEvent<span class="br0">(</span>e<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// space key pressed outside form (so not in an input element)</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// lighten background and hide the navigation panel.</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp;$<span class="br0">(</span><span class="st_h">'#darken'</span><span class="br0">)</span><span class="sy0">.</span>hide<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp;$<span class="br0">(</span><span class="st_h">'#qnav'</span><span class="br0">)</span><span class="sy0">.</span>hide<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	&nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// stop the default behavior (space is usually used as extra pagedown key)</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;e<span class="sy0">.</span>preventDefault<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">}</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; &nbsp; <span class="br0">}</span>
	</div>
	</li>
	<li class="li1">
	<div class="de1">
	&nbsp; &nbsp; <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
	<li class="li2">
	<div class="de2">
	<span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span>
	</div>
	</li>
</ol>
</div>
<p>
Let's have a look at the most important lines:
</p>
<ul>
	<li>Lines 1-5. Here we are declaring a global function that checks where the received event came from. See, we do not want the launch the Hotbox when a user presses the spacebar inside an editable element, such as a text box. Unfortunately, IE (as always!) behaves much different in detecting the event source than other browsers do. Therefore we have to do this the ugly way.</li>
	<li>Line 7. Start of our runtime code.</li>
	<li>Line 10. Capture the keydown event (this is different from the keypressed event!)</li>
	<li>Line 12. Check if it was the spacebar.</li>
	<li>Line 14. Check if the spacebar key down did not come from a form</li>
	<li>Lines 17-18. Show the dimmer (darken div) and the Hotbox (qnav div)</li>
	<li>Line 20. Prevent the default behavior of the spacebar key (usually it is an alternative pagedown key) </li>
	<li>Lines 26-39. Here we are doing almost the same thing. This time we capture the keyup event, check if it is a space not coming from a form, and then hide the dim and Hotbox.</li>
</ul>
<p>
That's all! It's a good thing we did this from scratch, it is a very lightweight solution.
</p>
<p>
<b>Next steps</b>
</p>
<p>
Surely you should use this as a base and extend it, here are some ideas:
</p>
<ul>
	<li>Playing around with the dim color and opacity.</li>
	<li>Using animations for the launch and closure of the Hotbox. Personally I am against this, as it let's the user wait for nothing.</li>
	<li>Most importantly: filling the Hotbox with a useful menu that helps users!</li>
	<li>Even cooler: Inside the Hotbox, capture other key events, so that users can control the Hotbox using arrow keys.</li>
	<li>Way cool: Using irregular Hotbox shapes, such as a circle for a navigation menu. This can be accomplished using transparent PNG images.</li>
</ul>
<p>
<b>A word of warning</b>
</p>
<p>
Finally, I'd like to end this article with a word of warning. If you are to use the Hotbox in a real web application, be aware of the following:
</p>
<ul>
	<li>No user will be familiar with such a shortcut, therefore you need to explicitly tell them</li>
	<li>Do not use a Hotbox for primary navigation, because of the previous reason. A hotbox is a shortcut, it is not to replace regular navigation.</li>
	<li>The Hotbox breaks the convention of the spacebar being used as an alternative page down key. You can either accept this violation, or you can tie the Hotbox to another key.</li>
</ul>
<p>
The demo was tested to work with Firefox 3, IE7, Opera 9.63 and Safari 3.2.2, all on Windows Vista. 
</p>
<p>
Hotboxes. Somewhat strange on the web, yet possible a nice innovation? Please rate/comment below...
</p>
<p>
<script type="text/javascript">
<!--
google_ad_client = "pub-8337087074568897";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_bg = "FFFFFF";
google_color_link = "FF6600";
google_color_text = "000000";
google_color_url = "6699CC";
//--></script>
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script>
</p>
]]></description>
</item>, <item>
<title>A scientific approach to web design</title> 
<pubDate>Tue, 3 Feb 2009 07:51:04 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-7NVPKA</link>
<description><![CDATA[ <p>
<img src="http://imgs.xkcd.com/comics/science.jpg" /> 
</p>
<p>
<b>The following might be considered as stereotyping, yet I believe it to have a core of truth:</b> 
</p>
<p>
A lot of programmers are good with code, but struggle with the creative task that is web and UI design. Programmers tend to prefer structure, patterns and rules over artistic creativity. The mind of an analyst and engineer is much different from that of an artist. In practice this typically leads to one of two scenarios: 
</p>
<ul>
	<li>The design is outsourced to a professional web designer</li>
	<li>The programmer attempts to do the design himself</li>
</ul>
<p>
The latter scenario quite often leads to poorly designed web applications. In some cases, you can even see &quot;the bones sticking out&quot;, where the design and user interaction is closely tied to the technical implementation path, such as the database model. Still, we live in the real world. It is quite common to not have a professional designer at your disposal. And yes, a truly good design will always require <b>some</b> level of creativity and insight in UI design.<br />
<br />
Still, the world of web design is not only for the artistically talented. There are in fact quite a lot of programmer-like rules for web design. Rules that are structured, scientific, much like coding conventions. Rules that you as a programmer can apply universally, rules that make your design look good.In this article, I will point out a few of these rules. Welcome to the scientific approach of web design.<br />
<br />
<b>1. The golden ratio or divine proportion or phi<br />
</b>
</p>
<p>
Let us start with the best tip. The golden ratio, also called divine proportion or phi, is a magical number. It is a universal design constant that can be seen in the solar system, nature, architecture, anatomy, everywhere.&nbsp; 
</p>
<p>
What is it? It is a constant of proportion. You get the number by dividing the larger object's length by the smaller object's length (or width, height, etc). The value of phi is 1.618033988749895. This constant is omnipresent, it is everywhere. You are programmed to find things in proportion when things are designed on this constant. An example? The total length of your arm divided by the length of your upper arm. It will approach phi.&nbsp; 
</p>
<p>
We can use this magical number to design a web layout too. Imagine you have a clean sheet and need to design the column layout. How will you know how wide the columns need to be? You use Phi! 
</p>
<p>
An example. Let's use a page layout of 960 pixels width. This is currently the standard for web designers, but you can use another base number if you want. To determine the proper proportion of the columns, divide the base number with phi: 
</p>
<p>
<i><b>960 / 1.618 ~=&nbsp; 593</b></i> 
</p>
<p>
Your main column should be 593 pixels wide. Your sidebar should be 960 - 593 =<b>367</b> pixels wide. No user will notice that you used phi, yet the design will feel right. Need an additional column? Just do the same calculation, this time using the column width as the base number. You can apply this to other elements too. Want to show images in a frame with the caption below it inside the frame? You now know how to calculate how <b>high</b> the caption row should be. 
</p>
<p>
<b>2. Proportioning type using a baseline grid.</b> 
</p>
<p>
Ok, so we have used a scientific constant to proportion layout elements. Another typical design choice concerns fonts (&quot;type&quot; is a better word). There are a few creative considerations for selecting the font type, however did you know that there is a mathematical approach to selecting the proper font <b>size</b>? 
</p>
<p>
The approach is as follow. We want to layout our text on the page on a fictional set of rows of equal height. Have a look at this <a href="http://www.alistapart.com/d/settingtypeontheweb/example_grid.html" target="_blank">example page</a> to see what I mean. The lines are of course markers for the example. Without the lines, nobody will notice the grid, yet the text in both columns feel &quot;right&quot;, as they have the correct alignment. The key to applying this technique is to add vertical space (such as line-height, margin and padding) based on a base number that you set for the page. If that base number is for example 15 pixels, you can add a bottom margin of 15, 30, 45, but not 12, 32 or any number that is not based on the base number.&nbsp; 
</p>
<p>
For a full explanation of this technique, please check out the excellent <a href="http://www.alistapart.com/http://www.ferdychristant.com/blog/articles/settingtypeontheweb">A List Apart article</a>. 
</p>
<p>
<b>3. Grid-based web design</b> 
</p>
<p>
Again grids. Grid systems are becoming increasingly popular in web design. Although not exactly scientific, it does have a mathematical element to it. In essence, these grids divide your page into a set of columns (typically 12 or 16). There is also spacing between these columns, called &quot;gutters&quot;. When combined with tip #1 in this article, you can very quickly layout a web page with correct proportions and proper white space. 
</p>
<p>
One of the most popular grid systems is&nbsp; <a href="http://960.gs/">960</a>, I encourage you to check out their website to learn more. 
</p>
<p>
<b>More rules</b> 
</p>
<p>
Ok, so we now have covered three mathematical methods to apply to web design. They're structured, easy, and universal. Just the way we programmers like it. Three is not much though, is it? Definitely not enough to finish a complete design. Luckily, there is a wealth of other rules of structure. They may not be based on hard science. They are based on convention. Here's an example: 
</p>
<p>
<i><b>Use a sans-serif type for body text, and a large serif type for headings.</b></i> 
</p>
<p>
If you don't know what this means: serif types are those fonts with curly endings. They are great for headings, but not very readible for small body text on a computer screen. A rule like this is well known by most designers. Still, there is no artistic element to it, it's just a rule you need to know about. There is no reason why you as a programmer cannot know about this rule and apply it.&nbsp; 
</p>
<p>
How will you know about all these &quot;hidden&quot; rules? There are a few things I can recommend specifically: 
</p>
<ul>
	<li>Dive into the community. Take any subject, and you will find a subculture somewhere on the internet. If you want to know about fonts, icons, color schemes or anything else: find the experts, they most likely have a blog.</li>
	<li>Reverse engineer designs that you love. If you find a great web design, simply analyse their CSS file. Do not copy...learn!</li>
	<li>Read the <a href="http://www.amazon.com/Prioritizing-Usability-VOICES-Jakob-Nielsen/dp/0321350316">&quot;Prioritizing web usability&quot;</a> book by Jakob Nielsen, the leading usability expert. This gem contains hundreds of design conventions that you can apply to your design right away.</li>
	<li>Subscribe yourself to the best online web design magazines, here's a few: 
	<ul>
		<li><a href="http://www.smashingmagazine.com/">Smashing Magazine</a></li>
		<li><a href="http://www.smashingapps.com/">Smashing Apps</a></li>
		<li><a href="http://sixrevisions.com/">Six Revisions</a></li>
		<li><a href="http://www.webdesignerdepot.com/">Web Designer Depot</a></li>
		<li><a href="http://webdesignledger.com/">Web Design Ledger</a></li>
		<li><a href="http://www.webdesignerwall.com/">Web Designer Wall</a></li>
		<li><a href="http://nettuts.com/">NetTuts</a></li>
	</ul>
	</li>
</ul>
<p>
That should leave you plenty to chew on. If you make it a frequent habit to invest small fragments of time into the above resources, you will soon know about the most important design rules and conventions.
</p>
<p>
<b>Conclusion</b> 
</p>
<p>
I hope I have convinced you that web and UI design is not for artists or pros only. There is a wealth of rules that are easy to apply (some mathematical, some by convention) that guide you in creating pleasant designs. None of these rules require an artist's eye. Sure, there will always be the need for true artistic talent (illustrations, color schemes, logo design, character design), but there is much that we can do ourselves. 
</p>
<p>
Please take the time to rate/comment on this article! 
</p>
<p>
<script type="text/javascript">
<!--
google_ad_client = "pub-8337087074568897";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_bg = "FFFFFF";
google_color_link = "FF6600";
google_color_text = "000000";
google_color_url = "6699CC";
//--></script>
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script>
</p>
]]></description>
</item>, <item>
<title>The ultimate guide to the Amazon S3 service</title> 
<pubDate>Mon, 5 Jan 2009 12:43:38 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-7MZGXA</link>
<description><![CDATA[ <p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/phps3_01.gif" />
</p>
<p>
In this article, I will explain how you can integrate the <a href="http://aws.amazon.com/s3/">Amazon S3 service</a> into your (PHP) application. Only a small part of this article is about actual code, so you should be able to use the instructions for any platform. We&rsquo;ll be touching on various topics, including the basic setup, URL routing, scripted file uploads, ways to lower your and control your Amazon bill and much more. I recommend you to read the <b>full</b> article to really get the most out of S3.
</p>
<p>
Since this article is rather long (13 pages) and contains some wide code listings that are not easy to publish on this blog, I have made it available as a downloadable PDF:
</p>
<p>
<a href="http://www.s3maphor3.org/download.php?get=The_ultimate_PHP_guide-to_the_Amazon_S3_service.pdf">Download the ultimate guide to the Amazon S3 service (PDF, 336KB)</a>
</p>
<p>
I would appreciate if you use the comments and ratings panel below to provide feedback! 
</p>
<p>
<script type="text/javascript">
<!--
google_ad_client = "pub-8337087074568897";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_bg = "FFFFFF";
google_color_link = "FF6600";
google_color_text = "000000";
google_color_url = "6699CC";
//--></script>
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script>
</p>
]]></description>
</item>, <item>
<title>Creating your own grunge papers</title> 
<pubDate>Thu, 11 Dec 2008 03:47:31 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-7M8LJ8</link>
<description><![CDATA[ <p>
If you have been paying attention to the web design field, you may have noticed the latest rage: Grunge Designs. It seems like the days of shiny, polished, perfects shapes with reflections and bright colours are counted. Instead, Grunge is taking over. Grunge is about realism, organic shapes and distorted patterns, sometimes beautiful, sometimes aged and ugly. I think a good analogy to explain Grunge is the way jeans are marketed. The spotless, clean jeans cost 50$. The damaged, bleached, torn jeans cost 150$. If you still don't know what I mean with this web trend, just <a href="http://www.smashingmagazine.com/2008/01/29/grunge-style-in-modern-web-design/">check out a few Grunge examples</a>. 
</p>
<p>
Anyway, in this short article I want to explain how to create one of these: 
</p>
<p>
<img src="http://www.ferdychristant.com/blog/resources/Fun/$FILE/grunge_paper01.jpg" width="305" border="0" height="444" /> 
</p>
<p>
It is supposed to represent a very old piece of paper, yet it started out as a sheet of plain white printer paper, A4 size. Whilst you may not need&nbsp;an image of an artificially aged piece of paper every day, the technique I will tell you about can be used to create pretty much any grunge image from scratch, whether it is metal, wood, rock or paper. Next, you can use them as backgrounds for anything you desire. 
</p>
<p>
<b>The process</b> 
</p>
<p>
There are multiple ways to create grunge images. One would be to steal a texture from the web and then digitally process it. Another one would be to start from scratch in Photoshop and then unleashing some digital filter randomness until you get a somewhat realistic result. That's all good and well, but if you want the best results, be completely original (no stealing) and have fun in the process, we'll start the analog way: 
</p>
<ul>
	<li>Take a piece of plain white printer paper</li>
	<li>(optional: draw some random pencil lines on it and then wipe the lines with your fingers to create dirty stains)</li>
	<li>Crack the paper in your fist, and then straighten it out again</li>
	<li>Pour some cold coffee in an oven&nbsp;scale and place the paper in it. Make sure both sides are soaked, yet make sure the paper is still strong enough to not fall apart</li>
	<li>Put the paper on a heater for about 10 minutes. If you have a radiator, and you do not want the grill lines to be shown on the paper, put something in between the paper and radiator</li>
	<li>When the paper is dry, light a candle. Next, randomly &quot;burn&quot; the image&nbsp;by holding it above the candle, be sure to vary your movement, speed and&nbsp;distance to the candle, to create a truly organic effect.</li>
	<li>Scan the paper in a high setting (at least 600DPI)</li>
</ul>
<p>
Inhabitants of your house may think you have lost your mind, but hey, artists are never really understood, are they? At this point, you should have a scan of a fairly aged/damaged piece of paper. Most likely, it is still a bit too light and clean to be considered old. Therefore, the next thing to do is to apply some digital processing. Make sure to do the processing on a copy of the scan, as the scan itself can be used as a base for many images. 
</p>
<p>
So, what are the steps for digital processing? There arent's many rules here, and it also depends on your input. Here's my approach: 
</p>
<ul>
	<li>Open the image in Adobe Lightroom. It has many sliders that show you results in real-time. Of particular interest are contrast (should be low), saturation, temp, and tint (should all be slightly increased), blacks (should be somewhat increased) and lens vignette, which marks the corners of the image as darker areas.</li>
	<li>Next, I open up the image in Photoshop. Here I played around with the levels, color balance and brightness. Next, I used the clone stamp and heal tools to fix areas that don't look right. </li>
	<li>Then I create one (or more) additional layer that will contain some kind of organic image data (for example Photoshop's render cloud) and then blend it back into the main image. When you look closely at the bottom of my example image, it shows some relief. This is due to the mixing of the 2nd layer.</li>
	<li>Finally I use the gradient tool (with a start color of light grey and as end color no color) and then draw random lines on the background layer. This results in the illusion of variation in lighting across the image.</li>
</ul>
<p>
As you can see, there are not a lot of rules. As long as the result looks natural, worn, organic, GRUNGE...all is&nbsp;good.&nbsp; 
</p>
<p>
<b>Note:</b>&nbsp;Once you have your grunge background, be careful how you use&nbsp;the foreground. It should not look too sharp or modern, otherwise the effect is lost, it will look like the foreground is completely seperated from the background. Instead, you will want to blend them. 
</p>
<p>
It is time to hand out the goodies! I have prepared 5 grunge papers that you can view <a href="http://fchristant.deviantart.com/gallery/">here</a>. If you open up a single image and then click the download link, you can download them in their original resolution, with insane detail (4600 x 7000px) 
</p>
<p>
<script type="text/javascript">
<!--
google_ad_client = "pub-8337087074568897";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_bg = "FFFFFF";
google_color_link = "FF6600";
google_color_text = "000000";
google_color_url = "6699CC";
//--></script>
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script>
</p>
]]></description>
</item>, <item>
<title>Building your own Captcha</title> 
<pubDate>Sun, 7 Dec 2008 03:09:32 +0100</pubDate>
<link>http://www.ferdychristant.com/fchristant/production/fdm.nsf/archive/DOMM-7M4KSG</link>
<description><![CDATA[ <p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/jd_captcha01.gif" />
</p>
<p>
A common sight on web forms nowadays is the <a href="http://en.wikipedia.org/wiki/Captcha">Captcha</a> check, a way to determine whether your are a human or bot user. Here is an example of a Captcha check, as taken from Digg.com:
</p>
<p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/jd_captcha02.gif" width="231" height="116" /> 
</p>
<p>
Surely no user is having fun filling these out, right? Yet, it seems to be a neccessary evil in our fight against spammers. With the lack of a better alternative, we <b>should</b> use Captchas. However, who is to say that we should present a Captcha as the example above? As a hurdle for the user?
</p>
<p>
In this article we will get creative in building our own Captcha. But, why would we do such a thing?
</p>
<ul>
	<li>Because a custom Captcha can fit exactly into the design and theme of your site. It will not look like some alient element that does not belong there.</li>
	<li>We want to take away the perception of a Captcha as an annoyance, and make it fun for the user.</li>
	<li>Because a custom Captcha, unlike the major Captcha mechanisms, obscure you as a target for spammers. Spammers have little interest in cracking a niche Captcha.</li>
	<li>Because we want to learn how they work, so it is best to build one ourselves.</li>
</ul>
<p>
Note that this article is a supplemental article to my previous one: <a href="http://www.ferdychristant.com/blog/articles/DOMM-7LZJN7">Advanced jQuery form validation</a>. Both articles combined enable for some quite robust web forms. While we're at it, you may also want to have a look at my <a href="http://www.ferdychristant.com/blog/articles/DOMM-7LDBXK">Building Unicode LAMP applications</a> article.<br />
<br />
With that out of the way, let's get started. First, we'll have a look at how Captcha's work.
</p>
<p>
<b>Captcha Logic</b>
</p>
<p>
I've dived into quite a number of open source Captcha scripts to see how they work. Luckily, the patterns used are quite simple, and easy to understand. Here are the steps:
</p>
<ol>
	<li>The Captcha image (or question) is generated. There are different ways to do this. The classic approach is to generate some random text, apply some random effects to it and convert it into an image.</li>
	<li>Step 2 is not really sequential. During step 1, the original text (pre-altered) is persisted somewhere, as this is the correct answer to the question. There are different ways to persist the answer, as a server-side session variable, cookie, file, or database entry.</li>
	<li>The generated Captcha is presented to the user, who is prompted to answer it. </li>
	<li>The back-end script checks the answer supplied by the user by comparing it with the persisted (correct) answer. If the value is empty or incorrect, we go back to step 1: <b>a new Captcha is generated</b>. Users should not never get a second shot at answering the same Captcha.</li>
	<li>If the answer supplied by the user is correct, the form post is successful and processing can continue. If applicable, the generated Captcha image is deleted.</li>
</ol>
<p>
<b>Note:</b> Some Captcha mechanisms have extra features to increase the accessibility of the check, for example a way to play the Captcha as a sound. For this article, we will stick to the basic approach.
</p>
<p>
<b>Introducing the JungleDragon Captcha check</b>
</p>
<p>
Throughout the remainder of this article, I will use the JungleDragon Captcha as an example for building a custom Captcha. JungleDragon is a wildlife image sharing site. A first step in designing a custom Captcha is to think about your user base in order to find a way to blend a Captcha check into the user experience. For JungleDragon, it has resulted in this:
</p>
<p>
<img src="http://www.ferdychristant.com/blog/resources/Article/$FILE/jd_captcha03.gif" />
</p>
<p>
Users are presented an image of an animal and then have to guess what it is. When they fail, a new random image is pulled up, as well as a fresh set of answers, their order and options shifted each time.I'm not saying users will have the time of their lives filling out this check. However, it does fit into the theme of the site much better, and it is quite userfriendly, don't you think?
</p>
<p>
<b>How it works</b>
</p>
<p>
Part of me does not want to disclose how it work, really. It may inspire the wrong kind of people. Ah well, it's just a learning exercise, so let us continue...
</p>
<p>
This particular Captcha works by randomly selecting an image. To start with, I collected a number of animal images and cropped them all to the same size. The more images, the better. Next, I placed these into a Captcha image directory. Finally, I sequentially numbered the files. That was easy. On to the coding.
</p>
<p>
I implemented my Captcha back-end into a PHP class, so I will use that throughout the rest of the article. The logic can apply to any platform though. First, we need to have a way to map the images to the answers, otherwise there is no way for us to know which animal is on which image. Inside my Captcha class, I capture these relations into an associative array (as a class property):
</p>
<p>
<i><b>&nbsp;var $images = array(<br />
&nbsp;&nbsp; &nbsp;1=&gt;&quot;parrot&quot;,<br />
&nbsp;&nbsp; &nbsp;2=&gt;&quot;panda&quot;,<br />
&nbsp;&nbsp; &nbsp;3=&gt;&quot;lion&quot;,<br />
&nbsp;&nbsp; &nbsp;4=&gt;&quot;snake&quot;,<br />
&nbsp;&nbsp; &nbsp;5=&gt;&quot;gorilla&quot;,<br />
&nbsp;&nbsp; &nbsp;6=&gt;&quot;turtle&quot;,<br />
&nbsp;&nbsp; &nbsp;7=&gt;&quot;elephant&quot;,<br />
&nbsp;&nbsp; &nbsp;8=&gt;&quot;pinguin&quot;,<br />
&nbsp;&nbsp; &nbsp;9=&gt;&quot;alligator&quot;,<br />
&nbsp;&nbsp; &nbsp;10=&gt;&quot;octopus&quot;<br />
&nbsp;&nbsp; &nbsp;);</b></i>
</p>
<p>
As stated before, the more images you have, the better. For now, let's stick to 10. At the heart of the class is the method that generates the Captcha, here it is:
</p>
<p>
<!-- code formatted by http://manoli.net/csharpformat/ -->
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
</p>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">   1:  </span>function generate_captcha($num_answers)
</pre>
<pre>
<span class="lnum">   2:  </span>{
</pre>
<pre class="alt">
<span class="lnum">   3:  </span>  <span class="rem">// get random image</span>
</pre>
<pre>
<span class="lnum">   4:  </span>  $image_num = rand(1,<span class="kwrd">sizeof</span>($<span class="kwrd">this</span>-&gt;images));
</pre>
<pre class="alt">
<span class="lnum">   5:  </span>  $image_name = $<span class="kwrd">this</span>-&gt;images[$image_num];
</pre>
<pre>
<span class="lnum">   6:  </span>        
</pre>
<pre class="alt">
<span class="lnum">   7:  </span>  <span class="rem">// set the correct answer in the session</span>
</pre>
<pre>
<span class="lnum">   8:  </span>  $<span class="kwrd">this</span>-&gt;CI-&gt;session-&gt;set_userdata(<span class="str">'captcha'</span>, $image_name);
</pre>
<pre class="alt">
<span class="lnum">   9:  </span>        
</pre>
<pre>
<span class="lnum">  10:  </span>  <span class="rem">// build up list of possible answers</span>
</pre>
<pre class="alt">
<span class="lnum">  11:  </span>  <span class="rem">// we'll start by including the correct answer</span>
</pre>
<pre>
<span class="lnum">  12:  </span>  $answers = array();
</pre>
<pre class="alt">
<span class="lnum">  13:  </span>  $answers[] = $image_name;
</pre>
<pre>
<span class="lnum">  14:  </span>        
</pre>
<pre class="alt">
<span class="lnum">  15:  </span>  <span class="rem">// next, we need to find num_answers - 1 additional options</span>
</pre>
<pre>
<span class="lnum">  16:  </span>  $count = 0;
</pre>
<pre class="alt">
<span class="lnum">  17:  </span>  <span class="kwrd">while</span> ($count &lt; ($num_answers-1)) {
</pre>
<pre>
<span class="lnum">  18:  </span>    $currentanswer = rand(1,<span class="kwrd">sizeof</span>($<span class="kwrd">this</span>-&gt;images));
</pre>
<pre class="alt">
<span class="lnum">  19:  </span>    <span class="kwrd">if</span> (!in_array($<span class="kwrd">this</span>-&gt;images[$currentanswer],$answers)) {
</pre>
<pre>
<span class="lnum">  20:  </span>      $answers[] = $<span class="kwrd">this</span>-&gt;images[$currentanswer];
</pre>
<pre class="alt">
<span class="lnum">  21:  </span>      $count++;
</pre>
<pre>
<span class="lnum">  22:  </span>    }
</pre>
<pre class="alt">
<span class="lnum">  23:  </span>  }
</pre>
<pre>
<span class="lnum">  24:  </span>        
</pre>
<pre class="alt">
<span class="lnum">  25:  </span>  <span class="rem">// shuffle the array so that the first answer is not</span>
</pre>
<pre>
<span class="lnum">  26:  </span>  <span class="rem">// always the right answer</span>
</pre>
<pre class="alt">
<span class="lnum">  27:  </span>   shuffle($answers);
</pre>
<pre>
<span class="lnum">  28:  </span>        
</pre>
<pre class="alt">
<span class="lnum">  29:  </span>  <span class="rem">// build data array and return it</span>
</pre>
<pre>
<span class="lnum">  30:  </span>  $data = array(
</pre>
<pre class="alt">
<span class="lnum">  31:  </span>    <span class="str">&quot;image_num&quot;</span> =&gt; $image_num,
</pre>
<pre>
<span class="lnum">  32:  </span>    <span class="str">&quot;image_name&quot;</span> =&gt; $image_name,
</pre>
<pre class="alt">
<span class="lnum">  33:  </span>    <span class="str">&quot;answers&quot;</span> =&gt; $answers
</pre>
<pre>
<span class="lnum">  34:  </span>  );
</pre>
<pre class="alt">
<span class="lnum">  35:  </span>        
</pre>
<pre>
<span class="lnum">  36:  </span>  <span class="kwrd">return</span> $data;
</pre>
<pre class="alt">
<span class="lnum">  37:  </span>}
</pre>
</div>
<p>
Now, let us walk through the relevant lines of code from this method:
</p>
<p>
1. The method signature. Note how we can pass in $num_answer, to indicate how many possible answers are showed for each image.
</p>
<hr size="2" width="100%" />
<p>
4. randomly select an image number based on the options in the associative array discussed earlier.
</p>
<hr size="2" width="100%" />
<p>
5. get the name that corresponds with the randomly selected image number from line 4. 
</p>
<hr size="2" width="100%" />
8. This is an important step. Here we are persisting the correct answer (image name) of the currently generated Captcha. We need to persist this securely. In my case, I'm using encrypted cookies, but you can also use server-side session variables, a file, or a database. <br />
<hr size="2" width="100%" />
12. With the image selected and the correct answer persisted, we now need to generate a set of possible answers. We'll store them in the $answers array.<br />
<hr size="2" width="100%" />
13. Are set of options always has to contain the correct answer, so we'll include that in the array
<hr size="2" width="100%" />
16-23. Next, we will generate the additional answers, which are all wrong. We'll keep looping until we have found the number of <b>unique </b>answers requested by $num_answers minus 1, since we already included one answer: the correct one.
<hr size="2" width="100%" />
27. We do not want the correct answer to be at the same position in the answer list, therefore we shuffle the answer list.
<hr size="2" width="100%" />
30-36. Here we are building up an array of values that the calling code needs to work with the Captcha, and then return it.
<hr size="2" width="100%" />
While we're still in this class, let's finish it. There is only one additional method: check_captcha. This method checks if the answer that is passed to it corresponds to the persisted answer:
<p>
<!-- code formatted by http://manoli.net/csharpformat/ -->
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
</p>
<div class="csharpcode">
<pre class="alt">
function check_captcha($answer) 
</pre>
<pre>
{
</pre>
<pre class="alt">
  <span class="rem">// check if captcha is correc</span>
</pre>
<pre>
  <span class="kwrd">return</span> ($<span class="kwrd">this</span>-&gt;CI-&gt;session-&gt;userdata(<span class="str">'captcha'</span>) === $answer) ? <span class="kwrd">true</span> : <span class="kwrd">false</span>;
</pre>
<pre class="alt">
}
</pre>
</div>
<p>
That's it. We can now start using this class. From our script that renders our front-end pages, we call:
</p>
<p>
<!-- code formatted by http://manoli.net/csharpformat/ -->
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
</p>
<div class="csharpcode">
<pre class="alt">
<span class="rem">// generate a new captcha</span>
</pre>
<pre>
$<span class="kwrd">this</span>-&gt;load-&gt;library(<span class="str">'captcha'</span>);
</pre>
<pre class="alt">
$captchadata = $<span class="kwrd">this</span>-&gt;captcha-&gt;generate_captcha(5);
</pre>
</div>
<p>
Note that this syntax of class loading and calling the method is specific for the CodeIgniter PHP framework. You can use the classic PHP syntax if you do not use this framework. 
</p>
<p>
With $captchadata in our pocket, we can then assign it to our presentation layer, which will render it:
</p>
<p>
<!-- code formatted by http://manoli.net/csharpformat/ -->
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
</p>
<div class="csharpcode">
<pre class="alt">
&lt;?
</pre>
<pre>
<span class="kwrd">foreach</span> ($answers <span class="kwrd">as</span> $answer) 
</pre>
<pre class="alt">
echo <span class="str">&quot;&lt;input type=\&quot;radio\&quot; name=\&quot;captcha_answer\&quot;</span>
</pre>
<pre>
 id=\&quot;$answer\&quot; value=\&quot;$answer\&quot; /&gt;\n
</pre>
<pre class="alt">
&lt;label for=\&quot;$answer\&quot;&gt;$answer&lt;/label&gt;&lt;br/&gt;\n&quot;;
</pre>
<pre>
?&gt;
</pre>
</div>
<p>
Finally, in our postback code, we will call the check_captcha to see if the user has entered the correct answer based on the field value of captcha_answer. It depends on the validation library you use how to call it, just make sure that a new Captcha is generated if the answer was empty or incorrect!
</p>
<p>
<b>Note:</b> We have ignored validation messages in this article. We will want to tell the user when he fails to answer the correct question. My previous article, <a href="http://www.ferdychristant.com/blog/articles/DOMM-7LZJN7">Advanced jQuery form validation</a>, explains how to do this effectively. 
</p>
<p>
<b>Spot the flaw!</b>
</p>
<p>
This concludes the explanation of the JungleDragon Captcha mechanism. Careful readers and security paranoids may have spotted two flaws:
</p>
<ul>
	<li>We are persisting the correct answer in a cookie. Although it is encrypted, a server-side approach is considered more secure.</li>
	<li>We are not transforming our images. Although randomly selected, each individual image looks the same each time. This allows spammers to apply a unique hash to each image and then check the captcha image with their list of hashes. </li>
</ul>
<p>
Both are good points, and I invite everyone to harden their custom Captcha mechanism. A third way to make it harder for Captcha abuse is to check the HTTP REFERER. A fourth one is to add or change the images regularly.
</p>
<p>
I do want to make a statement about the above flaws: they're not as bad as they seem. Beating spammers is not a hard science, you need to have multiple layers of defense. What you see above is in fact the most successful strategy against spammers: <b>obscurity</b>. Simply because we have a <b>CUSTOM</b> Captcha, makes us less of a target. Spammers go for mass targets, as their success rate is typically extremely low. Even if we would have a single animal image with just two answers, and the answers would be in the same order each time, we would drastically reduce spam submissions. 
</p>
<p>
An example of this effect is the site <a href="http://www.codinghorror.com/blog/">Coding Horror</a>, it has a custom Captcha check that simply lets you enter the word &quot;Orange&quot; to post a comment. Orange. Each time. Nothing is random, and there is only one answer. Still, it has drastically reduced the spam on that blog, and it's a big blog. Obscurity works. Not for security, but against spammers.
</p>
<p>
<b>Conclusion</b> 
</p>
<p>
With the security stuff out of the way, back to our original goal: providing a custom Captcha check for your users that is fun, and fits the design and theme of your web application. With a bit of creativity and the help of this article, it's easy! 
</p>
<p>
<script type="text/javascript">
<!--
google_ad_client = "pub-8337087074568897";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_bg = "FFFFFF";
google_color_link = "FF6600";
google_color_text = "000000";
google_color_url = "6699CC";
//--></script>
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script>
</p>
]]></description>
</item>
</channel>
</rss>
