<?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>Daniel Skinner: News and Articles on Web Development &#187; General</title>
	<atom:link href="http://www.daniel-skinner.co.uk/category/general/feed" rel="self" type="application/rss+xml" />
	<link>http://www.daniel-skinner.co.uk</link>
	<description>Daniel Skinner&#039;s Blog: Web Development news and articles</description>
	<lastBuildDate>Wed, 18 Mar 2009 15:11:23 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Custom sorting order in LINQ (ORDER BY WEIGHTING)</title>
		<link>http://www.daniel-skinner.co.uk/custom-sorting-order-in-linq-order-by-weighting/18/03/2009</link>
		<comments>http://www.daniel-skinner.co.uk/custom-sorting-order-in-linq-order-by-weighting/18/03/2009#comments</comments>
		<pubDate>Wed, 18 Mar 2009 15:10:18 +0000</pubDate>
		<dc:creator>Daniel Skinner</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[LINQ]]></category>

		<guid isPermaLink="false">http://www.daniel-skinner.co.uk/?p=32</guid>
		<description><![CDATA[I have developed a C# LINQ extension method to allow very flexible ordering by assigning weightings to the sort keys of the elements to be ordered. I was inspired by the functionality offered by SQL Server&#8217;s ORDER BY CASE WHEN:

ORDER BY
CASE SEASON
    WHEN 'WINTER' THEN 1
    WHEN 'SPRING' THEN [...]]]></description>
			<content:encoded><![CDATA[<p>I have developed a C# LINQ extension method to allow very flexible ordering by assigning weightings to the sort keys of the elements to be ordered. I was inspired by the functionality offered by SQL Server&#8217;s ORDER BY CASE WHEN:</p>
<pre>
ORDER BY
CASE SEASON
    WHEN 'WINTER' THEN 1
    WHEN 'SPRING' THEN 2
    WHEN 'SUMMER' THEN 3
    WHEN 'AUTUMN' THEN 4
END
</pre>
<p>The extension method I have created lets you pass a lambda function which allows the use of logic to apply custom weightings to the sort keys.</p>
<pre>
var data = dt.Select(g =&gt; new
{
    Season = g.season,
    AverageTemp = g.temp
}).OrderByWeight(a =&gt; a.Season, x =&gt;
{
    if (x == "WINTER") return 1;
    if (x == "SPRING") return 2;
    if (x == "SUMMER") return 3;
    if (x == "AUTUMN") return 4;
    return 99;
});
</pre>
<p>The above will return an IOrderedEnumerable sorted by Season in the order WINTER, SPRING, SUMMER, AUTUMN. However, the OrderByWeight extension method provides even more powerful functionality as the lambda allows us to perform string comparisons and more:</p>
<pre>
var data = dt.Select(g =&gt; new
{
    Year = g.year,
}).OrderByWeight(a =&gt; a.Year, x =&gt;
{
    if (x.Contains("2008")) return 1;
    if (x.Contains("2009")) return 2;
    if (x.Contains("2010") return 3;
    return 99;
});
</pre>
<p>Using the above, a non-trivial list such as {&#8216;London 2010&#8242;, &#8216;Leeds 2008&#8242;, &#8216;Cardiff 2009&#8242;, &#8216;Glasgow 2011&#8242;} can be easily sorted to {&#8216;Leeds 2008&#8242;, &#8216;Cardiff 2009&#8242;, &#8216;London 2010&#8242;, &#8216;Glasgow 2011&#8242;}</p>
<p>The extension method used to implement this functionality is:</p>
<pre>
public static IOrderedEnumerable&lt;TSource&gt; OrderByWeight&lt;TSource, TKey&gt;(this IEnumerable&lt;TSource&gt; source, Func&lt;TSource, TKey&gt; keySelector, Func&lt;TKey, int&gt; weighting) where TKey : IComparable
{
    Dictionary&lt;TSource, int&gt; order = new Dictionary&lt;TSource, int&gt;();
    foreach (TSource item in source)
    {
        if (!order.ContainsKey(item)) order.Add(item, weighting(keySelector(item)));
    }
    return source.OrderBy(s => order[s]);
}
</pre>
<p>It has not been throughly unit tested yet but it should have the same behaviour as GroupBy. Whilst I have only provided the C# implementation I&#8217;m sure it can be converted to other languages using the CLR.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.daniel-skinner.co.uk/custom-sorting-order-in-linq-order-by-weighting/18/03/2009/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>String.Capitalize in C# (PHP&#8217;s ucwords in C#)</title>
		<link>http://www.daniel-skinner.co.uk/php-ucwords-in-c/25/02/2009</link>
		<comments>http://www.daniel-skinner.co.uk/php-ucwords-in-c/25/02/2009#comments</comments>
		<pubDate>Wed, 25 Feb 2009 15:10:50 +0000</pubDate>
		<dc:creator>Daniel Skinner</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Aggeregate]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[Extension Method]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[ucwords]]></category>

		<guid isPermaLink="false">http://www.daniel-skinner.co.uk/?p=31</guid>
		<description><![CDATA[I have been playing around with C# recently and found the need for functionality similar to that provided by PHP&#8217;s ucwords() function. I dont think this exists in C# as standard so here is a simple extension method to achieve ucwords in C# using a little bit of LINQ (the extremely useful Aggregate extension method) [...]]]></description>
			<content:encoded><![CDATA[<p>I have been playing around with C# recently and found the need for functionality similar to that provided by PHP&#8217;s ucwords() function. I dont think this exists in C# as standard so here is a simple extension method to achieve ucwords in C# using a little bit of LINQ (the extremely useful Aggregate extension method) to achieve it:</p>
<pre>public static string Capitalize(this String s)
{
  return s.ToCharArray().Aggregate(String.Empty,
    (working, next) =>
      working.Length == 0 &#038;&#038; next != ' ' ? next.ToString().ToUpper() : (
        working.EndsWith(" ") ? working + next.ToString().ToUpper() :
          working + next.ToString()
    )
  );
}</pre>
<p>With this included in your name space, the extension method can be used on any String instance like:</p>
<pre>string myString = "this sentence needs capitalization!";
Console.WriteLine(myString.Capitalize());
//This Sentence Needs Capitalization!</pre>
<p>Short but sweet!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.daniel-skinner.co.uk/php-ucwords-in-c/25/02/2009/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Cloning Zend_Config without side-effects</title>
		<link>http://www.daniel-skinner.co.uk/cloning-zend_config-without-side-effects/26/08/2008</link>
		<comments>http://www.daniel-skinner.co.uk/cloning-zend_config-without-side-effects/26/08/2008#comments</comments>
		<pubDate>Tue, 26 Aug 2008 19:09:57 +0000</pubDate>
		<dc:creator>Daniel Skinner</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.daniel-skinner.co.uk/?p=29</guid>
		<description><![CDATA[Cloning in PHP5
PHP5 with its much improved object-oriented style passes objects by reference by default. To create a copy of an object, a new construct &#8216;clone&#8217; is introduced. Cloning an object in PHP5 creates a shallow copy &#8211; any properties that are references to other variables, will remain references. Additionally, PHP5 brings the __clone() magic [...]]]></description>
			<content:encoded><![CDATA[<h2>Cloning in PHP5</h2>
<p>PHP5 with its much improved object-oriented style passes objects by reference by default. To create a copy of an object, a new construct &#8216;clone&#8217; is introduced. Cloning an object in PHP5 creates a shallow copy &#8211; any properties that are references to other variables, will remain references. Additionally, PHP5 brings the __clone() magic method to allow you to customise the cloning behaviour of objects, making those referenced objects full copies if that is the desired behaviour.</p>
<h2>Zend_Config</h2>
<p>Zend_Config is a component of the Zend Framework. Zend_Config makes it trivial to load configuration data into PHP from a range of file types.</p>
<p>Using Zend_Config is easy:</p>
<pre lang="php">$config = new Zend_Config_Xml('/path/to/config');
echo $config->database->host;
</pre>
<p>In a particular scenario of mine I have a heirachy of config files, each inheriting data from it&#8217;s parent and overwriting keys if necessary. Merging two config files to get the resultant is also trivial:</p>
<pre lang="php">(void) $parent->merge($child);
</pre>
<p>The Zend_Config instance $parent has now been augmented with the values of the Zend_Config instance $child and keys may have been overwritten in the parent if a value for that key existed in the child.</p>
<p>Here lies my problem: What I really wanted to do was keep $parent as it was whilst creating a new instance that was the product of $parent merged with $child.</p>
<p>Easy:</p>
<pre lang="php">

$newConfig = clone $parent;
$newConfig->merge($child);
</pre>
<p>Or not&#8230; Currently Zend_Config only implements a shallow clone which effectively means my $newConfig is still tied up with $parent. In fact if I make changes to $newConfig, those changes may well be reflected in $parent. This is not the side-effect-free behaviour I expected when using clone. </p>
<p>It is true that Zend_Config is typically meant to be used in read-only situations but the power of merging has been realised and implemented, making Zend_Config often used in read-write situations aswell (here writing refers to changing the values in the instance, not the source configuration file).</p>
<p>Here is an example of the problem:</p>
<pre lang="php">

$parent = new Zend_Config(array('key' => array('nested' => 'parent')), true); //allow read-write for merging
$newConfig = clone $parent;
$newConfig->merge(new Zend_Config(array('key' => array('nested' => 'override')), true));
echo $newConfig->key->nested; // 'override'  - as expected
echo $parent->key->nested; // 'override' - I was expecting this to be 'parent'
</pre>
<p>This is actually perfectly reasonable behaviour for a shallow clone &#8211; The nested data value was cloned only by reference so (Zend_Config) $newConfig-&gt;key is actually a reference to the original (Zend_Config) $parent-&gt;key object and so changing any one will affect the other. However, this is not what I would expect to happen when cloning a Zend_Config object.</p>
<h2>Solution 1: toArray</h2>
<p>The toArray solution is simple: Flatten the Zend_Config object to a simple array and create a brand new Zend_Config object with the data. All objects are copied into the array and we get a deep copy of the object.</p>
<pre lang="php">$parent = new Zend_Config(array('key' => array('nested' => 'parent')), true); //allow read-write for merging
$newConfig = new Zend_Config($parent->toArray(), true); //cast the parent object to an array and create a new Zend_Config
$newConfig->merge(new Zend_Config(array('key' => array('nested' => 'override')), true));
echo $newConfig->key->nested; // 'override'  - as expected
echo $parent->key->nested; // 'parent' - as expected
</pre>
<h2>Solution 2: Performing a Deep Clone</h2>
<p>OK &#8211; That&#8217;s how deep cloning is achieved with the current release but what about the problem of the misleading and unexpected operation of the clone construct? The simple and intuitive solution is to create a __clone() method that generates a full deep clone which is completely independent:</p>
<pre lang="php">

    /**
     * Perform a deep clone of this instance to allow side-effect free cloning.
     * @return void
     */
    public function __clone()
    {
        $data = array();
        foreach ($this->_data as $key => $value)
        {
            if ($value instanceof Zend_Config)
            {
                $data[$key] = clone $value;
            } else {
                $data[$key] = $value;
            }
        }
        $this->_data = $data;
    }
</pre>
<p>Now we can do a full clone intuitively without having to cast to an array first:</p>
<pre lang="php">

$parent = new Zend_Config(array('key' => array('nested' => 'parent')), true); //allow read-write for merging
$newConfig = clone $parent;
$newConfig->merge(new Zend_Config(array('key' => array('nested' => 'override')), true));
echo $newConfig->key->nested; // 'override'  - as expected
echo $parent->key->nested; // 'parent' - as expected
</pre>
<h2>Summary</h2>
<p>To summarise, cloning a Zend_Config object doesn&#8217;t have intuitive results due to shallow cloning. To get a full clone we must cast the original object to an array before creating a brand new instance. Alternatively, the Zend_Config class should implement deep cloning to get the desired and expected behaviour.</p>
<p>Test cases, the extended class, and a patch can be downloaded <a title="Zend Config Clone Test Cases" href="http://www.destiny-denied.co.uk/files/ZendConfigClone.zip">here</a> (tests work on R9566 as provided in the file).</p>
<h3>Supporting Test Cases</h3>
<pre lang="php">

/**
 * This file is part of ZendConfigClone
 *
 * @package   ZendConfigClone
 * @author    Daniel Skinner
 */
require_once dirname(__FILE__) . '/../AbstractTest.php';
/**
 */
class ZendConfigCloneTest extends AbstractTest
{
    /**
     * 0 - Use original Zend_Config object R9566
     * 1 - Use new ZendConfigClone object
     *
     */
	const VERSION = 1;
    public function setUp ()
    {
        $this->baseConfig = self::factory(array(
            'value1' => 'base1',
            'value2' => array(
                'nestedkey' => 'nestedvalue'
            )
        ), true);
    }
    /**
     * As expected, flattening the object into an array prevents any
     * references from being maintained and allows for a complete clone
     * of the Zend_Config object.
     *
     */
    public function testToArrayDoesNotKeepReferences()
    {
    	$newConfig = self::factory($this->baseConfig->toArray(), true);
    	$newConfig->value1 = 'newvalue1';

    	$this->assertNotEquals($newConfig->value1, $this->baseConfig->value1);
    	$this->assertEquals($newConfig->value2->nestedkey, $this->baseConfig->value2->nestedkey);
    }
    /**
     * As expected, flattening the object into an array prevents any
     * references from being maintained and allows for a complete clone
     * of the Zend_Config object.
     *
     */
    public function testNestedToArrayDoesNotKeepReferences()
    {
        $newConfig = self::factory($this->baseConfig->toArray(), true);
        $newConfig->value2->nestedkey = 'newvalue1';

        $this->assertNotEquals($newConfig->value2->nestedkey, $this->baseConfig->value2->nestedkey);
    }
    /**
     * With the current Zend_Config, a shallow clone will copy
     * first level values correctly.
     *
     */
    public function testShallowCloneDoesNotKeepReferences()
    {
        $newConfig = clone $this->baseConfig;
        $newConfig->value1 = 'newvalue1';

        $this->assertNotEquals($newConfig->value1, $this->baseConfig->value1);
    }
    /**
     * Currently cloning Zend_Config isn't side-effect free.
     *
     * A shallow clone means deep nested Zend_Config objects are
     * not cloned and changing values in the cloned object still
     * affects the original.
     *
     * This test should pass with ZendConfigClone
     *
     */
    public function testDeepCloneDoesNotKeepReferences()
    {
        $newConfig = clone $this->baseConfig;
        $newConfig->value2->nestedkey = 'newvalue1';

        $this->assertNotEquals($newConfig->value2->nestedkey, $this->baseConfig->value2->nestedkey);
    }
    /**
     * Factory method for generating a concrete Zend_Config instance
     *
     * @param mixed $arg,... Arguments to pass to the constructor
     * @return Zend_Config
     */
    private static function factory()
    {
    	$args = func_get_args();
    	switch (self::VERSION)
    	{
    		//Zend_Config
    		case 0:
    			$refObj = new ReflectionClass('Zend_Config');
    			return $refObj->newInstanceArgs($args);
    			break;
    		//ZendConfigClone
    		case 1:
                $refObj = new ReflectionClass('ZendConfigClone');
                return $refObj->newInstanceArgs($args);
    			break;
    	}
    	throw new Exception('VERSION should be enum{0, 1}');
    }
}
</pre>
<h3>A new class with deep clone functionality for testing:</h3>
<pre lang="php">

/**
 * This file is part of ZendConfigClone
 *
 * @package   ZendConfigClone
 * @author    Daniel Skinner
 */

class ZendConfigClone extends Zend_Config
{
    /**
     * Perform a deep clone of this instance to allow side-effect free cloning.
     * @return void
     */
    public function __clone()
    {
        $data = array();
        foreach ($this->_data as $key => $value)
        {
            if ($value instanceof Zend_Config)
            {
                $data[$key] = clone $value;
            } else {
                $data[$key] = $value;
            }
        }
        $this->_data = $data;
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.daniel-skinner.co.uk/cloning-zend_config-without-side-effects/26/08/2008/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Hair by Caroline</title>
		<link>http://www.daniel-skinner.co.uk/hair-by-caroline/14/04/2008</link>
		<comments>http://www.daniel-skinner.co.uk/hair-by-caroline/14/04/2008#comments</comments>
		<pubDate>Mon, 14 Apr 2008 23:05:39 +0000</pubDate>
		<dc:creator>Emma Place</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.daniel-skinner.co.uk/hair-by-caroline/14/04/2008</guid>
		<description><![CDATA[Hair by Caroline first launched back in 2005&#8230;three years down the line and we decided it was in great need of a re-design. It was also important to update the content, adding more material and creating a new gallery was among the important factors to consider.
15thApril 2008 has been re-launched, with a new and improved [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.hairbycaroline.co.uk" title="Hair Salon Castleford">Hair by Caroline</a> first launched back in 2005&#8230;three years down the line and we decided it was in great need of a re-design. It was also important to update the content, adding more material and creating a new gallery was among the important factors to consider.</p>
<p>15thApril 2008 has been re-launched, with a new and improved navigation, modern images and a whole lot more content to help improve its ranking in the search engines.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.daniel-skinner.co.uk/hair-by-caroline/14/04/2008/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Yicrosoft Directory Competition</title>
		<link>http://www.daniel-skinner.co.uk/yicrosoft-directory-competition/09/02/2008</link>
		<comments>http://www.daniel-skinner.co.uk/yicrosoft-directory-competition/09/02/2008#comments</comments>
		<pubDate>Sat, 09 Feb 2008 00:20:20 +0000</pubDate>
		<dc:creator>Emma Place</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[yicrosoft]]></category>
		<category><![CDATA[yicrosoft directory]]></category>

		<guid isPermaLink="false">http://www.daniel-skinner.co.uk/yicrosoft-directory-competition/09/02/2008</guid>
		<description><![CDATA[Ryan at SEO Noobs have hosted a competition, which many of you are probably aware of by now. The key word is “Yicrosoft Directory” which is a word which had zero results in the Google search when the competition started; it’s also a word that has been put together in the light of Microsoft’s $44.6 [...]]]></description>
			<content:encoded><![CDATA[<p>Ryan at <a href="http://seonoobs.com/" rel="external nofollow">SEO Noobs</a> have hosted a competition, which many of you are probably aware of by now. The key word is “<strong><a href="http://yicrosoftdirectory.com" rel="external">Yicrosoft Directory</a></strong>” which is a word which had zero results in the Google search when the competition started; it’s also a word that has been put together in the light of <a href="http://yicrosoftdirectory.com/2008/microsoft-and-yahoo-merge/" rel="external">Microsoft’s $44.6 billion bid to take over Yahoo</a>. All the competitors have until 4<sup>th</sup> March 2008 to produce a website to appear at number one in Google.com search engine rankings. I decided to take part in this competition, not only because it is interesting but to also give myself the opportunity to create and optimise the content of a website the best I can. I guess this is really going to test my skills as a writer! If I can aim to post something remotely interesting daily, perhaps I could get the site to page one! Who knows, but as time goes on more and more people are entering the competition, the Google search alone now holds nearly 2,000 results for “<strong><a href="http://yicrosoftdirectory.com" rel="external">Yicrosoft Directory</a></strong>”. Only time will tell! Of course everyone is in it to win but in all honesty if our website makes it to number one in the Google search I will be more than happy. I’ll keep you all posted on the progression.</p>
<p>I decided to create a Yahoo Directory parody website: <strong><a href="http://yicrosoftdirectory.com" rel="external">http://yicrosoftdirectory.com/</a></strong>. At this point I would like to invite everyone and anyone to submit any type of original, written content to help broaden the horizons! Your help would be much appreciated. If you don’t have anything to say why not come along and vote on the poll anyway.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.daniel-skinner.co.uk/yicrosoft-directory-competition/09/02/2008/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zend Certified Engineer!</title>
		<link>http://www.daniel-skinner.co.uk/zend-certified-engineer/31/01/2008</link>
		<comments>http://www.daniel-skinner.co.uk/zend-certified-engineer/31/01/2008#comments</comments>
		<pubDate>Thu, 31 Jan 2008 17:01:27 +0000</pubDate>
		<dc:creator>Daniel Skinner</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zce]]></category>
		<category><![CDATA[zend]]></category>

		<guid isPermaLink="false">http://www.daniel-skinner.co.uk/zend-certified-engineer/31/01/2008</guid>
		<description><![CDATA[I finally got round to booking the Zend PHP 5 Exam and successfully passed earlier this week!]]></description>
			<content:encoded><![CDATA[<p>I finally got round to booking the Zend PHP 5 Exam and successfully passed earlier this week!</p>
<p>I didn&#8217;t think that the exam was particularly hard but whilst revising I did learn about a few interesting features of the language.</p>
<p>I would recommend becoming a Zend Engineer to anyone who is serious about PHP software development. If anyone is interested I have a few online practice exams going spare.</p>
<p>For more information on Zend certification, see <a title="ZCE" rel="nofollow" href="http://en.wikipedia.org/wiki/ZCE">this article</a></p>
<p><a rel="nofollow external" href="http://www.zend.com/store/education/certification/authenticate.php?ClientCandidateID=ZEND006969&amp;RegistrationID=223910931"><img src="http://www.zend.com/images/training/php5_zce_logo.gif" title="Zend Certified Engineer" alt="Zend Certified Engineer" width="73" height="47" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.daniel-skinner.co.uk/zend-certified-engineer/31/01/2008/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Nofollow on WordPress Comments Still?</title>
		<link>http://www.daniel-skinner.co.uk/nofollow-on-wordpress-comments-still/15/01/2008</link>
		<comments>http://www.daniel-skinner.co.uk/nofollow-on-wordpress-comments-still/15/01/2008#comments</comments>
		<pubDate>Tue, 15 Jan 2008 18:54:27 +0000</pubDate>
		<dc:creator>Daniel Skinner</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[wordpress nofollow]]></category>

		<guid isPermaLink="false">http://www.daniel-skinner.co.uk/nofollow-on-wordpress-comments-still/15/01/2008</guid>
		<description><![CDATA[I have only just noticed that comments on this WordPress blog have rel=&#8221;nofollow&#8221; set as default. I believe that if someone is willing to contribute to a blog by commenting then the least they deserve is an inlink to their site.
A quick search shows that this is the default for all WordPress installations. The main [...]]]></description>
			<content:encoded><![CDATA[<p>I have only just noticed that comments on this WordPress blog have rel=&#8221;nofollow&#8221; set as default. I believe that if someone is willing to contribute to a blog by commenting then the least they deserve is an inlink to their site.</p>
<p>A quick search shows that this is the default for all WordPress installations. The main reason seems to be to dissuade <a href="http://forums.digitalpoint.com/showthread.php?t=653429" rel="external nofollow">spamming</a>. However, with the new Akismet anti-spam plugin I have never seen one spam comment get through the net. Is it time for WordPress to change the default setting and give commenters at least a bit of recognition?</p>
<h3>Nofollow Free</h3>
<p>I don&#8217;t see the reason for nofollow and I am more than willing to give people some recognition for commenting on my blog.  Bloggers should encourage quality comments as much as possible. For this reason I have installed the <a href="http://wordpress.org/extend/plugins/nofollow-case-by-case/" rel="external nofollow">Nofollow Case by Case</a> plugin to remove nofollow from links by default and <strong>this blog is now nofollow free</strong>.</p>
<h3>Is there a reason?</h3>
<p>Have I missed the real reason for nofollow on comments? Is it time for WordPress to change the default setting? Are commenters more inclined to comment on a blog that doesn&#8217;t use nofollow?</p>
<p>Feel free to give your opinions and correct me if I am wrong, there is a little bit on link juice in it for you! :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.daniel-skinner.co.uk/nofollow-on-wordpress-comments-still/15/01/2008/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Setup Subversion and Trac on CentOS 5</title>
		<link>http://www.daniel-skinner.co.uk/setup-subversion-and-trac-on-centos-5/06/01/2008</link>
		<comments>http://www.daniel-skinner.co.uk/setup-subversion-and-trac-on-centos-5/06/01/2008#comments</comments>
		<pubDate>Sun, 06 Jan 2008 17:19:17 +0000</pubDate>
		<dc:creator>Daniel Skinner</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Guides]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[trac]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[version control]]></category>

		<guid isPermaLink="false">http://www.daniel-skinner.co.uk/setup-subversion-and-trac-on-centos-5/06/01/2008</guid>
		<description><![CDATA[Recently I set up a virtual server to use as a development machine. It runs on CentOS 5 and hosts several Subversion repositories with associated Trac projects.
There are many guides and plenty of help on the net to help you setup such a system. However, when I tried to do it I came across a [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I set up a virtual server to use as a development machine. It runs on CentOS 5 and hosts several <a href="http://subversion.tigris.org/" title="Subversion" rel="external">Subversion</a> repositories with associated <a href="http://trac.edgewall.org/" title="Trac" rel="external">Trac</a> projects.</p>
<p>There are many guides and plenty of help on the net to help you setup such a system. However, when I tried to do it I came across a few problems and I hope this post may help at least a few people trying to do the same as me. I am not going to rewrite the great tutorials out there, I will just point you to them and note what things I did differently.</p>
<p>This &#8216;guide&#8217; should get you from a fresh install of CentOS 5 linux to one or more working Subversion (<abbr title="Subversion">SVN</abbr>) repositories and associated Trac wiki&#8217;s. Apache/WebDAV is used as the network layer. I have only tested this on a fresh install of CentOS 5.</p>
<p><span id="more-18"></span></p>
<h2>The Environment</h2>
<p>I am aiming for the following:</p>
<ul>
<li>CentOS 5, <abbr title="Subversion">SVN</abbr> installed. Apache2 as the network layer using mod_dav_svn.</li>
<li>Trac running on Apache with mod_python</li>
<li><abbr title="Subversion">SVN</abbr> repositories located at: /srv/svn (e.g. /srv/svn/my-project), accessible via http://server/svn/my-project</li>
<li>Trac projects located at: /srv/trac (e.g /srv/trac/my-project) accessible via http://server/trac/my-project</li>
</ul>
<h2>How I did it</h2>
<p>Not all the steps are vital (probably) but this is how I got it working. Feel free to skip any non-relevant steps (i.e. there is probably no need for a fresh install). Replace any occurence of <span class="inline-code">&lt;project&gt;</span> with the name of your first project.</p>
<p><strong>1.</strong> Fresh install of CentOS. I followed most of the <a href="http://www.howtoforge.com/perfect_setup_centos5.0" title="The Perfect Setup: CentOS 5.0" rel="external">Perfect Setup Guide</a>, except the mail and ISPConfig stuff. The important part is setting up the Apache2 web server.</p>
<p><strong>2.</strong> Make sure <abbr title="Subversion">SVN</abbr> and mod_dav_svn are installed. As root:</p>
<pre>yum install subversion mod_dav_svn</pre>
<pre>vim /etc/httpd/conf/httpd.conf</pre>
<p>If the following two lines are not present, add them:</p>
<pre>LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so</pre>
<p><strong>3.</strong> Install Trac: Follow <a href="http://www.techyouruniverse.com/software/installing-trac-with-subversion-on-cent-os-5-with-neon-and-quicksilver" title="Installing Trac with SubVersion on CentOS 5" rel="external">Nick&#8217;s guide</a> with the alternative Clearsilver installation below. Skip the Apache Configuration part.</p>
<p>Follow all of parts 1 and 2. Instead of part 3 do:</p>
<pre>wget http://dag.wieers.com/rpm/packages/clearsilver/clearsilver-0.10.4-1.el5.rf.i386.rpm
rpm -i clearsilver-0.10.4-1.el5.rf.i386.rpm
wget http://dag.wieers.com/rpm/packages/clearsilver/python-clearsilver-0.10.4-1.el5.rf.i386.rpm
rpm -i python-clearsilver-0.10.4-1.el5.rf.i386.rpm</pre>
<p>Continue with parts 4.1 and 4.2 of Nick&#8217;s guide. Remember, leave out Apache configuration section.</p>
<p><strong>4. </strong>Create your first <abbr title="Subversion">SVN</abbr> Repository:</p>
<pre>svnadmin create --fs-type fsfs /srv/svn/&lt;project&gt;</pre>
<p><strong>5.</strong> Initialise a Trac project for your new repository:</p>
<pre>trac-admin /srv/trac/&lt;project&gt; initenv</pre>
<p>For the trac-admin command use the defaults if not sure, giving a descriptive name for the project. The `Path to repository` is: <span class="inline-code">/srv/svn/&lt;project&gt;</span>.</p>
<p><strong>6.</strong> Set the correct file permissions for apache</p>
<pre>chown -R apache.apache /srv/svn/&lt;project&gt;
chown -R apache.apache /srv/trac/&lt;project&gt;</pre>
<p><strong>7.</strong> Tell apache where to find the new repository. Here we create an additional Apache configuration file specifically for the <abbr title="Subversion">SVN</abbr> repositories.</p>
<pre>vim /etc/httpd/conf.d/subversion.conf</pre>
<p>Add the following directive:</p>
<pre>&lt;Location /svn/&lt;project&gt;&gt;
	DAV svn
	SVNPath /srv/svn/&lt;project&gt;
	AuthType Basic
	AuthName "&lt;project&gt; Repository"
	AuthzSVNAccessFile /srv/svn/svn-acl-conf
	AuthUserFile /srv/svn/&lt;project&gt;.htpasswd
	Require valid-user
&lt;/Location&gt;</pre>
<p><strong>8.</strong> Add a repository user:</p>
<pre>touch /srv/svn/&lt;project&gt;.htpasswd
htpasswd -m /srv/svn/&lt;project&gt;.htpasswd &lt;username&gt;</pre>
<p><strong>9. </strong>Create the Access Control List for the SVN Repository</p>
<pre>vim /srv/svn/svn-acl-conf</pre>
<p>Add the following directives:</p>
<pre>[&lt;project&gt;:/]
&lt;username&gt; =  rw</pre>
<p>Where <span class="inline-code">&lt;username&gt;</span> represents the username of the repository user you created earlier.</p>
<p><strong>10.</strong> Tell apache where to find the new Trac project. Here we create an additional Apache configuration file specifically for the Trac projects.</p>
<pre>vim /etc/httpd/conf.d/trac.conf</pre>
<p>Add the following directives:</p>
<pre>&lt;Location /trac/&lt;project&gt;&gt;
	SetHandler mod_python
	PythonHandler trac.web.modpython_frontend
	PythonOption TracEnv /srv/trac/&lt;project&gt;
	PythonOption TracUriRoot /trac/&lt;project&gt;
&lt;/Location&gt;

&lt;Location "/trac/&lt;project&gt;/login"&gt;
	AuthType Basic
	AuthName "trac"
	AuthUserFile /srv/trac/&lt;project&gt;.htpasswd
	Require valid-user
&lt;/Location&gt;</pre>
<p><strong>11.</strong> Add a Trac user:</p>
<pre>touch /srv/trac/&lt;project&gt;.htpasswd
htpasswd -m /srv/trac/&lt;project&gt;.htpasswd &lt;username&gt;</pre>
<p><strong>12.</strong> Give admin permissions to the Trac user you just created:</p>
<pre>trac-admin /srv/trac/&lt;project&gt; permission add &lt;username&gt; TRAC_ADMIN</pre>
<p>Where <span class="inline-code">&lt;username&gt;</span> represents the username of the Trac user you just created.</p>
<p><strong>13.</strong> Restart Apache:</p>
<pre>service httpd restart</pre>
<p>You should now have <abbr title="Subversion">SVN</abbr> and Trac installed. You will have an <abbr title="Subversion">SVN</abbr> repository setup (http://server/svn/&lt;project&gt;) and the Trac wiki (http://server/trac/&lt;project&gt;) associated with the repository.</p>
<p>Please let me know if this helped you. If you come across any problems I will be happy to try and help.</p>
<h2>Resources</h2>
<p>The last part of <a href="http://" title="CentOS HowTos: Subversion">CentOS HowTos: Subversion</a> will give you a quick introduction on how to use <abbr title="Subversion">SVN</abbr>.</p>
<p>Subversion setup guides: <a href="http://www.jimohalloran.com/2006/01/15/subversion-server-on-centos-42/" title="Subversion setup guide" rel="external">here</a> and <a href="http://www.techyouruniverse.com/software/installing-trac-with-subversion-on-cent-os-5-with-neon-and-quicksilver" title="Subversion setup guide" rel="external">here</a></p>
<p>Trac setup guides: <a href="http://trac.edgewall.org/wiki/TracOnRhel4" title="Trac setup guide" rel="external">here</a> and <a href="http://trac.edgewall.org/wiki/TracOnFedoraCore" title="Trac setup guide" rel="external">here</a>.</p>
<p><a href="http://www.clearsilver.net/" title="ClearSilver" rel="external">ClearSilver template system</a> (used by Trac).</p>
<p><a href="http://www.howtoforge.com/perfect_setup_centos5.0_p7" title="The Perfect Setup: CentOS 5.0" rel="external">Setting up CentOS 5.0</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.daniel-skinner.co.uk/setup-subversion-and-trac-on-centos-5/06/01/2008/feed</wfw:commentRss>
		<slash:comments>63</slash:comments>
		</item>
		<item>
		<title>Zend Framework 1.0.3 Released</title>
		<link>http://www.daniel-skinner.co.uk/zend-framework-103-released/30/11/2007</link>
		<comments>http://www.daniel-skinner.co.uk/zend-framework-103-released/30/11/2007#comments</comments>
		<pubDate>Fri, 30 Nov 2007 15:54:44 +0000</pubDate>
		<dc:creator>Daniel Skinner</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[openid]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://www.daniel-skinner.co.uk/zend-framework-103-released/30/11/2007</guid>
		<description><![CDATA[Zend Framework (ZF) 1.0.3 has been released. This is the third maintenance release since the launch of Zend Framework 1.0 at the beginning of July 2007, which goes to show how quickly the ZF community is growing.
Zend Framework is quickly becoming the most popular PHP5 framework, mostly due to the fact that it does not tie you [...]]]></description>
			<content:encoded><![CDATA[<p>Zend Framework (ZF) 1.0.3 has been released. This is the third maintenance release since the launch of Zend Framework 1.0 at the beginning of July 2007, which goes to show how quickly the ZF community is growing.</p>
<p>Zend Framework is quickly becoming the most popular PHP5 framework, mostly due to the fact that it does not tie you to coding in a specific way. You can use individual components or choose to use the entire Model-View-Controller (MVC) architecture. In a post written on the <a title="Zend Blog" rel="external" href="http://blogs.zend.com/2007/11/22/zend-framework-launch-zendcon-roadmap-and-zf-11/">Zend Blog</a>, the ZF team are expecting over 3 million downloads of the framework by the end of the year.</p>
<p>The near future roadmap for ZF includes adding support for even more web services and providing a standard solution for handling web forms. There will also be improvements in the online documentation (which is already an excellent reference) and tutorials as well as support for <a title="Open ID - An open and decentralized identity system" rel="external" href="http://openid.net/">OpenID.</a></p>
<p>We can expect some of these features to be ready for the upcoming 1.1.0 release which is expected in the first quarter of 2008.</p>
<p>For more information, see <a title="ZF Components" rel="external" href="http://framework.zend.com/manual/components">Zend Framework Components</a> and the <a title="ZF Roadmap" rel="external" href="http://framework.zend.com/whyzf/future/">Zend Framework roadmap</a>.</p>
<p><a title="Download ZF" rel="external" href="http://framework.zend.com/download">Download Zend Framework</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.daniel-skinner.co.uk/zend-framework-103-released/30/11/2007/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
