<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>CastlesBlog</title>
<link>http://www.castlesblog.com/</link>
<description>A blog about making a blog</description>
<copyright>All content is copyright to Marc Castles</copyright>
<language>en-au</language>
<generator>CastlesBlog</generator><item>
<title>Get mySQL Enumeration Values as an Array </title>
<link>http://www.castlesblog.com/2010/august/30/enums-to-array</link>
<description>&lt;p&gt;I often use &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/enum.html&quot;&gt;enumeration values&lt;/a&gt; when defining a list of options in mySQL. In the past I would make sure my web form matched my database and update each form when I change the database.... but not any more.. I've written a quick function that will return the possible values from mySQL as an array. I can then use the result in my forms and the only place that needs to change is the database.&lt;/p&gt;

&lt;pre&gt;function getEnums($table,$field) {
	$sql = &quot;SELECT
			COLUMN_TYPE
		FROM 
			INFORMATION_SCHEMA.COLUMNS
		WHERE
			TABLE_NAME = '$table'
			AND COLUMN_NAME = '$field'&quot;;

	$this-&gt;query($sql);

	preg_match_all('/\'(.[^\']+)\'/',$this-&gt;get('COLUMN_TYPE'),$matches);

	return $matches[1];
}&lt;/pre&gt;&lt;p&gt;I'm using this in my database class. Modify it to suit your needs.&lt;/p&gt;</description>
<pubDate>Mon, 30 Aug 2010 13:02:51 +0000</pubDate>
</item><item>
<title>MythTV Minimal OSD</title>
<link>http://www.castlesblog.com/2010/august/30/mythtv-minimal-osd</link>
<description>&lt;h2&gt;A new theme&lt;/h2&gt;
&lt;p&gt;Presenting a new OSD theme for Mythtv .23. Designed to be a minimalistic theme that covers up the smallest amount of picture.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Minimal&lt;/strong&gt; is built for 16:10 screens and I don't really have any plans to make a 16:9 version. If your after a different aspect ratio post a comment and I might think about it.&lt;/p&gt;&lt;h2&gt;Download&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://static.castlesblog.com/public/Minimal-OSD-V1.zip&quot;&gt;Version 1&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h2&gt;Please Note&lt;/h2&gt;
&lt;p&gt;This has only been tested in MythTV .23 - The OSD theming for OSD's has changed significantly in .24 and hence this will probably break when its released. I intend to update this theme as well as my &lt;a href=&quot;/2009/november/30/mythtv-glass-osd&quot;&gt;Glass theme&lt;/a&gt; when .24 is available.&lt;/p&gt;&lt;h2&gt;Screenshots&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;http://static.castlesblog.com/data/mythtv-minimal-osd-screenshot-1.jpg&quot; alt=&quot;Mythtv Minimal OSD Theme Screenshot 1&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://static.castlesblog.com/data/mythtv-minimal-osd-screenshot-2.jpg&quot; alt=&quot;Mythtv Minimal OSD Theme Screenshot 2&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://static.castlesblog.com/data/mythtv-minimal-osd-screenshot-3.jpg&quot; alt=&quot;Mythtv Minimal OSD Theme Screenshot 3&quot; /&gt;&lt;/p&gt;</description>
<pubDate>Sun, 29 Aug 2010 14:04:25 +0000</pubDate>
</item><item>
<title>Using PHP to minify Javascript and CSS</title>
<link>http://www.castlesblog.com/2010/august/14/php-javascript-css-minification</link>
<description>&lt;h2&gt;An Update to the Dynamic Javascript include&lt;/h2&gt;
&lt;p&gt;&lt;a href=/2010/february/27/cookieless-domain#dynamic-static&gt;Back in February&lt;/a&gt; I wrote the code to combine all the javascript into one file with the intention to limit the requests to the server as recommended by &lt;a href=http://code.google.com/speed/page-speed/docs/rtt.html#CombineExternalJS&gt;PageSpeed&lt;/a&gt; and &lt;a href=http://developer.yahoo.com/performance/rules.html#num_http&gt;YSlow&lt;/a&gt;. I have revisited this code to make it do a few extra things:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Checks which file was last edited and returns a Not Modified header if applicable&lt;/li&gt;&lt;li&gt;Minification (white space removed)&lt;/li&gt;&lt;li&gt;Links to Google&amp;#39;s CDN for jQuery and fall back to a local version&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So lets look at the new script...&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

$files = array(
    
    &amp;#39;../javascript/jquery.easing.js&amp;#39;
    
    ,&amp;#39;../templates/castlesblog/template.js&amp;#39;

);
    
$modified = 0;

foreach($files as $file) {        
    $age = filemtime($file);
    if($age &amp;gt; $modified) {
        $modified = $age;
    }
}

