<?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>Pixel Acres &#187; Programming</title>
	<atom:link href="http://f6design.com/journal/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://f6design.com/journal</link>
	<description>Adventures in web and graphic design</description>
	<lastBuildDate>Wed, 16 May 2012 06:50:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>A jQuery plugin boilerplate</title>
		<link>http://f6design.com/journal/2012/05/06/a-jquery-plugin-boilerplate/</link>
		<comments>http://f6design.com/journal/2012/05/06/a-jquery-plugin-boilerplate/#comments</comments>
		<pubDate>Sun, 06 May 2012 14:17:46 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Toolbox]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=2430</guid>
		<description><![CDATA[I created this boilerplate for a jQuery plugin I&#8217;m working on, and you can use it to kick start your own jQuery plugin development. The features of my boilerplate are: Plugin can be customised using options Setters/Getters for options Private and public methods Callback hooks Plugin instances can be destroyed The boilerplate Here is the [...]]]></description>
			<content:encoded><![CDATA[<p>I created this boilerplate for a jQuery plugin I&#8217;m working on, and you can use it to kick start your own jQuery plugin development. The features of my boilerplate are:</p>
<ul>
<li>Plugin can be customised using options</li>
<li>Setters/Getters for options</li>
<li>Private and public methods</li>
<li>Callback hooks</li>
<li>Plugin instances can be destroyed</li>
</ul>
<h2>The boilerplate</h2>
<p>Here is the bare bones, uncommented boilerplate source code:</p>
<pre class="brush: jscript; title: ; notranslate">/**
 * A jQuery plugin boilerplate.
 * Author: Jonathan Nicol @f6design
 */
;(function($) {
  var pluginName = 'demoplugin';

  function Plugin(element, options) {
    var el = element;
    var $el = $(element);

    options = $.extend({}, $.fn[pluginName].defaults, options);

    function init() {
      // Add any initialization logic here...

      hook('onInit');
    }

    function fooPublic() {
      // Code goes here...
    }

    function option (key, val) {
      if (val) {
        options[key] = val;
      } else {
        return options[key];
      }
    }

    function destroy() {
      $el.each(function() {
        var el = this;
        var $el = $(this);

        // Add code to restore the element to its original state...

        hook('onDestroy');
        $el.removeData('plugin_' + pluginName);
      });
    }

    function hook(hookName) {
      if (options[hookName] !== undefined) {
        options[hookName].call(el);
      }
    }

    init();

    return {
      option: option,
      destroy: destroy,
      fooPublic: fooPublic
    };
  }

  $.fn[pluginName] = function(options) {
    if (typeof arguments[0] === 'string') {
      var methodName = arguments[0];
      var args = Array.prototype.slice.call(arguments, 1);
      var returnVal;
      this.each(function() {
        if ($.data(this, 'plugin_' + pluginName) &amp;&amp; typeof $.data(this, 'plugin_' + pluginName)[methodName] === 'function') {
          returnVal = $.data(this, 'plugin_' + pluginName)[methodName].apply(this, args);
        } else {
          throw new Error('Method ' +  methodName + ' does not exist on jQuery.' + pluginName);
        }
      });
      if (returnVal !== undefined){
        return returnVal;
      } else {
        return this;
      }
    } else if (typeof options === &quot;object&quot; || !options) {
      return this.each(function() {
        if (!$.data(this, 'plugin_' + pluginName)) {
          $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
        }
      });
    }
  };

  $.fn[pluginName].defaults = {
    onInit: function() {},
    onDestroy: function() {}
  };

})(jQuery);</pre>
<p>&#8230;and with liberal comments:</p>
<pre class="brush: jscript; title: ; notranslate">/**
 * A jQuery plugin boilerplate.
 * Author: Jonathan Nicol @f6design
 */
;(function($) {
  // Change this to your plugin name.
  var pluginName = 'demoplugin';

  /**
   * Plugin object constructor.
   * Implements the Revealing Module Pattern.
   */
  function Plugin(element, options) {
    // References to DOM and jQuery versions of element.
    var el = element;
    var $el = $(element);

    // Extend default options with those supplied by user.
    options = $.extend({}, $.fn[pluginName].defaults, options);

    /**
     * Initialize plugin.
     */
    function init() {
      // Add any initialization logic here...

      hook('onInit');
    }

    /**
     * Example Public Method
     */
    function fooPublic() {
      // Code goes here...
    }

    /**
     * Get/set a plugin option.
     * Get usage: $('#el').demoplugin('option', 'key');
     * Set usage: $('#el').demoplugin('option', 'key', value);
     */
    function option (key, val) {
      if (val) {
        options[key] = val;
      } else {
        return options[key];
      }
    }

    /**
     * Destroy plugin.
     * Usage: $('#el').demoplugin('destroy');
     */
    function destroy() {
      // Iterate over each matching element.
      $el.each(function() {
        var el = this;
        var $el = $(this);

        // Add code to restore the element to its original state...

        hook('onDestroy');
        // Remove Plugin instance from the element.
        $el.removeData('plugin_' + pluginName);
      });
    }

    /**
     * Callback hooks.
     * Usage: In the defaults object specify a callback function:
     * hookName: function() {}
     * Then somewhere in the plugin trigger the callback:
     * hook('hookName');
     */
    function hook(hookName) {
      if (options[hookName] !== undefined) {
        // Call the user defined function.
        // Scope is set to the jQuery element we are operating on.
        options[hookName].call(el);
      }
    }

    // Initialize the plugin instance.
    init();

    // Expose methods of Plugin we wish to be public.
    return {
      option: option,
      destroy: destroy,
      fooPublic: fooPublic
    };
  }

  /**
   * Plugin definition.
   */
  $.fn[pluginName] = function(options) {
    // If the first parameter is a string, treat this as a call to
    // a public method.
    if (typeof arguments[0] === 'string') {
      var methodName = arguments[0];
      var args = Array.prototype.slice.call(arguments, 1);
      var returnVal;
      this.each(function() {
        // Check that the element has a plugin instance, and that
        // the requested public method exists.
        if ($.data(this, 'plugin_' + pluginName) &amp;&amp; typeof $.data(this, 'plugin_' + pluginName)[methodName] === 'function') {
          // Call the method of the Plugin instance, and Pass it
          // the supplied arguments.
          returnVal = $.data(this, 'plugin_' + pluginName)[methodName].apply(this, args);
        } else {
          throw new Error('Method ' +  methodName + ' does not exist on jQuery.' + pluginName);
        }
      });
      if (returnVal !== undefined){
        // If the method returned a value, return the value.
        return returnVal;
      } else {
        // Otherwise, returning 'this' preserves chainability.
        return this;
      }
    // If the first parameter is an object (options), or was omitted,
    // instantiate a new instance of the plugin.
    } else if (typeof options === &quot;object&quot; || !options) {
      return this.each(function() {
        // Only allow the plugin to be instantiated once.
        if (!$.data(this, 'plugin_' + pluginName)) {
          // Pass options to Plugin constructor, and store Plugin
          // instance in the elements jQuery data object.
          $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
        }
      });
    }
  };

  // Default plugin options.
  // Options can be overwritten when initializing plugin, by
  // passing an object literal, or after initialization:
  // $('#el').demoplugin('option', 'key', value);
  $.fn[pluginName].defaults = {
    onInit: function() {},
    onDestroy: function() {}
  };

})(jQuery);</pre>
<h2>Usage</h2>
<p>The first thing you&#8217;ll need to do is change the name of the plugin, which is hardcoded as &#8216;demoplugin&#8217;, to something a little more descriptive. After that you should be able to follow the comments in the source code to customise the plugin.</p>
<p>Here are examples of how an end-user would interact with the plugin:</p>
<pre class="brush: jscript; title: ; notranslate">// Initialize plugin with default options.
$('#element').demoplugin();

// Initialize plugin with user defined options.
$('#element').demoplugin({
  option1: 2000,
  option2: 'value',
  callback1: function () { ... }
});

// Call a public method, no arguments.
$('#element').demoplugin('publicFunctionName');

// Call a public method with arguments.
$('#element').demoplugin('publicFunctionName', 'arg1', 'arg2');

// Get a plugin option.
$('#element').demoplugin('option', 'key');

// Set a plugin option after plugin initialization.
$('#element').demoplugin('option', 'key', value);

// Destroy plugin.
$('#element').demoplugin('destroy');</pre>
<h2>Setup options</h2>
<p>It is very useful to be able to customise jQuery plugins on a per instance basis. The boilerplate implements default settings which can be overwritten when the plugin is initialized:</p>
<pre class="brush: jscript; title: ; notranslate">// Default plugin options.
$.fn[pluginName].defaults = {
  color: '#ff0000',
  height: 200
};</pre>
<pre class="brush: jscript; title: ; notranslate">$('#element').demoplugin({
  color: '#0000ff',
  height: 400
});</pre>
<p>Options can also be overwritten after the plugin is initialized, using the <code>option</code> method:</p>
<pre class="brush: jscript; title: ; notranslate">$('#element').demoplugin('option', 'color', '#00ff00');</pre>
<p>An option value can be fetched using the same method by simply omitting the third parameter:</p>
<pre class="brush: jscript; title: ; notranslate">var color = $('#element').demoplugin('option', 'color');</pre>
<h2>Public and private methods</h2>
<p>Private functions reduce the chance of your users inadvertently calling the plugin&#8217;s utility methods. I&#8217;m a fan of the <a href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript">Revealing Module pattern</a>, so that&#8217;s how I chose to implement private/public functionality in my boilerplate.</p>
<pre class="brush: jscript; title: ; notranslate">function Plugin(element, options) {
  // This method is public.
  function fooPublic(param1, param2) {
    // ...
  }

  // This method is private.
  function fooPrivate() {
    // ...
  }

  // Expose methods of Plugin we wish to be public.
  return {
    fooPublic: fooPublic
  };
}</pre>
<p>Public functions can be called by your users like so:</p>
<pre class="brush: jscript; title: ; notranslate">$('#element').demoplugin('fooPublic', 'val1', 'val2');</pre>
<h2>Callback hooks</h2>
<p>Callback hooks are incredibly powerful. They allow your users to listen for events in your plugin&#8217;s behaviour and respond accordingly. Hooks are implemented as functions in the default options object:</p>
<pre class="brush: jscript; title: ; notranslate">$.fn[pluginName].defaults = {
  onSlideshowFinished: function() {}
};</pre>
<p>Each function is empty to begin with, since the callback&#8217;s behaviour will be defined by the user. This is done by overwriting the callback function when setting the plugin&#8217;s options. The scope of the callback is the DOM element the plugin is attached to, so in the following example the DOM element would be hidden.</p>
<pre class="brush: jscript; title: ; notranslate">$('#element').demoplugin({
  onSlideshowFinished: function() {
    $(this).hide();
  }
});</pre>
<p>To trigger a hook, call the plugin&#8217;s <code>hook</code> method:</p>
<pre class="brush: jscript; title: ; notranslate">hook('onSlideshowFinished');</pre>
<p>There are two callbacks implemented by default in the boilerplate: <code>onInit</code> and <code>onDestroy</code>.</p>
<h2>Destroying a plugin instance</h2>
<p>Your users can remove an instance of the plugin by calling its <code>destroy</code> method:</p>
<pre class="brush: jscript; title: ; notranslate">$('#element').demoplugin('destroy');</pre>
<p>The plugin stores all its functionality in its DOM element&#8217;s <code>data</code> object. By default the <code>destroy</code> method simply removes the stored <code>data</code> values. You will probably need to customise <code>destroy</code> to restore the DOM element to its original state and remove any event handlers your plugin has created.</p>
<h2>Credit</h2>
<p>My boilerplate takes inspiration from a number of sources, most notably the jQuery <a href="http://docs.jquery.com/Plugins/Authoring">plugin authoring guidelines</a>, Stefan Gabos&#8217; <a href="http://stefangabos.ro/jquery/jquery-plugin-boilerplate-oop/">boilerplate</a>, and Zeno Rocha and Addy Osmani&#8217;s <a href="http://jqueryboilerplate.com/">jQuery Boilerplate</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2012/05/06/a-jquery-plugin-boilerplate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Test your JavaScript skills with js-assessment</title>
		<link>http://f6design.com/journal/2012/04/15/test-your-javascript-skills-with-js-assessment/</link>
		<comments>http://f6design.com/journal/2012/04/15/test-your-javascript-skills-with-js-assessment/#comments</comments>
		<pubDate>Sun, 15 Apr 2012 09:47:52 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[News & Reviews]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=2365</guid>
		<description><![CDATA[I recently discovered js-assessment, a &#8220;test-driven approach to assessing JavaScript skills&#8221; created by Rebecca Murphey. The js-assessment application contains a series of tests designed to assess a job candidate&#8217;s grasp of JavaScript, but it can also be used to gauge your own knowledge of the language. Think of it as a mini Project Euler for [...]]]></description>
			<content:encoded><![CDATA[<p>I recently discovered <a href="https://github.com/rmurphey/js-assessment">js-assessment</a>, a &#8220;test-driven approach to assessing JavaScript skills&#8221; created by <a href="http://rmurphey.com/">Rebecca Murphey</a>. The js-assessment application contains a series of tests designed to assess a job candidate&#8217;s grasp of JavaScript, but it can also be used to gauge your own knowledge of the language. Think of it as a mini <a href="http://projecteuler.net/">Project Euler</a> for JavaScript.</p>
<p>The questions are divided into five topics covering different aspects of the language: arrays, objects and context, functions, asynchronous behavior and <a href="http://documentcloud.github.com/backbone/">Backbone</a> views. If, like me, you have a decent grasp of JavaScript, but wouldn&#8217;t feel confident writing &#8220;JavaScript programmer&#8221; on your curriculum vitae, then I think you&#8217;ll find the tests an enjoyable challenge. None of the questions are super difficult, though I confess to needing help from <a href="https://developer.mozilla.org/en-US/">MDN</a> to arrive at a few of the solutions. I definitely learned a thing or two about JavaScript along the way.</p>
<p>Because Rebecca&#8217;s application is built in Node, you&#8217;ll need to have <a href="http://nodejs.org">Node</a> and <a href="http://npmjs.org/">NPM</a> installed before you can run it. That&#8217;s a shortcoming I think, since it throws up a fairly large barrier-to-entry, but if you&#8217;re serious about JavaScript then you really ought to delve into Node anyway. I won&#8217;t bore you with instructions for installing Node &#8211; you can do it using <a href="http://mxcl.github.com/homebrew/">Homebrew</a> or download an installer from the official <a href="http://nodejs.org/#download">Node website</a>. After that, just follow the steps on the <a href="https://github.com/rmurphey/js-assessment">js-assessment github</a> and you&#8217;ll be up and running.</p>
<p>Rebecca seems undecided about whether to publish solutions to the tests, but in the name of sharing the knowledge (and at the risk of exposing my own shortcomings as a programmer), you&#8217;ll find my answers below. My solutions won&#8217;t make much sense taken out of context like this, but once your start working your way through js-assessment things will become a lot clearer.</p>
<p>Although my solutions pass Rebecca&#8217;s tests I&#8217;m sure some of them could be improved, so if you have suggestions for optimizing my code please leave a comment below.</p>
<h2>Arrays</h2>
<h4>1. You should be able to determine the location of an item in an array</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (arr, targ) {
  for (var pos=0; pos &lt; arr.length; pos++){
    if (arr[pos] == targ){
      return pos;
    }
  }
};</pre>
<h4>2. You should be able to add the values of an array</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (arr) {
  var total = 0;
  for (var pos=0; pos &lt; arr.length; pos++) {
    total += arr[pos];
  }
  return total;
};</pre>
<h4>3. You should be able to remove an item from an array</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (arr, itemToRemove) {
  for (var pos=0; pos &lt; arr.length; pos++){
    if (arr[pos] == itemToRemove){
      var removedItem = arr.splice(pos,1);
    }
  }
  return arr;
};</pre>
<h4>4. You should be able to add an item to the end of an array</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (arr, itemToAdd) {
  arr.push(itemToAdd);
  return arr;
};</pre>
<h4>5. You should be able to create an array from two arrays</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (arr1, arr2) {
  var arr = arr1.concat(arr2);
  return arr;
};</pre>
<h4>6. You should be able to add an item anywhere in an array</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (arr, itemToAdd, pos) {
  arr.splice(pos, 0, itemToAdd);
  return arr;
};</pre>
<h2>Objects and context</h2>
<h4>1. You should be able to alter the context in which a method runs</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function () {
  // Call the sayIt() function and pass it the
  // 'b' object as its context.
  return a.sayIt.call(b);
};</pre>
<h4>2. You should be able to alter multiple objects at once</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (greeting) {
  C.prototype.greeting = greeting;
};</pre>
<h4>3. You should be able to iterate over an object&#8217;s &#8216;own&#8217; properties</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (obj) {
  var ownProperties = [];
  for (var prop in obj) {
    // hasOwnProperty returns true if the property
    // belongs to the object, not its prototype chain.
    if (obj.hasOwnProperty(prop)) {
      ownProperties.push(prop + ': ' + obj[prop]);
    }
  }
  return ownProperties;
};</pre>
<h2>Functions</h2>
<h4>1. You should be able to use an array as arguments when calling a function</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (opts) {
  // Call the sayIt() function in the context of 'this'
  // and pass it the 'opts' array.
  return sayIt.apply(this, opts);
};</pre>
<h4>2. You should be able to change the context in which a function is called</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (opts){
  // Call the speak() function in the context of 'obj'.
  return speak.call(obj);
};</pre>
<h4>3. You should be able to return a function from a function</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (prefix) {
  var concatFn = function(suffix) {
    return prefix + ', ' + suffix;
  };
  return concatFn;
};</pre>
<h4>4. You should be able to create a &#8216;partial&#8217; function</h4>
<pre class="brush: jscript; title: ; notranslate">fn = function (func, greeting, name) {
  var partialFn = function(punctuation) {
    return func(greeting, name, punctuation);
  };
  return partialFn;
};</pre>
<h2>Async behavior</h2>
<h4>1. You should understand how to uses &#8216;promises&#8217;</h4>
<p>As far as I know promises are not part of the JavaScript language, and need to be implemented using a third party library. In my solution I used jQuery&#8217;s <a href="http://api.jquery.com/deferred.promise/">deferred object</a> to return a promise.</p>
<pre class="brush: jscript; title: ; notranslate">fn = function () {
  // This is a contrived example to demonstrate that the promise
  // is returned asynchronously after a 1sec timeout.
  var dfd = $.Deferred();
  var timeoutID = window.setTimeout(function(){
    dfd.resolve(true);
  }, 1000);
  return dfd.promise();
};</pre>
<h4>2. You should be able to receive data from the server and manipulate it</h4>
<pre class="brush: jscript; title: ; notranslate">var get = $.ajax({
  url: url
});

// Since jQuery's $.ajax returns a promise, we can use
// .done and .fail callbacks.
get.done(function(response){
  peopleArray = [];
    for (var person in response.people){
      peopleArray.push(response.people[person].name);
    }
    peopleArray.sort(); // Not required in this case.
    tests();
});

get.fail(function(){
  console.log('Load failed');
});</pre>
<h2>Backbone views</h2>
<p>This section of the test relies on knowledge of the <a href="http://documentcloud.github.com/backbone/">Backbone</a> framework. Personally that doesn&#8217;t bother me since I have used Backbone before, but I&#8217;m not sure that Backbone knowledge should be considered mandatory for a JavaScript professional.</p>
<h4>1. You should be able to render a view using a template</h4>
<pre class="brush: jscript; title: ; notranslate">var MyView = Backbone.View.extend({
  template : tpl,
  render : function() {
    // This could be written on a single line, but I've
    // split across 3 lines for readability:
    var compiledTemplate = _.template(this.template);
    var viewHTML = compiledTemplate(this.model.toJSON());
    $('body').append(viewHTML);
  }
});</pre>
<h4>2. You should be able to update the view when the model changes</h4>
<pre class="brush: jscript; title: ; notranslate">var MyView = Backbone.View.extend({
  initialize : function() {
    this.model.bind('change:greeting', this.render, this);
    this.model.set({greeting: 'Goodbye, world'});
  },
  template : tpl,
  render : function() {
    $('#my-view').html(this.model.get('greeting'));
  }
});</pre>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2012/04/15/test-your-javascript-skills-with-js-assessment/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t believe the hype</title>
		<link>http://f6design.com/journal/2012/04/12/dont-believe-the-hype/</link>
		<comments>http://f6design.com/journal/2012/04/12/dont-believe-the-hype/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 03:17:27 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=2329</guid>
		<description><![CDATA[This week I came across a new JavaScript framework, called Meteor, which promises to simplify the process of developing web applications. It looks like an interesting project, run by some very smart and talented people, but something about the Meteor marketing pitch rubbed me the wrong way. The Meteor website is full of claims about [...]]]></description>
			<content:encoded><![CDATA[<p>This week I came across a new JavaScript framework, called <a href="http://meteor.com">Meteor</a>, which promises to simplify the process of developing web applications. It looks like an interesting project, run by some very smart and talented people, but something about the Meteor marketing pitch rubbed me the wrong way.</p>
<p>The Meteor website is full of claims about how amazingly easy the framework will make web developer&#8217;s lives. It will allow us to build &#8220;top-quality web apps in a fraction of the time.&#8221; Its demo applications require &#8220;no programming knowledge.&#8221; What &#8220;once took weeks, even with the best tools, now takes hours.&#8221; In fact, you can &#8220;build a complete application in a weekend.&#8221;</p>
<p>If building Facebook or Twitter was really something that could be done in a weekend, wouldn&#8217;t everyone and their dog be CEO of their own Internet startup? If the barrier to entry was as low as the Meteor team would have us believe, then business owners would have no need for developers at all &#8211; a few hours of training and they&#8217;d have all the skills required to build their own app or website.</p>
<p>Obviously that&#8217;s not the case. Success in any field is hard earned, and it bugs me that some of our industry&#8217;s leaders perpetuate the idea that there are short cuts to becoming an accomplished web developer. Sure, it&#8217;s <em>possible</em> to build a killer app in a weekend, but to do so requires years of experience and a deep knowledge of your tools, and many more days, weeks, or months are required to turn that prototype into a robust website or application.</p>
<p>It may sound as if my gripe is with Meteor specifically, but that isn&#8217;t the case. I see similarly hyperbolic claims wherever I look. Publishers hawk their technical reference books with promises to convert novice coders into &#8220;ninjas&#8221;. The sales pitch for a commercial iOS design tutorial implies that it can &#8220;make you tons of money, and elevate your status within the design community&#8221;. An advertisement for <a href="http://teamtreehouse.com/">Treehouse</a> suggests that after joining their service you&#8217;ll soon be rubbing shoulders with Mark Zuckerberg. If you take these claims at face value you could be forgiven for thinking that all that is required to excel as a developer is a few hours of your time, a couple of hundred bucks to spend on training, and the right JavaScript framework.</p>
<p>In reality, web design and development are highly specialised disciplines that take years of practice to master, and require ongoing training to stay abreast of the near-constant advances in the field. I don&#8217;t think it does our industry any favours to pretend that mastery can be achieved in a weekend. If we don&#8217;t take our own professional expertise seriously, why should anyone else?</p>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2012/04/12/dont-believe-the-hype/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Launching XAMPP at OSX startup</title>
		<link>http://f6design.com/journal/2012/03/12/launching-xampp-at-osx-startup/</link>
		<comments>http://f6design.com/journal/2012/03/12/launching-xampp-at-osx-startup/#comments</comments>
		<pubDate>Mon, 12 Mar 2012 21:42:14 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=2298</guid>
		<description><![CDATA[A few days ago I posted about my experiences setting up XAMPP on OSX. Here&#8217;s another little XAMPP tip&#8230; By default XAMPP won&#8217;t start the Apache and MySQL services at system startup, so every time you reboot your computer you&#8217;ll need to restart them. Wouldn&#8217;t it be nice if those services started automatically? One way [...]]]></description>
			<content:encoded><![CDATA[<p>A few days ago I posted about my experiences setting up XAMPP on OSX. Here&#8217;s another little XAMPP tip&#8230;</p>
<p>By default XAMPP won&#8217;t start the Apache and MySQL services at system startup, so every time you reboot your computer you&#8217;ll need to restart them. Wouldn&#8217;t it be nice if those services started automatically? One way of doing that is to create a Launch Daemon that runs at system startup and have it start XAMPP for us.</p>
<p>Fire up Terminal, and run the following command:</p>
<pre class="brush: bash; title: ; notranslate">cd /Library/LaunchDaemons
sudo nano apachefriends.xampp.apache.start.plist</pre>
<p>Enter your OSX password when prompted, then in <a href="http://en.wikipedia.org/wiki/GNU_nano">nano</a> paste the following into your new plist:</p>
<pre class="brush: xml; title: ; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
&lt;dict&gt;
&lt;key&gt;EnableTransactions&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;Label&lt;/key&gt;
&lt;string&gt;apachefriends.xampp.apache.start&lt;/string&gt;
&lt;key&gt;ProgramArguments&lt;/key&gt;
&lt;array&gt;
&lt;string&gt;/Applications/XAMPP/xamppfiles/xampp&lt;/string&gt;
&lt;string&gt;startapache&lt;/string&gt;
&lt;/array&gt;
&lt;key&gt;RunAtLoad&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;WorkingDirectory&lt;/key&gt;
&lt;string&gt;/Applications/XAMPP/xamppfiles&lt;/string&gt;
&lt;key&gt;KeepAlive&lt;/key&gt;
&lt;false/&gt;
&lt;key&gt;AbandonProcessGroup&lt;/key&gt;
&lt;true/&gt;
&lt;/dict&gt;
&lt;/plist&gt;</pre>
<p>Save the file and exit nano (<code>control+o</code>, <code>return</code>, <code>control+x</code>).</p>
<p>Now run the following terminal command:</p>
<pre class="brush: bash; title: ; notranslate">sudo nano apachefriends.xampp.mysql.start.plist</pre>
<p>And into this new file paste:</p>
<pre class="brush: xml; title: ; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
&lt;dict&gt;
&lt;key&gt;EnableTransactions&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;Label&lt;/key&gt;
&lt;string&gt;apachefriends.xampp.mysql.start&lt;/string&gt;
&lt;key&gt;ProgramArguments&lt;/key&gt;
&lt;array&gt;
&lt;string&gt;/Applications/XAMPP/xamppfiles/xampp&lt;/string&gt;
&lt;string&gt;startmysql&lt;/string&gt;
&lt;/array&gt;
&lt;key&gt;RunAtLoad&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;WorkingDirectory&lt;/key&gt;
&lt;string&gt;/Applications/XAMPP/xamppfiles&lt;/string&gt;
&lt;key&gt;KeepAlive&lt;/key&gt;
&lt;false/&gt;
&lt;key&gt;AbandonProcessGroup&lt;/key&gt;
&lt;true/&gt;
&lt;/dict&gt;
&lt;/plist&gt;</pre>
<p>Save the file and exit nano (<code>control+o</code>, <code>return</code>, <code>control+x</code>).</p>
<p>When you restart your computer the XAMPP Apache and MySQL services should start automatically. You can check this by launching XAMPP Control and checking that Apache and MySQL have green lights displayed next to them.</p>
<h3>A note about security</h3>
<p>If you&#8217;re concerned about the security of your system while running XAMPP, the safest approach is not to run Apache or MySQL at all, in which case you might not want to have those services running while you&#8217;re not using them. However, I&#8217;m fairly certain that unless you intentionally open up port 80 in your hardware/software firewall your XAMPP server should be invisible outside your local network.</p>
<h3>Credit</h3>
<p>A hat tip to &#8216;cwd&#8217;, who <a href="http://superuser.com/questions/243606/i-cant-get-xampp-to-start-automatically-in-os-x">posted this solution</a> on Superuser. I tried a couple of other approaches before I stumbled upon this one which actually works.</p>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2012/03/12/launching-xampp-at-osx-startup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Configuring VirtualHosts in XAMPP on Mac</title>
		<link>http://f6design.com/journal/2012/03/11/configuring-virtualhosts-in-xampp-on-mac/</link>
		<comments>http://f6design.com/journal/2012/03/11/configuring-virtualhosts-in-xampp-on-mac/#comments</comments>
		<pubDate>Sun, 11 Mar 2012 12:02:51 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=2242</guid>
		<description><![CDATA[A few weeks back I rejoined the &#8220;Cult of Mac&#8221; when I replaced my old Asus notebook with a MacBook Pro, and since then I&#8217;ve been busy settling into my new OSX workflow. I do all my development locally, so one of the first applications I installed was XAMPP, a cross platform Apache/MySQL/PHP stack. While [...]]]></description>
			<content:encoded><![CDATA[<p>A few weeks back I rejoined the &#8220;Cult of Mac&#8221; when I replaced my old Asus notebook with a MacBook Pro, and since then I&#8217;ve been busy settling into my new OSX workflow. I do all my development locally, so one of the first applications I installed was <a href="http://www.apachefriends.org/en/xampp-macosx.html">XAMPP</a>, a cross platform Apache/MySQL/PHP stack. While I know that <a href="http://www.mamp.info/">MAMP</a> is very popular on Mac, I have been using XAMPP for many years so I thought I&#8217;d stick with what I know.</p>
<p>Installing XAMPP was a snap, but when I came to create my own <a href="http://httpd.apache.org/docs/2.0/vhosts/">Apache VirtualHosts</a> things started getting fiddly. Here are the steps I followed to get everything running smoothly.</p>
<h3>What are VirtualHosts?</h3>
<p>First, some quick background on what we&#8217;re trying to achieve.</p>
<p>VirtualHosts allow Apache to map a hostname to a directory on the filesystem. You can set up as many VirtualHosts as you need, so that each website operates under its own hostname. For example, you might want to map <code>mysite.local</code> to <code>/Users/yourusername/mysite</code>. To test your development site all you would need to do is plug &#8220;http://mysite.local&#8221; into your browser&#8217;s address bar.</p>
<h3>Enable VirtualHosts</h3>
<p>The first thing you&#8217;ll need to do is open the file <code>/Applications/XAMPP/xamppfile/etc/httpd.conf</code> in your favourite text editor. Look for the following lines:</p>
<pre class="brush: plain; title: ; notranslate"># Virtual hosts
#Include /Applications/XAMPP/etc/extra/httpd-vhosts.conf</pre>
<p>Uncomment the second line by removing the hash (<code>#</code>), so that Apache loads your custom VirtualHosts configuration file:</p>
<pre class="brush: plain; title: ; notranslate"># Virtual hosts
Include /Applications/XAMPP/etc/extra/httpd-vhosts.conf</pre>
<h3>Create your VirtualHosts</h3>
<p>Open the file <code>/Applications/XAMPP/xamppfile/etc/extra/httpd-vhosts.conf</code>. Towards the bottom of the file you will see some example VirtualHosts, which you should comment out or delete.</p>
<p>At the bottom of the file, add &#8216;localhost&#8217; as the default named VirtualHost:</p>
<pre class="brush: plain; title: ; notranslate"># localhost
&lt;VirtualHost *:80&gt;
    ServerName localhost
    DocumentRoot &quot;/Applications/XAMPP/htdocs&quot;
    &lt;Directory &quot;/Applications/XAMPP/htdocs&quot;&gt;
        Options Indexes FollowSymLinks Includes execCGI
        AllowOverride None
        Order Allow,Deny
        Allow From All
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;</pre>
<p>This step is necessary to ensure that http://localhost still points at XAMPP&#8217;s <code>htdocs</code> directory once we&#8217;ve created our custom VirtualHosts. Personally I don&#8217;t use the <code>htdocs</code> directory a lot, but occasionally it&#8217;s useful to have somewhere to perform quick tests.</p>
<p>Now you are ready to create your own VirtualHosts. After the default localhost that you just created, add:</p>
<pre class="brush: plain; title: ; notranslate"># My custom host
&lt;VirtualHost *:80&gt;
    ServerName mysite.local
    DocumentRoot &quot;/Users/yourusername/path/to/your/site&quot;
    &lt;Directory &quot;/Users/yourusername/path/to/your/site&quot;&gt;
        Options Indexes FollowSymLinks Includes ExecCGI
        AllowOverride None
        Order Allow,Deny
        Allow From All
    &lt;/Directory&gt;
    ErrorLog &quot;logs/mysite.local-error_log&quot;
&lt;/VirtualHost&gt;</pre>
<p>In the above example you should replace &#8220;mysite.local&#8221; with your own hostname. This can be anything you wish, but make sure you choose a hostname that won&#8217;t conflict with a real domain name. Using a .local extension makes it obvious that the site is hosted locally rather than on a public web server.</p>
<p>The path to your website can point at any folder in your OSX user directory. I store most of my sites inside of <a href="https://www.dropbox.com/">Dropbox</a> so that I can access them on both my home and work machines. If your path includes spaces, make sure you enclose it in quotes, like in my example.</p>
<h3>Edit your hosts file</h3>
<p>Once you&#8217;ve saved your <code>httpd.conf</code> and <code>httpd-vhosts.conf</code> files, the next step is to edit your OSX <a href="http://en.wikipedia.org/wiki/Hosts_(file)">hosts file</a> so it knows how to handle your new <code>ServerName</code>. The hosts file is used by OSX to map hostnames to IP addresses. In this case we want to map your new <code>ServerName</code> to the IP address 127.0.0.1, which is your localhost.</p>
<p>Fire up a Terminal instance, and at the prompt type the following command:</p>
<pre class="brush: bash; title: ; notranslate">sudo nano /etc/hosts</pre>
<p>Enter your OSX password when prompted, and the hosts file will be opened in the <a href="http://en.wikipedia.org/wiki/GNU_nano">nano</a> text editor. You&#8217;ll see that the hosts file already contains some default hostname mappings (e.g. &#8220;127.0.0.1 localhost&#8221;). Use your keyboard&#8217;s arrow keys to navigate to the bottom of the file and add your own mapping:</p>
<pre class="brush: plain; title: ; notranslate"># XAMPP VirtualHost mappings
127.0.0.1 mysite.local</pre>
<p>Save the host file using the key combo <code>control+o</code>, and pressing return when prompted to choose the filename. Close the file using <code>control+x</code>.</p>
<h3>Restart Apache</h3>
<p>So that your changes take effect, restart Apache. This can be done using XAMPP Control, which is found at <code>/Applications/XAMPP/XAMPP Control.app</code>.</p>
<p>Point your browser at http://mysite.local (or whatever ServerName you chose) and you should see your website. However, there&#8217;s a chance that instead you&#8217;ll be faced with a&#8230;</p>
<h3>403 error</h3>
<p>Because Apache runs as the &#8216;nobody&#8217; user by default, it may not have adequate permission to browse your OSX user directory or some of its subdirectories, in which case you&#8217;ll see a 403 &#8216;access forbidden&#8217; error when you try and view your development site. Similarly, you may find that although you can view your dev site, PHP throws errors when you attempt to write files or make directories on the filesystem.</p>
<p>To fix this you can configure Apache to run as your OSX user. Open <code>/Applications/XAMPP/xamppfile/etc/httpd.conf</code> and look for the following lines:</p>
<pre class="brush: plain; title: ; notranslate"># User/Group: The name (or #number) of the user/group to run httpd as.
# It is usually good practice to create a dedicated user and group for
# running httpd, as with most system services.
#
User nobody
Group nogroup</pre>
<p>Change <code>User</code> to your OSX username, and save the file:</p>
<pre class="brush: plain; title: ; notranslate">User yourusername</pre>
<p>Restart Apache and you should now be able to navigate your site without any issues, including manipulating files and folders using PHP.</p>
<p>Making the change I&#8217;ve described above carries certain security risks, and if you choose to run Apache as your OSX user then you&#8217;ll need to be quite certain that XAMPP is not accessible from outside your local network. From what I understand, XAMPP&#8217;s built in security features ensure that <a href="http://bravo.newnetenterprises.com/wordpress/xampp/the-basics-of-xampp-security/">this is the case</a> out-of-the-box, and it is straightforward to <a href="http://www.apachefriends.org/en/xampp-macosx.html#873">beef up security</a> for additional piece of mind.</p>
<p>If you&#8217;re not convinced that it&#8217;s safe to let Apache run as your OSX user, another option is to <a href="http://stackoverflow.com/questions/2001881/correct-owner-group-permissions-for-apache-2-site-files-folders-under-mac-os-x">change the permissions</a> of your dev directories so that the &#8216;nobody&#8217; or &#8216;_www&#8217; user can read/write to them.I suspect that I would quickly tire of setting folder permissions, which is why I have opted to take the path of least resistance!</p>
<h3>Conclusion</h3>
<p>Hopefully this post helps someone else to get XAMPP up and running on OSX. I imagine that MAMP Pro streamlines this process somewhat (I know it has a wizard for creating VirtualHosts), but as long as you don&#8217;t mind getting your hands dirty XAMPP is a fantastic way to learn how Apache actually works.</p>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2012/03/11/configuring-virtualhosts-in-xampp-on-mac/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Build a parallax scrolling website interface with jQuery and CSS</title>
		<link>http://f6design.com/journal/2011/08/06/build-a-parallax-scrolling-website-interface-with-jquery-and-css/</link>
		<comments>http://f6design.com/journal/2011/08/06/build-a-parallax-scrolling-website-interface-with-jquery-and-css/#comments</comments>
		<pubDate>Sun, 07 Aug 2011 02:36:52 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML/XHTML]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=2141</guid>
		<description><![CDATA[Parallax scrolling website interfaces have been popping up all over the place recently. I didn&#8217;t want to miss out on the fun, so I have put together a parallax scrolling demo built using jQuery and CSS. Parallax what? Even if you&#8217;re not familiar with the term &#8220;parallax scrolling&#8221; you will certainly be familiar with the [...]]]></description>
			<content:encoded><![CDATA[<p>Parallax scrolling website interfaces have been popping up all over the place recently. I didn&#8217;t want to miss out on the fun, so I have put together a parallax scrolling demo built using jQuery and CSS.</p>
<p><a href="http://f6design.com/projects/parallax-scrolling/"><img src="http://f6design.com/journal/wp-content/uploads/2011/08/parallax-screenshot-578w.jpg" alt="Parallax scrolling interface" width="578" height="423" class="contentImg" /></a></p>
<h3>Parallax what?</h3>
<p>Even if you&#8217;re not familiar with the term &#8220;parallax scrolling&#8221; you will certainly be familiar with the technique. <a href="http://en.wikipedia.org/wiki/Parallax_scrolling">Parallax scrolling</a> is a 2d animation process that creates an illusion of depth by animating foreground layers faster than background layers. When you observe the landscape from a moving car, objects closer to the car appear to pass you faster than scenery further away. Parallax scrolling uses the same principle to trick the viewer into thinking they are observing a 3d scene.</p>
<h3>Demo and Download</h3>
<p>My demo web page shows one approach to building a vertical parallax scrolling interface:</p>
<p><a href="http://f6design.com/projects/parallax-scrolling/">View demo</a><br />
<a href="http://f6design.com/projects/parallax-scrolling/parallax-scrolling-demo.zip">Download source</a></p>
<p>You can scroll in the usual fashion, use the navigation menu at the right-hand side of the page, or the next/prev buttons that appear underneath each article. As you scroll, the page&#8217;s four content layers are animated independently of one another to create an illusion of depth.</p>
<p>The scrolling looks smoothest in Safari (at least that&#8217;s the case on my PC), but my demo should work in any modern browser.</p>
<p><em><strong>Disclaimer 1:</strong> Because this is just an experiment I&#8217;ve not spent any time optimising the demo to work on mobile devices. I wanted to keep the demo lean &#8216;n&#8217; mean, and not clutter it by sniffing mobile browsers and forking my code. On a production site you&#8217;d want to ensure that the site degrades gracefully on mobile devices, where scroll events and fixed positioning might work in unexpected ways.</em></p>
<p><em><strong>Disclaimer 2:</strong> The navigation menu in my demo is inspired by the menu on the Nike <a href="http://www.nikebetterworld.com/">Better World</a> website. If you plan on implementing a similar menu on a production site, please be aware of its origin.</em></p>
<h3>How it works</h3>
<p>The articles and background layers are given a fixed positioned with CSS, and assigned a <code>z-index</code> so that the foreground layers appear above the background layers. The four layers are: small clouds, large clouds, balloon/landscape images, articles.</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">/* foreground (ballons/landscape) */</span>
<span style="color: #cc00cc;">#parallax-bg3</span> <span style="color: #00AA00;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">z-index</span><span style="color: #00AA00;">:</span> <span style="color: #cc66cc;">3</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">position</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">fixed</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">left</span><span style="color: #00AA00;">:</span> <span style="color: #933;">50%</span><span style="color: #00AA00;">;</span> <span style="color: #808080; font-style: italic;">/* align left edge with center of viewport */</span>
    <span style="color: #000000; font-weight: bold;">top</span><span style="color: #00AA00;">:</span> <span style="color: #cc66cc;">0</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span> <span style="color: #933;">940px</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">margin-left</span><span style="color: #00AA00;">:</span> <span style="color: #933;">-470px</span><span style="color: #00AA00;">;</span> <span style="color: #808080; font-style: italic;">/* move left by half element's width */</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<p>Within each layer individual content elements are absolutely positioned. This was the most fiddly part of the process, since the elements need to positioned in such a way that they align in a pleasing manner when the user scrolls to any of the four articles. In this case it was really just a process of trial and error.</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #cc00cc;">#bg3-1</span> <span style="color: #00AA00;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">position</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">absolute</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">top</span><span style="color: #00AA00;">:</span> <span style="color: #933;">-111px</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">left</span><span style="color: #00AA00;">:</span> <span style="color: #933;">355px</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
<span style="color: #cc00cc;">#bg3-2</span> <span style="color: #00AA00;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">position</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">absolute</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">top</span><span style="color: #00AA00;">:</span> <span style="color: #933;">812px</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">left</span><span style="color: #00AA00;">:</span> <span style="color: #933;">321px</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
<span style="color: #808080; font-style: italic;">/* etc... */</span></pre></div></div>

<p>A few lines of jQuery control the parallax effect, triggered by a scroll event. I was surprised how easy this was to achieve, it is literally just a handful of lines of code.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span>window<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'scroll'</span><span style="color: #339933;">,</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    parallaxScroll<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">function</span> parallaxScroll<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> scrolled <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>window<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">scrollTop</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#parallax-bg1'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'top'</span><span style="color: #339933;">,</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">-</span><span style="color: #009900;">&#40;</span>scrolled<span style="color: #339933;">*</span>.25<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #3366CC;">'px'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#parallax-bg2'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'top'</span><span style="color: #339933;">,</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">-</span><span style="color: #009900;">&#40;</span>scrolled<span style="color: #339933;">*</span>.5<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #3366CC;">'px'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#parallax-bg3'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'top'</span><span style="color: #339933;">,</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">-</span><span style="color: #009900;">&#40;</span>scrolled<span style="color: #339933;">*</span>.75<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #3366CC;">'px'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>As you can see the CSS <code>top</code> property is used to move each layer as the user scrolls. The foreground layer is always aligned to the top of the document, while the movement of other layers is adjusted according to their depth. The lower a layer sits in the stack, the less distance it is moved.</p>
<p>The rest of the jQuery is concerned with controlling the navigation menus. When the user clicks a navigation button the page scrolls to the top of the associated article. In the event that the user has JavaScript disabled, regular HTML anchor links still allow the page to be navigated, but without any fancy pants animations.</p>
<h3>Next steps</h3>
<p>I&#8217;m sure there are plenty of other approaches to parallax scrolling, and hopefully my experiment provides a starting point for your own explorations of the technique.</p>
<h3>Update</h3>
<p>I have updated the demo so that each parallax layer is given a fixed, rather than absolute, position. This approach gives a smoother scrolling effect.</p>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2011/08/06/build-a-parallax-scrolling-website-interface-with-jquery-and-css/feed/</wfw:commentRss>
		<slash:comments>71</slash:comments>
		</item>
		<item>
		<title>FormBuilder updated to v1.5</title>
		<link>http://f6design.com/journal/2011/07/18/formbuilder-updated-to-v1-5/</link>
		<comments>http://f6design.com/journal/2011/07/18/formbuilder-updated-to-v1-5/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 07:10:26 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Toolbox]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=2079</guid>
		<description><![CDATA[It&#8217;s been almost exactly four years since I updated my FormBuilder PHP class, but believe it or not I have been slowly modifying and improving the class during the intervening years. I figured it was high time I rolled those improvements into the public version of the class, so here&#8217;s what&#8217;s new in version 1.5 [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been almost exactly four years since I updated my <a href="http://f6design.com/journal/2007/04/27/formbuilder-html-forms-made-simple/">FormBuilder</a> PHP class, but believe it or not I have been slowly modifying and improving the class during the intervening years. I figured it was high time I rolled those improvements into the public version of the class, so here&#8217;s what&#8217;s new in version 1.5 of FormBuilder:</p>
<ul>
<li>Better handling of checkbox results in the <code>emailResults</code> method.</li>
<li>A custom form submit URL can be passed to the FormBuilder constructor. Useful when using FormBuilder in an environment that is performing URL rewriting.</li>
<li>Replaced deprecated <code>ergei</code> functions with <code>preg_match</code>.</li>
<li>Checkbox field types are correctly processed when field is not mandatory, and the user didn&#8217;t check any of the available options.</li>
<li>Added new field type: file (for file uploads). Note that files are currently <em>not</em> emailed when using the <code>emailResults</code> method. Any handling of the uploaded files should be accomplished manually by accessing PHP&#8217;s <code>$_Files</code> array.</li>
<li>The textbox and textarea field types now accept an optional <code>defaultvalue</code> parameter.</li>
<li>Fixed a bug that meant checkboxes had a CSS class of &#8216;fbheckbox&#8217; instead of &#8216;fbcheckbox&#8217;.</li>
</ul>
<p>If you encounter any problems with the new version please let me know.</p>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2011/07/18/formbuilder-updated-to-v1-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Monokai theme for phpDesigner</title>
		<link>http://f6design.com/journal/2011/04/27/monokai-theme-for-phpdesigner/</link>
		<comments>http://f6design.com/journal/2011/04/27/monokai-theme-for-phpdesigner/#comments</comments>
		<pubDate>Wed, 27 Apr 2011 22:15:42 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML/XHTML]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Toolbox]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=1364</guid>
		<description><![CDATA[Last year I created a port of the Monokai syntax highlighting theme for phpDesigner and posted it in the phpDesigner forums, but I think it deserves a proper home so I&#8217;m archiving it here on Pixel Acres. PHP example: HTML example: CSS example: JavaScript example: I&#8217;m not sure who designed the Monokai theme originally, but [...]]]></description>
			<content:encoded><![CDATA[<p>Last year I created a port of the Monokai syntax highlighting theme for <a href="http://www.mpsoftware.dk/phpdesigner.php">phpDesigner</a> and posted it in the <a href="http://www.facebook.com/topic.php?uid=108672675347&#038;topic=11050">phpDesigner forums</a>, but I think it deserves a proper home so I&#8217;m archiving it here on Pixel Acres.</p>
<h4>PHP example:</h4>
<p><img src="http://f6design.com/journal/wp-content/uploads/2011/04/monokai_theme_php.png" alt="" title="monokai_theme_php" width="450" height="389" class="alignnone size-full wp-image-1377" /></p>
<h4>HTML example:</h4>
<p><img src="http://f6design.com/journal/wp-content/uploads/2011/04/monokai_theme_html.png" alt="" title="monokai_theme_html" width="450" height="179" class="alignnone size-full wp-image-1378" /></p>
<h4>CSS example:</h4>
<p><img src="http://f6design.com/journal/wp-content/uploads/2011/04/monokai_theme_css.png" alt="" title="monokai_theme_css" width="450" height="224" class="alignnone size-full wp-image-1381" /></p>
<h4>JavaScript example:</h4>
<p><img src="http://f6design.com/journal/wp-content/uploads/2011/04/monokai_theme_js.png" alt="" title="monokai_theme_js" width="450" height="258" class="alignnone size-full wp-image-1383" /></p>
<p>I&#8217;m not sure who designed the Monokai theme originally, but it has cropped up in <a href="http://macromates.com/">Textmate</a>, <a href="http://notepad-plus-plus.org/">Notepad++</a>, <a href="http://www.sublimetext.com/">Sublime</a> &#8211; where it is the default colour scheme &#8211; and no doubt a bunch of other editors as well.</p>
<p>My version of Monokai is based on a Notepad++ theme, but I have standardised the color of variables (green) and symbols (white) across all the languages.</p>
<p>I don&#8217;t actually use phpDesigner much these days &#8211; I&#8217;ve jumped ship for <a href="http://www.aptana.com/products/studio3">Aptana Studio 3</a> &#8211; but I still think it is a great code editor, and hopefully someone out there will get some use from my theme.</p>
<h3>Download</h3>
<p><a href="http://f6design.com/projects/f6-monokai-phpd-theme/f6_monokai_phpd_theme.rar">Download Monokai theme for phpDesigner</a></p>
<p>Installation and uninstallation instructions are included with the theme. The theme has syntax highlighting colors for the four languages I work with: HTML, CSS, JavaScript and PHP.</p>
<h3>Important</h3>
<p>There is currently a bug in phpDesigner that sometimes causes the ‘separator’ colors to revert to their defaults (e.g. the color of  tags reverts to black). The only sure-fire way to get things back to normal is to open the phpDesigner preferences dialog, and click ‘OK’.</p>
<p>Apparently this bug will be fixed in the next release of phpDesigner (yay!).</p>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2011/04/27/monokai-theme-for-phpdesigner/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Display recent Twitter tweets using PHP</title>
		<link>http://f6design.com/journal/2010/10/07/display-recent-twitter-tweets-using-php/</link>
		<comments>http://f6design.com/journal/2010/10/07/display-recent-twitter-tweets-using-php/#comments</comments>
		<pubDate>Fri, 08 Oct 2010 01:26:28 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=1151</guid>
		<description><![CDATA[If you&#8217;ve ever wanted to display your latest Twitter tweets on a website, here is method to do that using PHP. My approach has the following features: Tweets are cached to avoid exceeding Twitter&#8217;s limit of 150 requests for a user&#8217;s RSS feed per hour A fallback is provided in case the twitter feed fails [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve ever wanted to display your latest Twitter tweets on a website, here is method to do that using PHP. My approach has the following features:</p>
<ul>
<li>Tweets are cached to avoid exceeding Twitter&#8217;s limit of 150 requests for a user&#8217;s RSS feed per hour</li>
<li>A fallback is provided in case the twitter feed fails to load</li>
<li>Replies (tweets beginning with @) can optionally be ignored</li>
<li>A configuration parameter allows you to specify how many tweets are displayed</li>
<li>Dates can optionally be displayed in &#8220;Twitter style&#8221;, e.g. &#8220;12 minutes ago&#8221;</li>
<li>You can edit the HTML that wraps your tweets, tweet status and meta information</li>
<li>The username which prepends each tweet in Twitter RSS feeds is automatically stripped</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
 * TWITTER FEED PARSER
 * 
 * @version	1.1.3
 * @author	Jonathan Nicol
 * @link	http://f6design.com/journal/2010/10/07/display-recent-twitter-tweets-using-php/
 * 
 * Notes:
 * Caching is employed because Twitter only allows their RSS feeds to be accesssed 150
 * times an hour per user client.
 * --
 * Dates can be displayed in Twitter style (e.g. &quot;1 hour ago&quot;) by setting the 
 * $twitter_style_dates param to true.
 * 
 * Credits:
 * Hashtag/username parsing based on: http://snipplr.com/view/16221/get-twitter-tweets/
 * Feed caching: http://www.addedbytes.com/articles/caching-output-in-php/
 * Feed parsing: http://boagworld.com/forum/comments.php?DiscussionID=4639
 */</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> display_latest_tweets<span style="color: #009900;">&#40;</span>
	<span style="color: #000088;">$twitter_user_id</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$cache_file</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'./twitter.txt'</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$tweets_to_display</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">100</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$ignore_replies</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$twitter_wrap_open</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;h2&gt;Latest tweets&lt;/h2&gt;&lt;ul id=&quot;twitter&quot;&gt;'</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$twitter_wrap_close</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;/ul&gt;'</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$tweet_wrap_open</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;li&gt;&lt;span class=&quot;status&quot;&gt;'</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$meta_wrap_open</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;/span&gt;&lt;span class=&quot;meta&quot;&gt; '</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$meta_wrap_close</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;/span&gt;'</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$tweet_wrap_close</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;/li&gt;'</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$date_format</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'g:i A M jS'</span><span style="color: #339933;">,</span>
	<span style="color: #000088;">$twitter_style_dates</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// Seconds to cache feed (1 hour).</span>
	<span style="color: #000088;">$cachetime</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">60</span><span style="color: #339933;">*</span><span style="color: #cc66cc;">60</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// Time that the cache was last filled.</span>
	<span style="color: #000088;">$cache_file_created</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">file_exists</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cache_file</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #990000;">filemtime</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cache_file</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">:</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// A flag so we know if the feed was successfully parsed.</span>
	<span style="color: #000088;">$tweet_found</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// Show file from cache if still valid.</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #000088;">$cachetime</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$cache_file_created</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
		<span style="color: #000088;">$tweet_found</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
		<span style="color: #666666; font-style: italic;">// Display tweets from the cache.</span>
		<span style="color: #990000;">readfile</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cache_file</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
&nbsp;
	<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">// Cache file not found, or old. Fetch the RSS feed from Twitter.</span>
		<span style="color: #000088;">$rss</span> <span style="color: #339933;">=</span> <span style="color: #990000;">file_get_contents</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'http://twitter.com/statuses/user_timeline/'</span><span style="color: #339933;">.</span><span style="color: #000088;">$twitter_user_id</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'.rss'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rss</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
			<span style="color: #666666; font-style: italic;">// Parse the RSS feed to an XML object.</span>
			<span style="color: #000088;">$xml</span> <span style="color: #339933;">=</span> <span style="color: #990000;">simplexml_load_string</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rss</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$xml</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
				<span style="color: #666666; font-style: italic;">// Error check: Make sure there is at least one item.</span>
				<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$xml</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">channel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">item</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
					<span style="color: #000088;">$tweet_count</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
&nbsp;
					<span style="color: #666666; font-style: italic;">// Start output buffering.</span>
					<span style="color: #990000;">ob_start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
					<span style="color: #666666; font-style: italic;">// Open the twitter wrapping element.</span>
					<span style="color: #000088;">$twitter_html</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$twitter_wrap_open</span><span style="color: #339933;">;</span>
&nbsp;
					<span style="color: #666666; font-style: italic;">// Iterate over tweets.</span>
					<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$xml</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">channel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">item</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$tweet</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
						<span style="color: #666666; font-style: italic;">// Twitter feeds begin with the username, &quot;e.g. User name: Blah&quot;</span>
						<span style="color: #666666; font-style: italic;">// so we need to strip that from the front of our tweet.</span>
						<span style="color: #000088;">$tweet_desc</span> <span style="color: #339933;">=</span> <span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">description</span><span style="color: #339933;">,</span><span style="color: #990000;">strpos</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">description</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;:&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
						<span style="color: #000088;">$tweet_desc</span> <span style="color: #339933;">=</span> <span style="color: #990000;">htmlspecialchars</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet_desc</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
						<span style="color: #000088;">$tweet_first_char</span> <span style="color: #339933;">=</span> <span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet_desc</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
						<span style="color: #666666; font-style: italic;">// If we are not ignoring replies, or tweet is not a reply, process it.</span>
						<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet_first_char</span><span style="color: #339933;">!=</span><span style="color: #0000ff;">'@'</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$ignore_replies</span><span style="color: #339933;">==</span><span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
							<span style="color: #000088;">$tweet_found</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
							<span style="color: #000088;">$tweet_count</span><span style="color: #339933;">++;</span>
&nbsp;
							<span style="color: #666666; font-style: italic;">// Add hyperlink html tags to any urls, twitter ids or hashtags in the tweet.</span>
							<span style="color: #000088;">$tweet_desc</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/(https?:\/\/[^\s&quot;&lt;&gt;]+)/'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'&lt;a href=&quot;$1&quot;&gt;$1&lt;/a&gt;'</span><span style="color: #339933;">,</span><span style="color: #000088;">$tweet_desc</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
							<span style="color: #000088;">$tweet_desc</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/(^|[\n\s])@([^\s&quot;\t\n\r&lt;:]*)/is'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'$1&lt;a href=&quot;http://twitter.com/$2&quot;&gt;@$2&lt;/a&gt;'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tweet_desc</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
							<span style="color: #000088;">$tweet_desc</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/(^|[\n\s])#([^\s&quot;\t\n\r&lt;:]*)/is'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'$1&lt;a href=&quot;http://twitter.com/search?q=%23$2&quot;&gt;#$2&lt;/a&gt;'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tweet_desc</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
 							<span style="color: #666666; font-style: italic;">// Convert Tweet display time to a UNIX timestamp. Twitter timestamps are in UTC/GMT time.</span>
							<span style="color: #000088;">$tweet_time</span> <span style="color: #339933;">=</span> <span style="color: #990000;">strtotime</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">pubDate</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
 							<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$twitter_style_dates</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
								<span style="color: #666666; font-style: italic;">// Current UNIX timestamp.</span>
								<span style="color: #000088;">$current_time</span> <span style="color: #339933;">=</span> <span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
								<span style="color: #000088;">$time_diff</span> <span style="color: #339933;">=</span> <span style="color: #990000;">abs</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$current_time</span> <span style="color: #339933;">-</span> <span style="color: #000088;">$tweet_time</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
								<span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$time_diff</span><span style="color: #009900;">&#41;</span> 
								<span style="color: #009900;">&#123;</span>
									<span style="color: #b1b100;">case</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$time_diff</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">60</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span>
										<span style="color: #000088;">$display_time</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$time_diff</span><span style="color: #339933;">.</span><span style="color: #0000ff;">' seconds ago'</span><span style="color: #339933;">;</span>                  
										<span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>      
									<span style="color: #b1b100;">case</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$time_diff</span> <span style="color: #339933;">&gt;=</span> <span style="color: #cc66cc;">60</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$time_diff</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">3600</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span>
										<span style="color: #000088;">$min</span> <span style="color: #339933;">=</span> <span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$time_diff</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">60</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
										<span style="color: #000088;">$display_time</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$min</span><span style="color: #339933;">.</span><span style="color: #0000ff;">' minutes ago'</span><span style="color: #339933;">;</span>                  
										<span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>      
									<span style="color: #b1b100;">case</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$time_diff</span> <span style="color: #339933;">&gt;=</span> <span style="color: #cc66cc;">3600</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$time_diff</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">86400</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span>
										<span style="color: #000088;">$hour</span> <span style="color: #339933;">=</span> <span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$time_diff</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">3600</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
										<span style="color: #000088;">$display_time</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'about '</span><span style="color: #339933;">.</span><span style="color: #000088;">$hour</span><span style="color: #339933;">.</span><span style="color: #0000ff;">' hour'</span><span style="color: #339933;">;</span>
										<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$hour</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> <span style="color: #000088;">$display_time</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">'s'</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span>
										<span style="color: #000088;">$display_time</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">' ago'</span><span style="color: #339933;">;</span>
										<span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>          
									<span style="color: #b1b100;">default</span><span style="color: #339933;">:</span>
										<span style="color: #000088;">$display_time</span> <span style="color: #339933;">=</span> <span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$date_format</span><span style="color: #339933;">,</span><span style="color: #000088;">$tweet_time</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
										<span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
								<span style="color: #009900;">&#125;</span>
 							<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
 								<span style="color: #000088;">$display_time</span> <span style="color: #339933;">=</span> <span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$date_format</span><span style="color: #339933;">,</span><span style="color: #000088;">$tweet_time</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 							<span style="color: #009900;">&#125;</span>
&nbsp;
							<span style="color: #666666; font-style: italic;">// Render the tweet.</span>
							<span style="color: #000088;">$twitter_html</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$tweet_wrap_open</span><span style="color: #339933;">.</span><span style="color: #990000;">html_entity_decode</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet_desc</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #000088;">$meta_wrap_open</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&lt;a href=&quot;http://twitter.com/'</span><span style="color: #339933;">.</span><span style="color: #000088;">$twitter_user_id</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot;&gt;'</span><span style="color: #339933;">.</span><span style="color: #000088;">$display_time</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&lt;/a&gt;'</span><span style="color: #339933;">.</span><span style="color: #000088;">$meta_wrap_close</span><span style="color: #339933;">.</span><span style="color: #000088;">$tweet_wrap_close</span><span style="color: #339933;">;</span>
&nbsp;
						<span style="color: #009900;">&#125;</span>
&nbsp;
						<span style="color: #666666; font-style: italic;">// If we have processed enough tweets, stop.</span>
						<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet_count</span> <span style="color: #339933;">&gt;=</span> <span style="color: #000088;">$tweets_to_display</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
							<span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
						<span style="color: #009900;">&#125;</span>
&nbsp;
					<span style="color: #009900;">&#125;</span>
&nbsp;
					<span style="color: #666666; font-style: italic;">// Close the twitter wrapping element.</span>
					<span style="color: #000088;">$twitter_html</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$twitter_wrap_close</span><span style="color: #339933;">;</span>
					<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$twitter_html</span><span style="color: #339933;">;</span>
&nbsp;
					<span style="color: #666666; font-style: italic;">// Generate a new cache file.</span>
					<span style="color: #000088;">$file</span> <span style="color: #339933;">=</span> <span style="color: #990000;">fopen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cache_file</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'w'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
					<span style="color: #666666; font-style: italic;">// Save the contents of output buffer to the file, and flush the buffer. </span>
					<span style="color: #990000;">fwrite</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$file</span><span style="color: #339933;">,</span> <span style="color: #990000;">ob_get_contents</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
					<span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$file</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
					<span style="color: #990000;">ob_end_flush</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
				<span style="color: #009900;">&#125;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span> 
	<span style="color: #666666; font-style: italic;">// In case the RSS feed did not parse or load correctly, show a link to the Twitter account.</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$tweet_found</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$twitter_wrap_open</span><span style="color: #339933;">.</span><span style="color: #000088;">$tweet_wrap_open</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'Oops, our twitter feed is unavailable right now. '</span><span style="color: #339933;">.</span><span style="color: #000088;">$meta_wrap_open</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&lt;a href=&quot;http://twitter.com/'</span><span style="color: #339933;">.</span><span style="color: #000088;">$twitter_user_id</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot;&gt;Follow us on Twitter&lt;/a&gt;'</span><span style="color: #339933;">.</span><span style="color: #000088;">$meta_wrap_close</span><span style="color: #339933;">.</span><span style="color: #000088;">$tweet_wrap_close</span><span style="color: #339933;">.</span><span style="color: #000088;">$twitter_wrap_close</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
display_latest_tweets<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'YOUR_TWITTER_ID'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<h3>Usage</h3>
<p>You should edit the Twitter ID in the function call above before using the function (it appears at the very bottom of the code snippet).</p>
<p>You probably also want to edit the location where the twitter feed is cached &#8211; by default it is written to the root level of your domain. To change the location, modify the <code>$cache_file</code> variable, or pass the new location as a function parameter.</p>
<h3>Notes</h3>
<p>Twitter feeds may contain UTF-8 characters. I have found that running PHP&#8217;s <code>utf_decode</code> method on tweets didn&#8217;t have the expected result, so my recommendation is to instead <a href="http://www.w3.org/International/O-charset">set the charset of your HTML page to UTF-8</a>. Really we should all be doing this anyway.</p>
<h3>Credits</h3>
<p>The hashtag/username parsing in my example is from <a href="http://snipplr.com/view/16221/get-twitter-tweets/">Get Twitter Tweets</a> by <a href="http://snipplr.com/users/gripnrip/">gripnrip</a>.</p>
<p>My RSS parsing is based on replies in the forum discussion <a href="http://boagworld.com/forum/comments.php?DiscussionID=4639">&#8220;embedding twitter tweets&#8221;</a> on the Boagworld website.</p>
<p>The file caching is based on the AddedBytes article <a href="http://www.addedbytes.com/articles/caching-output-in-php/">&#8220;Caching output in PHP&#8221;</a>.</p>
<h3>Changelog</h3>
<h4>v1.1.2, 17 April 2012</h4>
<ul>
<li>HTML entities in tweets are now decoded e.g. &amp;lt;</li>
</ul>
<h4>v1.1.1, 28 January 2011</h4>
<ul>
<li>Fixed bug in the logic that pluralises the number of hours since a tweet</li>
</ul>
<h4>v1.1, 14 January 2011</h4>
<ul>
<li>Fixed URL parsing regular expression to make it much more liberal. It will no longer choke on hyphens.</li>
<li>Added an optional parameter $twitter_style_dates which will format dates the same way as the Twitter website, e.g. &#8220;12 minutes ago&#8221;. It is set to false by default.</li>
<li>Dates are now formatted the same as on the Twitter website, e.g. &#8220;3:48 PM Jan 14th&#8221;. This can be overridden using the $date_format parameter.</li>
<li>The username parser will no longer include a trailing colon as part of the username, so the autolink for a string like &#8220;@username: hello!&#8221; won&#8217;t get messed up.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2010/10/07/display-recent-twitter-tweets-using-php/feed/</wfw:commentRss>
		<slash:comments>81</slash:comments>
		</item>
		<item>
		<title>Sunset: A syntax highlighting theme for phpDesigner</title>
		<link>http://f6design.com/journal/2010/09/29/sunset-a-syntax-highlighting-theme-for-phpdesigner/</link>
		<comments>http://f6design.com/journal/2010/09/29/sunset-a-syntax-highlighting-theme-for-phpdesigner/#comments</comments>
		<pubDate>Thu, 30 Sep 2010 07:19:24 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML/XHTML]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Toolbox]]></category>

		<guid isPermaLink="false">http://f6design.com/journal/?p=1057</guid>
		<description><![CDATA[My weapon of choice for code editing is the excellent program phpDesigner, but every so often I like to test drive a different editor to see what I might be missing out on. Recently I spent some time playing with Notepad++, and one feature that jumped out at me was the ability to choose from [...]]]></description>
			<content:encoded><![CDATA[<p>My weapon of choice for code editing is the excellent program <a href="http://www.mpsoftware.dk/">phpDesigner</a>, but every so often I like to test drive a different editor to see what I might be missing out on. Recently I  spent some time playing with <a href="http://notepad-plus-plus.org/">Notepad++</a>, and one feature that jumped out at me was the ability to choose from a large number of pre-installed <a href="http://en.wikipedia.org/wiki/Syntax_highlighting">syntax highlighting</a> themes.</p>
<p>When I switched back to phpDesigner, the default blue-on-white color scheme seemed a tad boring, so I decided it was time to pimp my IDE! Unfortunately user created themes for phpDesigner are thin on the ground, which left me no option but to make my own.</p>
<h4>PHP example:</h4>
<p><img src="http://f6design.com/journal/wp-content/uploads/2010/09/sunset_theme_php.png" alt="Sunset theme for phpDesigner - PHP code" width="450" height="389" /></p>
<h4>HTML example:</h4>
<p><img src="http://f6design.com/journal/wp-content/uploads/2010/09/sunset_theme_html.png" alt="Sunset theme for phpDesigner - HTML markup" width="450" height="164" /></p>
<h4>CSS example:</h4>
<p><img src="http://f6design.com/journal/wp-content/uploads/2010/09/sunset_theme_css.png" alt="Sunset theme for phpDesigner - CSS" width="450" height="224" /></p>
<h4>JavaScript example:</h4>
<p><img src="http://f6design.com/journal/wp-content/uploads/2010/09/sunset_theme_js.png" alt="Sunset theme for phpDesigner - JavaScript code" width="450" height="258" /></p>
<p>I&#8217;ve named my theme Sunset, and it is inspired by the <a href="http://alexgorbatchev.com/SyntaxHighlighter/manual/themes/midnight.html">Midnight theme</a> for <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a>. If any phpDesigner fans are looking for a light-on-dark color scheme to spruce up their code editor, perhaps Sunset will fit the bill.</p>
<h3>Download</h3>
<p><a href="http://www.f6design.com/projects/f6-sunset-phpd-theme/f6_sunset_phpd_theme_1.2.rar">Download Sunset theme for phpDesigner</a></p>
<p>Installation and uninstallation instructions are included with the theme. Currently the theme has syntax highlighting colors for the four languages I work with: HTML, CSS, JavaScript and PHP.</p>
<h3>Important</h3>
<p>There is currently a <a href="http://www.facebook.com/topic.php?topic=12989&#038;post=148620&#038;uid=108672675347">bug in phpDesigner</a> that sometimes causes the &#8216;separator&#8217; colors to revert to their defaults (e.g. the color of <code>&lt;?php ?&gt;</code> tags reverts to black). The only sure-fire way to get things back to normal is to open the phpDesigner preferences dialog, and click &#8216;OK&#8217;. You might also try closing all your open documents and restarting the application. Hopefully this bug will be fixed in a future version of phpDesigner.</p>
]]></content:encoded>
			<wfw:commentRss>http://f6design.com/journal/2010/09/29/sunset-a-syntax-highlighting-theme-for-phpdesigner/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>

