 

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>Paul Herron: Articles</title>
		<link>http://www.paulherron.net</link>
		<description>Recent articles published by Paul Herron.</description>
		<language>en-us</language>
		<pubDate>Tue, 8 Jul 2008 22:09:44 GMT</pubDate>
		<docs>http://blogs.law.harvard.edu/tech/rss</docs>
		<generator>CakePHP</generator>  
		<item>
			<title>Fat Links in CakePHP</title>
			<link>http://www.paulherron.net/articles/view/fat_links_in_cakephp</link>
			<description>&lt;p&gt;
Occasionally, several links are relevant to the same piece of text. The usual approach to presenting this is to apply separate anchors to individual words within that text:
&lt;/p&gt;
&lt;blockquote&gt;
	&lt;div&gt;
	There are &lt;a href=&quot;http://google.com&quot;&gt;many&lt;/a&gt; &lt;a href=&quot;http://yahoo.com&quot;&gt;search&lt;/a&gt; &lt;a href=&quot;http://www.searchmash.com/&quot;&gt;engines&lt;/a&gt; available...
	&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;
This of course makes very little sense semantically, and it might not be immediately obvious that more than one link is available.
&lt;/p&gt;
&lt;p&gt;
Another option is to make a &lt;code&gt;ul&lt;/code&gt; or an &lt;code&gt;ol&lt;/code&gt; and place that inline within the document. That can be detrimental to the flow of the text though, and isn't really in the non-linear spirit of hypertext.
&lt;/p&gt;
&lt;p&gt;
The solution below takes a fat link approach, whereby several &lt;abbr title=&quot;Uniform Resource Locator&quot;&gt;URL&lt;/abbr&gt;s are rolled into one. An appropriate script can then extract the links and present them as a list on their own page.
&lt;/p&gt;
&lt;blockquote&gt;
	&lt;div&gt;
	There are &lt;a href=&quot;../../links/Google|http://google.com;Yahoo|http://yahoo.com;SearchMash|http://www.searchmash.com/&quot;&gt;many search engines&lt;/a&gt; available...
	&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;
