<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Christopher Imrie's Blog</title>
		<link>http://www.christopherimrie.com/blog</link>
		<description>Christopher Imrie is a print and web development specialist, as well as an Adobe Certified Instructor based in England.  He provides web development and consultancy services as well as certified training to individuals and companies working in the UK creative industry.</description>
		<copyright>2012 Farpoint Developments Ltd.  All Rights Reserved.</copyright>
		<lastBuildDate>Sat, 15 Jan 2011 20:00:12 +0000</lastBuildDate>
		
		
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/moresoda_poster#When:01:50:11Z</guid>
					<title>I&#8217;m giving up freelancing and joining Moresoda!</title>
					<link>http://www.christopherimrie.com/blog/moresoda_poster</link>
					<description>
					<![CDATA[
					<p>
	<img alt="" src="http://www.christopherimrie.com/images/uploads/moresoda-bigger.jpg" /></p>
<p>
	I have just recently announced that as of next week I will be giving up freelancing to join the Bath, England based <a href="http://www.moresoda.co.uk">Moresoda</a> as their lead developer! &nbsp;To commemorate the event I knocked up the poster above. &nbsp;</p>
<p>
	Its inspired by the early work of <a href="http://www.signalnoise.com">James White</a>.</p>

					]]>
					</description>
					<pubDate>Sun, 16 Jan 2011 1:50:11 +0000</pubDate>
				</item>
					
							<item>	
					<guid isPermaLink='false'>http://www.christopherimrie.com/video/photoshop_vanishing_point_3d_layers#When:01:43:42Z</guid>
					<title>Photoshop Vanishing Point and 3D Layers</title>
					<link>http://www.christopherimrie.com/video/photoshop_vanishing_point_3d_layers</link>
					<description>In this video I show how to use vanishing point to turn your photo into a 3D model that you can move &amp;amp; rotate in 3D space.</description>
					<pubDate>Sun, 07 Nov 2010 1:43:42 +0000</pubDate>
					<enclosure url="http://c1626802.cdn.cloudfiles.rackspacecloud.com/ps_vanishing_point_3d_layers.mp4" length="25899241" type="video/mp4" />
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/making_the_codeigniter_session_class_more_useful_with_custom_flashdata#When:17:38:22Z</guid>
					<title>Extending flashdata in CodeIgniter</title>
					<link>http://www.christopherimrie.com/blog/making_the_codeigniter_session_class_more_useful_with_custom_flashdata</link>
					<description>
					<![CDATA[
					<p>
	Following on from my previous article explaining how I achieve a very transparent security and authentication system in CodeIgniter (CI), I thought I would also post another of my custom libraries that I use in nearly every custom CI application.</p>
<p>
	CodeIgniter comes with a Session class that includes a flashdata feature. &nbsp;Flashdata is really handy as it allows us to show a message for the next page request, but then have it removed for any requests thereafter. &nbsp;So if we try to insert something in the database, and succeed, we can set flashdata message to give feedback along the lines of &quot;Database insertion successful&quot;. &nbsp;This will only be show for a single page load, and as the user navigates away, the message will be hidden and hence not shown.</p>
<p>
	The current flashdata methods allow us to give the message both &quot;name&quot; and &quot;message&quot; properties. &nbsp;So if an error occurs, we can set a message with the name &quot;error&quot; and then in the message describe the error to the user. &nbsp;We could do the same for giving feedback when something succeeds, but instead we would give this a name of &quot;success&quot;.</p>
<p>
	In our templates we could then simply detect for the presence of either a &quot;success&quot; or &quot;error&quot; message. &nbsp;However, we are most likely going to want to style it at the same time. &nbsp;So you will end up with something like this at the top of your templates:</p>
<pre class="prettyprint">
&lt;?php
    if($this-&gt;session-&gt;flashdata(&#39;success&#39;)){
        
        echo &quot;&lt;p class=&#39;success&#39;&gt;&quot; . $this-&gt;session-&gt;flashdata(&#39;success&#39;) . &quot;&lt;/p&gt;&quot;;
        
    }elseif($this-&gt;session-&gt;flashdata(&#39;error&#39;)){
        
        echo &quot;&lt;p class=&#39;error&#39;&gt;&quot; . $this-&gt;session-&gt;flashdata(&#39;error&#39;) . &quot;&lt;/p&gt;&quot;;
        
    }
?&gt;

</pre>
<p>
	This is a little too verbose for my liking, since this is likely to be on <strong>every</strong> page if you are building some sort of control panel. &nbsp;Also having to place the delimiters (the HTML tags that wrap the message) in the conditional doesnt look right. &nbsp;It would be more useful to be able to have the flashdata <em>know</em> whether it was a success or an error, and then wrap the message in a html tag with an error/success class that would allow us to style it.</p>
<h2>
	A better way</h2>
<p>
	By creating a custom class that extends the native CI Session class, we can create out own flashdata methods. &nbsp;Here is one that I use regularly, and has never let me down:</p>
<pre class="prettyprint">
&lt;?php  if ( ! defined(&#39;BASEPATH&#39;)) exit(&#39;No direct script access allowed&#39;);

/**
* 
*/
class MY_Session extends CI_Session
{
	
	function MY_Session()
	{
		parent::CI_Session();

	}



	/**
	 * Add or change success flashdata, only available
	 * until the next request
	 *
	 * @access	public
	 * @param	mixed
	 * @param	string
	 * @return	void
	 */
	function set_success_flashdata($newdata = array(), $newval = &#39;&#39;)
	{
		if (is_string($newdata))
		{
			$newdata = array($newdata =&gt; $newval);
		}

		if (count($newdata) &gt; 0)
		{
			foreach ($newdata as $key =&gt; $val)
			{
				$flashdata_key = $this-&gt;flashdata_key.&#39;:new:&#39;.$key;
				$this-&gt;set_userdata($flashdata_key, &quot;&lt;p class=&#39;success&#39;&gt;&quot;.$val.&quot;&lt;/p&gt;&quot;);
			}
		}
	}
	
	/**
	 * Add or change error flashdata, only available
	 * until the next request
	 *
	 * @access	public
	 * @param	mixed
	 * @param	string
	 * @return	void
	 */
	function set_error_flashdata($newdata = array(), $newval = &#39;&#39;)
	{
		if (is_string($newdata))
		{
			$newdata = array($newdata =&gt; $newval);
		}

		if (count($newdata) &gt; 0)
		{
			foreach ($newdata as $key =&gt; $val)
			{
				$flashdata_key = $this-&gt;flashdata_key.&#39;:new:&#39;.$key;
				$this-&gt;set_userdata($flashdata_key, &quot;&lt;p class=&#39;error&#39;&gt;&quot;.$val.&quot;&lt;/p&gt;&quot;);
			}
		}
	}
}

</pre>
<p>
	Simply save this file as &quot;<strong>MY_Session.php</strong>&quot; and place it in your <strong>/system/application/libraries</strong> folder. &nbsp;If you have left the CI config settings concerning custom library loading untouched, then CI will automatically load this file at runtime.</p>
<p>
	Now whenever you want to set success or error flashdata from your controllers/models, simply call:</p>
<pre class="prettyprint">
//Set a success message
    $this-&gt;session-&gt;set_success_flashdata(&#39;feedback&#39;, &#39;Success message for client to see&#39;);
    
    //Set an error message
    $this-&gt;session-&gt;set_error_flashdata(&#39;feedback&#39;, &#39;Error message for client to see&#39;);

</pre>
<p>
	Things get really nice and simple in your templates, since now you can skip any conditionals and simply call a single method:</p>
<pre class="prettyprint">
&lt;?php
    $this-&gt;session-&gt;flashdata(&#39;feedback&#39;);
?&gt;

</pre>
<p>
	The output from the method above will produce a message already wrapped in a paragraph containing the correct success/error class. &nbsp;Much simpler!</p>

					]]>
					</description>
					<pubDate>Thu, 28 Oct 2010 17:38:22 +0000</pubDate>
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/implementing_secure_password_protected_controllers_in_codeigniter#When:14:46:28Z</guid>
					<title>Implementing secure, password protected controllers in CodeIgniter</title>
					<link>http://www.christopherimrie.com/blog/implementing_secure_password_protected_controllers_in_codeigniter</link>
					<description>
					<![CDATA[
					<p>
	<img alt="" class="left" src="http://www.christopherimrie.com/images/uploads/ci-logo.png" style="width: 240px; height: 250px; " />My day to day activities as a freelance web developer have me doing all sorts of things from converting Photoshop files to XHTML &amp; CSS, to adding Javascript interactivity all the way to writing custom web apps. &nbsp;The latter is the most mentally satisfying for me since each web application has a different need to the next, and requires solving a unique set of problems. &nbsp;</p>
<p>
	I build all my web applications using the <a href="http://www.codeigniter.com">CodeIgniter</a> framework due to its robustness, flexibility and speed. &nbsp;If you are a PHP developer and have not come across it before, I highly recommend you check it out since it&#39;s a great framework to work with.</p>
<p>
	A common need amongst web applications is the need for password protected areas of your web application. &nbsp;Coming up with a good security structure within CodeIgniter can be tricky for those new to the framework since there is no clear method to doing so. &nbsp;I am not saying that the framework is lacking, merely that the creators (the lovely folks at EllisLab) have left the framework in such a state that it makes no assumptions on its use, and therefore it is up to you the developer to implement your own security model.</p>
<p>
	The model I have developed has the following features:</p>
<ul>
	<li>
		Supports both secure and unsecure controllers (for public areas of your site)</li>
	<li>
		No modification of core files</li>
	<li>
		CodeIgniter library can be upgraded with new releases without breaking the security model</li>
	<li>
		Un-authenticated URL requests are intercepted, shown a login screen, then redirected to the original URL</li>
	<li>
		Controllers are kept &quot;security code&quot; free.</li>
</ul>
<h2>
	Transparency</h2>
<meta charset="utf-8" />
<p>
	Having built many web applications over the years, I have implemented many different sorts of security models, each with varying degrees of transparency to my day to day working. When I refer to transparency, I refer to the awareness of the developer that the security model is in place. &nbsp;If I have to copy and paste a security check and redirect script into the top of every file I wish to be protected, then this is very <strong>un-transparent</strong> in its implementation. &nbsp;I am very aware that there is a security check at the start of each file. &nbsp;Not only that, it means that if I wish to change the nature of the security (eg: add a new feature) I have to modify the code on every single file that needs to be secure. &nbsp;Not only is this inefficient, it is prone to errors and mistakes.</p>
<p>
	The method I am going to show you is the complete opposite of what I describe above. &nbsp;The security is loaded silently in the background and your controllers only need three characters added to them in order to inherit the protection for the security system. &nbsp;Therefore I can work in my CodeIgniter controllers without any extraneous security code getting in the way.</p>
<h2>
	Keeping things as secure as possible</h2>
<p>
	In order for the method I show you to have the best security, make sure you have the following setup:</p>
<ul>
	<li>
		Session library is autoloaded (<a href="http://codeigniter.com/user_guide/general/autoloader.html">More info</a>)</li>
	<li>
		Session data is saved to the database (<a href="http://codeigniter.com/user_guide/libraries/sessions.html">More info</a>)</li>
	<li>
		Session data is encrypted in your session preferences (<a href="http://codeigniter.com/user_guide/libraries/sessions.html">More info</a>)</li>
</ul>
<h2>
	How it works</h2>
<p>
	The system works by extending the CodeIgniter Controller class and having any secure controllers extending from this new class. &nbsp;Therefore make sure that in your preferences you have set your Class Extension Prefix to the following (this is the default, so it probably wont have changed):</p>

<pre class="prettyprint lang-php">
$config[&#39;subclass_prefix&#39;] = &#39;MY_&#39;;
</pre>
<p>
	This will allow us to have the custom controller loaded automatically by CodeIgniter on each page load.</p>
<h3>
	Custom Controller</h3>
<p>
	Here is the first file, it is a custom controller that extends the default controller file. &nbsp;I have commented it as extensively as I can and pointed out where you need to add your own customized code. &nbsp;You need to save this file as <code>MY_Controller.php</code> and place it in your <code>./system/application/libraries/</code> folder.</p>
<pre class="prettyprint lang-php">
&lt;?php  if ( ! defined(&#39;BASEPATH&#39;)) exit(&#39;No direct script access allowed&#39;);
/**
 * Custom secure Controller
 *
 * @package default
 * @author Christopher Imrie
 */
class MY_Controller extends Controller {
    
    /**
     * Secure Constructor
     *
     * 
     */
    function MY_Controller()
    {   
        parent::Controller();
        
        // When someone successfully logs in, I set a session userdata variable of &quot;logged_in&quot;.
        // Here we check if it exists
        if(!$this-&gt;session-&gt;userdata(&#39;logged_in&#39;)){

            // ====================
            // = Login has failed =
            // ====================

            // If not logged in, record what url they are attempting to acces and show the login form
            $this-&gt;session-&gt;set_userdata(&#39;REDIRECT&#39; , uri_string());

            // Give the browser an Unauthorized HTTP header
            $this-&gt;output-&gt;set_status_header(&#39;401&#39;);

            // Redirect to the login page, change this to your login controller/method
            redirect(&#39;login&#39;);

        }else{
            
            // =======================
            // = Login has succeeded =
            // =======================
            
            //This is optional, but I have a method that sets up some constants
            $this-&gt;_login_init();

        }
    }
	// END MY_Controller method
    
    /**
     * Performs all login functionality such as setting up constants
     *
     * @return void
     * @author Christopher Imrie
     **/
    private function _login_init()
    {
        // I have a model designed to fetch user data.  Since I am logging a user in,
        // I am loading it here and fetching the user&#39;s data
        $this-&gt;load-&gt;model(&quot;users&quot;);
        
        
        // I call a method here to setup some constants to be available to all secure controllers
        if($userdata = $this-&gt;users-&gt;get_userdata($this-&gt;session-&gt;userdata(&#39;username&#39;)))
        {
            //If we have data, then setup the constants or do special functionality in here
            
            
            // ===========
            // = Example =
            // ===========
            
            /**
            * Logged in users email
            **/
            // define(&#39;USERNAME&#39;, $userdata-&gt;username);


        }else{
            // ===========================
            // = Error fetching userdata =
            // ===========================
            
            //Destroy the session
            $this-&gt;session-&gt;sess_destroy();

            //Log it
            log_message(&#39;error&#39;, &#39;Session error.  Session id not found&#39;);
            
            //Show it
            show_error(&#39;Session error, please log in again.&#39;);
        }

    }
    // END _login_init method
}
// END MY_Controller class

/* End of file MY_Controller.php */
/* Location: ./system/application/libraries/MY_Controller.php */

</pre>
<h3>
	Login Controller</h3>
<p>
	For clarity I have also included the login controller that functions as the login screen. &nbsp;This file is to be named <code>login.php</code> and placed in your <code>./system/application/controllers/</code> folder.</p>
<pre class="prettyprint lang-php">
&lt;?php if ( ! defined(&#39;BASEPATH&#39;)) exit(&#39;No direct script access allowed&#39;);
/**
 * Login Controller
 *
 * @package default
 * @author Christopher Imrie
 */
class Login extends Controller {

    /**
     * Login Controller
     *
     * 
     */
    function Login()
    {
        
        parent::Controller();	
    
    }
    // END Login method

    function index()
    {
        //Check to see if some key session userdata is still available
        if($this-----&gt;session-&gt;userdata(&#39;logged_in&#39;) &amp;&amp; $this-&gt;session-&gt;userdata(&#39;username&#39;))
        {
            // ===========================
            // = User is still logged in =
            // ===========================
            
            //Dont bother with the login page, just send em on to the start page
            redirect(&#39;start&#39;);
            
        }else{
            // =========================
            // = User is not logged in =
            // =========================
            
            // Lets use the form validation library to keep things simple &amp; robust
            $this-&gt;load-&gt;library(&#39;form_validation&#39;);
            $this-&gt;form_validation-&gt;set_rules(&#39;username&#39;, &#39;Username&#39;, &#39;required|callback__verify_username_password&#39;);
            $this-&gt;form_validation-&gt;set_rules(&#39;password&#39;, &#39;Password&#39;, &#39;required&#39;);
            
            //We have a custom method that is checking the username &amp; password validity
            $this-&gt;form_validation-&gt;set_message(&#39;_verify_username_password&#39;, &quot;Username or password is incorrect&quot;);

            if(!$this-&gt;form_validation-&gt;run())
            {
                // ====================
                // = Login has failed =
                // ====================
                
                //Load up the login screen
                $this-&gt;load-&gt;view(&#39;login_view&#39;);
            
            }else{
                // =======================
                // = Login has succeeded =
                // =======================
                
                //Set our custom session userdata to be checked by our secure controller
                $this-&gt;session-&gt;set_userdata(&#39;logged_in&#39; ,TRUE);
        		$this-&gt;session-&gt;set_userdata(&#39;username&#39; , $this-&gt;input-&gt;post(&#39;username&#39;));

                
                // =================================
                // = Redirect based on user intent =
                // =================================
                
                //Check if user was trying to access a specific URL before login procedure
                if($this-&gt;session-&gt;userdata(&#39;REDIRECT&#39;))
                {
                    //Save the REDIRECT
                    $redirect = $this-&gt;session-&gt;userdata(&#39;REDIRECT&#39;);
                    
                    //Unset the REDIRECT otherwise we end up in a loop
                    $this-&gt;session-&gt;unset_userdata(&#39;REDIRECT&#39;);
                    
                    //Away we go..!
                    redirect($redirect);
                    
                }else{
                    
                    // There is no REDIRECT set, just send em to the start page
                    redirect(&#39;start&#39;);
                    
                }
            }
        }
    }
    // END index method
    
    
    /**
     * Verifies that the username and password are correct
     *
     * @return void
     * @author Christopher Imrie
     **/
    function _verify_username_password($str)
    {
        $username = $str;
        $password = $this-&gt;input-&gt;post(&#39;password&#39;);
        
        /*
         * Perform your username and password check here.
         * 
         * Fetch stuff from the DB, or do whatever you like as long as you return TRUE/FALSE
         */
         
         //return TRUE / FALSE;
    }
}
// END Login class

/* End of file login.php */
/* Location: ./system/application/controllers/login.php */

</pre>
<p>
	This is a very bare bones login controller but it will do the trick very nicely and crucially sets up some session userdata that is checked by the custom controller I showed you above. &nbsp;Simply create a view named <code>login_view.php</code> (or modify the code above to suit your naming structure) and have this show a form with username and password fields. &nbsp;You will also need to fill in the <code>_verify_username_password()</code> method with your own verification code and then return TRUE/FALSE to indicate a successful username &amp; password match.</p>
<h3>
	Creating a secure controller</h3>
<p>
	Now that those two controllers have been setup, the act of creating a secure controller is a breeze. &nbsp;Simply have any page that to be protected extend from the secure class like so:</p>
<pre class="prettyprint lang-php">
&lt;?php if ( ! defined(&#39;BASEPATH&#39;)) exit(&#39;No direct script access allowed&#39;);

class Secure_page extends MY_Controller {
	
	function Secure_page()
	{
		parent::MY_Controller();
		
	}
	
}

/* End of file secure_page.php */
/* Location: ./system/admin/controllers/secure_page.php */

</pre>
<p>
	Notice that this class extends from <strong>MY_Controller</strong>, and not from <strong>Controller</strong>, as is usual with controllers in CodeIgniter. &nbsp;This simple addition of &quot;MY_&quot; to the Controller key word will completely protect this controller from any unauthorized access.</p>
<p>
	If any user tries to access a controller that extends from My_Controller, the request will be intercepted, routed to a login page and then sent back to their original url request once authorization has been completed.</p>

					]]>
					</description>
					<pubDate>Sun, 24 Oct 2010 14:46:28 +0000</pubDate>
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/sending_expressionengine_1.6.x_templates_through_the_communicate_panel#When:14:55:07Z</guid>
					<title>Sending ExpressionEngine 1.6.x templates through the Communicate panel</title>
					<link>http://www.christopherimrie.com/blog/sending_expressionengine_1.6.x_templates_through_the_communicate_panel</link>
					<description>
					<![CDATA[
					<p>
	Further on from <a href="http://www.christopherimrie.com/blog/sending_expressionengine_2_templates_through_the_communicate_panel">an article</a> I wrote a while ago about how to send templates via email through the EE2.0 control panel, I&#39;ve seen requests for how to do this in EE1.6.x.</p>
<p>
	I originally developed the method to achieve this functionality for EE1.6.x, and I then ported it and refined it for EE 2.0, so I am only too happy to share my original code if it helps someone.</p>
<p>
	The code will add a drop down list of templates from a specified template group and when the user selects one, it will show the user a preview of the rendered email where they normally compose their email. &nbsp;You can even get this little snippet to automatically set the &quot;From&quot; email address and name. &nbsp;This is very handy for consistency.</p>
<p>
	Few of things you will need before you add the code below:</p>
<ul>
	<li>
		Make sure jQuery for the Control Panel is enabled.</li>
	<li>
		Make sure your email settings in the EE admin area are set to automatically send Emails as &quot;HTML&quot; and that &quot;Word Wrap&quot; is switched off.</li>
	<li>
		Ajax loader image. &nbsp;You will need to upload an ajax image loader to your server. &nbsp;I recommend downloading and using <a href="http://vmcg.co.uk/images/public/ajax-loader.gif">this one</a>, since it is the right size. Change the $loaderImage path to point to this image.</li>
	<li>
		The code below will create a drop down list of all templates in a specified group. &nbsp;This is handy for what i needed since I had a template group called &quot;newsletters&quot; and in there I put various email templates the client could select to send. &nbsp;Set the $templGroup to the template group ID you want listed.</li>
	<li>
		You can optionally set the $autoFromEmail and $autoFromName to values that will auto populate the &quot;From Email&quot; and &quot;From Name&quot; respectively. &nbsp;You will need to uncomment the respective commands further in the code to enable this (there are comments to show you where).</li>
</ul>
<p class="error">
	Disclaimer: &nbsp;As you would expect, this is a bit of a hack, so if you update EE you will need to reapply this code each time. &nbsp;Also you apply this at your own risk and I am not responsible for any damage made to your Database due to modifications made to the code below.</p>
<p>
	Open up the file: <code>system/cp/cp.communicate.php</code></p>
<p>
	Around line 419 you will see the following code:&nbsp;</p>
<pre class="prettyprint">
if ($DSP-&gt;allowed_group(&#39;can_email_mailinglist&#39;) AND $this-&gt;mailinglist_exists == TRUE)	  
    {
</pre>
<p>
	Immediately after this add the following code, and update the config variables as I explained above:</p>
<pre class="prettyprint">
//-- ================================================================ --&gt;
//-- =             CUSTOM TEMPLATE VIA EMAIL CODE                   = --&gt;
//-- ================================================================ --&gt;

  //Config
  $templGroup = 13;
  $loaderImage = &quot;/images/public/ajax-loader.gif&quot;;
  $autoFromEmail = &#39;noreply@youremail.com&#39;;
  $autoFromName = &#39;Company Name&#39;;
  //
  
  
  $sql  = &quot;SELECT tg.group_id, tg.group_name, t.template_id, t.template_name
       FROM exp_template_groups tg , exp_templates t
       WHERE tg.group_id = t.group_id
       AND tg.site_id = &#39;&quot;.$DB-&gt;escape_str($PREFS-&gt;ini(&#39;site_id&#39;)).&quot;&#39;&quot;;
  $sql .= &quot; AND tg.group_id =&#39;&quot; . $templGroup .&quot;&#39;&quot;; 
  $sql .= &quot; ORDER BY tg.group_order, t.group_id, t.template_name&quot;;  
  $query = $DB-&gt;query($sql);

  $r .= $DSP-&gt;table(&#39;tableBorder&#39;, &#39;0&#39;, &#39;&#39;, &#39;300px&#39;).
      $DSP-&gt;tr().
      $DSP-&gt;td(&#39;tableHeading&#39;).
      $DSP-&gt;qdiv(&#39;itemWrapper&#39;, &quot;Template&quot;).
      $DSP-&gt;td_c().
      $DSP-&gt;tr_c();

    $style = ($i++ % 2) ? &#39;tableCellOne&#39; : &#39;tableCellTwo&#39;;

    $r .= $DSP-&gt;tr().
        $DSP-&gt;td($style, &#39;50%&#39;).&quot;Select Email Template: &quot;.&quot;&lt;select class=&#39;select&#39; name=&#39;email_template&#39; id=&#39;template&#39;&gt;&quot;;
    $r .= $DSP-&gt;input_select_option(&quot; &quot;, &quot;None&quot;, &#39;&#39;);
        foreach($query-&gt;result as $row){
          if($row[&#39;template_name&#39;] != &#39;index&#39;){
            $r .= $DSP-&gt;input_select_option(&quot;/index.php/&quot;.$row[&#39;group_name&#39;].&quot;/&quot;.$row[&#39;template_name&#39;], $row[&#39;template_name&#39;], &#39;&#39;);
          }
        }
    $r .= $DSP-&gt;input_select_footer()
        .&quot;&lt;img id=&#39;loader&#39; src=&#39;&quot; . $loaderImage .&quot;&#39; style=&#39;display:none&#39;/&gt;&quot;
        .$DSP-&gt;td_c()
        .$DSP-&gt;tr_c();


  $r .= $DSP-&gt;table_c(); 
  $r .= &lt;&lt;&lt; SCRIPT
&lt;script type=&quot;text/javascript&quot;&gt;
$(document).ready(function(){
$(&quot;select#template&quot;).change(function(){
var preview_url = $(this).val();
$(&quot;#loader&quot;).css(&#39;display&#39;, &#39;inline-block&#39;);

if(preview_url != &quot; &quot;){
$.get($(this).val(), function(data){
  $(&quot;#message&quot;).val(data).css(&quot;display&quot;, &quot;none&quot;).after(&quot;&lt;iframe src=&#39;&quot; + preview_url + &quot;&#39; width=&#39;96%&#39; height=&#39;440&#39; style=&#39;border:1px solid #999&#39;&gt;Your Browser does not support iFrames.&lt;/iframe&quot;);
  $(&quot;#loader&quot;).css(&#39;display&#39;, &#39;none&#39;);
  
  // - Uncomment this if you want the &#39;from email&#39; to be automatically set on template selection
  //$(&quot;input#from&quot;).val($autoFromEmail);
  
  // - Uncomment this if you want to &#39;from&#39; name to be automatically set on template selection
  //$(&quot;input[name=&#39;name&#39;]&quot;).val($autoFromName);
});
}else{
$(&quot;#message&quot;).val(&quot; &quot;).css(&quot;display&quot;, &quot;block&quot;);
$(&quot;iframe&quot;).remove();
$(&quot;#loader&quot;).css(&#39;display&#39;, &#39;none&#39;);
$(&quot;input[name=&#39;name&#39;]&quot;).val(&#39; &#39;);

}
});
});
&lt;/script&gt;
SCRIPT;

//-- =============================================================== --&gt;
//-- =                 END CUSTOM CODE                             = --&gt;
//-- =============================================================== --&gt;
</pre>
<p>
	Thats it!</p>
<p>
	You should now have a drop down list of templates on the right hand side of the communicate panel that you can select templates from and then send.</p>

					]]>
					</description>
					<pubDate>Wed, 25 Aug 2010 14:55:07 +0000</pubDate>
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/3_months_on_and_google_chrome_still_going_strong#When:03:06:17Z</guid>
					<title>3 months on and Google Chrome still going strong</title>
					<link>http://www.christopherimrie.com/blog/3_months_on_and_google_chrome_still_going_strong</link>
					<description>
					<![CDATA[
					<p>
	<img alt="" class="left" src="http://www.christopherimrie.com/images/uploads/i-love-chrome.png" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; background-color: transparent; width: 35%; " />I switched to using <a href="http://www.google.com/chrome">Google Chrome</a> full time for all my development and personal use about 3 months ago, and I must say I havent looked back. &nbsp;It hasn&#39;t been without its occasional bumps, but I have recently come to love two features included in this web browser.</p>
<p>
	I experienced some issues with Flash crashing the pages I was viewing, hoever, I cannot say whether it was the browser or the Flash plugin. &nbsp;Needless to say some sites were doing this repeatedly and Firefox and Safari were experiencing no problems. &nbsp;True to Chrome&#39;s word though, only the window I was viewing crashed and the remaining windows stayed open. &nbsp;I havent experienced this problem for a while, so it appears they may have fixed it.</p>
<p>
	There are two features that make me love this browser more than any other, and yes I know I can get the bookmark sync to work on others, I just found that Google Chrome&#39; just works - and its lightning quick at updating. Now there are many more in Chrome that are great such as the developer tools, unified search and address bar, but this is about two features:</p>
<h3>
	File Upload Progress</h3>
<p>
	Recently I have had to do a lot of uploading via forms. &nbsp;I wasn&#39;t able to use FTP since I had some custom scripts moving the files around, creating thumbnails as well as storing cache information in a DB. &nbsp;During this time I discovered an amazing feature of Chrome which has come to be my favourite feature, a progress indicator when uploading a file.</p>
<p>
	<img alt="" class="right" src="http://www.christopherimrie.com/images/uploads/Screen shot 2010-07-07 at 14_58_43.png" style="width: 25%; " />You can see an image of the progress indicator to the right, and it is just a simple percentage written in the bottom left of the window. &nbsp;This allows me to quickly find out whether the connection has gone dead, if its still uploading etc. &nbsp;Damn useful - and I had no idea it existed until a couple of weeks ago!</p>
<h3>
	Bookmark syncing across multiple machines</h3>
<p>
	<img alt="" class="left" src="http://www.christopherimrie.com/images/uploads/Screen shot 2010-07-07 at 16_19_27.png" style="width: 35%; " />Now being a Mac user, I know full well that Safari can achieve this very easily and probably just as effectively using MobileMe. &nbsp;But I have refused to pay for MobileMe since the days it used to be called <strong>.Mac</strong>. &nbsp;Dont get me wrong, its a fantastic service that really makes it easy to sync up across multiple machines, but being a bit of an industrious fellow I was fully aware that I could achieve the same functionality for free (except for the Find my iPhone - which I admit is very useful). &nbsp;</p>
<p>
	Another reason MobileMe bookmark sync doesn&#39;t appeal is that will sync my bookmarks for $99 as long as I use Safari. &nbsp;Admittedly the bookmark syncing that Google Chrome uses, which runs off your Google account, only works on Chrome - but it&#39;s <strong>free</strong>. &nbsp;</p>
<p>
	I currently have a desktop I use for my development work and a laptop for when I travel to deliver training courses. &nbsp;Once I setup the Bookmark Sync on each machine, I havent looked back, and it updates faster than I can notice. &nbsp;Even if one machine is open next to the other, the bookmark appears near instantaneously.&nbsp;</p>

					]]>
					</description>
					<pubDate>Wed, 07 Jul 2010 3:06:17 +0000</pubDate>
				</item>
					
							<item>	
					<guid isPermaLink='false'>http://www.christopherimrie.com/video/detecting_and_redirecting_an_iphone_or_ipad_using_javascript#When:20:23:17Z</guid>
					<title>Detecting and redirecting an iPhone or iPad using JavaScript</title>
					<link>http://www.christopherimrie.com/video/detecting_and_redirecting_an_iphone_or_ipad_using_javascript</link>
					<description>With the current boom in mobile web browsing, its becoming more and more important to optimise you site and content for small screen devices.&amp;nbsp; Here I will walk you through how to detect an iPhone, iPod Touch or iPad using JavaScript and then redirect them to a page optimised for that device.&amp;nbsp; The great thing about using a javascript method is that it will work on hosting services such as MobileMe or others that dont have PHP or ASP etc.</description>
					<pubDate>Wed, 02 Jun 2010 20:23:17 +0000</pubDate>
					<enclosure url="http://c1626802.cdn.cloudfiles.rackspacecloud.com/dw_iphone_ipad_detection_with_javascript.mp4" length="8935560" type="video/mp4" />
				</item>
					
							<item>	
					<guid isPermaLink='false'>http://www.christopherimrie.com/video/dreamweaver_and_jquery_basics_part_1#When:22:06:18Z</guid>
					<title>Dreamweaver and jQuery basics &#45; Part 1</title>
					<link>http://www.christopherimrie.com/video/dreamweaver_and_jquery_basics_part_1</link>
					<description>I thought I would put a nice basic tutorial on getting to grips with jQuery whilst working inside Dreamweaver.&amp;nbsp; I&#8217;ll run through the process of downloading the library, linking jQuery to our page, and then implementing some basic animation.&amp;nbsp; Getting to grips with JavaScript and JavaScript libraries such as jQuery is all the more important since HTML5&#8217;s new features and modules rely heavily on JavaScript.</description>
					<pubDate>Tue, 01 Jun 2010 22:06:18 +0000</pubDate>
					<enclosure url="http://c1626802.cdn.cloudfiles.rackspacecloud.com/dw_jquery_beginners_part_one.mp4" length="43027025" type="video/mp4" />
				</item>
					
							<item>	
					<guid isPermaLink='false'>http://www.christopherimrie.com/video/custom_web_fonts_using_the_google_font_api#When:21:41:17Z</guid>
					<title>Custom web fonts using the Google Font API</title>
					<link>http://www.christopherimrie.com/video/custom_web_fonts_using_the_google_font_api</link>
					<description>Web design has always been restricted by the use of the Web safe font set.&amp;nbsp; Thankfully Google has stepped up to the plate to try and provide a solution in the form of the Google Font API.&amp;nbsp; Its incredibly simple to use and this video shows you how to take advantage of Google&#8217;s new web font service.</description>
					<pubDate>Sun, 23 May 2010 21:41:17 +0000</pubDate>
					<enclosure url="http://c1626802.cdn.cloudfiles.rackspacecloud.com/dw_google_font_api.mp4" length="15147181" type="video/mp4" />
				</item>
					
							<item>	
					<guid isPermaLink='false'>http://www.christopherimrie.com/video/smart_objects_and_smart_filters#When:14:03:27Z</guid>
					<title>Smart Objects and Smart Filters</title>
					<link>http://www.christopherimrie.com/video/smart_objects_and_smart_filters</link>
					<description>A quick video tutorial on one of the many the benefits of using smart objects along with smart filters.</description>
					<pubDate>Fri, 21 May 2010 14:03:27 +0000</pubDate>
					<enclosure url="http://c1626802.cdn.cloudfiles.rackspacecloud.com/ps_intro_smart_objects_smart_filters.mp4" length="12996574" type="video/mp4" />
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/illustrator_lasers_pixels_at_dawn#When:02:07:40Z</guid>
					<title>Illustrator, lasers and pixels at dawn</title>
					<link>http://www.christopherimrie.com/blog/illustrator_lasers_pixels_at_dawn</link>
					<description>
					<![CDATA[
					<p>
	<img alt="" class="left" src="http://www.christopherimrie.com/images/uploads/pixels-at-dawn.jpg" />I&#39;ve just returned from London after providing Adobe Illustrator instruction for an event that was organized as part of <a href="http://www.rave.ac.uk/">Ravensbourne</a> College&#39;s <a href="http://www.putyourbusinessforward.com/">Commercializing Digital Technology</a> (CDT) programme. The event, entitled &quot;Pixels at Dawn&quot; (<a href="http://twitter.com/#search?q=%23pixelsatdawn">#pixelsatdawn</a>), was held at <a href="http://www.richmix.org.uk/">Richmix Cultural Foundation</a>&nbsp;in London and was an absolute blast!</p>
<p>
	For those not familiar with the CDT, it is a fantastic programme part funded by the <a href="http://ec.europa.eu/regional_policy/funds/feder/index_en.htm">European Regional Development Fund</a> that gives small-medium businesses access to free training in the creative field. &nbsp;As long as you qualify (Living in London, working for an under 250 employee business, working in the creative field) topic such as Adobe Flash animation, 3D compositing with Nuke, HD camera operations, intro to Final Cut and many more, are provided absolutely&nbsp;<strong>free</strong>. This is an incredible opportunity and I really do recommend you put your business forward if you are eligible. &nbsp;I have met some of the other tutors and I can say that they are all true industry experts from every realm of the creative industry.</p>
<p>
	<img alt="" class="right" src="http://www.christopherimrie.com/images/uploads/CDT_Logo_EDRF.gif" style="width: 150px; height: 113px; " />The event held last night was unique in that Ravensbourne had brought along their <a href="http://www.apple.com/education/labs/">mobile Mac lab</a>&nbsp;and&nbsp;<a href="http://www.hobartlasers.co.uk/">Hobarts</a> had provided a state of the art laser cutter for the evening. &nbsp;Industry creatives attending the free event were invited to design and create their artwork in Adobe Illustrator, then have the design either cut or engraved from a range of acrylics available on the night. &nbsp;I was on hand to help anyone with problems or give advice with regards to producing the artwork in Illustrator and then prepping it for cutting with a laser.</p>
<p>
	I produced a step by step instructional guide to using Illustrator and getting artwork ready for laser cutting specifically for this event. &nbsp;Students were given this as part of a larger information pack full of goodies courtesy of Ravensbourne college. &nbsp;If you attended the event and didnt get a copy, or if you are just interested, you can <a href="http://www.christopherimrie.com/images/uploads/Laser Cutting with Illustrator.pdf">download a PDF version</a>.</p>
<p>
	<img alt="" src="http://www.christopherimrie.com/images/uploads/IMG_6819.jpg" /></p>
<p>
	<img alt="" src="http://www.christopherimrie.com/images/uploads/IMG_6820.jpg" /></p>
<p>
	I must say, even though I have seen a lot of printing and high tech equipment (both in the printing and engineering fields), I was completely blown away by the laser cutter provided by Hobarts. &nbsp;The cutter was part of their state-of-the art PLS range and was capable of accuracies of less than 0.01mm when cutting and engraving. &nbsp;When I arrived I had the chance to produce a few pieces to serve as inspiration for the attendees, but unfortunately they didnt survive the event since some of them ended up in people pockets or were broken from rough handling (I wanted to show-off the accuracy, so the shapes were a bit delicate). &nbsp;</p>
<p>
	When the evening was over I did get the opportunity to produce a mirror plate with my web logo on it using the engraving feature. &nbsp;The photo doesn&#39;t do it justice, but the result is very impressive and I still cant get over the accuracy of the lines produced.</p>

					]]>
					</description>
					<pubDate>Wed, 12 May 2010 2:07:40 +0000</pubDate>
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/adobe_creative_suite_5_what_we_know_so_far#When:22:32:50Z</guid>
					<title>Adobe Creative Suite 5 &#45; What we know so far&#8230;</title>
					<link>http://www.christopherimrie.com/blog/adobe_creative_suite_5_what_we_know_so_far</link>
					<description>
					<![CDATA[
					<p>
	<em>[UPDATE: Adobe have now released the CS5 suite. &nbsp;You can find out more information on <a href="http://www.adobe.com/products/creativesuite/?promoid=GWYLM">Adobe&#39;s website</a>]</em></p>
<p>
	We are fast approaching that magical time, a time when developers and creatives alike rejoice in forking over hundreds of dollars to upgrade the latest and greatest version of the Adobe Creative Suite. If that sounds like I am bashing Adobe for the price of their software &ndash; I am not.</p>
<p>
	I love getting my hands on the latest version of the now industry standard (although some of the applications are more industry standard than others) Adobe creative suite, its almost like being a kid and getting a new toy (a really really expensive one). You want to play with it to see what it can do, and why it so much better than your other toys that you were playing with and through were great 5 minutes ago.</p>
<h3>
	When do I get to give them my money?</h3>
<p>
	Adobe have yet to announce an exact release date for Creative Suite 5 (CS5), although at a recent financial conference Adobe CEO Shantanu Narayen stated that it would ship along with the latest version of Flash in the first half of 2010.</p>
<p>
	Seeing as we are now halfway through March, and no advertising drive has begun, I reckon that puts the launch towards the end of April or beginning of May at the earliest.</p>
<p>
	Some rumours are flying around that it is slated for an April 22nd release date, but this could be entirely fictional.</p>
<h3>
	What will I get for my money?</h3>
<p>
	Well that&rsquo;s the big question isn&rsquo;t it? What do we get for our hard earned cash, and why should I upgrade from the current version? Over the past few weeks Adobe has quietly slipped out various sneak peak videos showcasing some new functionality for the various applications that make up the creative suite.</p>
<p>
	I&rsquo;ve tried to collate these videos in to one post. If I have missed any, please let me know.</p>
<p>
	[<em>Thanks to <a href="http://www.cs5.org">CS5.org</a> for getting the inside scoop on most of these features &amp; videos</em>]</p>
<p>
	<strong><em>Note: Adobe&rsquo;s official line is that the features outlined below may or may not be included in the release versions of CS5 but are merely technologies they are working on in their labs.<br />
	</em></strong></p>
<h2>
	Dreamweaver</h2>
<p>
	Most of the noise and rumours coming from the Dreamweaver camp are regarding HTML5 and Mobile device support. The two videos below outline some ideas that Adobe have been experimenting with in regards to using the HTML5 canvas and previewing/optimizing for mobile devices.</p>
<h5>
	Smart Paste (Illustrator &amp; HTML5 canvas)</h5>
<p>
	<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="350" width="425"><param name="src" value="http://www.youtube.com/v/8FGnlqcYoZY&amp;feature" /><embed height="350" src="http://www.youtube.com/v/8FGnlqcYoZY&amp;feature" type="application/x-shockwave-flash" width="425"></embed></object></p>
<h5>
	Multiscreen Authoring (Optimizing for Mobile devices)</h5>
<p>
	<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="350" width="425"><param name="src" value="http://www.youtube.com/v/nJP9fC0oH6A&amp;feature" /><embed height="350" src="http://www.youtube.com/v/nJP9fC0oH6A&amp;feature" type="application/x-shockwave-flash" width="425"></embed></object></p>
<h2>
	Photoshop</h2>
<h5>
	Realistic brushes &amp; canvas blending</h5>
<p>
	<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="350" width="425"><param name="src" value="http://www.youtube.com/v/BShE_jS8jLE" /><embed height="350" src="http://www.youtube.com/v/BShE_jS8jLE" type="application/x-shockwave-flash" width="425"></embed></object></p>
<h5>
	PatchMatch Technology</h5>
<p>
	<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="350" width="425"><param name="src" value="http://www.youtube.com/v/dgKjs8ZjQNg" /><embed height="350" src="http://www.youtube.com/v/dgKjs8ZjQNg" type="application/x-shockwave-flash" width="425"></embed></object></p>
<h5>
	Adobe &ldquo;Just do it&rdquo; day (JDI) improvements</h5>
<p>
	<a href="http://video.ak.facebook.com/video-ak-sf2p/v22831/199/30/549594795699_27482.mp4">http://video.ak.facebook.com/video-ak-sf2p/v22831/199/30/549594795699_27482.mp4</a><br />
	<a href="http://video.ak.facebook.com/cfs-ak-ash1/27331/000/885/550901322409_62246.mp4">http://video.ak.facebook.com/cfs-ak-ash1/27331/000/885/550901322409_62246.mp4</a><br />
	<a href="http://video.ak.facebook.com/video-ak-sf2p/v22831/249/85/548870452289_15488.mp4">http://video.ak.facebook.com/video-ak-sf2p/v22831/249/85/548870452289_15488.mp4</a><br />
	<a href="http://video.ak.facebook.com/video-ak-sf2p/v22831/105/103/550133341449_11705.mp4">http://video.ak.facebook.com/video-ak-sf2p/v22831/105/103/550133341449_11705.mp4</a></p>
<h2>
	Flash</h2>
<p>
	The biggest announcement (by Adobe themselves) is that Flash CS5 will enable developers to create native iPhone applications. The Flash development community is rather large, so by allowing them to convert work they have already produced into iPhone compatible bitcode is a boon for the whole community. It also means developers don&rsquo;t need to learn Objective C, the language used for iPhone (and all Mac) development.</p>
<h5>
	iPhone development</h5>
<p>
	<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="350" width="425"><param name="src" value="http://www.youtube.com/v/mpEUNqfk4rw" /><embed height="350" src="http://www.youtube.com/v/mpEUNqfk4rw" type="application/x-shockwave-flash" width="425"></embed></object></p>
<p>
	<a href="http://www.gotoandlearn.com/play?id=116">iPhone development in Flash CS5 (gotoandlearn.com)</a></p>
<p>
	<a href="http://www.gotoandlearn.com/play?id=118">Sneak peak of Flash CS5 (gotoandlearn.com)</a></p>
<h2>
	Premiere Pro</h2>
<p>
	Premier Pro CS5 is all about a new playback engine Adobe have created called &ldquo;Mercury&rdquo;. It allows, amongst other things, real time scrubbing and manipulation of native Red video files with no conversion necessary.</p>
<p>
	<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="350" width="425"><param name="src" value="http://www.youtube.com/v/De5N9IjUkNo&amp;feature" /><embed height="350" src="http://www.youtube.com/v/De5N9IjUkNo&amp;feature" type="application/x-shockwave-flash" width="425"></embed></object></p>
<p>
	<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="350" width="425"><param name="src" value="http://www.youtube.com/v/ukgcWrcVpZ8&amp;feature" /><embed height="350" src="http://www.youtube.com/v/ukgcWrcVpZ8&amp;feature" type="application/x-shockwave-flash" width="425"></embed></object></p>

					]]>
					</description>
					<pubDate>Sat, 20 Mar 2010 22:32:50 +0000</pubDate>
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/new_year_vegas_night_poster#When:15:33:11Z</guid>
					<title>New year &#8216;Vegas Night&#8217; poster</title>
					<link>http://www.christopherimrie.com/blog/new_year_vegas_night_poster</link>
					<description>
					<![CDATA[
					<p>
	<img alt="" src="http://www.christopherimrie.com/images/uploads/4291204159_58abc2b2f0_b.jpg" /></p>
<p>
	So I have been a web developer for a few years now, and I consider myself very good at what I do. Even though I tend to spend much of my time in front of a code editor these days, I am fully aware that a big reason for me being good at what I do is due to my time doing graphic design.</p>
<p>
	Even though I&rsquo;ve been using photoshop for many years (since I was about 15), I only really knew enough to tinker with it. I had nowhere near enough knowledge about the program to use it for practical project.</p>
<p>
	After I finished studying at University for my Aerospace Engineering degree, I decided to take a year out to raise a bit of cash to figure out what to do next.&nbsp; Naturally a bar job followed (luckily as a Bar Manager, not pint pourer) at a nightclub, where I worked for a couple of weeks shy of a full year.</p>
<p>
	During my time working there at&nbsp; I began digging out my Photoshop skills since we needed flyers and event posters made and I refused to pay out for a graphic designer.&nbsp; Part of this was due to arrogance on my part in thinking I could do just as well as them, but also I really enjoyed graphic designing.</p>
<p>
	Looking back now I cringe at some of the designs I produced when I first started out, but as the year went on I started to produce better and better work as I got more and more experienced.&nbsp; Not only did my design skills improve, but so did my knowledge of photoshop.&nbsp; Another benefit of having worked in an environment producing flyers and posters for a nightclub is that <strong>you learn a lot about paper</strong>.&nbsp; To this day, the majority of my practical knowledge about the printing process and the various paper &amp; finish options were learnt whilst cranking out flyers and poster.</p>
<p>
	So whilst going through some old files the other day I came across this gem of a poster I had produced for the nightclub.&nbsp; I got a call from the nightclub I used to manage, asking me to produce a poster for an upcoming New Years party.&nbsp; The theme was a James Bond casino night and the poster had to translate this.</p>

					]]>
					</description>
					<pubDate>Thu, 21 Jan 2010 15:33:11 +0000</pubDate>
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/absolut_pears_bank_holiday#When:20:35:32Z</guid>
					<title>Absolut Pears Bank Holiday</title>
					<link>http://www.christopherimrie.com/blog/absolut_pears_bank_holiday</link>
					<description>
					<![CDATA[
					<p>
	<img alt="" src="http://www.christopherimrie.com/images/uploads/absolut-mosaic.jpg" /></p>
<p>
	I mentioned in my previous post that I came across a whole load of artowork that I produced during my bar days.&nbsp; I used to manage a club in Bath and I ended up producing all of the flyers and posters for events over the course of the year I was there.</p>
<p>
	Here is poster I produced for a bank holiday launch party we held for the (at the time) new Absolut Pears vodka.&nbsp; The idea was to make up the bottle from a mosaic of photos taken of people in the nightclub I worked in.</p>
<p>
	The poster was printed quite large (2.5m x 3m) and then placed at the entrance to the club.&nbsp; Because of the stupendous resolution this poster was produced and printed at, the clientele were then encouraged to find themselves within the bottle.</p>
<p>
	<img alt="" src="http://www.christopherimrie.com/images/uploads/absolut-mosaic-small.jpg" /></p>
<p>
	Above is a zoomed in crop section to show the photos.</p>

					]]>
					</description>
					<pubDate>Wed, 20 Jan 2010 20:35:32 +0000</pubDate>
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/the_making_of_the_vmcg_website#When:22:26:05Z</guid>
					<title>The making of the VMCG.co.uk website</title>
					<link>http://www.christopherimrie.com/blog/the_making_of_the_vmcg_website</link>
					<description>
					<![CDATA[
					<p>
	I&rsquo;ve got a nice treat for anyone who is curious about development process of creating an HTML page from a photoshop mockup. Attached is a video time lapse of a recent project I completed (the website for <a href="http://www.vmcg.co.uk">Viper Marketing &amp; Communications Group</a>).</p>
<p>
	The video follows my development process of taking a flat jpg (original mockup was in Fireworks, hence no .psd) and converting it to a pixel perfect HTML &amp; CSS page that is fully valid and accessible. The development time for this first html page of the project took around five and a half hours, but I&rsquo;ve condensed the video down to 30 mins.</p>
<p>
	Hope you all enjoy.<br />
	<br />
	<br />
	<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="390" width="640"><param name="src" value="http://blip.tv/play/AYG%2BoWQA" /><param name="allowfullscreen" value="true" /><embed allowfullscreen="true" height="390" src="http://blip.tv/play/AYG%2BoWQA" type="application/x-shockwave-flash" width="640"></embed></object></p>

					]]>
					</description>
					<pubDate>Sun, 17 Jan 2010 22:26:05 +0000</pubDate>
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/sending_expressionengine_2_templates_through_the_communicate_panel#When:17:08:19Z</guid>
					<title>Sending ExpressionEngine 2.0 templates through the Communicate panel</title>
					<link>http://www.christopherimrie.com/blog/sending_expressionengine_2_templates_through_the_communicate_panel</link>
					<description>
					<![CDATA[
					<p>
	So one of the most frustrating things I always found about ExpressionEngine is Communicate panel.&nbsp; Now dont get me wrong, I think the communicate panel does exactly what it should do in a very clear and functional manner.&nbsp; The frustration comes from not being able to use the greatest thing about ExpressionEngine: the templates.</p>
<p>
	Now I&rsquo;m not suggesting that EllisLab have got it wrong by not allowing the templates to be used in the Communicate panel, but for some of my projects I like to at least have the option.&nbsp; Using the templates allows you to really get some nice looking emails stacked with all your site&rsquo;s content.</p>
<p>
	So to remedy my frustration I came up with a method of adding a drop down list to the ExpressionEngine 2.0 communicate panel that lists your sites templates by template group. You can send plain emails as normal but selecting a template from the list will fill the message text area with the rendered template. Since the template is fully rendered, you can send this very easily to your mailing lists and the unsubscribe links will be appended to the bottom of the email automatically.</p>
<p>
	Here is a screenshot:</p>
<p>
	<img alt="" src="http://www.christopherimrie.com/images/uploads/communicate.jpg" style="width: 620px; height: 443px;" /></p>
<p>
	<em><strong>On a serious note, the code below is to be considered a hack. </strong></em> It requires modifying core system files, and as such it will have to be reapplied after each ExpressionEngine update. There may also be a future update that breaks it all together.</p>
<h2>
	Modifying the communicate controller</h2>
<p>
	The first step is inserting some code into the communicate controller.&nbsp; The file you want is:</p>
<pre class="prettyprint lang-php">
system/expressionengine/controllers/cp/tools_communicate.php</pre>
<p>
	This file controls the rendering of the Communicate panel.&nbsp; We dont need to do anything very complicated in the backend, since all we want to do is add a list of the templates to the control panel and then have this added to the message textarea when its selected.</p>
<p>
	Add this at around line 274:</p>
<pre class="prettyprint lang-php">
$this-&gt;javascript-&gt;output(&#39;$(&quot;select#template&quot;).change(function(){
								$.get($(this).val(), function(data){
										$(&quot;#message&quot;).val(data);
								});});&#39;);
$q = $this-&gt;template_model-&gt;get_templates();
$qa = $q-&gt;result_array();
$tmpl = array(&quot; &quot; =&gt; array(&quot; &quot; =&gt; &quot;None&quot;));
for($i = 0; $i &lt; sizeof($qa); $i++){
		$tmpl[$qa[$i][&#39;group_name&#39;]][site_url($qa[$i][&#39;group_name&#39;].&quot;/&quot;.$qa[$i][&#39;template_name&#39;])] = $qa[$i][&#39;template_name&#39;];
}
$vars[&#39;templates&#39;]	= 	$tmpl;
</pre>
<h2>
	Modifying the communicate view</h2>
<p>
	Since ExpressionEngine 2.0 is now based on the MVC pattern, we need to modify the view file that is used to render the communicate control panel. The file you want is:</p>
<pre class="prettyprint lang-php">
themes/cp_themes/default/tools/communicate.php</pre>
<p>
	All you need to do is add the following at around line 59:</p>
<pre class="prettyprint lang-php">
&lt;h3&gt;Template&lt;/h3&gt;
		&lt;ul class=&quot;shun&quot;&gt;
				&lt;li class=&quot;odd&quot;&gt;
				&lt;?php echo form_dropdown(&#39;template&#39;, $templates, &#39;0&#39;, &#39;id=&quot;template&quot;&#39;)?&gt;
				&lt;/li&gt;
		&lt;/ul&gt;
</pre>
<p>
	You should now have a drop down list on your communicate panel that will allow you send your templates via email.</p>
<h3>
	Using non-standard site index name</h3>
<p>
	If you are using a non-standard site index name (ie: not index.php) then you may hit a problem where the template is not inserted into the message text area.&nbsp; To fix this, find the config file:</p>
<pre class="prettyprint lang-php">
system/expressionengine/config/config.php</pre>
<p>
	And then change the index page name at around line 49 to whatever you have named your index file:</p>
<pre class="prettyprint lang-php">
$config[&#39;index_page&#39;] = &#39;index.php&#39;;
</pre>

					]]>
					</description>
					<pubDate>Sat, 16 Jan 2010 17:08:19 +0000</pubDate>
				</item>
					
							<item>
					<guid isPermaLink='false'>http://www.christopherimrie.com/blog/talking_to_expressionengines_metaweblog_api_with_codeigniter2#When:21:53:53Z</guid>
					<title>Talking to ExpressionEngine’s MetaWeblog API with CodeIgniter</title>
					<link>http://www.christopherimrie.com/blog/talking_to_expressionengines_metaweblog_api_with_codeigniter2</link>
					<description>
					<![CDATA[
					<p>
	On a recent project I had the need to interface between ExpressionEngine (1.6.8) and CodeIgniter.</p>
<p>
	There are several situations where this is very useful even if you know ExpressionEngine&rsquo;s module and extension development API&rsquo;s like the back of your hand.&nbsp; More often than not it&rsquo;s just easier to use the <a href="http://www.xmlrpc.com/metaWeblogApi">Metaweblog API </a>since it ships with the system.</p>
<p>
	In my case I had a page that included a form with some validation functionality that required, among other things, to have the user confirm via email as well as store some custom data in a database for other uses.&nbsp; As the rest of the website was being run on ExpressionEngine,&nbsp; I wanted the users data posted into the ExpressionEngine system once all the validation and custom scripts had been executed so that it could be managed via the control panel.</p>
<p>
	However well you know ExpressionEngine, inserting directly into the ExpressionEngine database is always a bad idea, since EllisLab may update the database structure and then your custom script could end up wreaking havoc on the database.&nbsp; So I decided very early on that the Metaweblog API was the way to go.</p>
<p>
	After looking around on the net, I couldn&rsquo;t find any good tutorials on how to get CodeIgniter to talk to the Metaweblog API so I figured I&rsquo;d write my own.</p>
<h3>
	XML -RPC</h3>
<p>
	The Metaweblog API works over what is known as <a href="http://www.xmlrpc.com/">XML -RPC</a>.&nbsp; Its a pretty common data interchange format that is designed to be simpler than methods such as <a href="../2010/01/12/talking-to-expressionengines-metaweblog-api-with-codeigniter/en.wikipedia.org/wiki/SOAP">SOAP</a>.&nbsp; It works by sending data encoded in a certain XML structure to a server that then processes the data.</p>
<p>
	If you&rsquo;re like me, you&rsquo;ll find reading the official xml-rpc specification to be a little dry and tricky to put into practice in terms of coding a solution from scratch.&nbsp; Luckily for us, CodeIgniter has a built in XML-RPC server and client library that can get us up and running quickly.</p>
<h3>
	CodeIgniter&rsquo;s XML-RPC Class</h3>
<p>
	This isn&rsquo;t a tutorial on how to use CodeIgniter, so if you need a primer on that then check out the <a href="http://codeigniter.com/user_guide/">official user documentation</a>.&nbsp; I still believe its the best written user documentation out there.</p>
<p>
	The CodeIgniter <a href="http://codeigniter.com/user_guide/libraries/xmlrpc.html">XML-RPC documentation</a> is a great resource on how to use the the client library, however, its not exactly easy to apply it to the Metaweblog API.&nbsp; After a bit of trial and error I figured it out and although it is very simple I discovered that there are some restrictions to using it.</p>
<h2>
	Setting up ExpressionEngine</h2>
<p>
	Firstly, you&rsquo;ll have to install the Metaweblog API module in your ExpressionEngine install.&nbsp; You&rsquo;ll find this, obviously, under the Modules tab of the control panel.&nbsp; Once installed you can click on the Metaweblog API to change the settings. Once installed you&rsquo;ll see something like this:</p>
<p>
	<img alt="" src="http://www.christopherimrie.com/images/uploads/config.jpg" style="width: 620px; height: 280px;" /></p>
<p style="text-align: left;">
	<em>Make a note of the URL on the configuration page since you will need it later</em></p>
<p style="text-align: left;">
	When using the Metaweblog API&nbsp; each script or weblog you want to interface with will need its own configuration.&nbsp; The reason for this is that xml-rpc can only carry so much information, and it is designed for interfacing with simpler blogging systems such as Blogger or Wordpress, where there is one blog made up of the following fields:</p>
<ul>
	<li>
		Excerpt</li>
	<li>
		Content</li>
	<li>
		More Content</li>
	<li>
		Keywords</li>
</ul>
<p>
	If you&rsquo;re an ExpressionEngine developer though, you&rsquo;ll know that the beauty of EE is that you don&rsquo;t need to follow this pattern and you can choose your own. So when using the Metaweblog API, you need to map the incoming excerpt, content, more &amp; keyword fields to your own fields.&nbsp; You dont need to map them all, you just need to choose what incoming data is going where.</p>
<p>
	When you click on the name of the configuration you want to edit, you&rsquo;ll be presented with the following options:</p>
<p>
	<img alt="" src="http://www.christopherimrie.com/images/uploads/config2.jpg" style="width: 620px; height: 439px;" /></p>
<p>
	Now although it looks like there are several input data fields you can use, the many here are actually for the <strong>MoveableType API</strong> which is also part of this module ( though its not really written anywhere).&nbsp; <em>So for incoming data, you can only use the Content field.</em></p>
<h4>
	Configuration Name</h4>
<p style="padding-left: 30px;">
	<em>Enter the name of this configuration. You can leave this as Default, unless you are using more than one interface configuration.</em></p>
<h4>
	Text Formatting Preference</h4>
<p style="padding-left: 30px;">
	<em>Choose whether you want ExpressionEngine to parse any EE tags in the incoming data</em></p>
<h4>
	Entry Status</h4>
<p style="padding-left: 30px;">
	<em>You can choose what status to apply to the incoming data when it is inserted into the database, or allow it to be specified by the incoming data (more on this later).</em></p>
<h4>
	Channel Field Group</h4>
<p style="padding-left: 30px;">
	<em>Select the ExpressionEngine field group you want data inserted into. You must keep in mind that when you are sending data from CodeIgniter, you can specify the weblog to be posted into, </em><em><strong>however</strong>, make sure that you select the corresponding field group for that weblog here.</em></p>
<h4>
	Excerpt Field</h4>
<p style="padding-left: 30px;">
	<em><strong>MoveableType API&nbsp; only -</strong> Select what field you want the incoming excerpt data inserted into. The field must be a textarea.</em></p>
<h4>
	Content Field</h4>
<p style="padding-left: 30px;">
	<em>Select what field you want the incoming content data inserted into. The field must be a textarea.</em></p>
<h4>
	More Field</h4>
<p style="padding-left: 30px;">
	<em><strong>MoveableType API&nbsp; only -</strong> </em><em>Select what field you want the incoming more data inserted into. The field must be a textarea.</em></p>
<h4>
	Keywords Field</h4>
<p style="padding-left: 30px;">
	<em><strong>MoveableType API&nbsp; only -</strong> </em><em>Select what field you want the incoming keyword data inserted into. The field must be a textarea.</em></p>
<h4>
	Upload directory for file uploading</h4>
<p style="padding-left: 30px;">
	<em>If you are uploading files (although not covered here) you can specify where you want those files to be delivered.</em></p>
<p>
	So keep in mind that since we are using the Metaweblog API we can only use the Content area for incoming data, and also that the field it gets mapped to must be a textarea.</p>
<h2>
	Setting up CodeIgniter</h2>
<p>
	The code needed in order get the xml-rpc class talking to ExpressionEngine is pretty simple.&nbsp; All you need to do is load the library in your controller.&nbsp; Here i am loading the library in the controller constructor.</p>
<pre class="prettyprint lang-php">
class Metaweblog extends Controller {

	function Metaweblog()
	{
		parent::Controller();

		//load the library
		$this-&gt;load-&gt;library(&#39;xmlrpc&#39;);
	}
}
</pre>
<p>
	Once the library is loaded, you need to specify the server address.</p>
<pre class="prettyprint lang-php">
class Metaweblog extends Controller {

	function Metaweblog()
	{
		parent::Controller();

		//load the library
		$this-&gt;load-&gt;library(&#39;xmlrpc&#39;);

		//specify the server address
		$this-&gt;xmlrpc-&gt;server($this-&gt;config-&gt;item(&#39;metaweblog_url&#39;));

	}
}
</pre>
<p>
	The Metaweblog API has various methods that can be used (eg: Editing, Deleting etc) but in this case we want to post a new item.&nbsp; So we need to specify the method:</p>
<pre class="prettyprint lang-php">
class Metaweblog extends Controller {

	function Metaweblog()
	{
		parent::Controller();

		//load the library
		$this-&gt;load-&gt;library(&#39;xmlrpc&#39;);

		//specify the server address
		$this-&gt;xmlrpc-&gt;server($this-&gt;config-&gt;item(&#39;metaweblog_url&#39;));

		//Choose the metaWeblog API method
		$this-&gt;xmlrpc-&gt;method(&#39;metaWeblog.newPost&#39;);
	}
}
</pre>
<p>
	So now our configurations are in, we just have to format the xml to the correct structure.&nbsp; Using the library in CodeIgniter, we set the structure of the resulting xml by creating an array():</p>
<pre class="prettyprint lang-php">
//Setup paramaters for posting
$data = array(
	//Param[0]: Weblog ID
	&quot;weblog ID&quot;,
	//Param[1]: Username
	&quot;username&quot;,
	//Param[2]:Password
	&quot;password&quot;,
	//Param[3]:Data
	array(
			array(
				&#39;title&#39; 		=&gt;	&quot;Title of the weblog&quot;,
				&#39;description&#39;	=&gt;	&quot;Content of the weblog data being posted&quot;
				//This is needed for the array to be recognized
				), &quot;struct&quot;
		),
	//Param[4]:Status
	1
	);
</pre>
<p>
	I&rsquo;ve commented the code above, so its pretty self explanatory.&nbsp; As you can see, you specify the title and description data.&nbsp; Whatever is in the description will be inserted into the field you chose to map the &ldquo;Content field&rdquo; to in the ExpressionEngine Metaweblog API module settings.</p>
<p>
	Once we&rsquo;ve set this array up, we then add the array to the xml-rpc library and send the request.&nbsp; So once this is all put together, the full controller looks like so:</p>
<pre class="prettyprint lang-php">
class Metaweblog extends Controller {

	function Metaweblog()
	{
		parent::Controller();

		//load the library
		$this-&gt;load-&gt;library(&#39;xmlrpc&#39;);

		//specify the server address
		$this-&gt;xmlrpc-&gt;server($this-&gt;config-&gt;item(&#39;metaweblog_url&#39;));

		//Choose the metaWeblog API method
		$this-&gt;xmlrpc-&gt;method(&#39;metaWeblog.newPost&#39;);
	}

 	function publish()
	{
		//Setup paramaters for posting
		$data = array(
			//Param[0]: Weblog ID
			&quot;weblog ID&quot;,
			//Param[1]: Username
			&quot;username&quot;,
			//Param[2]:Password
			&quot;password&quot;,
			//Param[3]:Data
			array(
					array(
						&#39;title&#39; 		=&gt;	&quot;Title of the weblog&quot;,
						&#39;description&#39;	=&gt;	&quot;Content of the weblog data being posted&quot;
						//This is needed for the array to be recognized
						), &quot;struct&quot;
				),
			//Param[4]:Status
			1
			);

			//Add the array to the xml-rpc library
			$this-&gt;xmlrpc-&gt;request($data);

			//Make the request
			$this-&gt;xmlrpc-&gt;send_request();
}
}
</pre>
<p>
	And thats it!</p>
<p>
	If you are having trouble with the data, and want to know what is going on, you can turn on the debug mode by adding the following line in the contructor of your controller:</p>
<pre class="prettyprint lang-php">
$this-&gt;xmlrpc-&gt;set_debug(TRUE);</pre>
<p>
	Hope this is of help to someone.</p>

					]]>
					</description>
					<pubDate>Mon, 11 Jan 2010 21:53:53 +0000</pubDate>
				</item>
					
	</channel>
</rss>
