<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Open Source Web Thoughts</title>
	<atom:link href="http://blog.dewaldbotha.co.za/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.dewaldbotha.co.za</link>
	<description></description>
	<lastBuildDate>Fri, 25 Nov 2011 09:17:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>MySQL data dumps done right.</title>
		<link>http://blog.dewaldbotha.co.za/2009/04/08/mysql-data-dumps-done-right/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/04/08/mysql-data-dumps-done-right/#comments</comments>
		<pubDate>Wed, 08 Apr 2009 11:17:19 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[data only]]></category>
		<category><![CDATA[mysqldump]]></category>
		<category><![CDATA[procedures]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[triggers]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-04-08/mysql-data-dumps-done-right/</guid>
		<description><![CDATA[To dump data in MySQL command line is one of the easiest things to do.  All you have to do is follow these 3 easy steps in your linux command line: 1.  Dump the schema only.  This will  not contain any data, procedures or triggers, but only create info.  This will allow you to easily <a href="http://blog.dewaldbotha.co.za/2009/04/08/mysql-data-dumps-done-right/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>To dump data in MySQL command line is one of the easiest things to do.  All you have to do is follow these 3 easy steps in your linux command line:</p>
<p>1.  <strong>Dump the schema only</strong>.  This will  not contain any data, procedures or triggers, but only create info.  This will allow you to easily import your original schema later on.</p>
<pre lang="php">
mysqldump -uroot -proot -d --skip-triggers myDatabase > myDatabase_schema.sql</pre>
<p>The -u specifies your username, and must be followed by your username e.g. -uroot.  This is the same with your password, -proot.</p>
<p>The -d tells mysqldump to not dump any data in the schema and the &#8211;skip-triggers will skip all triggers and procedures.</p>
<p>The myDabase is the name of your database and the > myDatabase_schema.sql is where you want to dump it.</p>
<p>2.  <strong>Dump the triggers/procedures</strong>.  This will only contain the triggers and procedures contained within your database.</p>
<pre lang="php">
mysqldump -uroot -proot -d --no-create-info myDatabase > myDatabase_triggers_procs.sql</pre>
<p>Here we have a &#8211;no-create-info to tell mysqldump that no create statements must be allowed, thus eliminating any schema sql and again the -d parameter to skip all data.</p>
<p>3. <strong> Dump the data only</strong> without triggers and create statements.</p>
<pre lang="php">
mysqldump -uroot -proot --skip-triggers --no-create-info myDatabase > myDatabase_base_data.sql</pre>
<p>Finally we can dump the data only.  The &#8211;skip-triggers skips all triggers and procedures, whils the &#8211;no-create-info skips sql create statements.</p>
<p><strong>This will allow you to have 3 different sql files:</strong></p>
<ul>
<li>myDatabase_schema.sql (only contains the schema)</li>
<li>myDatabase_triggers_procs.sql (only contains triggers/procs)</li>
<li>myDatabase_base_data.sql (only contains data)</li>
</ul>
<h3>Now to import.</h3>
<p>This is fairly trivial.</p>
<p>All you have to remember is to <strong>import your data in a sequence</strong>.</p>
<p>First the schema, then the triggers and procedures and then finally the base data.  The schema will create your tables, the triggers and procs can then be added to your tables and finally the tables can be populated with data.</p>
<p><strong>1.  Import schema</strong></p>
<pre lang="php">
mysql -uroot -proot myDatabase < myDatabase_schema.sql</pre>
<p><strong>2.  Import triggers/procs</strong></p>
<pre lang="php">
mysql -uroot -proot myDatabase < myDatabase_triggers.sql</pre>
<p><strong>3.  Import base data</strong></p>
<pre lang="php">
mysql -uroot -proot myDatabase < myDatabase_base_data.sql</pre>
<p>And your done. <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/04/08/mysql-data-dumps-done-right/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Test drive your PHP code</title>
		<link>http://blog.dewaldbotha.co.za/2009/03/30/test-drive-your-php-code/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/03/30/test-drive-your-php-code/#comments</comments>
		<pubDate>Mon, 30 Mar 2009 14:53:14 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[agile]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[test driven development]]></category>
		<category><![CDATA[unit testing]]></category>
		<category><![CDATA[martin fowler]]></category>
		<category><![CDATA[phpunit]]></category>
		<category><![CDATA[uml]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-03-30/test-drive-your-php-code/</guid>
		<description><![CDATA[Lately I&#8217;ve ventured fully submerged into the world of Test driven development (TDD). This might start out a bit scary, especially if you have only heard about it, but never done it yourself. There is a couple of good reads on the net, so you might want to start out by familiarising yourself with this <a href="http://blog.dewaldbotha.co.za/2009/03/30/test-drive-your-php-code/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>Lately I&#8217;ve ventured fully submerged into the world of <a href="http://en.wikipedia.org/wiki/Test-driven_development" title="Test Driven Development">Test driven development (TDD)</a>.</p>
<p>This might start out a bit scary, especially if you have only heard about it, but never done  it yourself.  There is a couple of good reads on the net, so you might want to start out by familiarising yourself with this exciting way of doing things.</p>
<p>Have a look at <a href="http://en.wikipedia.org/wiki/Test-driven_development" title="Test Driven Development" target="_blank">http://en.wikipedia.org/wiki/Test-driven_development</a> or <a href="http://lmgtfy.com/?q=test+driven+development" title="Test Driven Development" target="_blank">Google it</a>.</p>
<h3>What is test driven development?</h3>
<p><a href="http://en.wikipedia.org/wiki/Test-driven_development" title="Test Driven Development">Test driven development (TDD)</a> is more a change in coding philosophy than anything else.   Some of us might say: &#8220;&#8230;yip, I&#8217;ve written a couple of unit tests when I had some spare time at the end of my project.&#8221;</p>
<p>To be honest, this is a bit of the wrong way round method of doing things, kind of like building a house by putting on the roof first.   I think <a href="http://martinfowler.com/" title="Martin Fowler" target="_blank">Martin Fowler</a> describes it best when he pointed out these three components.</p>
<ul>
<li>Write a test for the next bit of functionality you want to add.</li>
<li>Write the functional code until the test passes.</li>
<li>Refactor both new and old code to make it well structured.</li>
</ul>
<p><a href="http://en.wikipedia.org/wiki/Test-driven_development" title="Test Driven Development" target="_blank">TDD</a> is a branch of <a href="http://en.wikipedia.org/wiki/Agile_software_development" title="Agile Development" target="_blank">Agile development</a> which was based upon the first stages of <a href="http://en.wikipedia.org/wiki/Extreme_programming" title="Extreme Programming" target="_blank">extreme programming</a>, but has really become a coding methodology that changed the way in which a lot of projects are being done.<br />
<span id="more-17"></span></p>
<h3>What do I need to get started?</h3>
<h4>UML</h4>
<p>It is always good to have a basic <a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language" target="_blank">Unified Modeling Language (UML)</a> diagram of how you would like your objects/classes to work and behave, but believe me, after you analyzed it through testing, you would do a fair amount of refactoring.</p>
<p>Here we have some pretty <a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language" target="_blank">UML</a> for a very basic Message object which must create and delete messages.  The Message implements a Message_Store object for message storage.</p>
<p><img src="http://farm4.static.flickr.com/3451/3397964953_6165f47f15.jpg" alt="Message UML" /></p>
<h4>PHPUnit</h4>
<p>Now before you even attempt to write a line of code &#8211; go to <a href="http://www.phpunit.de/" title="PHPUnit" target="_blank">http://www.phpunit.de/</a>.</p>
<p>This will become your friend in days/months/years to come and you will learn to love it.  <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><strong>Background:</strong></p>
<p><a href="http://www.phpunit.de/" title="PHPUnit" target="_blank">PHPUnit</a> was created by a German fellow called <a href="http://sebastian-bergmann.de/" title="Sebastian Bergmann" target="_blank">Sebastian Bergmann</a> and has grown into a full fledge PHP testing framework.  It was based upon <a href="http://en.wikipedia.org/wiki/SUnit" title="SUnit" target="_blank">SUnit</a>, which was developed by the father of <a href="http://en.wikipedia.org/wiki/Extreme_programming" title="Extreme Programming" target="_blank">extreme programming</a>, <a href="http://en.wikipedia.org/wiki/Kent_Beck" title="Kent Beck" target="_blank">Kent Beck</a>,  to accommodate testing in <a href="http://en.wikipedia.org/wiki/Smalltalk" title="Smalltalk" target="_blank">Smalltalk</a>.</p>
<p><strong>Installing:</strong></p>
<p>The easiest way to install <a href="http://www.phpunit.de/" title="PHPUnit" target="_blank">PHPUnit</a> would be via your <a href="http://pear.php.net/" title="Pear" target="_blank">PEAR</a> Installer.</p>
<p>First you must register <a href="http://www.phpunit.de/" title="PHPUnit" target="_blank">PHPUnit</a> <a href="http://pear.php.net/" title="Pear" target="_blank">PEAR</a> channel with your local <a href="http://pear.php.net/" title="Pear" target="_blank">PEAR</a> environment.</p>
<pre lang="php">
pear channel-discover pear.phpunit.de</pre>
<p>Now you can install <a href="http://www.phpunit.de/" title="PHPUnit" target="_blank">PHPUnit</a> to your local <a href="http://pear.php.net/" title="Pear" target="_blank">PEAR</a> packages</p>
<pre lang="php">
pear install phpunit/PHPUnit</pre>
<p>That should be it for now &#8211; <a href="http://www.phpunit.de/" title="PHPUnit" target="_blank">PHPUnit</a> should hopefully be installed on your system.  According to the <a href="http://www.phpunit.de/" title="PHPUnit" target="_blank">PHPUnit</a> website the directory it is located in is /usr/lib/php/PHPUnit, but I instead found it inside /usr/share/php/PHPUnit on my Ubuntu installation.  In all likelyhood it should be located inside the same directory as your <a href="http://pear.php.net/" title="Pear" target="_blank">PEAR</a> installation.</p>
<h3>Let the testing commence.</h3>
<p>&#8220;Whoa, whoa, whoa!&#8221;, most developers would cry.  &#8220;How can you possibly test code you haven&#8217;t written yet?&#8221;, they all sing together.</p>
<p>Here is where the mind shift starts.  You should have a basic understanding of how your code should work/behave after you have done the <a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language" target="_blank">UML</a> for your class.   So why not use the way you think your code should behave in your tests.</p>
<h4>Your test class</h4>
<p>First things first.  If you have a look at your <a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language" target="_blank">UML</a> diagram you would see that there is a dependency between the Message class and Message_Store class.</p>
<p><img src="http://farm4.static.flickr.com/3451/3397964953_6165f47f15.jpg" alt="Message UML" /></p>
<p>You should now write the test for how your Message object should behave.</p>
<pre lang="php">
//Include the base class for PHPUnit in order for your tests to work
require_once 'PHPUnit/Framework/TestCase.php';

//Include the Message class you are testing
require_once 'Message.php';

//Your Message Test Class
class MessageTest extends PHPUnit_Framework_TestCase
{

//Create a private class variable for re-use
private $oMessage;

/*
The setUp class function is native to PHPUnit and is executed infront of each
test function.  This will help you do things such as create a new object to work with before each new test.
*/
protected function setUp()
{
    $this->oMessage = new Message();
}

/*
The tearDown class function is reverse of the setUp() function and is executed after each test.
This will help you do things such as setting objects to a NULL value for re-use.
*/
protected function tearDown()
{
  $this->oMessage = null;
}

/*
First you test the construction of your Message object.
This isn't really necessary, since you know that a PHP constructor is suppose to work <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> , but is just done
for completeness sake.
$this->assertType() tests to see if the object you created is of the type 'Message'.
*/
public function testMessageConstructed()
{
    $this->assertType('Message', new Message());
}

/*
Now you start testing all the public methods inside your class.  Since you are going to test the way you want
your code to work in, you will only be allowed to test the public accessible methods.  The tests will still cover any
private methods which is called from the public method tested.
This is kind of a double-barrel test. Since you can prove that the setStore is working if the getStore returns the
correct object.
$this->assertSame() will test if two different variables are of the exact same type
*/
public function testSetAndGetStore()
{
    $oPDO = new PDO('mysql:host=localhost;dbname=localdb', 'username', 'password');
    $oMessageStore = new Message_Store_Pdo($oPDO);
    $this->oMessage->setStore($oMessageStore);
    $this->assertSame($oMessageStore,$this->oMessage->getStore());
}

/*
You will now test if the save function will return a variable of bool type, either true if correctly saved or
false if incorrectly saved
*/
public function testSave()
{
    $oPDO = new PDO('mysql:host=localhost;dbname=localdb', 'username', 'password');
    $oMessageStore = new Message_Store_Pdo($oPDO);
    $this->oMessage->setStore($oMessageStore);
    $this->assertType('boolean',$this->oMessage->save('Hello'));
}

/*
You will now test if the delete function will return a variable of bool type, either true if deleted or
false if not deleted.
*/
public function testDelete()
{
    $oPDO = new PDO('mysql:host=localhost;dbname=localdb', 'username', 'password');
    $oMessageStore = new Message_Store_Pdo($oPDO);
    $this->oMessage->setStore($oMessageStore);
    $this->assertType('boolean',$this->oMessage->delete(1));
}

}</pre>
<h4>What does our test class tell us?</h4>
<p>That&#8217;s it &#8211; we now have a couple of basic tests to cover our Message class.  The important thing about writing tests is that you should cover all public functions used in the class you are testing.  At the moment these tests shouldn&#8217;t run, but it will give you a clear idea of where to start and is great for debugging whilst writing code.</p>
<p>Already there is a bit of a discrepancy of what is happening in the unit tests and <a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language" target="_blank">UML</a>.  The way we test our code, is the way we would like our objects to behave.  In the <a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language" target="_blank">UML</a> we assumed that the the message store could be part of the message object, but as our tests showed us &#8211; there might be a more elegant way using a storage object, which would allow for more pluggable, <a href="http://en.wikipedia.org/wiki/Loosely_coupled" title="Loosely coupled" target="_blank">loosely-coupled</a> code.</p>
<p>If we passed a storage object into the Message object itself, after a while the message object will become bloated and unusable, since now you have to cater for your different storage objects within the Message object.  For e.g. create a saveToFileSystem function and a saveToDatabase function, where some functions might become redundant when using a specific storage object.</p>
<p>So instead of passing a PDO storage object directly to the message, you could have a Message_Store object which <a href="http://php.net/interfaces" title="PHP Inteface" target="_blank">interfaces</a> to your various storage objects, such as a PDO or filesystem etc.</p>
<p>Thus turning:</p>
<pre lang="php">
$oMessage = new Message();
$oPDO = new PDO('mysql:host=localhost;dbname=localdb', 'username', 'password');
$oMessage->setStore($oPDO);</pre>
<p>Into:</p>
<pre lang="php">
$oMessage = new Message();
$oPDO = new PDO('mysql:host=localhost;dbname=localdb', 'username', 'password');
$oMessageStore = new MessageStore($oPDO);
$oMessage->setStore($oMessageStore);</pre>
<p>By creating a Message_Store class, rather than building extra code onto your Message object, you reverse any dependencies that might occur within the Message object.  All this means is that for you can now create a message object, and pass a <a href="http://php.net/interfaces" title="Interface" target="_blank">interfaced</a> storage object to it, thus allowing your code to become more flexible, without building layers of complexity itself into the Message object.</p>
<h4>Refactor your code.</h4>
<p>Now update your <a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language" target="_blank">UML</a> to include an interface to the Message_Store object.</p>
<p><img src="http://farm4.static.flickr.com/3633/3367692592_1f58519ff7.jpg" alt="Message UML" /></p>
<p>Let&#8217;s build our message class according to the tests and updated <a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language" target="_blank">UML</a> diagram.</p>
<pre lang="php">
class Message
{

    private $oMessageStore;

    public function __construct($oMessageStore=Null)
    {
        $this->oMessageStore = $oMessageStore;
    }

    public function setStore($oMessageStore)
    {
        $this->oMessageStore = $oMessageStore;
    }

    public function getStore()
    {
        return $this->oMessageStore;
    }

    public function save()
    {
        return $this->oMessageStore->create($this);
    }

    public function delete($sMessageId)
    {
        return $this->oMessageStore->delete($sMessageId);
    }

}</pre>
<p>Now your Message class is starting to look elegant.  Now you can create the interface.</p>
<pre lang="php">
interface Message_Store_Interface
{
public function __construct($oStorage);
public function create($oMessage);
public function delete($sMessageId);
}</pre>
<p>You can now implement the interface in the various Message store objects.</p>
<pre lang="php">
class Message_Store_Pdo implements Message_Store_Interface{

    private $oPdo;

    public function __construct($oPdo)
    {
        $this->oPdo = $oPdo;
    }

    public function create($oMessage)
    {
        $sSql = "insert into message_store (message)
        values (?)";
        $oSql = $this->oPdo->prepare($sSql);
        $oSql->bindParam(1, $oMessage->sMessage);
        $oSql->execute();
        return (bool) $this->oPdo->lastInsertId();
    }

    public function delete($sMessageId)
    {
        $sSql = "DELETE FROM message_store
        WHERE message_id = ?";
        $oSql = $this->oPdo->prepare($sSql);
        $oSql->bindParam(1, $sMessageId);
        $oSql->execute();
        return (bool) $oSql->rowCount();
    }

}</pre>
<h3>The advantages of Test Driven Development and Unit Testing</h3>
<h4>Running the unit tests</h4>
<p>Now the big moment has arrived.  Time to run your test.  Assuming there is no syntax errors the test should execute fine.<br />
Run this by going to your command prompt and enter the following</p>
<pre lang="php">
phpunit tests/MessageTest.php</pre>
<p>If you saved the tests to MessageTest.php in the tests directory, everything should execute fine and the following would be displayed.</p>
<pre lang="php">
dewald@dewald-desktop:/var/www/mobi$ phpunit tests/MessageTest.php
PHPUnit 3.3.14 by Sebastian Bergmann.

....

Time: 0 seconds

OK (4 tests, 4 assertions)
dewald@dewald-desktop:/var/www/mobi$</pre>
<p>You have compiled your tests and ran it succesfully. <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Whoohoo &#8211; if your tests gave an error, just follow the debug messages and fix your code.  Easy as that.</p>
<p>You can also create reports to see if you have achieved acceptable code coverage by running.</p>
<pre lang="php">
phpunit --coverage-html /tmp/tests/ tests/MessageTest.php</pre>
<p>The reports should can be found in the /tmp/tests/ directory and should look something like this:</p>
<p><img src="http://farm4.static.flickr.com/3636/3398100607_9eab3051fd.jpg" alt="Test Report" /></p>
<h4>In the End</h4>
<p>In the beginning of the article I wrote that <a href="http://martinfowler.com/" title="Martin Fowler" target="_blank">Martin Fowler</a> said the following about <a href="http://en.wikipedia.org/wiki/Test-driven_development" title="Test Driven Development" target="_blank">Test Driven Development</a>:</p>
<p><strong>Write a test for the next bit of functionality you want to add.</strong></p>
<p>We wrote all our test for the functionality of our Message object in the way which we would like our object to behave.  We then test the results of that object.</p>
<p><strong>Write the functional code until the test passes.</strong></p>
<p>We wrote the functional code for the classes to make it work as we determined through our tests.</p>
<p><strong>Refactor both new and old code to make it well structured.</strong></p>
<p>After writing the tests, we realised that our code has some short-comings and dependencies, which we could reverse in-time, since we saw the way it was supposed to work in unit tests meant refactoring our <a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language" target="_blank">UML</a> and inherently we would have needed to refactor our code.</p>
<p><strong>What now?</strong><br />
<a href="http://en.wikipedia.org/wiki/Test-driven_development" title="Test Driven Development" target="_blank">TDD</a> doesn&#8217;t come naturally.  Especially if you were used to years of a different kinds of development techniques.  It comes through practice and experience.</p>
<p>I&#8217;ll suggest you read through the <a href="http://www.phpunit.de/manual/3.3/en/" title="PHPunit manual and examples" target="_blank">PHPUnit manual and examples</a>, as to see how flexible the testing framework can be, also as a start, write some unit tests for your old code, and you might be surprised just how efficient you could have been.  <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/03/30/test-drive-your-php-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>the down-low on mobile device detection</title>
		<link>http://blog.dewaldbotha.co.za/2009/02/19/the-down-low-on-mobile-device-detection/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/02/19/the-down-low-on-mobile-device-detection/#comments</comments>
		<pubDate>Thu, 19 Feb 2009 14:28:09 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[apache]]></category>
		<category><![CDATA[architecture]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[devicealtas]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[mobile device detection]]></category>
		<category><![CDATA[php alternative cache]]></category>
		<category><![CDATA[php apc]]></category>
		<category><![CDATA[wurfl]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-02-19/the-down-low-on-mobile-device-detection/</guid>
		<description><![CDATA[so &#8211; you say you want to detect which mobile devices hit your site? &#8211; in the past, this has been a bit of an issue, but lately &#8211; with really nice projects available out there such as WURFL or DeviceAtlas, you are able to concentrate harder on other issues, instead of having to write <a href="http://blog.dewaldbotha.co.za/2009/02/19/the-down-low-on-mobile-device-detection/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>so &#8211; you say you want to detect which mobile devices hit your site? &#8211; in the past, this has been a bit of an issue, but lately &#8211; with really nice projects available out there such as <a href="http://wurfl.sourceforge.net/" title="WURFL" target="_blank">WURFL</a> or <a href="http://deviceatlas.com/" title="DeviceAtlas" target="_blank">DeviceAtlas</a>, you are able to concentrate harder on other issues, instead of having to write a complete library of your own.</p>
<p>so for this, i&#8217;ve decided on <a href="http://deviceatlas.com/" title="DeviceAtlas" target="_blank">DeviceAtlas</a>.  just head on over to <a href="http://deviceatlas.com/" title="DeviceAtlas" target="_blank">DeviceAtlas</a> and open a developers account &#8211; you will get a one year developer&#8217;s license to play around to see how cool it is.</p>
<p>after registering &#8211; click on the <a href="http://deviceatlas.com/downloads" title="download DeviceAtlas" target="_blank">downloads</a> link &#8211; then go to the php example and download the source files.  after de-tar-and-un-zipping the file, just extract the contents.  at the moment all we are really interested in, is the <em><strong>Mobi/Mtld/DA </strong></em>directory and its contents &#8211; also create a <em><strong>json</strong></em> directory and drop the <em><strong>Sample.jso</strong></em>n file inside.</p>
<p>dump everything into a web directory somewhere. <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><span id="more-16"></span>create a <em><strong>deviceatlas.php</strong></em> file in the working directory root and put the following inside.</p>
<pre lang="php">//includes the DeviceAtlas API

include 'Mobi/Mtld/DA/Api.php';//fetch the previously populated apc cache instance into a variable

$tree = apc_fetch('tree');

//Get the properties from a variable containing a JSON tree loaded from cache

$properties = Mobi_Mtld_DA_Api::getProperties($tree, $_SERVER['HTTP_USER_AGENT']);

//Output the phone properties for your viewing pleasure

print_r($properties);</pre>
<p>&#8216;hhmmm, that&#8217;s it?&#8217;, you might ask, and if you were clever you would have noticed something strange in the code above.</p>
<p>yip, that is pretty much it &#8211; but you also need caching.  the <em><strong>apc_fetch(&#8216;tree&#8217;)</strong></em> command in the code above actually fetches the json file already dumped into a &#8216;tree&#8217; cache instance in <a href="http://www.php.net/manual/en/intro.apc.php" title="PHP APC Cache" target="_blank">PHP APC</a> (Alternative PHP Cache).</p>
<p>why <a href="http://www.php.net/manual/en/intro.apc.php" title="PHP APC Cache" target="_blank">PHP APC</a>, you may also ask.  well, besides using the overstated <a href="http://www.danga.com/memcached/" title="Memcached" target="_blank">memcached</a> (<a href="http://www.phpbuilder.com/board/archive/index.php/t-10346692.html" title="Memcache vs APC" target="_blank">you might want to read this</a>), there are some methods to the madness.  with <a href="http://www.php.net/manual/en/intro.apc.php" title="PHP APC Cache" target="_blank">PHP APC</a>, the cache is shared on a server.  it might not be accessible from other servers, but this is not really a con in my mind.</p>
<p>if you wish to scale your application later one and add another server, there is going to be some issues, you might say &#8211; but there will also be issues if you have millions of users hit one central instance of <a href="http://deviceatlas.com/" title="DeviceAtlas" target="_blank">DeviceAtlas</a>.  so, having one instance of <a href="http://deviceatlas.com/" title="DeviceAtlas" target="_blank">DeviceAtlas</a> per server might not be too much of an issue.  also when it comes to updating the json file, you might want to consider the <a href="http://en.wikipedia.org/wiki/Single_point_of_failure" title="Single Point of Failure" target="_blank">single point of failure</a> issue of just having one server.</p>
<p>so have a couple of servers, and just write some scripts to update the single instances of <a href="http://deviceatlas.com/" title="DeviceAtlas" target="_blank">DeviceAtlas</a>, rather than updating one, already busy server which still needs a cache update.</p>
<p>but, back to business.</p>
<p>first you have to install <a href="http://www.php.net/manual/en/intro.apc.php" title="PHP APC Cache" target="_blank">PHP APC</a>.  i found <a href="http://www.howtoforge.com/apc-php5-apache2-debian-etch" title="Apc Installation guide" target="_blank">this handy guide</a> on the net, which helped me install it on my <a href="http://en.wikipedia.org/wiki/Debian" title="Debian" target="_blank">debian</a> system and integrate it with <a href="http://en.wikipedia.org/wiki/Apache_server" title="Apache" target="_blank">apache</a> and <a href="http://en.wikipedia.org/wiki/Php5" title="PHP 5" target="_blank">php5</a> &#8211; there is also a guide at the bottom for <a href="http://en.wikipedia.org/wiki/Red_hat" title="Red Hat" target="_blank">fedora</a> based machines, so don&#8217;t fret my <a href="http://en.wikipedia.org/wiki/Linux" title="Linux" target="_blank">linux</a> loving friends <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>you can create a php script to run the following &#8211; which should cache your <a href="http://deviceatlas.com/" title="DeviceAtlas" target="_blank">DeviceAtlas</a> tree into <a href="http://www.php.net/manual/en/intro.apc.php" title="PHP APC Cache" target="_blank">PHP APC</a>.</p>
<pre lang="php">//ads the sample json data from DeviceAtlas

apc_add('tree', Mobi_Mtld_DA_Api::getTreeFromFile("json/Sample.json"));</pre>
<p>from the first code example, the output might look something like this (depending on your phone)</p>
<p>Array<br />
(<br />
[wmv] =&gt; 0<br />
[vendor] =&gt; Nokia<br />
[mobileDevice] =&gt; 1<br />
[memoryLimitMarkup] =&gt; 357000<br />
[memoryLimitDownload] =&gt; 61440<br />
[midiMonophonic] =&gt; 1<br />
[midiPolyphonic] =&gt; 1<br />
[mpeg4] =&gt; 1<br />
[3gpp] =&gt; 1<br />
[drmOmaForwardLock] =&gt; 1<br />
[drmOmaCombinedDelivery] =&gt; 1<br />
[drmOmaSeparateDelivery] =&gt; 1<br />
[markup.xhtmlMp10] =&gt; 1<br />
[markup.xhtmlBasic10] =&gt; 1<br />
[image.Jpg] =&gt; 1<br />
[image.Png] =&gt; 1<br />
[amr] =&gt; 1<br />
[mp3] =&gt; 1<br />
[aac] =&gt; 1<br />
[h263Type0InVideo] =&gt; 1<br />
[gprs] =&gt; 1<br />
[edge] =&gt; 1<br />
[image.Gif87] =&gt; 1<br />
[uriSchemeTel] =&gt; 0<br />
[qcelp] =&gt; 0<br />
[hsdpa] =&gt; 0<br />
[amrInVideo] =&gt; 1<br />
[3gpp2] =&gt; 0<br />
[displayColorDepth] =&gt; 18<br />
[model] =&gt; N70<br />
[https] =&gt; 1<br />
[image.Gif89a] =&gt; 0<br />
[umts] =&gt; 0<br />
[displayWidth] =&gt; 176<br />
[displayHeight] =&gt; 208<br />
[markup.xhtmlMp11] =&gt; 0<br />
[markup.xhtmlMp12] =&gt; 0<br />
[csd] =&gt; 0<br />
[hscsd] =&gt; 0<br />
[id] =&gt; 204255<br />
[_matched] =&gt; NokiaN70<br />
[_unmatched] =&gt; -1/5.0609.2.0.1 Series60/2.8 Profile/MIDP-2.0 Configuration/CLDC-1.1 UP.Link/6.3.1.13.0<br />
)</p>
<p><a href="http://deviceatlas.com/properties" title="DeviceAtlas properties" target="_blank">you can view the attribute explanations here </a></p>
<p>now you can use the phone&#8217;s specific properties to your advantage.  you also might want to look at the <a href="https://addons.mozilla.org/en-US/firefox/addon/59" title="User agent switcher" target="_blank">user agent switcher add-on</a> for firefox for testing purposes.</p>
<p>that&#8217;s it.  now every once in a while you can just update the json file, delete the current cache (<a href="http://www.php.net/manual/en/function.apc-delete.php" title="APC Delete Cache" target="_blank">http://www.php.net/manual/en/function.apc-delete.php</a>) and bob&#8217;s your device detecting, apc caching uncle.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/02/19/the-down-low-on-mobile-device-detection/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>game theory pattern code example</title>
		<link>http://blog.dewaldbotha.co.za/2009/02/17/game-theory-pattern-code-example/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/02/17/game-theory-pattern-code-example/#comments</comments>
		<pubDate>Tue, 17 Feb 2009 08:50:50 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[design patterns]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[game theory]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-02-17/game-theory-pattern-code-example/</guid>
		<description><![CDATA[so i finally took the time to write some code to better articulate my thoughts on &#8216;game theory pattern&#8217;. /* * Abstract Unifier class to select objects from different sources. */ abstract class childObjectUnifier { protected $currentObjectLocation; public function __construct() { $this->currentObjectLocation = get_class($this); } public function getData() { switch ($this->currentObjectLocation) { case 'currentServerLoginObject': return <a href="http://blog.dewaldbotha.co.za/2009/02/17/game-theory-pattern-code-example/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>so i finally took the time to write some code to better articulate my thoughts on &#8216;game theory pattern&#8217;.</p>
<pre lang="php">
/*
* Abstract Unifier class to select objects from different sources.
*/

abstract class childObjectUnifier
{
    protected $currentObjectLocation;

    public function __construct()
    {
        $this->currentObjectLocation = get_class($this);
    }

    public function getData()
    {
        switch ($this->currentObjectLocation)
        {
             case 'currentServerLoginObject':
                    return $this->currentServerLoginFunction();
                    break;

             case 'remoteServerLoginObject':
                    return $this->remoteServerLoginFunction();
                    break;

             default:
                    die('Current user load not available');
        }
    }
}

/*
* Login Object which exists on the current server.
* This object could still be hit on the current server if the current user load is not high.
* Better utilizes the current server.
*/

class currentServerLoginObject extends childObjectUnifier
{
    public function currentServerLoginFunction()
    {
         return 'Some function on the current server';
    }
}

/*
* This login object could exist remotely, for e.g. a restfull/soap/xml-rpc service
* which could be hit if the current server load is climbing.
* Could possibly use a dedicated 'login' server if user load is exceedingly high on current machine.
*/

class remoteServerLoginObject extends childObjectUnifier
{
    public function remoteServerLoginFunction()
    {
        return 'Some function on the remote server';
    }
}

/*
* The game theory pattern which decides which objects to instantiate based on logical
* decisions made by solid data.
* In this example the current user load.
*/

class GameTheoryPattern
{
    public $currentObject;

    function __construct($iCurrentUserLoad)
    {
        $this->currentObject = $this->baseObjectUponStrategicData($iCurrentUserLoad);
    }

    private function baseObjectUponStrategicData($iCurrentUserLoad)
    {
         switch ($iCurrentUserLoad)
         {
             case $iCurrentUserLoad < 1000:
                    return new currentServerLoginObject();
                    break;

             case $iCurrentUserLoad >= 1000 :
                    return new remoteServerLoginObject();
                    break;

             default:
                    die('Current user load not available');
        }
    }
}

//GetCurrentUserLoad
$iCurrentUserLoad = 1000;

//Create Login Object based on the Game Theory Pattern
$oLogin = new GameTheoryPattern($iCurrentUserLoad);

//Call an function from the unifier class
echo $oLogin->currentObject->getData();

?></pre>
<p>It should be pretty self explanatory &#8211; due to the high level comments <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>feel free to add suggestions or comments &#8211; since i&#8217;m pretty sure there could be a better way, but for now, just to convey the message it should be sufficient.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/02/17/game-theory-pattern-code-example/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>applying game theory patterns to development</title>
		<link>http://blog.dewaldbotha.co.za/2009/02/11/applying-game-theory-patterns-to-development/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/02/11/applying-game-theory-patterns-to-development/#comments</comments>
		<pubDate>Wed, 11 Feb 2009 07:29:23 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[architecture]]></category>
		<category><![CDATA[design patterns]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[game theory pattern]]></category>
		<category><![CDATA[software architecture]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-02-11/applying-game-theory-patterns-to-development/</guid>
		<description><![CDATA[mobile &#8211; that damned device that makes our life so easy, yet sometimes so inheritely difficult. as a developer, we kind of try and convince ourselves that developing for mobile and developing for a desktop browser is kind of the same thing.  but we all know that this is a stalling technique for the inevitable, <a href="http://blog.dewaldbotha.co.za/2009/02/11/applying-game-theory-patterns-to-development/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>mobile &#8211; that damned device that makes our life so easy, yet sometimes so inheritely difficult.</p>
<p>as a developer, we kind of try and convince ourselves that developing for <a href="http://mobiforge.com" title="Mobiforge" target="_blank">mobile</a> and developing for a desktop browser is kind of the same thing.  but we all know that this is a stalling technique for the inevitable, since invariably it becomes a whole different field of play.</p>
<p>every little feature you add, every little flow created and every branch of navigational hierarchy is a challenge on its own.</p>
<p><strong>enter the game theory pattern</strong></p>
<p><span id="more-14"></span>this is was where my idea of a <a href="http://en.wikipedia.org/wiki/Game_theory" title="Game Theory" target="_blank">game theory</a> patterns came into play.  game theory is a branch of applied mathematics, most notably used in social sciences (economics, biology, engineering etc.).  it is also used a bit in computer science, although referred to in that field as artificial intelligence.</p>
<p>thanks <a href="http://wikipedia.org" title="Wikipedia" target="_blank">wikipedia</a> <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>game theory allows someone to apply a bit of mathematics to capture data from a situation and use that data to build a strategic base, which allows you to make decisions to determine your success.</p>
<p>take for example morning traffic &#8211; you have 2 routes to take to work &#8211; one a bit longer than the other, but the longer route is less likely to be busy.</p>
<p>what do you do?  most of us will take the pro&#8217;s and con&#8217;s of both routes and use that to base our decision upon.</p>
<p>game theory works exactly, well almost, the same.  except you will probably use a bit of math to finalize your decision (average speed, distance etc.)</p>
<p>so why not use game theory in development, especially in a field like mobile, which is very limiting and very frustating at first.  but the good kind of limitation, the kind of limitation that could possibly create innovation.  the guys behind a phenomenon like <a href="http://twitter.com" title="Twitter" target="_blank">twitter</a> decided to limit people to 140 characters.  and despite this limitation, people have found innovative ways to increase the effect of that 140 character limited textual communication.</p>
<p>game theory would allow us to mathematically decide on feature sets, the use of algorythms, objects and could even change the flow of an application.</p>
<p>say on an example mobile application we have 3 major features &#8211; chat, activity, content sharing.</p>
<p>which one do we choose as our killer feature, and which would probably make the application more bloated and more problematic to use.  why not use the main variable in the equation to help you decide &#8211; the user.</p>
<p>i often secretly chuckle to myself, when a system gets developed for one purpose and all the users start using it for a totally different end result, no one really every thought of, or intended for.  you could use this to your advantage with game theory.</p>
<p>a simple case could be made using application flow as an example.  we have a menu with chat, activity feed and shared content.  which one is more important, which one would you make easier to access for the user.  by simply adding a click count to each feature, you could sort a menu by popularity, rather than obvious choice as this will invariably change someday.</p>
<p>if users decide this month, chat is the next best thing, let chat be number one on your menu &#8211; and i know some user interface expert will maintain that consistency is important, but if users consistently choose chat as their most important feature, what would the issue be?</p>
<p>this would change the way you develop and architecture software as well.  since you know chat is gaining in popularity according to your available data, then you should be able to utilize servers better for your chat functionality.  write scaling scripts which would use databases sharding.  and on the other hand, allow your game theory pattern to simplify things &#8211; why use a 40 slave/master instances of a database if all you need is one.  eliminate unnecessary overheads in that way &#8211; more layers makes for more complexity, makes for more overhead, and will eventually kill your application.</p>
<p>i&#8217;ve still got to convince a couple of people to maybe try this game theory pattern approach to development and if, by chance, <a href="http://martinfowler.com/" title="Martin Fowler" target="_blank">martin fowler</a> reads this article:</p>
<p>&#8216;please martin, consider this pattern as a topic for a new book! <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> &#8217;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/02/11/applying-game-theory-patterns-to-development/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>coolest guy on the internet</title>
		<link>http://blog.dewaldbotha.co.za/2009/01/30/coolest-guy-on-the-internet/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/01/30/coolest-guy-on-the-internet/#comments</comments>
		<pubDate>Fri, 30 Jan 2009 14:37:03 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[random]]></category>
		<category><![CDATA[cool]]></category>
		<category><![CDATA[coolest guy on the internet]]></category>
		<category><![CDATA[guy]]></category>
		<category><![CDATA[internet]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-01-30/coolest-guy-on-the-internet/</guid>
		<description><![CDATA[so &#8211; in our office we have a little competition to see who can come up 1st for the term &#8220;coolest guy on the internet&#8221; in google.  the seo gurus in our midst have taken to this, like a bear to honey.  so hopefully someone will coin the term &#8220;coolest guy on the internet&#8220;. who <a href="http://blog.dewaldbotha.co.za/2009/01/30/coolest-guy-on-the-internet/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>so &#8211; in our office we have a little competition to see who can come up 1st for the term &#8220;<a href="http://coolestguyontheinternet.com" title="Coolest guy on the internet" target="_blank">coolest guy on the internet</a>&#8221; in google.  the seo gurus in our midst have taken to this, like a bear to honey.  so hopefully someone will coin the term &#8220;<a href="http://coolestguyontheinternet.com" title="Coolest guy on the internet" target="_blank">coolest guy on the internet</a>&#8220;.</p>
<p>who know maybe even me?</p>
<p>-  <a href="http://coolestguyontheinternet.com" title="Coolest guy on the internet" target="_blank">coolest guy on the internet</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/01/30/coolest-guy-on-the-internet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>centering mobile web</title>
		<link>http://blog.dewaldbotha.co.za/2009/01/26/centering-mobile-web/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/01/26/centering-mobile-web/#comments</comments>
		<pubDate>Mon, 26 Jan 2009 14:17:58 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[mobile]]></category>
		<category><![CDATA[user experience]]></category>
		<category><![CDATA[mobile standards]]></category>
		<category><![CDATA[prototyping]]></category>
		<category><![CDATA[wurfl]]></category>
		<category><![CDATA[xhtml-mp]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-01-26/centering-mobile-web/</guid>
		<description><![CDATA[with all the focus being on the mobile web these days, one must have a basic understanding of how the pieces fit together before even writing a line of code. there is a great online community which supports mobile development called mobiforge which could be utilised to answer all of your mobile related questions. but <a href="http://blog.dewaldbotha.co.za/2009/01/26/centering-mobile-web/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>with all the focus being on the mobile web these days, one must have a basic understanding of how the pieces fit together before even writing a line of code.</p>
<p>there is a great online community which supports mobile development called <a href="http://mobiforge.com/" title="Mobiforge" target="_blank">mobiforge</a> which could be utilised to answer all of your mobile related questions.</p>
<p>but as a start i will point out some important steps/considerations to take/make:</p>
<p><span id="more-12"></span></p>
<h4>user-centered design</h4>
<p>before you start on any work, you have to realise that by doing a mobile site, the most important part of your equation is the user and his phone.  it is easy to develop/design a site which looks absolutely amazing in a pc browser, but fails to even load within a phone browser.</p>
<p>you have to make sacrifices in design/layout to suite the user of the site and understand the limitations your user might face with his specific mobile device.  people accessing a site with a lower end phone usually wants quick textual feedback about a certain subject, rather than big glossy images that fill your screen.  once you understand what the user need &#8211; and design according to those needs, then you will be ready to continue.</p>
<h4>keep your site simple</h4>
<p>it is easy in a web browser to go back in your history and traverse navigation, but on a mobile it is a bit different.  so why confuse the mobile user with 50 levels of navigation, where a simple three leveled hierarchy navigational solution would be more than sufficient</p>
<p>and remember that there is no need to overcomplicate things by adding features that is nice to have, rather than have to have.  it is a bad practice on mobile or pc.</p>
<h4>prototype it</h4>
<p>a while back i read a blog post written by <a href="http://fronttoback.org/" title="User experience" target="_blank">phil barret</a>, an user-experience guru , who used <a href="http://fronttoback.org/2008/08/11/to-scale-paper-prototyping-for-the-home/" title="Phil's prototyping method" target="_blank">prototyping to do the layout of his new home using newspapers</a>.  this is probably the best analogy you can use to describe the importance of prototyping your designs to control the flow of your site.</p>
<h4>design for the right device</h4>
<p>group mobile devices into specific groups, for e.g. low, middle and high.  where your low end would be your <a href="http://www.gsmarena.com/nokia_2610-1525.php" title="Nokia 2610" target="_blank">nokia 2610</a>, middle would be <a href="http://www.gsmarena.com/sony_ericsson_w890-2172.php" title="Sony erricsson" target="_blank">sony ericsson w890</a> and the rest, high end devices, such as the <a href="http://www.gsmarena.com/apple_iphone_3g-2424.php" title="iPhone" target="_blank">iphone</a>, <a href="http://www.gsmarena.com/palm_treo_650-907.php" title="Palm" target="_blank">palm</a> and other feature rich pda devices.</p>
<p>it would make sense to deliver more text-based content to lower end phones and more graphic rich sites to high end phones.  and make sure your features apply to the phone&#8217;s capabilities.  you shouldn&#8217;t give someone the option of uploading images if his phone doesn&#8217;t support it.  this could be achieved by using something like <a href="http://www.tera-wurfl.com/" title="tera-wurfl" target="_blank">tera-wurfl</a>.</p>
<h4>standardise</h4>
<p>make sure you comply with the industry standards.  for e.g. using <a href="http://en.wikipedia.org/wiki/XHTML_Mobile_Profile" title="XHTML Mobile Profile" target="_blank">XHTML-MP</a> as your markup language and something like <a href="http://www.developershome.com/wap/wcss/" title="WCSS" target="_blank">WCSS</a> as your presentation markup.  specify your doctype, character encoding and use well formed html code.  you can visit the <a href="http://www.openmobilealliance.org/" title="Open Mobile Alliance" target="_blank">oma</a> for more information.</p>
<p>this gives you more flexibility and would cut down on rendering issues in your mobile browser.</p>
<p>this is only very basic advice, and by no means do i advocate this as being the most correct approach, but it should give you some direction and hopefully a bit of a mind shift when it comes to mobile development.</p>
<h4>some usefull links:</h4>
<ul>
<li>wap 2 specifications &#8211; <a href="http://www.openmobilealliance.org/tech/affiliates/wap/wap-277-xhtmlmp-20011029-a.pdf" title="wap 2 specs" target="_blank">http://www.wapforum.org/what/technical.htm</a></li>
<li>XHTML-MP &#8211; <a href="http://www.openmobilealliance.org/tech/affiliates/wap/wap-277-xhtmlmp-20011029-a.pdf" title="XHTML-MP specs" target="_blank">http://www.openmobilealliance.org/tech/affiliates/wap/wap-277-xhtmlmp-20011029-a.pdf</a></li>
<li>comparison between XHTML-MP and XHTML basic &#8211; <a href="http://pc.dev.mobi/?q=node/119" title="Compare XHTML-MP and basic" target="_blank">http://pc.dev.mobi/?q=node/119</a></li>
<li>mobile web best practices &#8211; <a href="http://www.w3.org/TR/mobile-bp/" title="Best practices in mobile web" target="_blank">http://www.w3.org/TR/mobile-bp/</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/01/26/centering-mobile-web/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>crossing the mvc divide, kohana and zend style</title>
		<link>http://blog.dewaldbotha.co.za/2009/01/23/crossing-the-mvc-divide-kohana-and-zend-style/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/01/23/crossing-the-mvc-divide-kohana-and-zend-style/#comments</comments>
		<pubDate>Fri, 23 Jan 2009 09:36:40 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[framework]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[kohana]]></category>
		<category><![CDATA[kohanaphp]]></category>
		<category><![CDATA[model view controller]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-01-23/crossing-the-mvc-divide-kohana-and-zend-style/</guid>
		<description><![CDATA[so, i&#8217;ve been pretty much a zend framework addict, ever since i coded my first bootstrap.  thinking back to that countless hours trying to understand the beast that is zf, ahhh, what fond memories&#8230;  and lately i&#8217;ve also been playing around a bit with kohana, which is another web based mvc framework, but definitely a <a href="http://blog.dewaldbotha.co.za/2009/01/23/crossing-the-mvc-divide-kohana-and-zend-style/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>so, i&#8217;ve been pretty much a <a href="http://framework.zend.com/" title="Zend Framework" target="_blank">zend framework</a> addict, ever since i coded my first bootstrap.  thinking back to that countless hours trying to understand the beast that is <a href="http://framework.zend.com/" title="Zend Framework" target="_blank">zf</a>, ahhh, what fond memories&#8230;  and lately i&#8217;ve also been playing around a bit with <a href="http://kohanaphp.com/" title="kohana" target="_blank">kohana</a>, which is another web based mvc framework, but definitely a bit more lightweight and easier to use than others.</p>
<p>there is however a bit of an issue with <a href="http://en.wikipedia.org/wiki/Model-view-controller#Implementations_of_MVC_as_web-based_frameworks" title="Web based mvc" target="_blank">web based mvc frameworks</a>, and in my opinion a large freaking elephant that no one seems to talk about.  how can i call a controller from within a view and assign an action to it &#8211; and is it correct to do so?</p>
<p>and before the quiet whispers start, i&#8217;d like to note that this does not necessarily go against <a href="http://en.wikipedia.org/wiki/Model-view-controller" title="Model View Controller" target="_blank">mvc</a> principles.  if you think about it &#8211; the whole point of <a href="http://en.wikipedia.org/wiki/Model-view-controller" title="Model View Controller" target="_blank">mvc</a> is to seperate business logic, application logic and the view (presentation logic) &#8211; and i&#8217;ve confirmed this with a couple of conversations with other developers.  but on the other hand, if you feel that i have overstepped a boundary &#8211; please do let me know if there is a better, or more correct way of doing this.</p>
<p><span id="more-11"></span><strong>now lets give a practical problem:</strong></p>
<p>i have a view template, lets call it home, which consists out of a header, navigation, content and footer.  now my content is pretty much controlled by the controller and whatever the view calls to display.  but say for example something you wish to partially include a login form in the top header.</p>
<p>how do i actually use a controller to change the way the view behaves, without building the logic into all the controllers which i access.  now in order to overcome this &#8211; we can attach a controller, lets call it log controller, to the view.  this controller will have the business logic to decide whether or not a login or a logout form must be generated.</p>
<p>now the obvious would be to include a partial view, but then the issue arrives where you let your view start making logic decisions, instead of presentation. on the other hand, you can use the current controller to help you decide this, but if you ask me, that might be a bit of overkill and lots of extra and duplicate coding.</p>
<h3>the solution:</h3>
<p>in <a href="http://framework.zend.com/" title="Zend Framework" target="_blank">zend framework</a>, i found the solution to be a bit easier than in <a href="http://kohanaphp.com/" title="kohana" target="_blank">kohana</a>, but still fun to figure out.</p>
<h4><img src="http://farm4.static.flickr.com/3415/3219206619_3a9927a7ca_o.jpg" alt="Zend Framework" width="429" height="255" /></h4>
<h3><a href="http://framework.zend.com/" title="Zend Framework" target="_blank">zend framework</a>:</h3>
<p>okay, so i have my home template, which is controlled by my home controller.  on my home template in my header i have a form which would change depending on if the user is logged in or not, which i would like to be controlled by my log controller.</p>
<p>so, in my view i would do the following call:<strong><code></code></strong></p>
<p><strong><code>&lt;?php echo $this-&gt;action('log','generateForm') ?&gt;</code></strong></p>
<p>which would go to the log controller and call the method generateForm() &#8211; so in generate form i will be able to decide whether the user is logged in or not and assign the corresponding result to the view assigned to the controller, in the case above it would most likely be the generateForm view.</p>
<p>there you go &#8211; without having to overcomplicate things or duplicate code, you can assign controllers as part of your presentation logic with a simple call.  i have however not yet figured out how to pass variables to the action method you are calling, but as soon as i have an update i will let you know.</p>
<h4><img src="http://farm4.static.flickr.com/3102/3219908744_e4b6f969c4_o.png" alt="Kohana" width="400" height="200" /></h4>
<h3><a href="http://kohanaphp.com/" title="kohana" target="_blank">kohana</a>:</h3>
<p>in <a href="http://kohanaphp.com/" title="kohana" target="_blank">kohana</a> the task is  a bit more complicated &#8211; luckily i found in the underbelly of the <a href="http://forum.kohanaphp.com/" title="kohana" target="_blank">kohana forums</a> an user with the same problem &#8211; which came up with the following solution -</p>
<p><strong><code>&lt;?php<br />
class Dispatch_Core{</code></strong></p>
<p><strong><code>protected $controller;</code></strong></p>
<p><strong><code> public static function controller($controller)</code><br />
<code>{</code><br />
<code>$controller_file=strtolower($controller);</code></strong></p>
<p><strong><code>// Set controller class name</code><br />
<code>$controller = ucfirst($controller).'_Controller';</code></strong></p>
<p><strong><code>if(!class_exists($controller, FALSE))</code><br />
<code>{</code><br />
<code>// If the file doesn't exist, just return</code><br />
<code>if (($filepath = Kohana::find_file('controllers', $controller_file)) === FALSE)</code><br />
<code>return FALSE;</code></strong></p>
<p><strong><code>// Include the Controller file</code><br />
<code>require_once $filepath;</code><br />
<code>}</code></strong></p>
<p><strong><code>// Run system.pre_controller</code><br />
<code>Event::run('dispatch.pre_controller');</code></strong></p>
<p><strong><code>// Initialize the controller</code><br />
<code>$controller = new $controller;</code></strong></p>
<p><strong><code>// Run system.post_controller_constructor</code><br />
<code>Event::run('dispatch.post_controller_constructor');</code></strong></p>
<p><strong><code>return new Dispatch($controller);</code><br />
<code>}</code><br />
<code>public function __construct(Controller $controller)</code><br />
<code>{</code><br />
<code>$this-&gt;controller=$controller;</code></strong></p>
<p><strong><code>}</code></strong></p>
<p><strong><code>public function __get($key)</code><br />
<code>{</code><br />
<code>if($key=='controller')</code><br />
<code>{</code><br />
<code>return $this-&gt;$key;</code><br />
<code>}</code><br />
<code>else</code><br />
<code>{</code><br />
<code>return $this-&gt;controller-&gt;$key;</code><br />
<code>}</code><br />
<code>}</code></strong></p>
<p><strong><code>public function __set($key,$value)</code><br />
<code>{</code><br />
<code>$this-&gt;controller-&gt;$key=$value;</code><br />
<code>}</code></strong></p>
<p><strong><code>public function __toString()</code><br />
<code>{</code><br />
<code>return $this-&gt;render();</code><br />
<code>}</code></strong></p>
<p><strong><code>public function render()</code><br />
<code>{</code><br />
<code>return (string) $this-&gt;controller;</code><br />
<code>}</code></strong></p>
<p><strong><code>public function __call($name,$arguments=null)</code><br />
<code>{</code><br />
<code>if(method_exists($this-&gt;controller,$name))</code><br />
<code>{</code><br />
<code>return $this-&gt;method($name,$arguments);</code><br />
<code>}</code><br />
<code>return false;</code><br />
<code>}</code></strong></p>
<p><strong><code>public function method($method,$arguments=null)</code><br />
<code>{</code><br />
<code>if(!method_exists($this-&gt;controller,$method))</code><br />
<code>return false;</code></strong></p>
<p><strong><code>if (method_exists($this-&gt;controller,'_remap'))</code><br />
<code>{</code><br />
<code>// Make the arguments routed</code><br />
<code>$arguments = array($method, $arguments);</code></strong></p>
<p><strong><code>// The method becomes part of the arguments</code><br />
<code>array_unshift($arguments, $method);</code></strong></p>
<p><strong><code>// Set the method to _remap</code><br />
<code>$method = '_remap';</code><br />
<code>}</code></strong></p>
<p><strong><code>ob_start();</code></strong></p>
<p><strong><code>if(is_string($arguments))</code><br />
<code>{</code><br />
<code>$arguments=array($arguments);</code><br />
<code>}</code></strong></p>
<p><strong><code>switch(count($arguments))</code><br />
<code>{</code><br />
<code>case 1:</code><br />
<code>$result=$this-&gt;controller-&gt;$method($arguments[0]);</code><br />
<code>break;</code><br />
<code>case 2:</code><br />
<code>$result=$this-&gt;controller-&gt;$method($arguments[0], $arguments[1]);</code><br />
<code>break;</code><br />
<code>case 3:</code><br />
<code>$result=$this-&gt;controller-&gt;$method($arguments[0], $arguments[1], $arguments[2]);</code><br />
<code>break;</code><br />
<code>case 4:</code><br />
<code>$result=$this-&gt;controller-&gt;$method($arguments[0], $arguments[1], $arguments[2], $arguments[3]);</code><br />
<code>break;</code><br />
<code>default:</code><br />
<code>// Resort to using call_user_func_array for many segments</code><br />
<code>$result=call_user_func_array(array($this-&gt;controller, $method), $arguments);</code><br />
<code>break;</code><br />
<code>}</code></strong></p>
<p><strong><code>// Run system.post_controller</code><br />
<code>Event::run('dispatch.post_controller');</code></strong></p>
<p><strong><code>if($result!=NULL)</code><br />
<code>{</code><br />
<code>$result=ob_get_contents();</code></strong></p>
<p><strong><code>ob_end_clean();</code><br />
<code>}</code></strong></p>
<p><strong><code>return $result;</code><br />
<code>}</code></strong></p>
<p><strong><code>}</code></strong></p>
<p>now the above you can save under your library directory in your application for ease of use as something like dispatch.php.</p>
<p>so to solve the problem of the login form &#8211; in my default home template i&#8217;ve added <strong><code>&lt;?php echo $this-&gt;template-&gt;partial = new View('log/generateform');?&gt;</code></strong></p>
<p>in the generateform view i called i will use the following:</p>
<p><strong><code>&lt;?php</code><br />
<code>//call the log controller</code><br />
<code>$dispatch = Dispatch::Controller('log');</code><br />
<code>//call the generateForm method</code><br />
<code>$dispatch-&gt;method('generateForm');</code><br />
<code>//return the result from the template to the view</code><br />
<code>echo $dispatch-&gt;template;</code><br />
<code>?&gt;</code></strong></p>
<p>the above will call the  log controller and the method generateForm, in the controller, you can specify the template, for e.g. <strong><code>&lt;?php public $template = 'kohana/partial/navigation';?&gt;</code></strong> and then in the action / controller assign any values to be used by the template view/presentation.</p>
<p>oh, and one more cool thing with the above is that you can also call the method using parameters for e.g. <strong><code>&lt;?php $dispatch-&gt;generateForm(array('title'='login'));?&gt;</code></strong></p>
<h3>recap</h3>
<p>as i said in the beginning, if anyone feels that i&#8217;ve overstepped the <a href="http://en.wikipedia.org/wiki/Model-view-controller" title="Model View Controller" target="_blank">mvc</a> divide, please let me know, i&#8217;m sure that with the assigning of a controller/action from within a view is totally acceptable, since only your presentation logic is affected by it really, and the controller still decides on what is available for the view to pull, without having adjust your controllers to cater for everything.</p>
<p>and if someone knows of a quicker method in <a href="http://kohanaphp.com/" title="kohana" target="_blank">kohana</a>, also do let me know.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/01/23/crossing-the-mvc-divide-kohana-and-zend-style/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>we be having web 2.0</title>
		<link>http://blog.dewaldbotha.co.za/2009/01/20/we-be-having-web-20/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/01/20/we-be-having-web-20/#comments</comments>
		<pubDate>Tue, 20 Jan 2009 08:31:52 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[random]]></category>
		<category><![CDATA[we will build it and they will come]]></category>
		<category><![CDATA[web 2.0]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-01-20/we-be-having-web-20/</guid>
		<description><![CDATA[so &#8211; at our office there has been huge focus on breaking into the lucrative web 2.0 market. as a short term solution to this i will show you how to make your own web 2.0 social network in no time. feeling confused? no need to be &#8211; just follow these easy steps: 1.  get <a href="http://blog.dewaldbotha.co.za/2009/01/20/we-be-having-web-20/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>so &#8211; at our office there has been huge focus on breaking into the lucrative web 2.0 market.</p>
<p>as a short term solution to this i will show you how to make your own web 2.0 social network in no time.</p>
<p><span id="more-10"></span><img src="http://farm4.static.flickr.com/3335/3211566351_8850080539.jpg" alt="Confused?" width="500" align="middle" height="332" /></p>
<h3>feeling confused?</h3>
<p>no need to be &#8211; just follow these easy steps:</p>
<h3>1.  get a funky name</h3>
<p>use this cool site to generate that cutting edge and hip web 2.0 company name &#8211; one that will make silicon valley startups look like a bunch of geeks with ancient 2008 <a href="http://www.apple.com/macbook/" title="Apple Mac" target="_blank">macbooks</a> &#8211; <a href="http://www.dotomator.com/web20.html" title="Web 2.0 name generator" target="_blank">http://www.dotomator.com/web20.html</a> and register it &#8211; before someone else takes it.</p>
<p>i chose <a href="http://tagvine.ning.com/" title="Tagvine" target="_blank">tagvine</a> &#8211; it sounds like something me and my friends should belong too.</p>
<h3>2.  make them jealous with a shiny logo</h3>
<p>take your funk-a-licious company name and generate a web 2.0 logo of format using <a href="http://creatr.cc/creatr/" title="Creatr - create your own web 2.0 logo" target="_blank">http://creatr.cc/creatr/</a> &#8211; remember it looks more professional and web 2.0ish with a bright beta tag in the top right corner.</p>
<p><a href="http://tagvine.ning.com/" title="Tagvine" target="_blank"><img src="http://farm4.static.flickr.com/3374/3211592013_8bf0a90d7c_o.png" alt="Tagvine" width="432" align="middle" height="257" /></a></p>
<h3>3.  lunch</h3>
<p>after a hard mornings worth of work &#8211; you&#8217;ve probably worked up a mighty appetite.  so take your <a href="http://www.apple.com/macbook/" title="macbook" target="_blank">macbook</a> and head over to the <a href="http://www.vidaecaffe.com/" title="Vida" target="_blank">nearest trendy coffee shop</a> and surf some net.</p>
<h3>4.  socialize your brand</h3>
<p>now that the hard work is finished &#8211; head over to <a href="http://www.ning.com/" title="Ning" target="_blank">http://www.ning.com/</a> &#8211; just enter your company name &#8211; register your url, choose some colors and themes, upload your logo and <a href="http://tagvine.ning.com/" title="Tagvine" target="_blank">voila!</a> &#8211; a shiny, trendy web 2.0 company is born -&gt; <a href="http://tagvine.ning.com/" title="Tagvine" target="_blank">tagvine</a></p>
<h3><strong>5.  monetize your brand</strong></h3>
<p>no need &#8211; just stand back &#8211; and watch your super awesome <a href="http://www.thestandard.com/news/2008/11/07/facebook-twitter-making-money-takes-back-seat-growth" title="Not making money with web 2.0" target="_blank">web 2.0 social company generate some theoretical dollars</a>.  i&#8217;ll suggest taking that beefy <a href="http://www.apple.com/macbook/" title="macbook" target="_blank">macbook</a> of yours and head over to that <a href="http://www.vidaecaffe.com/" title="Vida" target="_blank">trendy coffee shop</a> and have another tall mocha-chocha-chino.</p>
<p>as everyone knows the new web 2.0 motto is &#8211; we will build it and they will come</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/01/20/we-be-having-web-20/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>the great search balancing act</title>
		<link>http://blog.dewaldbotha.co.za/2009/01/14/the-great-search-balancing-act/</link>
		<comments>http://blog.dewaldbotha.co.za/2009/01/14/the-great-search-balancing-act/#comments</comments>
		<pubDate>Wed, 14 Jan 2009 06:29:24 +0000</pubDate>
		<dc:creator>dewaldbotha</dc:creator>
				<category><![CDATA[architecture]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[tomcat]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[haproxy]]></category>
		<category><![CDATA[keepalived]]></category>
		<category><![CDATA[load balancing]]></category>
		<category><![CDATA[replication]]></category>
		<category><![CDATA[search engine]]></category>

		<guid isPermaLink="false">http://blog.dewaldbotha.co.za/2009-01-14/the-great-search-balancing-act/</guid>
		<description><![CDATA[it&#8217;s been a while since my last post &#8211; and as interests fade with time, others jump up faster than a beach ball at a nickelback concert. so i&#8217;ve been looking into solr the last couple of days.  solr is relatively new in the arena and probably outshined a bit in popularity by other search <a href="http://blog.dewaldbotha.co.za/2009/01/14/the-great-search-balancing-act/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>it&#8217;s been a while since my last post &#8211; and as interests fade with time, others jump up faster than a beach ball at a nickelback concert.</p>
<p>so i&#8217;ve been looking into <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> the last couple of days.  <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> is relatively new in the arena and probably outshined a bit in popularity by other search engines such as <a href="http://lucene.apache.org/solr/" title="Lucene" target="_blank">lucene</a> and <a href="http://lucene.apache.org/nutch/" title="Nutch" target="_blank">nutch</a>.  &#8220;but why <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a>?&#8221;, you may find yourself asking.</p>
<p>Well <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> has a couple of tricks up the sleave &#8211; which is likely due to the fact that its a fresher version of the old, dare i call it legacy, search engines.</p>
<p><span id="more-9"></span><strong>some of the features of <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> includes:</strong></p>
<ul>
<li>highly scalabe <a href="http://www.java.com/en/" title="Java" target="_blank">java</a> search server (as i will try to show you through this article)</li>
<li>works with the <a href="http://lucene.apache.org/solr/" title="Lucene" target="_blank">lucene</a> search library (tried and tested)</li>
<li>you can update your engine with <a href="http://en.wikipedia.org/wiki/XML" title="XML" target="_blank">xml</a> using a kind of lightweight <a href="http://java.sun.com/developer/technicalArticles/WebServices/restful/" title="Resftul" target="_blank">restful</a> service.</li>
<li>can parse html, openoffice, microsoft office suite documents, pdf&#8217;s etc using <a href="http://lucene.apache.org/solr/" title="Lucene" target="_blank">lucene</a> parsers.</li>
<li>custom tokenizer, filter and analyzer  steps for control over indexing and query processing</li>
<li>extremely rich indexing of fields and metadata, including numbers</li>
<li>can combine fields for fulltext-type searching</li>
<li>tuned for high performance even when updating</li>
<li>spell checkers included, etc, only 2 name a couple of features.</li>
</ul>
<p><a href="http://lucene.apache.org/solr/features.html" title="Solr Features" target="_blank">click here to view a more complete list.</a></p>
<p><a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> currently have api&#8217;s for <a href="http://www.ruby-lang.org/en/" title="Ruby" target="_blank">ruby</a>, <a href="http://www.php.net/" title="PHP" target="_blank">php</a>, <a href="http://www.python.org/" title="Python" target="_blank">python</a>, <a href="http://www.json.org/" title="JSON" target="_blank">json</a>, <a href="http://forrest.apache.org/" title="Forrest" target="_blank">forrest</a>/<a href="http://cocoon.apache.org/" title="Cocoon" target="_blank">cocoon</a>.</p>
<p>the obvious elephant that is missing from the list above is the fact that solr is not compiled with a crawler of some sort.  luckily some friendly open source guys already <a href="http://blog.foofactory.fi/2007/02/online-indexing-integrating-nutch-with.html" title="Integrate Nutch with Solr as a crawler" target="_blank">released a guide for integrating nutch</a> with <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> for an all round experience.</p>
<p>you might also want to look into <a href="http://www.gissearch.com/localsolr" title="localsolr" target="_blank">localsolr</a> &#8211; which enables geographical and spatial searches with <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a></p>
<h3>now&#8230; where to begin:</h3>
<p>first things first &#8211; since <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> is <a href="http://www.java.com/en/" title="Java" target="_blank">java</a> based, it has to be wrapped in a <a href="http://www.java.com/en/" title="Java" target="_blank">java</a> container of some sorts.  i choose the friendly open source <a href="http://tomcat.apache.org/" title="Apache Tomcat" target="_blank">tomcat</a> as a basis.  i installed <a href="http://tomcat.apache.org/" title="Apache Tomcat" target="_blank">tomcat</a> 5.5 using <a href="http://linux-sxs.org/internet_serving/c140.html" title="Tomcat Installation" target="_blank">this helpful guide as a reference</a>.  read a bit more than what is required and make sure you understand the concept of using web applications and the configuration of <a href="http://tomcat.apache.org/" title="Apache Tomcat" target="_blank">tomcat</a>.</p>
<p>after <a href="http://tomcat.apache.org/" title="Apache Tomcat" target="_blank">tomcat</a> is installed, its time for <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a>.  and as luck would have it <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  &#8211; a <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> installation in <a href="http://tomcat.apache.org/" title="Apache Tomcat" target="_blank">tomcat</a> is probably one of the easiets most straight forward ways of doing it &#8211; and i <a href="http://wiki.apache.org/solr/SolrTomcat" title="Install Solr in Tomcat" target="_blank">just followed this handy guide</a>, provided by <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a>, as a reference.</p>
<p>now after <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> is up and running, you should be able to access your admin screen via the following url <a href="http://localhost:8180/solr/" title="Solr" target="_blank">http://127.0.0.1:8180/solr</a></p>
<p>that would be assuming your <a href="http://tomcat.apache.org/" title="Apache Tomcat" target="_blank">tomcat</a> port is 8180 and <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> is installed under the directory <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> in your web applications.</p>
<p>now after installing <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> &#8211; and accessing the admin screen you should &#8211; you should be able view your configuration and perform a basic search.  to update the schema and import data into <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> is a whole other post on its own, and as soon as i figure it out, you will be the first to know &#8211; but for know we are going to focus on replication and scalability.</p>
<p>look at the following diagram (done by me using <a href="http://www.gliffy.com/" title="Gliffy" target="_blank">gliffy</a>)</p>
<p style="text-align: center"><img src="http://farm4.static.flickr.com/3397/3194302830_7100b86480_o.jpg" alt="Solr Replication and Loab Balancing" /></p>
<p>as you can see above &#8211; there is 3 main levels</p>
<ol>
<li>load balancers (wrapped in a monitoring service &#8211; <a href="http://www.keepalived.org/" title="Keepalived" target="_blank">keepalived</a> which is optional)</li>
<li><a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> slave instances</li>
<li><a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> master</li>
</ol>
<p>you can see that it isn&#8217;t the most original idea in the book, but it works.  especially if you should run it within a cloud where your instances could almost be infinite.</p>
<h3>searching with <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a></h3>
<p>lets start from the bottom up &#8211; at the base &#8211; you have the <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> master &#8211; which would be the <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> instance where all your data importing from <a href="http://en.wikipedia.org/wiki/XML" title="XML" target="_blank">xml</a> happens.</p>
<p>above that is the slave instances, which is will replicate their indexes from the master.  the slaves will in turn handle all search request from the load balancers which sits at the top.  this reduces load on the master, which will be used as the primary indexer.</p>
<p>also the load balancers will be wrapped in a monitoring system, which will alert you in case something goes wrong, and also reduced the risk of a single point of entry failure.  this monitoring system is really optional, since the load balancer i will be using has built in failover checks.  but nevertheless it is good practice to look into a monitoring system like <a href="http://www.keepalived.org/" title="Keepalived" target="_blank">keepalived</a> for your architecture.<a href="http://www.howtoforge.com/high-availability-load-balancer-haproxy-heartbeat-debian-etch" title="HaProxy Multiple load balancers on shared ip" target="_blank"></a></p>
<p>now for the specifics &#8211; to update the index of your master is almost a trivial exercise &#8211; since <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> has a kind of a <a href="http://java.sun.com/developer/technicalArticles/WebServices/restful/" title="Resftul" target="_blank">restful</a> approach of doing this -</p>
<p><code><strong>#the following would be in a .sh file<br />
FILES=$*<br />
URL=http://localhost:8180/solr/update</strong></code><br />
<code><br />
<strong>for f in $FILES; do<br />
echo Posting file $f to $URL<br />
curl $URL --data-binary @$f -H 'Content-type:text/xml; charset=utf-8'<br />
</strong></code><code><br />
<strong>#send the commit command to make sure all the changes are flushed and visible<br />
curl $URL --data-binary '&lt;commit/&gt;' -H 'Content-type:text/xml; charset=utf-8'</strong></code></p>
<p>so &#8211; if you save the above script as for e.g. post.sh, make it executable (chmod a+x post.sh), then you could run it with a xml dataset (./post.sh dataset.xml), and it will update the index using its semi restful interface.  all you have to do is change your url in the above script to the <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> instance you wish to update.</p>
<p>then comes the replication of data to the slaves &#8211; this is done by using scripts in the bin directory of your <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> installation.  <a href="http://wiki.apache.org/solr/SolrCollectionDistributionScripts" title="Solr Update Scripts" target="_blank">here is the descriptions of these scripts</a> from the <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> websit.  we would most likely be interested in the snapshooter &#8211; which takes a snapshot of the current master index &#8211; from there you would use the snappuller &#8211; which would pull the latest snapshot from the master index and update the index.</p>
<p>after you&#8217;ve mastered these scripts, you can store run them as cron jobs every so often and update the slave indexes.  i&#8217;ve also read on there site, that in the new release they would be compiling replication as a feature into <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a>, where you can actually just tweak a couple of configuration settings, and it should replicate without external tools, so just keep a lookout for the new <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> version.</p>
<h3>load balancing with <a href="http://haproxy.1wt.eu/" title="Haproxy" target="_blank">haproxy</a></h3>
<p>so as a load balancing solution i chose <a href="http://haproxy.1wt.eu/" title="Haproxy" target="_blank">haproxy</a>, which offers high availability and balancing for tcp and http based applications.  <a href="http://haproxy.1wt.eu/" title="Haproxy" target="_blank">haproxy</a> does not deliver content such as <a href="http://www.apache.org/" title="Apache" target="_blank">apache</a>, neither does it do caching in a way <a href="http://www.squid-cache.org/" title="squid" target="_blank">squid</a> does it, but it&#8217;s small, simple and works very well.</p>
<p>to install <a href="http://haproxy.1wt.eu/" title="Haproxy" target="_blank">haproxy</a>:</p>
<p><code><strong>mkdir /opt/haproxy<br />
cd /opt/haproxy<br />
wget http://haproxy.1wt.eu/download/1.3/src/haproxy-1.3.15.7.tar.gz<br />
gunzip haproxy-1.3.15.7.tar.gz<br />
tar -xf haproxy-1.3.15.7.tar<br />
cd haproxy-1.3.15.7<br />
make<br />
cp ./haproxy /usr/bin/haproxy</strong><br />
</code><br />
then create a file called haproxy.cfg that contains the following data:</p>
<p><code><br />
<strong>global<br />
log 127.0.0.1   local0               #logs all haproxy info to local0 log<br />
log 127.0.0.1   local1 notice    #logs all notifications to local1 log</strong></code><br />
<code><br />
<strong>daemon                                     #specifies haproxy to run as a deamon instance<br />
maxconn         4096                 # total max connections (dependent on ulimit)</strong></code><br />
<code><br />
<strong>defaults   #setup some default values<br />
log            global<br />
mode       http<br />
option      httplog<br />
option      dontlognull</strong><br />
</code><code><br />
<strong>clitimeout        60000       # maximum inactivity time on the client side<br />
srvtimeout        30000       # maximum inactivity time on the server side<br />
timeout connect   4000        # maximum time to wait for a connection attempt to a server to succeed</strong><br />
</code><code><br />
<strong>option            httpclose     # disable keepalive (HAProxy does not yet support the HTTP keep-alive mode)<br />
option            abortonclose  # enable early dropping of aborted requests from pending queue<br />
option            httpchk       # enable HTTP protocol to check on servers health<br />
option            forwardfor    # enable insert of X-Forwarded-For headers</strong><br />
</code><code><br />
<strong>balance roundrobin            # each server is used in turns, according to assigned weight</strong><br />
</code><code><br />
<strong>stats enable                  # enable web-stats at /haproxy?stats<br />
stats auth        admin:pass  # force HTTP Auth to view stats<br />
stats refresh     5s        # refresh rate of stats page</strong><br />
</code><code><br />
<strong>listen myloadbalancer 127.0.0.1:8888 #where the loadbalancer should listen for requests<br />
server slave1 192.168.1.6:8180 #a slave</strong></code><br />
<code><strong>server slave2 192.168.1.6:8180 #another slave</strong><br />
</code><br />
&#8211;</p>
<p>and that is it.  now all you do is run:</p>
<p><code><strong>/usr/bin/haproxy -f haproxy.cfg</strong></code></p>
<p>and bob&#8217;s your uncle &#8211; just go to <a href="http://127.0.0.1:8888/haproxy?stats" title="Haproxy Admin" target="_blank">http://127.0.0.1:8888/haproxy?stats</a> to verify that it is running (the username is: admin and the password: pass &#8211; as specified in the config file above)</p>
<p>just note &#8211; if you get binding errors, make sure the port you specify in the config file is open, and not in use by something like <a href="http://www.apache.org/" title="apache" target="_blank">apache</a>, <a href="http://tomcat.apache.org/" title="Apache Tomcat" target="_blank">tomcat</a>, <a href="http://yaws.hyber.org/" title="yaws" target="_blank">yaws</a> etc.</p>
<p>now if you have all your slave instances running a version of <a href="http://lucene.apache.org/solr/" title="Solr" target="_blank">solr</a> &#8211; you should be easily able to connect to them in a round robin fasion &#8211; for e.g. connecting to <a href="http://127.0.0.1:8888/solr" title="Solr" target="_blank">http://127.0.0.1:8888/solr</a> &#8211; you can confirm this in the syslog or with the above stats link.</p>
<h3>monitor that architecture, with <a href="http://www.keepalived.org/" title="Keepalived" target="_blank">keepalived</a></h3>
<p>last, but not the least would be the enabling of the load balancing monitor &#8211; <a href="http://www.keepalived.org/" title="Keepalived" target="_blank">keepalived</a> was suggested to me as a viable option, however, with <a href="http://haproxy.1wt.eu/" title="Haproxy" target="_blank">haproxy</a>  you can have do failover checks and <a href="http://www.howtoforge.com/high-availability-load-balancer-haproxy-heartbeat-debian-etch" title="HaProxy Multiple load balancers on shared ip" target="_blank">run multiple loadbalancers under a shared ip</a> so this isn&#8217;t really a necessary part, but as explained earlier, it is good practice to run a monitor like <a href="http://www.keepalived.org/" title="Keepalived" target="_blank">keepalived</a> on your system.</p>
<h3>conclusion</h3>
<p>because it is late, and i still have to proofread this sucker, i haven&#8217;t really got around to <a href="http://www.keepalived.org/" title="Keepalived" target="_blank">keepalived</a>, although &#8211; do yourself a favor and read up on it &#8211; i know i certainly will have a cup of java and research it a bit more.</p>
<p>so &#8211; there you go &#8211; you have a fully load balanced system &#8211; running a search engine, which should scale horizontally with your hardware buying budget. <img src='http://blog.dewaldbotha.co.za/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dewaldbotha.co.za/2009/01/14/the-great-search-balancing-act/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