$offset = 60 * 60 * 24 * 7; // Cache for 1 weeks
header (&amp;#39;Expires: &amp;#39; . gmdate (&amp;quot;D, d M Y H:i:s&amp;quot;, time() + $offset) . &amp;#39; GMT&amp;#39;);

if (isset($_SERVER[&amp;#39;HTTP_IF_MODIFIED_SINCE&amp;#39;]) &amp;amp;&amp;amp; strtotime($_SERVER[&amp;#39;HTTP_IF_MODIFIED_SINCE&amp;#39;]) &amp;gt;= $modified) {
    header(&amp;quot;HTTP/1.0 304 Not Modified&amp;quot;);
    header (&amp;#39;Cache-Control:&amp;#39;);
} else {
    header (&amp;#39;Cache-Control: max-age=&amp;#39; . $offset);
    header (&amp;#39;Content-type: text/javascript; charset=UTF-8&amp;#39;);
    header (&amp;#39;Pragma:&amp;#39;);
    header (&amp;quot;Last-Modified: &amp;quot;.gmdate(&amp;quot;D, d M Y H:i:s&amp;quot;, $modified ).&amp;quot; GMT&amp;quot;);
    
    function compress($buffer) {
        /* remove comments */
        $buffer = preg_replace(&amp;quot;/((?:\/\*(?:[^*]|(?:\*+[^*\/]))*\*+\/)|(?:\/\/.*))/&amp;quot;, &amp;quot;&amp;quot;, $buffer);
        /* remove tabs, spaces, newlines, etc. */
        $buffer = str_replace(array(&amp;quot;\r\n&amp;quot;,&amp;quot;\r&amp;quot;,&amp;quot;\t&amp;quot;,&amp;quot;\n&amp;quot;,&amp;#39;  &amp;#39;,&amp;#39;    &amp;#39;,&amp;#39;     &amp;#39;), &amp;#39;&amp;#39;, $buffer);
        /* remove other spaces before/after ) */
        $buffer = preg_replace(array(&amp;#39;(( )+\))&amp;#39;,&amp;#39;(\)( )+)&amp;#39;), &amp;#39;)&amp;#39;, $buffer);
        return $buffer;
    }
    
    ob_start(&amp;#39;ob_gzhandler&amp;#39;);

        foreach($files as $file) {
            if(strpos(basename($file),&amp;#39;.min.&amp;#39;)===false) { //compress files that aren&amp;#39;t minified
                ob_start(&amp;quot;compress&amp;quot;);
                    include($file);
                ob_end_flush();
            } else {
                include($file);
            }
        }
    
    ob_end_flush();
}&lt;/pre&gt;
&lt;h2&gt;Explanation&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;Firstly, you will see an array of javascript files to include. It loops through each one to work out which is the newest.&lt;/li&gt;&lt;li&gt;The next two lines set a header that should cache the file for one week.&lt;/li&gt;&lt;li&gt;After that we work out if the modified date is newer than what the browser has in cache and if so return the Not Modified header.&lt;/li&gt;&lt;li&gt;Alternatively if the file is modified or new to the browser it sets/resets a few more headers and then loops through our array again and includes the code.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I&amp;#39;ve wrapped the include in two ob_start methods. The first one gzips the output and the second runs the defined compress function.&lt;/p&gt;&lt;p&gt;It will only run the compress on files that don&amp;#39;t have .min. in the filename. This was added because the compress function messes up scripts that are already minified such as jQuery. The compress function uses a few regular expressions for the minification. Suggestions on how to improve this is welcome.&lt;/p&gt;&lt;h2&gt;A few things to note&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Using &lt;a href=http://developer.yahoo.com/yui/compressor/&gt;Yahoo&amp;#39;s YUI Compressor&lt;/a&gt; or &lt;a href=http://code.google.com/closure/compiler/&gt;Google&amp;#39;s Closure Compiler&lt;/a&gt; will do a better job. The advantage of this is there is less work involved in compressing the files. All you need to change when adding a new script is the array.&lt;/li&gt;&lt;li&gt;The regular expressions can break the javascript if there is a double forward slash in the code (URLs etc). The fix is to escape the slashes.. htt:\/\/www.url...&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;CSS Minification&lt;/h2&gt;&lt;p&gt;The CSS is using a similar minification process. &lt;/p&gt;&lt;pre&gt;&amp;lt;?php

$files = array(
    
    &amp;#39;../templates/castlesblog/template.css&amp;#39;

);
    
$modified = 0;

foreach($files as $file) {        
    $age = filemtime($file);
    if($age &amp;gt; $modified) {
        $modified = $age;
    }
}

$offset = 60 * 60 * 24 * 7; // Cache for 1 weeks
header (&amp;#39;Expires: &amp;#39; . gmdate (&amp;quot;D, d M Y H:i:s&amp;quot;, time() + $offset) . &amp;#39; GMT&amp;#39;);

if (isset($_SERVER[&amp;#39;HTTP_IF_MODIFIED_SINCE&amp;#39;]) &amp;amp;&amp;amp; strtotime($_SERVER[&amp;#39;HTTP_IF_MODIFIED_SINCE&amp;#39;]) &amp;gt;= $modified) {
    header(&amp;quot;HTTP/1.0 304 Not Modified&amp;quot;);
    header (&amp;#39;Cache-Control:&amp;#39;);
} else {
    header (&amp;#39;Cache-Control: max-age=&amp;#39; . $offset);
    header (&amp;#39;Content-type: text/css; charset=UTF-8&amp;#39;);
    header (&amp;#39;Pragma:&amp;#39;);
    header (&amp;quot;Last-Modified: &amp;quot;.gmdate(&amp;quot;D, d M Y H:i:s&amp;quot;, $modified ).&amp;quot; GMT&amp;quot;);
    
    function compress($buffer) {
        /* remove comments */
        $buffer = preg_replace(&amp;#39;!/\*[^*]*\*+([^/][^*]*\*+)*/!&amp;#39;, &amp;#39;&amp;#39;, $buffer);
        /* remove tabs, spaces, newlines, etc. */
        $buffer = str_replace(array(&amp;quot;\r\n&amp;quot;,&amp;quot;\r&amp;quot;,&amp;quot;\n&amp;quot;,&amp;quot;\t&amp;quot;,&amp;#39;  &amp;#39;,&amp;#39;    &amp;#39;,&amp;#39;     &amp;#39;), &amp;#39;&amp;#39;, $buffer);
        /* remove other spaces before/after ; */
        $buffer = preg_replace(array(&amp;#39;(( )+{)&amp;#39;,&amp;#39;({( )+)&amp;#39;), &amp;#39;{&amp;#39;, $buffer);
        $buffer = preg_replace(array(&amp;#39;(( )+})&amp;#39;,&amp;#39;(}( )+)&amp;#39;,&amp;#39;(;( )*})&amp;#39;), &amp;#39;}&amp;#39;, $buffer);
        $buffer = preg_replace(array(&amp;#39;(;( )+)&amp;#39;,&amp;#39;(( )+;)&amp;#39;), &amp;#39;;&amp;#39;, $buffer);
        return $buffer;
    }
    
    ob_start(&amp;#39;ob_gzhandler&amp;#39;);

        foreach($files as $file) {
            if(strpos(basename($file),&amp;#39;.min.&amp;#39;)===false) { //compress files that aren&amp;#39;t minified
                ob_start(&amp;quot;compress&amp;quot;);
                    include($file);
                ob_end_flush();
            } else {
                include($file);
            }
        }
    
    ob_end_flush();
}&lt;/pre&gt;&lt;h2&gt;Changes to .htaccess&lt;/h2&gt;&lt;p&gt;To make nice urls to these files the following is added to the .htaccess&lt;/p&gt;&lt;pre&gt;RewriteRule ^scripts.js$ includes/scripts.php [L]

RewriteRule ^styles.css$ includes/styles.php [L]&lt;/pre&gt;&lt;h2&gt;Use Google&amp;#39;s CDN for jQuery&lt;/h2&gt;&lt;p&gt;One final change was to remove jQuery from the included scripts and use Google CDN version.&lt;/p&gt;&lt;pre&gt;&amp;lt;script src=&amp;quot;http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;!window.jQuery &amp;amp;&amp;amp; document.write(&amp;#39;&amp;lt;script src=&amp;quot;js/jquery-1.4.2.min.js&amp;quot;&amp;gt;&amp;lt;\/script&amp;gt;&amp;#39;)&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=http://happyworm.com/blog/2010/01/28/a-simple-and-robust-cdn-failover-for-jquery-14-in-one-line/&gt;Here&lt;/a&gt; is a few reasons why this is a good idea.&lt;/p&gt;</description>
<pubDate>Sat, 14 Aug 2010 10:52:25 +0000</pubDate>
</item><item>
<title>Cross Domain Fonts in Firefox</title>
<link>http://www.castlesblog.com/2010/august/12/cross-domain-fonts-in-firefox</link>
<description>&lt;p&gt;Today I realised that @font-face wasn't working properly in Firefox because I'm linking to the resource on a different domain (&lt;a href=/2010/february/27/cookieless-domain&gt;see cookieless domain post&lt;/a&gt;). It appears that Firefox has cross-site permissions that prevent resources being read. To allow remote access all I needed to add to the .htaccess on the server thats hosting the fonts was:&lt;/p&gt;&lt;pre&gt;&amp;lt;FilesMatch &amp;quot;\.(ttf|otf|eot|woff)$&amp;quot;&amp;gt;
    &amp;lt;IfModule mod_headers.c&amp;gt;
        Header set Access-Control-Allow-Origin &amp;quot;http://castlesblog.com&amp;quot;
    &amp;lt;/IfModule&amp;gt;
&amp;lt;/FilesMatch&amp;gt;&lt;/pre&gt;&lt;p&gt;For more information checkout the &lt;a href=https://developer.mozilla.org/en/HTTP_access_control&gt;HTTP access Control&lt;/a&gt; article at the Mozilla Dev Center.&lt;/p&gt;</description>
<pubDate>Thu, 12 Aug 2010 12:54:43 +0000</pubDate>
</item><item>
<title>HTML5 Drag and Drop Upload</title>
<link>http://www.castlesblog.com/2010/july/13/html5-drag-drop-upload</link>
<description>&lt;p&gt;I've been playing around with drag and drop in HTML5 and I'm pretty excited about it. A lot of the examples I've found online are firefox specific which isn't ideal so I've come up with a solution that works in as many browsers as possible.&lt;/p&gt;&lt;h2&gt;Browser Support&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;http://www.getfirefox.com&quot;&gt;&lt;img src=&quot;http://static.castlesblog.com/data/firefox-icon.jpg&quot; alt=&quot;Firefox&quot; width=&quot;60&quot; height=&quot;60&quot;/&gt;&lt;/a&gt;&lt;a href=&quot;http://www.apple.com/safari&quot;&gt;&lt;img src=&quot;http://static.castlesblog.com/data/safari-icon.jpg&quot; alt=&quot;Safari&quot; width=&quot;60&quot; height=&quot;60&quot;/&gt;&lt;/a&gt;&lt;a href=&quot;http://www.google.com/chrome&quot;&gt;&lt;img src=&quot;http://static.castlesblog.com/data/chrome-icon.jpg&quot; alt=&quot;Chrome&quot; width=&quot;60&quot; height=&quot;60&quot;/&gt;&lt;/a&gt;&lt;a href=&quot;http://www.webkit.org/&quot;&gt;&lt;img src=&quot;http://static.castlesblog.com/data/webkit-icon.jpg&quot; alt=&quot;Webkit&quot; width=&quot;60&quot; height=&quot;60&quot;/&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Support for drag and drop &amp;amp; the file API is limited to cutting edge browsers and as the &lt;a href=&quot;http://dev.w3.org/html5/spec/Overview.html&quot;&gt;spec&lt;/a&gt; isn't finalised features are inconsistent... to say the least.&lt;/p&gt;&lt;p&gt;I've come up with a solution thats tested and works in Firefox 3.6, Safari 5, Chrome 6 and Webkit. I'll be adding support for Opera and IE if/when its available.&lt;/p&gt;&lt;h2&gt;What I've discovered:&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;SAFARI 5 doesn't support FileReader&lt;/li&gt;&lt;li&gt;Only Firefox 3.6 supports addEventListener on FileReaders&lt;/li&gt;&lt;li&gt;Only Firefox 3.6 supports sendAsBinary in XML Http Requests&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Because of these issues I've coded three ways to upload files.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Browsers that support sendAsBinary send the data using proper headers and PHP can easily read the $_FILES array&lt;/li&gt;&lt;li&gt;Browsers that support FileReader send the file as base64 encoded string. The file information is passed in via headers&lt;/li&gt;&lt;li&gt;Browsers that don't support FileReader send the file itself and is read the same way as no. 2&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;The Code&lt;/h2&gt;&lt;p&gt;So, without any further ado, &lt;a href=&quot;/html5_upload.php&quot;&gt;here is a demo&lt;/a&gt;. And here is the code:&lt;/p&gt;
&lt;pre&gt;&amp;lt;?php
$upload_folder = &amp;#39;data&amp;#39;;

if(count($_FILES)&amp;gt;0) { //browser supported sendAsBinary()
	if( move_uploaded_file( $_FILES[&amp;#39;upload&amp;#39;][&amp;#39;tmp_name&amp;#39;] , $upload_folder.&amp;#39;/&amp;#39;.$_FILES[&amp;#39;upload&amp;#39;][&amp;#39;name&amp;#39;] ) ) {
		echo &amp;#39;done&amp;#39;;
	}
	exit();
} else if(isset($_GET[&amp;#39;up&amp;#39;])) {

	if(isset($_GET[&amp;#39;base64&amp;#39;])) {
		$content = base64_decode(file_get_contents(&amp;#39;php://input&amp;#39;));
	} else {
		$content = file_get_contents(&amp;#39;php://input&amp;#39;);
	}

	$headers = getallheaders();
	
	$headers = array_change_key_case($headers, CASE_UPPER); //different case was being used for different browsers
	
	if(file_put_contents($upload_folder.&amp;#39;/&amp;#39;.$headers[&amp;#39;UP-FILENAME&amp;#39;], $content)) {
		echo &amp;#39;done&amp;#39;;
	}
	exit();
}
?&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=utf-8&amp;gt;
    &amp;lt;title&amp;gt;HTML5 Upload Demo&amp;lt;/title&amp;gt;
    
    &amp;lt;style&amp;gt;
    body{font-family:Helvetica,Arial;font-size:12px}
	#drop-area{border:2px solid black;padding:10px;background-size:contain;min-height:200px;overflow:auto}
	#drop-area.hover{border:2px dashed red}
	#drop-area div{width:150px;height:150px;border:1px solid #CCC;font-size:.5em;padding:5px;background-position:center;background-repeat:no-repeat;background-size:contain;float:left;margin:10px;word-wrap:break-word}
	#status {background-color:black;color:white;padding:5px 20px;margin-bottom:10px}
	&amp;lt;/style&amp;gt;
    
	&amp;lt;!--[if lt IE 9]&amp;gt;
	&amp;lt;script src=http://html5shiv.googlecode.com/svn/trunk/html5.js&amp;gt;&amp;lt;/script&amp;gt;
	&amp;lt;![endif]--&amp;gt;
	
	&amp;lt;script src=http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;

&amp;lt;div id=status&amp;gt;Drag and Drop files to begin...&amp;lt;/div&amp;gt;
&amp;lt;div id=drop-area&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;

var up = {
	
	$drop :			null,
	queue :			[],
	processing :	null,
	uploading :		false,
	binaryReader :	null,
	dataReader :	null,
	xhr:			null,

	init : function() {
		up.$drop = $(&amp;#39;#drop-area&amp;#39;);
		
		up.$drop.bind(&amp;#39;dragenter&amp;#39;,up.enter);
		up.$drop.bind(&amp;#39;dragleave&amp;#39;,up.leave);
		up.$drop.bind(&amp;#39;dragover&amp;#39;,up.over);
		up.$drop.bind(&amp;#39;drop&amp;#39;,up.drop);
		
		$(&amp;#39;#status&amp;#39;).click(up.cancel);
		
		up.xhr = new XMLHttpRequest();
		up.xhr.upload.addEventListener(&amp;#39;progress&amp;#39;, up.uploadProgress , false);
		up.xhr.upload.addEventListener(&amp;#39;load&amp;#39;, up.uploadLoaded , false);
		
	},
	
	enter : function(e){
		$(e.target).addClass(&amp;#39;hover&amp;#39;);
		return false;
	},
	
	leave : function(e){
		$(e.target).removeClass(&amp;#39;hover&amp;#39;);
		return false;
	},
	
	over : function(e){
		return false;
	},
	
	drop : function(e){
		$(e.target).removeClass(&amp;#39;hover&amp;#39;);
		
		var files = e.originalEvent.dataTransfer.files;
		for (var i = 0; i&amp;lt;files.length; i++) {
			var file = files[i];
			up.queue.push(file);
		}

		if(up.uploading == false) {
			up.uploading = true;
			up.process();
		}
		
		return false;
	},
	
	process : function() {
		up.processing = up.queue.shift();
		
		up.$drop.append(&amp;#39;&amp;lt;div&amp;gt;&amp;#39;+up.processing.name+&amp;#39;&amp;lt;/div&amp;gt;&amp;#39;);
		
		if(window.FileReader) { //firefox 3.6, Chrome 6, Webkit

			if(up.processing.type.match(/image/gi) != null) { //is an image - read it
				up.dataReader = new FileReader();
				if(up.dataReader.addEventListener) { //firefox
					up.dataReader.addEventListener(&amp;#39;loadend&amp;#39;, up.binaryLoad, false);
					up.dataReader.addEventListener(&amp;#39;error&amp;#39;, up.loadError, false);
					up.dataReader.addEventListener(&amp;#39;progress&amp;#39;, up.loadProgress, false);
				} else { //chrome / webkit
					up.dataReader.onloadend = up.binaryLoad;
					up.dataReader.onerror = up.loadError;
					up.dataReader.onprogress = up.loadProgress;
				}
				up.dataReader.readAsDataURL(up.processing);
			}
			
			up.binaryReader = new FileReader();
			if(up.binaryReader.addEventListener) { //firefox
				up.binaryReader.addEventListener(&amp;#39;loadend&amp;#39;, up.binaryLoad, false);
				up.binaryReader.addEventListener(&amp;#39;error&amp;#39;, up.loadError, false);
				up.binaryReader.addEventListener(&amp;#39;progress&amp;#39;, up.loadProgress, false);
			} else { //chrome / webkit
				up.binaryReader.onloadend = up.binaryLoad;
				up.binaryReader.onerror = up.loadError;
				up.binaryReader.onprogress = up.loadProgress;
			}
			up.binaryReader.readAsBinaryString(up.processing);
			
			
		} else { // safari 5 + others?
		
			up.xhr.abort(); //make sure xhr is a new request
			up.xhr.open(&amp;#39;POST&amp;#39;, &amp;#39;/html5_upload.php?up=true&amp;#39;, true);
		
			up.xhr.setRequestHeader(&amp;#39;UP-FILENAME&amp;#39;, up.processing.name);
			up.xhr.setRequestHeader(&amp;#39;UP-SIZE&amp;#39;, up.processing.size);
			up.xhr.setRequestHeader(&amp;#39;UP-TYPE&amp;#39;, up.processing.type);
			
			up.xhr.send(up.processing); 
			up.xhr.onload = up.onload;
		}
		
	},
	
	loadError : function(e) {
		switch(e.target.error.code) {
			case e.target.error.NOT_FOUND_ERR:
				alert(&amp;#39;File Not Found!&amp;#39;);
			break;
			case e.target.error.NOT_READABLE_ERR:
				alert(&amp;#39;File is not readable&amp;#39;);
			break;
			case e.target.error.ABORT_ERR:
			break; 
			default:
				alert(&amp;#39;An error occurred reading this file.&amp;#39;);
		};

	},
	
	loadProgress : function(e) {
		if (e.lengthComputable) {
			var percentage = Math.round((e.loaded * 100) / e.total);
			$(&amp;#39;#status&amp;#39;).html(&amp;#39;loaded: &amp;#39;+percentage+&amp;#39;%&amp;#39;);
		}
	},
		
	binaryLoad : function(e) {
		
		var isimage = (up.processing.type.match(/image/gi)!=null);
		if( isimage &amp;amp;&amp;amp; up.dataReader.readyState == 2 &amp;amp;&amp;amp; up.$drop.find(&amp;#39;div:last&amp;#39;).css(&amp;#39;background-image&amp;#39;)==&amp;#39;none&amp;#39;) {
			up.$drop.find(&amp;#39;div:last&amp;#39;).css(&amp;#39;background-image&amp;#39;,&amp;#39;url(&amp;#39; + up.dataReader.result + &amp;#39;)&amp;#39;);	
		}
		
		if(isimage &amp;amp;&amp;amp; up.dataReader.readyState == 2 &amp;amp;&amp;amp; up.binaryReader.readyState == 2 || !isimage &amp;amp;&amp;amp; up.binaryReader.readyState == 2 ) {
			
			up.xhr.abort(); //make sure xhr is a new request
			
			var binary = e.target.result;
			
			if(up.xhr.sendAsBinary != null) { //firefox
			
				up.xhr.open(&amp;#39;POST&amp;#39;, &amp;#39;/html5_upload.php?up=true&amp;#39;, true);
	
				var boundary = &amp;#39;xxxxxxxxx&amp;#39;;
			    
				var body = &amp;#39;--&amp;#39; + boundary + &amp;quot;\r\n&amp;quot;;  
				body += &amp;quot;Content-Disposition: form-data; name=&amp;#39;upload&amp;#39;; filename=&amp;#39;&amp;quot; + up.processing.name + &amp;quot;&amp;#39;\r\n&amp;quot;;  
				body += &amp;quot;Content-Type: application/octet-stream\r\n\r\n&amp;quot;;  
				body += binary + &amp;quot;\r\n&amp;quot;;  
				body += &amp;#39;--&amp;#39; + boundary + &amp;#39;--&amp;#39;;  
			    
			    up.xhr.setRequestHeader(&amp;#39;content-type&amp;#39;, &amp;#39;multipart/form-data; boundary=&amp;#39; + boundary);
			    up.xhr.sendAsBinary(body);        	
			    
		    } else { //for browsers that don&amp;#39;t support sendAsBinary yet
			 
			 	up.xhr.open(&amp;#39;POST&amp;#39;, &amp;#39;/html5_upload.php?up=true&amp;amp;base64=true&amp;#39;, true);
			 
			 	up.xhr.setRequestHeader(&amp;#39;UP-FILENAME&amp;#39;, up.processing.name);
			 	up.xhr.setRequestHeader(&amp;#39;UP-SIZE&amp;#39;, up.processing.size);
			 	up.xhr.setRequestHeader(&amp;#39;UP-TYPE&amp;#39;, up.processing.type);
			 	
				up.xhr.send(window.btoa(binary)); 
		    }
			 
			up.xhr.onload = up.onload;
			
		}
	},
	
	uploadProgress : function(e) {
		if (e.lengthComputable) {
			var percentage = Math.round((e.loaded * 100) / e.total);
			$(&amp;#39;#status&amp;#39;).html(&amp;#39;uploaded: &amp;#39;+percentage+&amp;#39;%&amp;#39;);
		}
	},
	
	uploadLoaded : function(e) {
		$(&amp;#39;#status&amp;#39;).html(&amp;#39;Uploaded: 100%&amp;#39;);
	},
	
	onload : function (e) {
		if(up.queue.length &amp;gt; 0) {
			up.process();
		} else {
			up.uploading = false;
			$(&amp;#39;#status&amp;#39;).html(&amp;#39;Queue Uploaded&amp;#39;);
		}
	},
	
	cancel : function(e) {
		if(up.dataReader) {
			up.dataReader.abort();
		}
		if(up.dataReader) {
			up.binaryReader.abort();
		}
		if(up.xhr) {
			up.xhr.abort();
		}
		up.uploading = false;
		up.queue = [];
		up.processing = null;
		$(&amp;#39;#status&amp;#39;).html(&amp;#39;Drag and Drop files to begin...&amp;#39;);
		return false;
	}

}

$(up.init);

&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;p&gt;To keep it simple there is no size or filetype limit but could be added fairly easily. If the browser has FileReader support and the dropped file is an image it will read contents and display a preview.&lt;/p&gt;&lt;p&gt;If you have any questions please post them in the comments.&lt;/p&gt;&lt;h2&gt;References&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.robertnyman.com/html5/fileapi/fileapi.html&quot;&gt;www.robertnyman.com&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en/Using_files_from_web_applications&quot;&gt;developer.mozilla.org&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.appelsiini.net/2009/10/html5-drag-and-drop-multiple-file-upload&quot;&gt;Mika Tuupola&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://html5stars.com/?p=99&quot;&gt;HTML5STARS&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.html5rocks.com/tutorials/file/dndfiles/&quot;&gt;www.html5rocks.com&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.thecssninja.com/javascript/fileapi&quot;&gt;www.thecssninja.com&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</description>
<pubDate>Tue, 13 Jul 2010 02:23:06 +0000</pubDate>
</item><item>
<title>Same name cookie with a different path</title>
<link>http://www.castlesblog.com/2010/march/21/javascript-same-name-cookie-different-path</link>
<description>&lt;p&gt;I've been having mixed results setting and retrieving cookies with the same name and different paths. A cookie set with a path of &quot;/&quot; is accessible anywhere within a site. I wanted my cookies to be different depending on the URL. My solution is to name cookies in the root of a website different to the rest. Pretty simple really, just took me far too long to work this out.&lt;/p&gt;&lt;pre&gt;var cookie_name = 'my_great_cookie';
if(document.location.pathname == '/') {
    cookie_name = 'root_' + cookie_name;
}
//set/retrive cookie here
&lt;/pre&gt;</description>
<pubDate>Sun, 21 Mar 2010 08:39:17 +0000</pubDate>
</item><item>
<title>Feed Icon</title>
<link>http://www.castlesblog.com/2010/march/9/feed-icon</link>
<description>&lt;p&gt;I've made a few tweaks to the castlesblog template. Images now have padding and margins and headings look a bit neater.&lt;/p&gt;&lt;p&gt;You might also notice I added a feed icon to the top right. If your browser supports it there is a CSS rotation on it to it to make it a bit interesting. If its not rotated this is what you are missing out on...&lt;/p&gt;&lt;img src=&quot;http://static.castlesblog.com/data/feed-screenshot.png&quot; alt=&quot;Feed Screenshot&quot; /&gt;&lt;p&gt;As far as I know the rotation works in Firefox, Safari, Chrome and Opera. The CSS to do it is fairly simple:&lt;/p&gt;&lt;pre&gt;-o-transform:rotate(-15deg); /*OPERA*/
-moz-transform:rotate(-15deg); /*MOZILLA*/
-webkit-transform:rotate(-15deg); /*WEBKIT*/&lt;/pre&gt;
&lt;h2&gt;Update 14th March 2010&lt;/h2&gt;&lt;p&gt;I've just discovered you can rotate elements in IE using pure CSS... firstly a much simpler way of rotating is using the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms532918(VS.85).aspx&quot;&gt;rotation property&lt;/a&gt; filter but it only allows 90 degree increments. Thanks to this &lt;a href=&quot;http://www.boogdesign.com/examples/transforms/matrix-calculator.html&quot;&gt;matrix calculator&lt;/a&gt; by robertc it now works using the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms533014%28VS.85%29.aspx&quot;&gt;Matrix filter&lt;/a&gt;. The catch is the origin of rotation is different in IE so I have setup a new conditional stylesheet for IE that sets a different margin and included all IE specific CSS there.&lt;/p&gt;</description>
<pubDate>Mon, 8 Mar 2010 14:39:14 +0000</pubDate>
</item><item>
<title>Cookieless Domain</title>
<link>http://www.castlesblog.com/2010/february/27/cookieless-domain</link>
<description>&lt;h2&gt;Update&lt;/h2&gt;&lt;p&gt;There has been a few  updates to the new template to fix some errors plus I've given &lt;a href=&quot;http://www.opera.com&quot;&gt;Opera&lt;/a&gt; some love. The CSS background gradient is the only feature missing from Opera and while I could get it working with a background image the alternative looks fine. I'm sure the folks at Opera are working on CSS gradient support and it will be available soon.&lt;/p&gt;&lt;a href=&quot;http://static.castlesblog.com/data/opera-screenshot.jpg&quot;&gt;&lt;img src=&quot;http://static.castlesblog.com/data/opera-screenshot-thumb.png&quot;  alt=&quot;Opera Screenshot&quot; /&gt;&lt;/a&gt;&lt;h2&gt;PageSpeed &amp;amp; Yslow&lt;/h2&gt;&lt;p&gt;One of the main features I want to highlight with CastlesBlog is speed. I found the results were pretty good after inspecting &lt;a href=&quot;http://code.google.com/speed/page-speed/&quot;&gt;PageSpeed&lt;/a&gt; and &lt;a href=&quot;http://developer.yahoo.com/yslow/&quot;&gt;Yslow&lt;/a&gt; but there were a few optimisations that could be made.&lt;/p&gt;&lt;blockquote&gt;Tip: &lt;a href=&quot;http://code.google.com/speed/page-speed/&quot;&gt;PageSpeed&lt;/a&gt; and &lt;a href=&quot;http://developer.yahoo.com/yslow/&quot;&gt;Yslow&lt;/a&gt; are fantastic &lt;a href=&quot;http://www.getfirebug.com/&quot;&gt;Firebug&lt;/a&gt; addons and are great tools if you want to dig deep into a websites rendering speed.&lt;/blockquote&gt;&lt;p&gt;The main issue that they highlighted was to put my static content on a cookieless domain. I've never done anything like this before and I didn't even know what cookieless domain was. &lt;a href=&quot;http://code.google.com/speed/page-speed/docs/request.html#ServeFromCookielessDomain&quot;&gt;Read about it here.&lt;/a&gt; After a bit of investigating I think I worked it out. Here is my understanding: &lt;em&gt;When you create a cookie on a site the cookie information is transmitted and received with every request. That means every image, css or javascript file that doesn't actually need the information will get it and send it.&lt;/em&gt; Now I know your thinking that fairly trivial as cookies are generally tiny and not worth the hassle. I agree! Especially on this site which doesn't get the amount of traffic or have enough resources to warrant such optimisations. The problem for me was that I was intrigued and that sent me on a journey to work out how to actually get a cookieless domain working.&lt;/p&gt;&lt;p&gt;From what I read you can avoid sending cookies if you setup a separate domain or CNAME and serve the content from there.&lt;/p&gt;&lt;blockquote&gt;Tip: I found myself using cookies and I didn't even know it. Calling session_start(); in php will set a PHPSESSID cookie. &lt;/blockquote&gt;&lt;h2&gt;What is a CNAME?&lt;/h2&gt;&lt;p&gt;From &lt;a href=&quot;http://en.wikipedia.org/wiki/Cname&quot;&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;A CNAME record or Canonical Name record is a type of resource record in the Domain Name System (DNS) that specifies that the domain name is an alias of another, canonical domain name.&lt;/blockquote&gt;&lt;p&gt;So basically I could setup a CNAME that points to www.castlesblog.com and serve static resources from there. I wouldn't have to change the structure of my site and old content would still work fine. Sounds good to me.&lt;/p&gt;&lt;p&gt;To setup in Plesk I did the following:&lt;/p&gt; &lt;ol&gt;&lt;li&gt;Click on DNS Settings&lt;/li&gt;&lt;li&gt;Click Add Record&lt;/li&gt;&lt;li&gt;Select CNAME record type&lt;/li&gt;&lt;li&gt;Enter the domain name I wanted to use. I chose to use &quot;static&quot; (static.castlesblog.com)&lt;/li&gt;&lt;li&gt;Finally, enter the canonical name of the domain. For me I used www.castlesblog.com&lt;/li&gt;&lt;li&gt;Click Ok and then Save&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;One other thing I needed to do to get this to work in Plesk was to create a vhost.conf file in the domain conf directory (/var/www/vhosts/castlesblog.com/conf/vhost.conf) with the following content: &quot;ServerAlias static.castlesblog.com&quot; then reconfigure that domain:&lt;/p&gt;&lt;pre&gt;/usr/local/psa/admin/sbin/websrvmng --reconfigure-vhost --vhost-name=castlesblog.com&lt;/pre&gt;&lt;p&gt;The last thing I needed to do was update all my posts and html links to the static domain. For example the following:&lt;/p&gt;&lt;pre&gt;&amp;lt;img src=&amp;quot;/data/img1.jpg&amp;quot; /&amp;gt;&lt;/pre&gt;&lt;p&gt;would become:&lt;/p&gt;&lt;pre&gt;&amp;lt;img src=&amp;quot;http://static.castlesblog.com/data/img1.jpg&amp;quot; /&amp;gt;&lt;/pre&gt;&lt;p&gt;To prevent people browsing the secondary domain I setup a .htaccess redirect to redirect any non file requests to the proper domain. The code looks like this:&lt;/p&gt;&lt;pre&gt;# cookieless domain for images and stuff
RewriteCond %{HTTP_HOST} ^static\.castlesblog\.com [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ http://www.castlesblog.com/$1 [R=301,L]&lt;/pre&gt;&lt;a name=dynamic-static&gt;&lt;/a&gt;&lt;h2&gt;Serve dynamic-static files&lt;/h2&gt;&lt;p&gt;One final optimisation was to serve javascript as one file to save browser requests. I like to separate javascript files so that it obvious what is in them so I wasn't going to move all the javascript into one file. I managed to get the merge working with the following code:&lt;/p&gt;&lt;pre&gt;&amp;lt;?php
$offset = 60 * 60 * 24 * 7; // Cache for 1 weeks
header('Content-type: application/x-javascript');
header('Accept-Ranges: bytes');
header ('Cache-Control: max-age=' . $offset);
header ('Expires: ' . gmdate (&amp;quot;D, d M Y H:i:s&amp;quot;, time() + $offset) . ' GMT');
header ('Pragma: cache');

if(!ob_start(&amp;quot;ob_gzhandler&amp;quot;)) ob_start();

include('../javascript/jquery-1.4.2.min.js');
include('../javascript/jquery.easing.js');
include('../templates/castlesblog/template.js');&lt;/pre&gt;&lt;p&gt;When a site needs a new javascript file I will include it in this file and the php will do the rest.&lt;/p&gt;&lt;p&gt;To make the script tag look like this:&lt;/p&gt;&lt;pre&gt;&amp;lt;script src=&amp;quot;http://static.castlesblog.com/javascript/scripts.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;p&gt;I added the following to the .htaccess:&lt;/p&gt;&lt;pre&gt;#compile all scripts into one file...
RewriteRule ^javascript/scripts.js$ includes/scripts.php [L]&lt;/pre&gt;&lt;h2&gt;Final Test&lt;/h2&gt;&lt;p&gt;To see if this works I will include the same file from two different domains. This first file should have cookies and the second should not.&lt;/p&gt;&lt;img src=&quot;/data/iphone-screenshot.jpg&quot; alt=&quot;iPhone Preview&quot; /&gt;&lt;img src=&quot;http://static.castlesblog.com/data/iphone-screenshot.jpg&quot; alt=&quot;iPhone Preview&quot; /&gt;&lt;p&gt;And the results are in.. I think they speak for themselves:&lt;/p&gt;&lt;img src=&quot;http://static.castlesblog.com/data/cookieless-results.png&quot; alt=&quot;cookieless domain results&quot; /&gt;</description>
<pubDate>Sat, 27 Feb 2010 04:52:10 +0000</pubDate>
</item><item>
<title>New Template</title>
<link>http://www.castlesblog.com/2010/january/18/new-template</link>
<description>&lt;p&gt;Over the last month or so I've been putting together a new template for this site. It's not quite finished yet but I thought its better to release it at its current stage (Otherwise it will be another month before an update). The most notable features are:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;HTML5 compliant&lt;/li&gt;&lt;li&gt;
CSS3 Gradients&lt;/li&gt;&lt;li&gt;CSS3 rounded corners + rgba colours&lt;/li&gt;&lt;li&gt;Mobile device support (only tested on my iPhone)&lt;/li&gt;&lt;li&gt;@font-face for the title&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Surprisingly it looks alright in older browsers.... and cough.. IE. Internet Explorer manages a gradient behind the menu buttons via the use of a css expression.&lt;/p&gt;</description>
<pubDate>Mon, 18 Jan 2010 00:09:23 +0000</pubDate>
</item><item>
<title>MythTV Pre-Shutdown script</title>
<link>http://www.castlesblog.com/2010/january/1/mythtv-pre-shutdown-script</link>
<description>&lt;p&gt;Just like my previous post this is here so I won't forget how I setup my MythTV pre shutdown script. This will check for netatalk connections, terminal (via ssh or locally) or if transmission is open.&lt;/p&gt;&lt;p&gt;Script file: /usr/bin/mythpreshutdown.sh&lt;/p&gt;

&lt;pre&gt;#!/bin/sh

logfile=/var/log/mythtv/mythpreshutdown.log
echo `date` &gt; $logfile

ps_afpd=`ps axo euid,comm,user | grep afpd | grep -v -c root`
ps_who=`who | grep -c pts`
ps_transmission=`ps aux | grep transmission | grep -v -c grep`

SD=0

if [ $ps_who != 0 ]; then
  echo &quot;user logged in&quot; &gt;&gt; $logfile
  SD=1
fi

if [ $ps_afpd != 0 ]; then
  echo &quot;afpd connection exists&quot; &gt;&gt; $logfile
  SD=1
fi

if [ $ps_transmission != 0 ]; then
  echo &quot;transmission running&quot; &gt;&gt; $logfile
  SD=1
fi

exit $SD&lt;/pre&gt;</description>
<pubDate>Fri, 1 Jan 2010 07:08:07 +0000</pubDate>
</item></channel></rss>