This code is written for Cake&lt;abbr title=&quot;PHP Hypertext Preprocessor &quot;&gt;PHP&lt;/abbr&gt; 1.2, and has a controller action processing the fat link before sending an array of links to the view:
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[php]&amp;lt;?php&lt;br /&gt;
class LinksController extends AppController&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;var $argSeparator = &amp;quot;|&amp;quot;;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;function index()&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;$links = explode(';', str_replace('/' . $this-&amp;gt;params['controller'] . '/', '', $_SERVER['REQUEST_URI']));&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;foreach ($links as $key =&amp;gt; $link) {&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// If link text is present...&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;if (preg_match('^\|^', $link)) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;$link = explode('|', $link);&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;$links[$key] = array('text' =&amp;gt; urldecode($link[0]), 'href' =&amp;gt; $link[1]);&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// If no link text is present...&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;} else {&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;$links[$key] = array('text' =&amp;gt; $link, 'href' =&amp;gt; $link);&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;$this-&amp;gt;set('links', $links);&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;[/php]
&lt;/div&gt;
&lt;p&gt;
The view then outputs the array's values as an unordered list:
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[php]&amp;lt;h1&amp;gt;My list of links&amp;lt;/h1&amp;gt; &amp;lt;?php if (!empty($links)) { ?&amp;gt; &lt;br /&gt;
&amp;lt;ul&amp;gt; &amp;lt;?php foreach ($links as $link) { ?&amp;gt; &lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;li&amp;gt;&amp;lt;?php echo $html-&amp;gt;link($link['text'], $link['href']); ?&amp;gt;&amp;lt;/li&amp;gt; &amp;lt;?php } ?&amp;gt; &lt;br /&gt;
&amp;lt;/ul&amp;gt; &amp;lt;?php } ?&amp;gt;[/php]
&lt;/div&gt;
&lt;p&gt;
Finally, an optional extra is to declare a route to remove the need for '/index' to be included in the URL. This will appear in app/config/routes.php like so:
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[php]$Route-&amp;gt;connect ('/links/*', array('controller'=&amp;gt;'links', 'action'=&amp;gt;'index'));[/php]
&lt;/div&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;h3&gt;Simple links&lt;/h3&gt;
&lt;p&gt;
A series of simple links. No anchor text is defined, so the &lt;code&gt;href&lt;/code&gt; is presented instead. Links are separated with a semi-colon.
&lt;/p&gt;
&lt;blockquote&gt;
	&lt;div&gt;
	&lt;a href=&quot;http://paulherron.net/links/http://google.com;http://yahoo.com&quot;&gt;
	http://paulherron.net/links/http://google.com;http://yahoo.com&lt;/a&gt;
	&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Links with anchor text&lt;/h3&gt;
A series of simple links with anchor text specified. A pipe symbol separated the anchor text from the link itself.&lt;br /&gt;
&lt;blockquote&gt;
	&lt;div&gt;
	&lt;a href=&quot;http://paulherron.net/links/Google|http://google.com;Yahoo|http://yahoo.com&quot;&gt;
	http://paulherron.net/links/Google|http://google.com;Yahoo|http://yahoo.com&lt;/a&gt;
	&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Relative links&lt;/h3&gt;
Relative links work in a similar way.&lt;br /&gt;
&lt;blockquote&gt;
	&lt;div&gt;
	&lt;a href=&quot;http://paulherron.net/links/Articles|/articles&quot;&gt;
	http://paulherron.net/links/Articles|/articles&lt;/a&gt;
	&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Any mixture of the above&lt;/h3&gt;
&lt;blockquote&gt;
	&lt;div&gt;
	&lt;a href=&quot;http://paulherron.net/links/http://google.com;Yahoo|http://yahoo.com;Articles|/articles&quot;&gt;
	http://paulherron.net/links/http://google.com;Yahoo|http://yahoo.com;Articles|/articles&lt;/a&gt;
	&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Considerations&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;Be warned that spammers love to get their links on websites, and this method provides an open opportunity to do just that. Think carefully about where to implement it, and keep an eye on your analytics for signs of abuse.  &lt;/li&gt;
	&lt;li&gt;The syntax chosen to separate the links is important. In the above example, &lt;code&gt;|&lt;/code&gt; and &lt;code&gt;;&lt;/code&gt; are used as separators. These are arbitrary; any glyphs can be used so long as they don't appear in any of the &lt;abbr title=&quot;Uniform Resource Locator&quot;&gt;URL&lt;/abbr&gt;s you're trying to list.&lt;/li&gt;
	&lt;li&gt;For simplicity, I've presented the bulk of this code in the controller. It might be tidier to make something like a &lt;code&gt;LinkComponent&lt;/code&gt; and simply call that from the controller.&lt;/li&gt;
	&lt;li&gt;There might be a more Cakeish way to achieve this. For example, an alternative to &lt;code&gt;$_SERVER['REQUEST_URI']&lt;/code&gt; could be a &lt;code&gt;:links&lt;/code&gt; declaration in a custom route. This would grab the links string and pass it to the controller, but some tweaking would be required to stop Cake stripping out things like &lt;code&gt;http://&lt;/code&gt; from the links.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.useit.com/alertbox/20050103.html&quot;&gt;Reviving Advanced Hypertext&lt;/a&gt;, an article by Jakob Nielsen &lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Fat_link&quot;&gt;Fat Link article at Wikipedia&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
</description>
			<pubDate>2008-01-20 01:31:16</pubDate>
			<guid>http://www.paulherron.net/articles/view/fat_links_in_cakephp</guid>
		</item>  
		<item>
			<title>Managing Simple Pages in CakePHP</title>
			<link>http://www.paulherron.net/articles/view/managing_simple_pages_in_cakephp</link>
			<description>&lt;p&gt;
As well as complex functionality like blogs or product listings, websites often need simple pages. An &lt;em&gt;about us&lt;/em&gt; or &lt;em&gt;our services &lt;/em&gt;page, for example, might consist of only text and images.
&lt;/p&gt;
&lt;p&gt;
Cake&lt;abbr title=&quot;PHP Hypertext Preprocessor&quot;&gt;PHP&lt;/abbr&gt; has two obvious ways to set up simple pages like these. The first is to drop a view file into &lt;code&gt;app/views/pages&lt;/code&gt;. This is quick and easy, but the page won't be dynamic and the standard &lt;abbr title=&quot;Uniform Resource Locator&quot;&gt;URL&lt;/abbr&gt;s of &lt;code&gt;/pages/about&lt;/code&gt; and &lt;code&gt;/pages/services&lt;/code&gt; might seem strange when, from the user's perspective, &lt;code&gt;/about&lt;/code&gt; and &lt;code&gt;/services&lt;/code&gt; would be more logical.
&lt;/p&gt;
&lt;p&gt;
The second approach is to set up controllers and views for the pages. The above example could use an &lt;code&gt;AboutController&lt;/code&gt; and a &lt;code&gt;ServicesController&lt;/code&gt;, each with their own empty &lt;code&gt;index()&lt;/code&gt; action and an &lt;code&gt;index.ctp&lt;/code&gt; view file. The pages are now accessible at intuitve &lt;abbr title=&quot;Uniform Resource Locator&quot;&gt;URL&lt;/abbr&gt;s - &lt;code&gt;/about&lt;/code&gt; and &lt;code&gt;/services&lt;/code&gt; - and page content can easily be managed in the database, rather than being hard-coded into the view files. The disadvantage of this approach is that coding would be required to add new pages.
&lt;/p&gt;
&lt;h2&gt;Alternative Approach&lt;/h2&gt;
&lt;p&gt;
The best aspects of the techniques mentioned above can be combined by introducing the following:
&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;
	A &lt;code&gt;Page&lt;/code&gt; model. This will store all of the website's simple pages.&lt;/li&gt;
	&lt;li&gt;A dynamic route in &lt;code&gt;routes.php&lt;/code&gt;. This will recognise &lt;abbr title=&quot;Uniform Resource Locator&quot;&gt;URL&lt;/abbr&gt; requests for stored pages and route them through to the &lt;code&gt;PagesController&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The pages database table might look something like this:
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[sql]&amp;nbsp; `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&amp;nbsp; `title` TEXT,&lt;br /&gt;
&amp;nbsp; `slug` varchar(255),&lt;br /&gt;
&amp;nbsp; `content` TEXT,&lt;br /&gt;
&amp;nbsp; `created` datetime,&lt;br /&gt;
&amp;nbsp; `modified` datetime[/sql]
&lt;/div&gt;
&lt;p&gt;
The slug field is simply the relative &lt;abbr title=&quot;Uniform Resource Locator&quot;&gt;URL&lt;/abbr&gt; at which the page will be accessible. For example, a slug of &lt;code&gt;about&lt;/code&gt; will be used to set up a page at http://example.com/about and a slug of &lt;code&gt;services/technical&lt;/code&gt; will be available at http://example.com/services/technical.
&lt;/p&gt;
&lt;p&gt;
A &lt;code&gt;PagesController&lt;/code&gt; and corresponding views should be set up. A main &lt;code&gt;index()&lt;/code&gt; action will be used to display the stored pages. Admin actions such as &lt;code&gt;admin_add()&lt;/code&gt; could also be used to allow editing of the pages' content. It might also be worth taking a copy of Cake's core &lt;code&gt;display()&lt;/code&gt; action from &lt;code&gt;cake/libs/controller/pages_controller.php&lt;/code&gt; so that static pages in &lt;code&gt;app/views/pages&lt;/code&gt; can still be displayed.
&lt;/p&gt;
&lt;p&gt;
A route is then required to send requests for stored pages to &lt;code&gt;PagesController::index()&lt;/code&gt;. To recognise which &lt;abbr title=&quot;Uniform Resource Locator&quot;&gt;URL&lt;/abbr&gt;s correspond to stored pages, it will be necessary to load and query the &lt;code&gt;Page&lt;/code&gt; model. This gives us a list of slugs to add as conditions to the &lt;code&gt;$params&lt;/code&gt; array of the route. This could be done by putting the following code in &lt;code&gt;app/config/routes.php&lt;/code&gt;:
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[php]// Load details of stored pages. &lt;br /&gt;
uses('model' . DS . 'model');&lt;br /&gt;
loadModel('Page');&lt;br /&gt;
$Page = new Page();&lt;br /&gt;
$pages = $Page-&amp;gt;generateList(null,'slug DESC',null,null,'{n}.Page.slug');&lt;br /&gt;
&lt;br /&gt;
//If the URL matches the slug of a stored page, route to PagesController::index() and set $this-&amp;gt;params['page'] to whatever the slug is.&lt;br /&gt;
$Route-&amp;gt;connect ('/:page/*', array('controller'=&amp;gt;'pages', 'action'=&amp;gt;'index'), array('page' =&amp;gt; implode($pages, '|')));[/php]
&lt;/div&gt;
&lt;p&gt;
Note: It's important to retrieve the page slugs in descending alphabetical order, otherwise child pages will wrongly be routed to their parents. For example, if 'services' appears in the &lt;code&gt;$params&lt;/code&gt; array before 'services/technical', a &lt;abbr title=&quot;Uniform Resource Locator&quot;&gt;URL&lt;/abbr&gt; requesting 'services/technical' would be routed to 'services'.
&lt;/p&gt;
&lt;p&gt;
The &lt;code&gt;PagesController&lt;/code&gt; is then free to pick up &lt;code&gt;$this-&amp;gt;params['page']&lt;/code&gt; and fetch the relevant page using &lt;code&gt;$this-&amp;gt;Page-&amp;gt;findBySlug($this-&amp;gt;params['page'])&lt;/code&gt;.
&lt;/p&gt;
&lt;h2&gt;Extending the Idea&lt;/h2&gt;
&lt;p&gt;
This is a simple description of the technique; it could of course be extended in any number of ways. For example:&lt;br /&gt;
&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;
	The actual page content could be stored in a separate &lt;code&gt;sections&lt;/code&gt; table. Associations could then be set up to say that a page &lt;code&gt;hasMany&lt;/code&gt; sections and a section &lt;code&gt;belongsTo&lt;/code&gt; a page. This would allow any section on a page to be linked to directly, e.g. &lt;code&gt;/services/technical#programming&lt;/code&gt;. An extension of this would be outputting an 'on this page' element which lists and links to each section on the current page. &lt;/li&gt;
	&lt;li&gt;
	Pages could be given a &lt;code&gt;parent_id&lt;/code&gt;, making a hierarchical page structure possible. For example, &lt;code&gt;/services&lt;/code&gt; could be displayed as being a parent of &lt;code&gt;/services/technical&lt;/code&gt;. &lt;/li&gt;
	&lt;li&gt;
	Pages could be assigned positions on navigation menus. For example, a link to the &lt;code&gt;/about&lt;/code&gt; page could be set to appear on the site's main navigation menu.&lt;/li&gt;
&lt;/ul&gt;
</description>
			<pubDate>2007-07-15 14:12:37</pubDate>
			<guid>http://www.paulherron.net/articles/view/managing_simple_pages_in_cakephp</guid>
		</item>  
		<item>
			<title>A CakePHP Component for the Servage SMS API</title>
			<link>http://www.paulherron.net/articles/view/servage_sms_api_cakephp_component</link>
			<description>Being a &lt;a href=&quot;http://www.servage.net/&quot;&gt;Servage&lt;/a&gt; customer, I'm using its &lt;abbr title=&quot;Short Message Service&quot;&gt;SMS&lt;/abbr&gt; &lt;abbr title=&quot;Application Programming Interface&quot;&gt;API&lt;/abbr&gt;, which offers two main features:
&lt;ul&gt;
	&lt;li&gt;Check if a text message can be sent to a specified number.&lt;/li&gt;
	&lt;li&gt;Send a text message to a specified number. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Servage provides some example code for doing this, which I've rewritten as a Cake&lt;abbr title=&quot;PHP Hypertext Preprocessor&quot;&gt;PHP&lt;/abbr&gt; component.
&lt;/p&gt;
&lt;h2&gt;app/controllers/components/sms.php 
&lt;/h2&gt;
&lt;div class=&quot;codebox&quot;&gt;
[php]&amp;lt;?php &lt;br /&gt;
class SmsComponent extends Object {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; // The Servage URL for posting messages.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; var $send_url = 'http://smsgateway.servage.net/sms.php';&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; // The Servage URL for requesting coverage information. &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; var $coverage_url = 'http://smsgateway.servage.net/sms_coverage.php';&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; // Customer ID.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; var $customer = '00000';&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; // Customer key.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; var $key = '00000000';&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
&amp;nbsp;* Sends an SMS message to the specified number.&lt;br /&gt;
&amp;nbsp;* &lt;br /&gt;
&amp;nbsp;* @param int $to The phone number to which the message should be sent.&lt;br /&gt;
&amp;nbsp;* @param mixed $message The message to be sent.&lt;br /&gt;
&amp;nbsp;* @param mixed $from The name or number of the sender.&lt;br /&gt;
&amp;nbsp;* @param int $concat The number of messages to join when sending.&lt;br /&gt;
&amp;nbsp;* @return boolean True if the message was successfully posted to Servage.&lt;br /&gt;
&amp;nbsp;*/&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; function send($to,$message,$from = null,$concat = 1) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; // Add the parameters to the request URL.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; $request = $this-&amp;gt;send_url.'?customer='.$this-&amp;gt;customer.'&amp;amp;key='.$this-&amp;gt;key.'&amp;amp;number='.urlencode($to).'&amp;amp;message='.urlencode($message).'&amp;amp;concat='.$concat;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; if (!is_null($from))&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; $request .= '&amp;amp;from=' . $from;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; // Make the request.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; $ch = curl_init();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; curl_setopt($ch, CURLOPT_URL, $request);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; curl_setopt($ch, CURLOPT_HEADER, 0);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; $response = curl_exec($ch);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; curl_close($ch);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; // Get the status from the response string.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; $result = split(',',$response);&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; if ($result[0] == 'OK')&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
/**&lt;br /&gt;
&amp;nbsp;* Checks if coverage can be provided for the specified number.&lt;br /&gt;
&amp;nbsp;* &lt;br /&gt;
&amp;nbsp;* @param int $number The phone number with international dialling code, e.g. 447796544789.&lt;br /&gt;
&amp;nbsp;* @return boolean True if the specified number has coverage.&lt;br /&gt;
&amp;nbsp;*/&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; function hasCoverage($number) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; $ch = curl_init(); &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; curl_setopt($ch, CURLOPT_URL, $this-&amp;gt;coverage_url . '?number='.$number); &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; curl_setopt($ch, CURLOPT_HEADER, 0); &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; $response = curl_exec($ch); &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; curl_close($ch);&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; $result = split(',',$response);&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; if ($result[0] == 'OK')&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;[/php]
&lt;/div&gt;
&lt;p&gt;
Once the component is declared in the &lt;code&gt;$components&lt;/code&gt; array of the controller, it can be used like this:
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[php]// Check coverage.&lt;br /&gt;
$this-&amp;gt;Sms-&amp;gt;hasCoverage('447736044651');&lt;br /&gt;
// Send a message.&lt;br /&gt;
$this-&amp;gt;Sms-&amp;gt;send('447736044651', 'This is a test message.'));&lt;br /&gt;
// Send a message, this time specifying the sender and span.&lt;br /&gt;
$this-&amp;gt;Sms-&amp;gt;send('447736044651', 'This is a second test message.', 'graemegarden', 2));[/php]
&lt;/div&gt;
</description>
			<pubDate>2007-06-04 01:23:52</pubDate>
			<guid>http://www.paulherron.net/articles/view/servage_sms_api_cakephp_component</guid>
		</item>  
		<item>
			<title>Setting Up Domains for Local Projects on Windows Apache</title>
			<link>http://www.paulherron.net/articles/view/local_test_domains_wamp5</link>
			<description>In Apache, the easiest way to set up a project is to declare its directory path as the &lt;code&gt;DocumentRoot&lt;/code&gt; in &lt;code&gt;httpd.conf&lt;/code&gt;: 
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[code]# DocumentRoot: The directory out of which you will serve your&lt;br /&gt;
# documents. By default, all requests are taken from this directory, but&lt;br /&gt;
# symbolic links and aliases may be used to point to other locations.&lt;br /&gt;
#&lt;br /&gt;
DocumentRoot &amp;quot;C:\Design\myproject&amp;quot;[/code]
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
That directive, after restarting Apache, would make the contents of &lt;em&gt;myproject&lt;/em&gt; available at &lt;a href=&quot;http://localhost/&quot;&gt;http://localhost/&lt;/a&gt;. This is fine for one project, but accessing the contents of a different project directory - say, &lt;em&gt;C:\Design\myotherproject&lt;/em&gt; - as if it were the document root would require changing the config file and restarting Apache.
&lt;/p&gt;
&lt;h2&gt;VirtualHost Saves the Day&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;
In &lt;code&gt;httpd.conf&lt;/code&gt;, we can first use the &lt;code&gt;NameVirtualHost&lt;/code&gt; directive to specify the &lt;abbr title=&quot;Internet Protocol&quot;&gt;IP&lt;/abbr&gt; to which name-based requests will resolve. As we're working locally, this should be the loopback &lt;abbr title=&quot;Internet Protocol&quot;&gt;IP&lt;/abbr&gt; address, 127.0.0.1. We then give a series of &lt;code&gt;VirtualHost&lt;/code&gt; directives to specify the domain name and corresponding directory for each project. 
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[code]&amp;nbsp;NameVirtualHost 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;VirtualHost 127.0.0.1&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;C:/Design/myproject&amp;quot;&lt;br /&gt;
ServerName myproject.l&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;VirtualHost 127.0.0.1&amp;gt;&lt;br /&gt;
DocumentRoot &amp;quot;C:/Design/myotherproject&amp;quot;&lt;br /&gt;
ServerName myotherproject.l&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;[/code]
&lt;/div&gt;
&lt;p&gt;
We now need to take care of the &lt;abbr title=&quot;Domain Name System&quot;&gt;DNS&lt;/abbr&gt; part of this process. Requests for any of our test domains should map to 127.0.0.1, and this can be enforced in the Windows hosts file, usually available at &lt;a href=&quot;C:\WINDOWS\system32\drivers\etc\hosts&quot;&gt;C:\WINDOWS\system32\drivers\etc\hosts&lt;/a&gt;.
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[code]# Copyright (c) 1993-1999 Microsoft Corp.&lt;br /&gt;
#&lt;br /&gt;
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the mappings of IP addresses to host names. Each&lt;br /&gt;
# entry should be kept on an individual line. The IP address should&lt;br /&gt;
# be placed in the first column followed by the corresponding host name.&lt;br /&gt;
# The IP address and the host name should be separated by at least one&lt;br /&gt;
# space.&lt;br /&gt;
#&lt;br /&gt;
# Additionally, comments (such as these) may be inserted on individual&lt;br /&gt;
# lines or following the machine name denoted by a '#' symbol.&lt;br /&gt;
#&lt;br /&gt;
# For example:&lt;br /&gt;
#&lt;br /&gt;
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 102.54.94.97&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rhino.acme.com&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # source server&lt;br /&gt;
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 38.25.63.10&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; x.acme.com&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # x client host&lt;br /&gt;
&lt;br /&gt;
127.0.0.1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; localhost&lt;br /&gt;
127.0.0.1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; myproject.l&lt;br /&gt;
127.0.0.1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; myotherproject.l[/code]
&lt;/div&gt;
&lt;p&gt;
All being well, this setup would make the two example projects available at &lt;a href=&quot;http://myproject.l&quot;&gt;http://myproject.l&lt;/a&gt; and &lt;a href=&quot;http://myotherproject.l&quot;&gt;http://myotherproject.l&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Apache will need a restart for the changes to take effect. It might also be necessary to restart Windows' &lt;em&gt;DNS Client&lt;/em&gt; service, which can be found by right-clicking My Computer, selecting Manage and navigating to the &lt;em&gt;Services&lt;/em&gt; section under &lt;em&gt;Services and Applications&lt;/em&gt;.
&lt;/p&gt;
</description>
			<pubDate>2007-05-27 16:49:44</pubDate>
			<guid>http://www.paulherron.net/articles/view/local_test_domains_wamp5</guid>
		</item>  
		<item>
			<title>Using afterFind() to create pseudofields in CakePHP</title>
			<link>http://www.paulherron.net/articles/view/cakephp_afterfind_psuedofields</link>
			<description>One useful application of this feature is in merging data from two or more database fields into one pseudofield. In the example below, &lt;code&gt;afterFind()&lt;/code&gt; is added to a User model. A &lt;code&gt;foreach&lt;/code&gt; statement takes the &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt; fields for each user and creates a new field, &lt;code&gt;fullName&lt;/code&gt;.
&lt;div class=&quot;codebox&quot;&gt;
[php]&amp;lt;?php&lt;br /&gt;
class User extends AppModel&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; var $name = 'User';&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;function afterFind($results) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// For any results returned from the 'User' model, take 'firstName' and 'lastName' and use them to produce a 'fullName' pseudofield.&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;foreach ($results as $key =&amp;gt; $val) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;if (isset($val['User']['firstName']) &amp;amp;&amp;amp; isset($val['User']['lastName'])) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;$results[$key]['User']['fullName'] = $val['User']['firstName'] . ' ' . $val['User']['lastName']; &amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; return $results;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;[/php]
&lt;/div&gt;
&lt;p&gt;
Cake&lt;abbr title=&quot;PHP Hypertext Preprocessor&quot;&gt;PHP&lt;/abbr&gt; makes &lt;code&gt;$results&lt;/code&gt; available automatically, and automatically deals with them when they're returned from the &lt;code&gt;afterFind()&lt;/code&gt;, so this function should work 'as is'. 
&lt;/p&gt;
&lt;p&gt;
All being well, a &lt;code&gt;find()&lt;/code&gt;, &lt;code&gt;findAll()&lt;/code&gt; or &lt;code&gt;findBy&amp;lt;field&amp;gt;()&lt;/code&gt; query in the controller will now give an array structure like this:
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[php][User] =&amp;gt; Array&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;(&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;[0] =&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;(&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;[firstName] =&amp;gt; Graeme&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;[lastName] =&amp;gt; Garden&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;[fullName] =&amp;gt; Graeme Garden&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;[1] =&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;(&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;[firstName] =&amp;gt; Tim&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;[lastName] =&amp;gt; Brooke-Taylor&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;[fullName] =&amp;gt; Tim Brooke-Taylor&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;)[/php]
&lt;/div&gt;
&lt;p&gt;
&lt;code&gt;afterFind()&lt;/code&gt; can result in significantly tidier code, and puts this kind of processing where it belongs - in the model. It's also a useful workaround for inserting more than one field into a &lt;code&gt;generateList()&lt;/code&gt; statement. The label parameter in &lt;code&gt;generateList()&lt;/code&gt; can only be sourced from one field, but this can be the pseudofield generated in the example above.
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[php]$this-&amp;gt;set('users', $this-&amp;gt;User-&amp;gt;generateList(null,null,null,'{n}.User.id','{n}.User.fullName'));[/php]
&lt;/div&gt;
&lt;p&gt;
This would set a &lt;code&gt;$users&lt;/code&gt; array for use in the view, and could be used be used to output a select box with each option set to a user's full name.
&lt;/p&gt;
</description>
			<pubDate>2007-05-06 15:26:48</pubDate>
			<guid>http://www.paulherron.net/articles/view/cakephp_afterfind_psuedofields</guid>
		</item>  
		<item>
			<title>No-Cost Computing: The Best Free and Open Source Windows Applications</title>
			<link>http://www.paulherron.net/articles/view/best_open_source_apps</link>
			<description>&lt;h2&gt;Antivirus&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;
	&lt;p&gt;
	&lt;a href=&quot;http://www.avast.com/eng/avast_4_home.html&quot;&gt;avast!&lt;/a&gt;. It&amp;#39;s functional and updates its virus definitions regularly. This software has been keeping my computers virus-free for over a year.
	&lt;/p&gt;
	&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Browsers&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.mozilla.com/en-US/firefox/&quot;&gt;Mozilla Firefox&lt;/a&gt;. The fast, intuitive and &lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;extensible&lt;/a&gt; web browser with the increasingly large following.&lt;br /&gt;
	&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Email&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.mozilla.com/en-US/thunderbird/&quot;&gt;Mozilla Thunderbird&lt;/a&gt;. Like Firefox, it works a treat. A worthy alternative to &lt;a href=&quot;http://www.microsoft.com/windows/oe/&quot;&gt;Outlook Express&lt;/a&gt; or, coupled with &lt;a href=&quot;http://www.mozilla.org/projects/calendar/sunbird/&quot;&gt;Mozilla Sunbird&lt;/a&gt;, to &lt;a href=&quot;http://www.microsoft.com/outlook/&quot;&gt;Microsoft Outlook&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Environments, IDEs &amp;amp; Frameworks&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.eclipse.org/&quot;&gt;Eclipse&lt;/a&gt;. This Java-based editor is great for many types of programming. I use it with the &lt;a href=&quot;http://www.phpeclipse.de/tiki-view_articles.php&quot;&gt;PHPEclipse&lt;/a&gt; plugin for my &lt;a href=&quot;http://www.cakephp.org/&quot;&gt;CakePHP&lt;/a&gt; projects.&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.wampserver.com/en/&quot;&gt;Wamp5&lt;/a&gt;. Makes it possible to run Apache, &lt;abbr title=&quot;PHP Hypertext Preprocessor&quot;&gt;PHP&lt;/abbr&gt; and My&lt;abbr title=&quot;Structured Query Language&quot;&gt;SQL&lt;/abbr&gt; on a Windows &lt;abbr title=&quot;Personal Computer&quot;&gt;PC&lt;/abbr&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;File Sharing &amp;amp; Downloading&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.utorrent.com/&quot;&gt;&amp;micro;Torrent&lt;/a&gt;. A small, fast and user-friendly BitTorrent client. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;FTP&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://filezilla.sourceforge.net/&quot;&gt;FileZilla&lt;/a&gt;. An &lt;abbr title=&quot;File Transfer Protocol&quot;&gt;FTP&lt;/abbr&gt; and &lt;abbr title=&quot;Secure File Transfer Protocol&quot;&gt;SFTP&lt;/abbr&gt; client. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Graphics &amp;amp; Photo&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.gimp.org/windows/&quot;&gt;The GIMP&lt;/a&gt;. Rivals &lt;a href=&quot;http://www.adobe.com/products/photoshop/&quot;&gt;Adobe Photoshop&lt;/a&gt; in many respects. Add the &lt;a href=&quot;http://ufraw.sourceforge.net/&quot;&gt;UFRaw&lt;/a&gt; plugin for RAW image editing, but note that the program currently only supports editing at 8-bits per channel.
	&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.inkscape.org/&quot;&gt;Inkscape&lt;/a&gt;. A very capable vector drawing application.&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://freemind.sourceforge.net/wiki/&quot;&gt;FreeMind&lt;/a&gt;. A Java-based application for producing mind maps. Exports to &lt;abbr title=&quot;Extensible Hypertext Markup Language&quot;&gt;XHTML&lt;/abbr&gt; as well as various vector and raster formats.&amp;nbsp; &lt;/li&gt;
	&lt;li&gt;&lt;a name=&quot;pdfcreator&quot; href=&quot;http://sourceforge.net/projects/pdfcreator/&quot; title=&quot;pdfcreator&quot;&gt;&lt;abbr title=&quot;Portable Document Format&quot;&gt;PDF&lt;/abbr&gt; Creator&lt;/a&gt;. Sets up a virtual &lt;abbr title=&quot;Portable Document Format&quot;&gt;PDF&lt;/abbr&gt; printer, making it possible to save to &lt;abbr title=&quot;Portable Document Format&quot;&gt;PDF&lt;/abbr&gt; in any software that can print. &lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://sourceforge.net/projects/sicat/&quot;&gt;SICAT&lt;/a&gt;. A small executable with a very specific aim. If you want your screenshots to be automatically uploaded to your webspace via &lt;abbr title=&quot;File Transfer Protocol&quot;&gt;FTP&lt;/abbr&gt;, and the &lt;abbr title=&quot;Uniform Resource Locator&quot;&gt;URL&lt;/abbr&gt; copied to your clipboard, this program is for you.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Media Players &amp;amp; Codecs&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.foobar2000.org/&quot;&gt;foobar2000&lt;/a&gt;. The faster-loading, faster-working alternative to &lt;a href=&quot;http://www.winamp.com/&quot;&gt;Winamp&lt;/a&gt;, with all the useful features retained. It&amp;#39;s also compatible with the excellent music profiling service, &lt;a href=&quot;http://www.last.fm/&quot;&gt;Last.fm&lt;/a&gt;.&lt;br /&gt;
	&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.videolan.org/vlc/&quot;&gt;&lt;abbr title=&quot;VideoLAN Client&quot;&gt;VLC&lt;/abbr&gt;&lt;/a&gt;&lt;a href=&quot;http://www.videolan.org/vlc/&quot;&gt;&lt;abbr title=&quot;VideoLAN Client&quot;&gt;&lt;/abbr&gt; Media Player&lt;/a&gt;. A simple media player with many useful features. It has a wide range of inbuilt codecs and is particularly good at coping with damaged or incomplete files. It can even play media that&amp;#39;s in a disk image (.iso) file. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Messengers &amp;amp; VOIP&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.miranda-im.org/&quot;&gt;Miranda&lt;abbr title=&quot;Instant Messenger&quot;&gt;IM&lt;/abbr&gt;&lt;/a&gt;. A minimalist instant messaging client that gives access to protocols such as &lt;abbr title=&quot;I Seek You&quot;&gt;ICQ&lt;/abbr&gt;, &lt;abbr title=&quot;AOL Instant Messenger&quot;&gt;AIM&lt;/abbr&gt;, &lt;abbr title=&quot;Microsoft Network&quot;&gt;MSN&lt;/abbr&gt;, &lt;abbr title=&quot;Internet Relay Chat&quot;&gt;IRC&lt;/abbr&gt;, Yahoo!, Jabber and Google Talk. Consumes considerably fewer resources than &lt;a href=&quot;http://get.live.com/messenger/overview&quot;&gt;Windows Live Messenger&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Office &amp;amp; &lt;abbr title=&quot;Desktop Publishing&quot;&gt;DTP&lt;/abbr&gt; Applications&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.openoffice.org/&quot;&gt;OpenOffice.org&lt;/a&gt;. A suite applications to rival &lt;a href=&quot;http://office.microsoft.com/&quot;&gt;Microsoft Office&lt;/a&gt;.  &lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.w3.org/Talks/Tools/Slidy/&quot;&gt;HTML Slidy&lt;/a&gt;. Not so much a program as a useful script, but still deserves a mention as an excellent &lt;a href=&quot;http://www.openoffice.org/product/impress.html&quot;&gt;Impress&lt;/a&gt; or &lt;a href=&quot;http://www.microsoft.com/powerpoint/&quot;&gt;Powerpoint&lt;/a&gt; alternative. Produce some slides in HTML and display them fullscreen in your browser using Slidy. Many oft-used slideshow features are emulated, including keyboard navigation and incremental display of slide content. As with any web page, Flash and other media can be embedded. &lt;br /&gt;
	&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Sound &amp;amp; Music&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://audacity.sourceforge.net/&quot;&gt;Audacity&lt;/a&gt;. A feature-packed alternative to &lt;a href=&quot;http://www.sonymediasoftware.com/Products/ShowProduct.asp?PID=961&quot;&gt;Sony Sound Forge&lt;/a&gt;. &lt;br /&gt;
	&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://jj.consti.de/jjsoftware/uk/mp3renamer.html&quot;&gt;&lt;abbr title=&quot;Jens Jacobsen&quot;&gt;JJ&lt;/abbr&gt; &lt;abbr title=&quot;Moving Picture Experts Group Layer-3 Audio&quot;&gt;MP3&lt;/abbr&gt; Renamer&lt;/a&gt;. A useful freeware tool for tagging and renaming &lt;abbr title=&quot;Moving Picture Experts Group Layer-3&quot;&gt;MP3&lt;/abbr&gt; files.&lt;br /&gt;
	&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Utilities &amp;amp; Other&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://windirstat.info/&quot;&gt;WinDirStat&lt;/a&gt;. Displays disk usage information graphically.&lt;br /&gt;
	&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://notepad-plus.sourceforge.net/&quot;&gt;Notepad++&lt;/a&gt;. An excellent Notepad replacement and powerful text editor. Useful features include syntax highlighting and code autocompletion. &lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://sourceforge.net/projects/st-m&quot;&gt;Startup Manager&lt;/a&gt;. Easy customisation of which programs run when Windows boots.  &lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://home.a03.itscom.net/tsuzu/programing/en/&quot;&gt;&lt;abbr title=&quot;List&quot;&gt;LS&lt;/abbr&gt;&lt;/a&gt;. A useful application for generating a list of a directory&amp;#39;s contents. &lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.7-zip.org/&quot;&gt;7-Zip&lt;/a&gt;. A file archiver that&amp;#39;s very similar to &lt;a href=&quot;http://www.win-rar.com/&quot;&gt;Win&lt;abbr title=&quot;Roshal Archive&quot;&gt;RAR&lt;/abbr&gt;&lt;/a&gt;. Can be used to compress and decompress &lt;abbr title=&quot;Roshal Archive&quot;&gt;RAR&lt;/abbr&gt; and ZIP files.&amp;nbsp; &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Video&lt;/h2&gt;&lt;br /&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://mediacoder.sourceforge.net/&quot;&gt;MediaCoder&lt;/a&gt;. For all your video transcoding needs. MediaCoder supports a&amp;nbsp; variety of video and  audio formats and has an excellent interface. It supports encoding plugins for a range a devices, making it ideal for encoding video for products like the Apple iPod.
	&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://mediainfo.sourceforge.net/en&quot;&gt;MediaInfo&lt;/a&gt;. Drag a video, audio or subtitle file onto the this application to see comprehensive technical details, including information on the codec, file size, duration and more. &lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.virtualdub.org/&quot;&gt;VirtualDub&lt;/a&gt;. A video capture and linear editing tool.&lt;br /&gt;
	&lt;/li&gt;
&lt;/ul&gt;
</description>
			<pubDate>2007-01-01 20:08:56</pubDate>
			<guid>http://www.paulherron.net/articles/view/best_open_source_apps</guid>
		</item>  
		<item>
			<title>Donate Your Carcass Online</title>
			<link>http://www.paulherron.net/articles/view/uk_organ_transplant</link>
			<description>&lt;p&gt;
As someone who inadvertently destroys or loses donor cards on a regular basis, I was pleased to be referred by a friend to the &lt;a href=&quot;http://www.uktransplant.org.uk/&quot; class=&quot;external&quot;&gt;NHS UK Transplant website&lt;/a&gt;. Because a computerised database is difficult to put through the washing machine, I feel much happier that my desire to be broken down for spares will be respected. Signing up is simple, and the &lt;a href=&quot;http://www.uktransplant.org.uk/ukt/how_to_become_a_donor/questions/questions.jsp&quot; class=&quot;external&quot;&gt;questions page&lt;/a&gt; sums up rather neatly why this is such a good idea:
&lt;/p&gt;
&lt;blockquote&gt;
	&lt;div&gt;
	One donor can save the life of several people, restore the sight of two
	others and improve the quality of life of many more. The more people
	who pledge to donate their organs and tissue after their death, the
	more people stand to benefit. By choosing to join the NHS Organ Donor
	Register you could help to make sure life goes on for many others.
	&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;
There are moral considerations. I pity the poor bastard who, medical advances permitting, inherits this brain. It's inexplicably innumerate, and prone to complete shutdown at the mere mention of the words &amp;quot;essay plan&amp;quot;. 
&lt;/p&gt;
&lt;p&gt;
Wearing two pairs of glasses (one pair atop the other) as she awaited an emergency appointment at the optometrist's, my Year 9 classmate didn't take kindly to being called &amp;quot;six eyes&amp;quot; from across the room. I didn't say it, but evidently looked guilty enough to warrant a ferocious jab between the ribs with an HB pencil. That my liver survived the ordeal was nothing short of a miracle. If you have my liver and are reading this, please be aware that it's been jabbed very hard with a pencil. 
&lt;/p&gt;
&lt;p&gt;
But I digress. Indolence alone is insufficient reason for not signing up. Why not head over there now and stick your name down? In your absence, you may just be able to improve the lives of many people.
&lt;/p&gt;
</description>
			<pubDate>2006-11-30 20:08:56</pubDate>
			<guid>http://www.paulherron.net/articles/view/uk_organ_transplant</guid>
		</item>  
		<item>
			<title>Fetch a Random Database Entry with CakePHP</title>
			<link>http://www.paulherron.net/articles/view/cakephp_random_database_entry</link>
			<description>&lt;p&gt;
To achieve this, all we need to do is order our retrieved records randomly. We can do that by inserting the &lt;strong&gt;rand()&lt;/strong&gt; function in the &lt;strong&gt;$order&lt;/strong&gt; field.  
&lt;/p&gt;
&lt;p&gt;
To take only a certain number of these randomised entries, we can use the &lt;strong&gt;$limit&lt;/strong&gt; parameter. This is set to 1 in the example below.   
&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;
[php]// This statement queries a Testimonial model for one random entry.
$this-&amp;gt;Testimonial-&amp;gt;findAll(null,null,'rand()',1,null,null);[/php]
&lt;/div&gt;
</description>
			<pubDate>2006-11-27 20:08:56</pubDate>
			<guid>http://www.paulherron.net/articles/view/cakephp_random_database_entry</guid>
		</item> 	</channel>
</rss> 