<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Andy Thompson</title>
    <link>https://andytson.com/</link>
    <description>Recent content on Andy Thompson</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-gb</language>
    <copyright>Andy Thompson</copyright>
    <lastBuildDate>Sat, 23 Jun 2012 13:14:00 +0000</lastBuildDate>
    <atom:link href="https://andytson.com/" rel="self" type="application/rss+xml" />
       <item>
      <title>Getting chef running on your Raspberry Pi board (Debian Squeeze)</title>
      <link>https://andytson.com/blog/2012/06/getting-chef-running-on-your-raspberry-pi-board-debian-squeeze/</link>
      <pubDate>Sat, 23 Jun 2012 13:14:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2012/06/getting-chef-running-on-your-raspberry-pi-board-debian-squeeze/</guid>
      <description>&lt;p&gt;I received my new &lt;a href=&#34;http://www.raspberrypi.org/&#34;&gt;Raspberry Pi&lt;/a&gt; Model B board
yesterday, and immediately started messing around with it (as you might expect).&lt;/p&gt;

&lt;p&gt;Now I know that I might need to sometimes have to rebuild my installation on new
SD cards, so I think it&amp;rsquo;d be good practice to store this in configuration format
so it can be applied again to new builds.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://wiki.opscode.com/display/chef/Chef+Solo&#34;&gt;Chef solo&lt;/a&gt; is good for doing
server-less &lt;a href=&#34;http://en.wikipedia.org/wiki/Configuration_management&#34;&gt;configuration management&lt;/a&gt;,
as you can define all your apt package installations and configuration in one
place, commit it to github and clone from it again when you need to set up your
Raspberry Pi board again.&lt;/p&gt;

&lt;p&gt;The steps I&amp;rsquo;ve taken to do this are:&lt;/p&gt;

&lt;p&gt;First I resized my SD-card root partition to fill the entire flash space, and
enabled the openssh-server so it can be connected to remotely. I found a good
guide explaining these at:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://elsmorian.com/post/23366148056/basic-raspberry-pi-setup&#34;&gt;http://elsmorian.com/post/23366148056/basic-raspberry-pi-setup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next I took an &lt;a href=&#34;https://raw.github.com/opscode/chef/master/chef/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb&#34;&gt;existing knife bootstrap for Ubunutu 10.4&lt;/a&gt;.
&lt;a href=&#34;http://wiki.opscode.com/display/chef/Knife&#34;&gt;Knife&lt;/a&gt; is a tool for managing
cookbooks and installing Chef Client and Chef Solo to a remote host. A knife
bootstrap is a script that is pushed to the remote host which performs the
latter.&lt;/p&gt;

&lt;p&gt;I found an issue with this bootstrap, as it turned out the SSH call it was
performing wasn&amp;rsquo;t running login profiles, so wasn&amp;rsquo;t adding the sbin directories
to the PATH environmental variable. It was an easy fix to do, as the &amp;ldquo;bash -c&amp;rdquo;
at the start of the bootstrap file just needed changing to &amp;ldquo;bash -l -c&amp;rdquo;&lt;/p&gt;

&lt;p&gt;With the modifications, it was (for me) just:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;knife bootstrap -d debian6-gems -x pi --sudo &amp;lt;ip address of R-PI&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will SSH into the specified IP address as the pi user, and run the
bootstrap under sudo for root permissions.&lt;/p&gt;

&lt;p&gt;Given that there is additional knife configuration files needed to work out the
path that debian6-gems is located in, this could alternatively written with the
exact location of the bootstrap file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;knife bootstrap -t /path/to/debian6-gems.erb -x pi --sudo &amp;lt;ip address of R-PI&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I&amp;rsquo;ve added that knife bootstrap to a github &lt;a href=&#34;https://github.com/webtatic/configuration&#34;&gt;configuration repository&lt;/a&gt;,
so you can run it yourself by doing the following on your PC (assuming you have
ruby and rubygems set up already):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;gem install chef &lt;span class=&#34;c1&#34;&gt;# for the knife command&lt;/span&gt;
wget https://raw.github.com/webtatic/configuration/master/chef/bootstrap/debian6-gems.erb
knife bootstrap -t debian6-gems.erb -x pi --sudo &amp;lt;ip address of R-PI&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
</description>
    </item>

       <item>
      <title>Daemonising a PHP cli script on a posix system</title>
      <link>https://andytson.com/blog/2010/05/daemonising-a-php-cli-script-on-a-posix-system/</link>
      <pubDate>Mon, 24 May 2010 13:38:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2010/05/daemonising-a-php-cli-script-on-a-posix-system/</guid>
      <description>&lt;p&gt;I’ve been researching how to best write a long running PHP script executed on
the command-line, and whilst there are Linux commands you can use to daemonise a
command, these can also be written into a php script as well.&lt;/p&gt;

&lt;p&gt;The easiest way to daemonise a command on a posix system is to run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;nohup &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; &amp;lt; /dev/null &amp;gt; /dev/null 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;This simply calls nohup to execute the command, which in effect disables the
SIGHUP signal (used to tell a child its parent terminal is closing), and
backgrounds the process. All standard file descriptors are set to /dev/null to
stop the command from reading/outputting anything back to the terminal, and so
that when the terminal is closed, reads and writes from stdin/stdout/stderr do
not fail.&lt;/p&gt;

&lt;p&gt;This is a bit clunky, but the same can be achieved in PHP either by default, or
via a command-line argument.&lt;/p&gt;

&lt;h3 id=&#34;daemonise&#34;&gt;Daemonise&lt;/h3&gt;

&lt;p&gt;First, to achieve backgrounding, you must &lt;a href=&#34;http://php.net/manual/en/function.pcntl-fork.php&#34;&gt;fork&lt;/a&gt;
the process as the current process wont be able to background. Forking will
create a new process with the same memory as the parent, which will carry on on
the same line the parent forked on. Then detatch it from the terminal using
&lt;a href=&#34;http://php.net/manual/en/function.posix-setsid.php&#34;&gt;posix_setsid()&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;pcntl_fork&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;unable to fork&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// this is the child process&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// otherwise this is the parent process&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;posix_setsid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
     &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;could not setsid&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Next, we will replace the duplicated file descriptors (stdin, stdout and stderr)
with /dev/null. When a standard file descriptor is closed, it can be replaced
with one opened by php. The variables are not important, just the ordering of
the fopen calls.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;nb&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;STDIN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;STDOUT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;STDERR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;$stdIn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/dev/null&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// set fd/0&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;$stdOut&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/dev/null&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// set fd/1&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;$stdErr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;php://stdout&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// a hack to duplicate fd/1 to 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You may want to switch stderr to a log file instead e.g.
fopen(‘/path/to/errorlog’, ‘a’). PHP errors will output to this file as they
happen.&lt;/p&gt;

&lt;p&gt;Lastly SIGHUP, along with a few additional terminal signals, can be ignored by
the process:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;nb&#34;&gt;pcntl_signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SIGTSTP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SIG_IGN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;pcntl_signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SIGTTOU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SIG_IGN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;pcntl_signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SIGTTIN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SIG_IGN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;pcntl_signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SIGHUP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SIG_IGN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So that gives us the basic daemonising effect. The terminal can now be closed,
and the process will continue to run until terminated either internally or
externally.&lt;/p&gt;

&lt;h3 id=&#34;single-instance&#34;&gt;Single Instance&lt;/h3&gt;

&lt;p&gt;Now with most daemon programs you want to make sure that there can be only one
instance, and that instance can be tracked for termination later. To do this we
can use a locked file that contains the process id. If the file is locked for
write, the daemon is running, otherwise it isn’t. Also the file can be read by
other scripts to get the process id, which can be used to send signals to the
process.&lt;/p&gt;

&lt;p&gt;This you would do before any other code.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/path/to/pid&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;c+&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;flock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;LOCK_EX&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;LOCK_NB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;already running&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;pcntl_fork&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;unable to fork&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// this is the child process&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// otherwise this is the parent process&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;fseek&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;ftruncate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
    	&lt;span class=&#34;nb&#34;&gt;fwrite&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;fflush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The lock will prevent another script from continuing. Once the script terminates,
the lock will automatically be released allowing the script to be called again.&lt;/p&gt;

&lt;h3 id=&#34;the-full-code&#34;&gt;The full code&lt;/h3&gt;

&lt;p&gt;The end result is as follows:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/path/to/pid&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;c+&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;flock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;LOCK_EX&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;LOCK_NB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;already running&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;pcntl_fork&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;unable to fork&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// this is the child process&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// otherwise this is the parent process&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;fseek&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;ftruncate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
    	&lt;span class=&#34;nb&#34;&gt;fwrite&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;fflush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;posix_setsid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
     &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;could not setsid&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;STDIN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;STDOUT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;STDERR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;$stdIn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/dev/null&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// set fd/0&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;$stdOut&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/dev/null&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// set fd/1&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;$stdErr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;php://stdout&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// a hack to duplicate fd/1 to 2&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;pcntl_signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SIGTSTP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SIG_IGN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;pcntl_signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SIGTTOU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SIG_IGN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;pcntl_signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SIGTTIN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SIG_IGN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;pcntl_signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SIGHUP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SIG_IGN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;// do some long running work&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;300&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To see the replaced file descriptors have a look at the process’ proc entry.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;ls -al /proc/&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;cat /path/to/pid&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;/fd
 
total 0
dr-x------ &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; root root  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; May &lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; 09:41 .
dr-xr-xr-x &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; root root  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; May &lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; 09:34 ..
lr-x------ &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; May &lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; 09:41 &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -&amp;gt; /dev/null
l-wx------ &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; May &lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; 09:41 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -&amp;gt; /dev/null
l-wx------ &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; May &lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; 09:41 &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -&amp;gt; /dev/null
lrwx------ &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; May &lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; 09:41 &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; -&amp;gt; /path/to/pid
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here is a script that will then kill this daemon:&lt;/p&gt;

&lt;p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/path/to/pid&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;c+&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;flock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;LOCK_EX&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;LOCK_NB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;process not running&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;$pid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;fgets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;posix_kill&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SIGTERM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;h3 id=&#34;how-about-windows&#34;&gt;How about Windows?&lt;/h3&gt;

&lt;p&gt;None of the versions of Windows support the posix api, however Microsoft have
provided a &lt;a href=&#34;http://en.wikipedia.org/wiki/Windows_service&#34;&gt;service architecture&lt;/a&gt;
in all versions of Windows since XP. There is a PECL module
&lt;a href=&#34;http://docs.php.net/manual/en/win32service.installation.php&#34;&gt;win32service&lt;/a&gt;,
which can help you with dealing with setting up and controlling a PHP service.
An &lt;a href=&#34;http://docs.php.net/manual/en/win32service.examples-service.php&#34;&gt;example&lt;/a&gt;
can be seen in the PHP.net documentation.&lt;/p&gt;</description>
    </item>

       <item>
      <title>The Travelling Elephpant challenge, my two solutions</title>
      <link>https://andytson.com/blog/2010/05/travelling-elephpant-solutions/</link>
      <pubDate>Mon, 17 May 2010 11:47:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2010/05/travelling-elephpant-solutions/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://www.ibuildings.com/&#34;&gt;Ibuildings&lt;/a&gt;, a PHP development company with offices
in the Netherlands, UK and Italy, have been running a series of
&lt;a href=&#34;http://ibuildings.com/challenge/&#34;&gt;challenges&lt;/a&gt;, with prizes such as iPads and
tickets to the &lt;a href=&#34;http://phpconference.nl/&#34;&gt;Dutch PHP Conference&lt;/a&gt; (DPC, of which
they host). The latest completed challenge, the
&lt;a href=&#34;http://techportal.ibuildings.com/2010/05/17/the-elephpant-challenge-winners-and-results/&#34;&gt;Elephpant challenge&lt;/a&gt;,
was in the form of a code contest to write the fastest, shortest and least
complex algorithm in PHP to solve a
&lt;a href=&#34;http://en.wikipedia.org/wiki/Travelling_salesman_problem&#34;&gt;Travelling Salesman problem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’m happy to say that I was one of the winners for this task, getting 30 points
(10 in each scoring method), which was the maximum points possible, for the
medium category (people with 2 to 4 years experience), and winning a ticket to
the DPC.&lt;/p&gt;

&lt;p&gt;Here I will describe the two solutions I researched and completed. I only
submitted the one which I thought would give me the biggest chance of winning,
but each had their own specialities.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://andytson.com/files/2010/05/elephpant.jpg&#34; alt=&#34;&#34; width=&#34;500&#34; height=&#34;333&#34; /&gt;
Picture under
&lt;a href=&#34;http://creativecommons.org/licenses/by-nc/2.0/deed.en_GB&#34;&gt;Creative Commons Attribution Non-commercial license&lt;/a&gt;
by &lt;a href=&#34;http://www.flickr.com/photos/drewm/3191872515/in/pool-elephpants&#34;&gt;drewm&lt;/a&gt; on Flicker.&lt;/p&gt;

&lt;p&gt;First, to understand the problem you must research TSP. There are two types of
algorithms, exact and approximate, and a TSP can be asymetric (costs different
depending on the direction of travel) or symetric. In the challenge I needed a
&lt;a href=&#34;http://en.wikipedia.org/wiki/Travelling_salesman_problem#Exact_algorithms&#34;&gt;exact symetric algorithm&lt;/a&gt;,
of which Wikipedia briefly mentions several different algorithms.&lt;/p&gt;

&lt;p&gt;I picked the two most promising algorithms, one based on dynamic programming,
and one branch and bound algorithm. The former being shorter and least complex,
and the latter being faster and more scalable.&lt;/p&gt;

&lt;h3 id=&#34;dynamic-programming&#34;&gt;Dynamic Programming&lt;/h3&gt;

&lt;p&gt;I wont go into too much detail of this one. Although it was the one I picked to
submit for the competition it is in fact extremely simple, based on a single
premise that a optimal tour can be calculated by finding the minimum tour length
of each unvisited node added to the optimal subtour of the remaining nodes. It
is recursive in nature, dividing up into smaller subtours until there is a
single cost for traveling from one node to another.&lt;/p&gt;

&lt;p&gt;Where i is the last landmark and S is the set of landmarks excluding the first
and last.&lt;/p&gt;

&lt;p&gt;This I managed to write in a total of 33 (PHP_CodeCoverage) / 38 (result) lines
of executable code, a C.R.A.P index of 6 (as Ivo mentions in the comments, my
result would have been in fact 4 for his calculations), and according to the
Ibuildings test a time of 333 seconds. I however recorded the speed at 54
seconds on my laptop (not particularly high spec) with xdebug disabled.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://andytson.com/files/2010/05/contest.php&#34;&gt;Here is the solution&lt;/a&gt;, of which I have fully
commented. Please consider this script with having a New BSD license if you
wish to use a derivative of it.&lt;/p&gt;

&lt;h3 id=&#34;branch-and-bound&#34;&gt;Branch and bound&lt;/h3&gt;

&lt;p&gt;Wikipedia mentions branch and bound algorithms in relation to TSP as being the
best algorithm short of cutting-plane algorithms. I ignored the latter due to
lack of information found in my research, and the likelihood of it being much
too complex for the challenge.&lt;/p&gt;

&lt;p&gt;Branch and bound algorithms, it states as being an improvement in speed over
other algorithms such as the dynamic programming one above. It can handle a lot
more landmarks on top of this, however the challenge only needed to visit a
total of 12 landmarks (including the start and end nodes).&lt;/p&gt;

&lt;p&gt;When first testing the dynamic programming algorithm, I found it to be much too
slow, and wanted to try a branch and bound algorithm to compete with it. This
proved challenging and much harder to research and understand. I finally came
across an &lt;a href=&#34;http://lcm.csa.iisc.ernet.in/dsa/node187.html&#34;&gt;extremely helpful web page&lt;/a&gt;
describing a mathematical description of an algorithm.&lt;/p&gt;

&lt;p&gt;When writing a branch and bound algorithm, it is important to select a good
function to calculate the lower bound (something that is lower cost or equal
to the best solution). If a tour is found to be the best calculated so far, all
branches with higher lower bounds can be discarded.&lt;/p&gt;

&lt;p&gt;The lower bound I used was simply based on the premise that the best tour is the
sum of the edges of the tour, and therefore the lower bound must be equal to or
less than this.&lt;/p&gt;

&lt;p&gt;The rest of the algorithm is to choose the branches, add constraints that better
select the lower bound, and check through them, picking each edge one at a time,
testing whether to include or exclude it from the list of edges that make up the
lower bound. Eventually enough edges will be included to get a tour. This I
leave for you to read in the article I mentioned.&lt;/p&gt;

&lt;p&gt;Now when I had written this, there were several slow areas, such as calculating
the lower bound, and checking to eliminate subtours (tours that do not go
through every point, but form clusters of smaller tours). As the article didn’t
go into detail on how to do this, I had to come up with an inovative fast check.
I researched subtour elimination, and came across
&lt;a href=&#34;http://www.tsp.gatech.edu/methods/opt/subtour.htm&#34;&gt;this article&lt;/a&gt;, which
although did not give the exact answer in a way I could understand, gave me an
idea.&lt;/p&gt;

&lt;p&gt;My previous subtour checks were scanning through the list of included nodes,
tracing each path to see if it went back to the start or was too short. This was
slow (although twice the speed of my dynamic programming algorithm). My idea was
to instead track each cluster of joined edges as they get added, and check the
constraints on the ones affected by the addition, making sure they didn’t hit
the required edge count for each node without completing a full tour.&lt;/p&gt;

&lt;p&gt;This proved to be much faster, totalling a time of 20 seconds to calculate the
best tour, however the end result was a large amount of code, with many
functions, loops and if checks. I’d have been lucky to get 10 points with an
attempt at the fastest algorithm. Anyone who scored less than me in each section
(speed, lines of code, and complexity) could have scored better. So it was back
to optimising the dynamic programming algorithm above for me.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&#34;http://andytson.com/files/2010/05/contest-bab.php&#34;&gt;solution can be seen here&lt;/a&gt;,
which also I will license under New BSD. Sorry that there are no comments in the
code at the moment.&lt;/p&gt;

&lt;h3 id=&#34;speed-lines-of-executable-code-and-complexity&#34;&gt;Speed, lines of executable code and complexity&lt;/h3&gt;

&lt;p&gt;These were the categories of scoring, which award 10 points for each.&lt;/p&gt;

&lt;p&gt;Speed varies a lot with algorithms, and the choice could lead to 0 points if
choosing a brute force search, or 10 if choosing the best algorithm. I’d
recommend anyone who tries to then optimise the code should make use of
&lt;a href=&#34;http://xdebug.org/docs/profiler&#34;&gt;xdebug’s profiler&lt;/a&gt; to see which bits of code
are sub-optimal. Trying to optimise the code without this is just a guessing
game, and you may end up wasting time changing code that cannot be optimised
further.&lt;/p&gt;

&lt;p&gt;Lines of executable code I don’t consider the most important aspect of
programming, but it does add to complexity in maintaining code, and shorter code
can often be easier to understand. In a challenge, however, it can easily be
abused at the expense of readability.&lt;/p&gt;

&lt;p&gt;Complexity was calculated using a similar method to
&lt;a href=&#34;http://sebastian-bergmann.de/archives/877-CRAP-in-PHPUnit-3.5.html&#34;&gt;Change Risk Analysis and Predictions&lt;/a&gt;
(CRAP) index. This was new to me as I had not come across it before. It is
calculated based on the code coverage of a piece of code and the number of code
branches in the code (functions, ifs, loops, logical ands and ors etc). This can
also be abused to a point. As you can see in my winning code, when printing out
a list of the landmarks for the best tour, I chose rather than to write a
foreach to loop through and print out the names of the landmarks, I wrote a
single line function to splice the landmarks names onto an ordered list of
identifiers.&lt;/p&gt;

&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;In the end I submitted my first solution, which ended up winning as I had hoped.
The effort gone into the second solution I don’t consider wasted even if it was
not quicker than the results. It has the capability to run on a much larger set
of landmarks with a good time, although not good enough to
&lt;a href=&#34;http://www.tsp.gatech.edu/sweden/&#34;&gt;tour Sweden&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As for the &lt;a href=&#34;http://techportal.ibuildings.com/2010/05/17/the-elephpant-challenge-winners-and-results&#34;&gt;challenge results&lt;/a&gt;,
you can see that this was a difficult challenge. None of the entries with the
0-2 years work experience fit the requirements, and even in my category many
people failed the test.&lt;/p&gt;

&lt;p&gt;One thing I must consider is that in a few months I’ll no longer be in the
medium category, and challenges such as this will be much more competitive. I
have already completed Ibuildings next challenge, and it may be the last before
I can only enter into the senior category.&lt;/p&gt;

&lt;p&gt;I congratulate the winner for the senior category, Michiel Brandenburg, winning
the iPad, who scored 26. 10 for both lines of code and complexity, and 6 for
being the 3rd fastest in his category (which was faster than mine as well).&lt;/p&gt;

&lt;p&gt;Also, thanks to Ibuildings for running this challenge. I found it both
interesting and challenging. Ibuildings have already started a
&lt;a href=&#34;http://ibuildings.com/challenge/&#34;&gt;new challenge you can enter&lt;/a&gt; into, based on
Test Driven Development.&lt;/p&gt;

&lt;p&gt;For any of you reading who are going to the Dutch PHP Conference, I hope to see
you there :)&lt;/p&gt;

&lt;p&gt;Now all I need is to somehow win my own stuffed elephpant to complete my own
journey from London to the DPC.&lt;/p&gt;</description>
    </item>

       <item>
      <title>Page-level caching with Nginx</title>
      <link>https://andytson.com/blog/2010/04/page-level-caching-with-nginx/</link>
      <pubDate>Sat, 10 Apr 2010 22:22:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2010/04/page-level-caching-with-nginx/</guid>
      <description>&lt;p&gt;Since my &lt;a href=&#34;https://andytson.com/blog/2008/04/page-level-caching-with-nginx-0-6/&#34;&gt;last post&lt;/a&gt; on using
&lt;a href=&#34;http://wiki.nginx.org/Main&#34;&gt;Nginx&lt;/a&gt; to cache proxied content, they have added
proper cache handling via their proxy_cache* directives. These are much more
suitable for use, as they capture the HTTP response headers and also use more
advanced Cache-Control checks.&lt;/p&gt;

&lt;p&gt;To start, install the latest stable Nginx avaliable at &lt;a href=&#34;http://wiki.nginx.org/NginxInstall&#34;&gt;http://wiki.nginx.org/NginxInstall&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Next edit your nginx.conf and add the proxy_cache_path directive to define a
named cache storage. These are independant of servers and locations, and can be
reused inside each later on.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;k&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;s&#34;&gt;http&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;s&#34;&gt; &lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;proxy_cache_path&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/var/cache/nginx&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;keys_zone=anonymous:10m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt; &lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;vhosts/*.conf&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next create the directory for the cache:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;mkdir -p /var/cache/nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next define your server configuration, which can be done for example in
conf/vhosts/example.com.conf if you defined the include above.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;listen&lt;/span&gt;            &lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;servername&lt;/span&gt;        &lt;span class=&#34;s&#34;&gt;example.com&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt; &lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;proxy_set_header&lt;/span&gt;  &lt;span class=&#34;s&#34;&gt;X-Real-IP&lt;/span&gt;  &lt;span class=&#34;nv&#34;&gt;$remote_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_set_header&lt;/span&gt;  &lt;span class=&#34;s&#34;&gt;Host&lt;/span&gt;       &lt;span class=&#34;nv&#34;&gt;$host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt; &lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;kn&#34;&gt;proxy_pass&lt;/span&gt;    &lt;span class=&#34;s&#34;&gt;http://localhost:8080/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;kn&#34;&gt;proxy_cache&lt;/span&gt;   &lt;span class=&#34;s&#34;&gt;anonymous&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt; &lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# don&amp;#39;t cache admin folder, send all requests through the proxy&lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/admin&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;kn&#34;&gt;proxy_pass&lt;/span&gt;    &lt;span class=&#34;s&#34;&gt;http://localhost:8080/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt; &lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# handle static files directly. Set their expiry time to max, so they&amp;#39;ll&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# always use the browser cache after first request&lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;~&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;(css|js|png|jpe?g|gif|ico)&lt;/span&gt;$ &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;kn&#34;&gt;root&lt;/span&gt;          &lt;span class=&#34;s&#34;&gt;/var/www/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;${host}/http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;kn&#34;&gt;expires&lt;/span&gt;       &lt;span class=&#34;s&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As we don’t want the nginx worker processes to have root permissions when in use, add to the start of conf/nginx.conf:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;k&#34;&gt;user&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;nginx&lt;/span&gt;
&lt;span class=&#34;s&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;s&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then sort out the user and permissions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;useradd nginx
chown nginx:nginx /var/cache/nginx /usr/local/nginx/&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;fastcgi_temp,logs,proxy_temp&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To start nginx on bootup, add the following to the end of /etc/rc.local:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;/usr/local/nginx/sbin/nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then also run this command to start nginx now.&lt;/p&gt;

&lt;p&gt;That is all that is needed, no patches this time. There are several more
proxy_cache* directives avaliable that you can use to tweak its behaviour, see
the &lt;a href=&#34;http://wiki.nginx.org/NginxHttpProxyModule#proxy_cache&#34;&gt;proxy module documentation&lt;/a&gt;
for more details.&lt;/p&gt;</description>
    </item>

       <item>
      <title>OData, a RESTful contender for your API</title>
      <link>https://andytson.com/blog/2010/03/odata-a-restful-contender-for-your-api/</link>
      <pubDate>Wed, 17 Mar 2010 13:37:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2010/03/odata-a-restful-contender-for-your-api/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://www.odata.org/&#34;&gt;OData&lt;/a&gt; is a new API protocol that has recently been
released by Microsoft, along with the launch of their new site on the 16th March
2010. It is a &lt;a href=&#34;http://en.wikipedia.org/wiki/Representational_State_Transfer&#34;&gt;REST&lt;/a&gt;ful
standard, which adds a lot of its own goods to the table.&lt;/p&gt;

&lt;p&gt;As a RESTful standard, it exposes a web service in the form of resources
accessible via discrete HTTP urls, representing actions via the HTTP methods. It
fills in the gaps that the REST style of architecture leaves open, giving a full
specification, from the request to the response (although omitting
authentication and authorisation). OData surprisingly also allows
&lt;a href=&#34;http://www.odata.org/developers/protocols/operations#InvokingServiceOperations&#34;&gt;RPC-style operations as well&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;In essence, OData is as to RESTful service style as &lt;a href=&#34;http://www.w3.org/TR/soap/&#34;&gt;SOAP&lt;/a&gt;
is to RPC. Before this, I had a hard time taking REST seriously, given the lack
of protocol specifications meaning that each implementation of a RESTful service
tends to handle things differently.&lt;/p&gt;

&lt;p&gt;It also includes features that make it much more ready for the enterprise
environment, supporting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.odata.org/media/5986/%5Bmc-edmx%5D.htm&#34;&gt;a service definition language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;error message formatting – missing from the documentation at the moment&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.odata.org/developers/protocols/uri-conventions#InlinecountSystemQueryOption&#34;&gt;dataset paging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.odata.org/developers/protocols/uri-conventions&#34;&gt;advanced queries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.odata.org/developers/protocols/batch&#34;&gt;batch requests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are two request and response body formats which are supported,
&lt;a href=&#34;http://bitworking.org/projects/atom/rfc5023.html&#34;&gt;AtomPub&lt;/a&gt; and &lt;a href=&#34;http://www.json.org/&#34;&gt;JSON&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;features&#34;&gt;Features&lt;/h3&gt;

&lt;p&gt;Providing a web-service description language, it allows automatic creation of
proxy classes for clients to quickly consume with little knowledge of the
service. It also allows a level of client-side validation of a request before it
is sent out.&lt;/p&gt;

&lt;p&gt;If an error occurs, as with the REST architecture style, OData producers will
use &lt;a href=&#34;http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html&#34;&gt;HTTP error statuses&lt;/a&gt;
4xx/5xx to notify of an error, however this information is not usually enough to
help the consumer bug fix, so OData defines an error message specification which
is sent in the response body.&lt;/p&gt;

&lt;p&gt;A frequent problem faced when building a web-service that lists entries is that
it becomes a problem when the number of entries gets large. Asside from the fact
that not all HTTP servers are built for long streams of data, the consumer does
not need all of that information at once, so paging is required to limit the
response. OData defines this ability in its specification.&lt;/p&gt;

&lt;p&gt;Web services in a REST architecture tend to have limited functionality in an
individual request. As such, additional resources are needed to define complex
transactions. This means that the web-service needs multiple calls to different
resource actions. OData improves this by allowing multiple calls to be batched
into one request, removing the HTTP overhead associated.&lt;/p&gt;

&lt;h3 id=&#34;gdata-protocol&#34;&gt;GData protocol&lt;/h3&gt;

&lt;p&gt;If you have ever used any of Google’s API’s you may think this sounds very
similar to the &lt;a href=&#34;http://code.google.com/apis/gdata/&#34;&gt;Google GData protocol&lt;/a&gt;,
which has similar features. Google released the GData protocol for access to
it’s services, such as Calendar, Docs, and YouTube API.&lt;/p&gt;

&lt;p&gt;GData is really only pushed as a protocol to be consumed for Google’s services,
however OData appears to be an attempt to open the server side of the protocol
for other companies to use, providing much more for developers who wish to
develop a OData producer, including .Net libraries to help expose data in the
protocol.&lt;/p&gt;

&lt;h3 id=&#34;odata-sdk&#34;&gt;OData SDK&lt;/h3&gt;

&lt;p&gt;Microsoft has also provided as part of it’s OData SDK, along with the .Net
server libraries, client libraries for most major languages (Javascript, PHP,
Java, Objective-C, Silverlight, and obviously .Net), so is ready immediately for
several of Microsoft’s services, including Azure.&lt;/p&gt;

&lt;p&gt;Aside from the disappointment of no PHP server libraries for this (of which I
may try to rectify myself by creating my own), the new web-service protocol
appears to be the best thing since SOAP, if not better, and may even replace it
as my prefered choice in web-service development.&lt;/p&gt;

&lt;p&gt;See more information at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.odata.org/&#34;&gt;http://www.odata.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>

       <item>
      <title>Techniques for creating a secure shared web server</title>
      <link>https://andytson.com/blog/2010/01/techniques-for-creating-a-secure-shared-web-server/</link>
      <pubDate>Mon, 18 Jan 2010 13:05:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2010/01/techniques-for-creating-a-secure-shared-web-server/</guid>
      <description>&lt;p&gt;Here are several techniques for creating a secure shared web server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update 2010-03-14&lt;/strong&gt; – Revised opinion about APC and eAccellerator, which
possibly do use memory-mapped files, also added detail about mpm_worker not
working with mod_apparmor.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h3 id=&#34;php-open-basedir-ini-setting&#34;&gt;PHP open_basedir ini setting&lt;/h3&gt;

&lt;p&gt;PHP provides this setting in order to limit the access of functions which use
PHP’s fopen to a specified directory. PHP extensions may not always use this,
instead using the standard fopen, which wont be protected. Shell functions,
such as exec, will also be unable to restrict external programs, so should be
disabled.&lt;/p&gt;

&lt;p&gt;If you are using mod_php, you will need to use php_admin_value rather than
php_value, as .htaccess files can override php_value or php.ini settings:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-apache&#34; data-lang=&#34;apache&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;vhost&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;*:80&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
...

&lt;span class=&#34;nb&#34;&gt;php_admin_value&lt;/span&gt; open_basedir &lt;span class=&#34;sx&#34;&gt;/path/to/project&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;&amp;lt;/vhost&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;suexec-cgi-suphp&#34;&gt;suEXEC CGI/suPHP&lt;/h3&gt;

&lt;p&gt;This technique involves the use of setuid, which allows the super-user to change
to any other user. The way suEXEC does this is providing a program with the user
sticky bit set. With the right configuration, Apache will call this, passing in
a script to execute, and the user and group id for which to run from.&lt;/p&gt;

&lt;p&gt;Suexec will check a few conditions against it’s compiled settings, such as the
base directory from which scripts are allowed to run from, and directory
permissions. If these pass, it will execute the script.&lt;/p&gt;

&lt;p&gt;Using suExec in CGI mode, or when using suPHP, you will get the same
disadvantages of using CGI normally, and so would not be suitable for a server.&lt;/p&gt;

&lt;h3 id=&#34;suexec-fcgi&#34;&gt;suEXEC FCGI&lt;/h3&gt;

&lt;p&gt;suEXEC can also initialise a program supporting FastCGI, allowing better
utilisation of resources. The FastCGI server can then be connected to from
Apache. It does not have the benefit of Apache’s process pooling, and you may
not be able to modify the FastCGI pool once running.&lt;/p&gt;

&lt;p&gt;For more information check out
&lt;a href=&#34;http://blog.chty.org/post/2007/10/28/Apache2-mod_fastcgi-suexec-on-debian-etch&#34;&gt;this blog post&lt;/a&gt;
on setting it up.&lt;/p&gt;

&lt;h3 id=&#34;mpm-itk&#34;&gt;mpm_itk&lt;/h3&gt;

&lt;p&gt;mpm_itk is an Apache process model based on mpm_prefork, which instead runs its
master process as root, giving it the ability to fork and setuid Apache itself.
This gives many advantages over the above techniques, allowing use of any Apache
modules and process pooling.&lt;/p&gt;

&lt;p&gt;It however has a tradeoff. Firstly, the connection is established by a process
running as super-user. This, the module’s creator mentions, would be a problem
if there was a mod_ssl security hole.&lt;/p&gt;

&lt;p&gt;Secondly, since processes using setuid cannot return to super-user, the only
realistic possibility is to terminate the fork. From a performance viewpoint of
forking and terminating, this isn’t a big deal, however there is no way to
persist modified shared memory between requests, as forks
&lt;a href=&#34;http://en.wikipedia.org/wiki/Copy-on-write&#34;&gt;copy-on-write&lt;/a&gt;. Memory-mapped file
support should still work, as well as regular file caching.&lt;/p&gt;

&lt;p&gt;To use, install the mpm-itk, and add the configuration to your vhost:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-apache&#34; data-lang=&#34;apache&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;vhost&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;*:80&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
...

&lt;span class=&#34;nb&#34;&gt;AssignUserID&lt;/span&gt; myproject-apache myproject-apache
&lt;span class=&#34;nt&#34;&gt;&amp;lt;/vhost&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For more information checkout the &lt;a href=&#34;http://mpm-itk.sesse.net/&#34;&gt;mpm-itk&lt;/a&gt; project page.&lt;/p&gt;

&lt;h3 id=&#34;mod-apparmor&#34;&gt;mod_apparmor&lt;/h3&gt;

&lt;p&gt;This is an Apache module which comes with
&lt;a href=&#34;http://forge.novell.com/modules/xfmod/project/?apparmor&#34;&gt;AppArmor&lt;/a&gt;. AppArmor is
a kernel-level access control module, which allows processes to run under
different configurations (called hats). mod_apparmor can change the hat a vhost
is running under, giving kernel-level access control to all calls to files to
all Apache modules.&lt;/p&gt;

&lt;p&gt;This, unlike mpm-itk, isn’t restricted to a request fork and terminate
processing model, so should work on more Apache2 mpms.&lt;/p&gt;

&lt;p&gt;Mpm_worker, however will have problems with changing hats per process, as
multiple requests to different vhosts share the same hat, so mod_apparmor
shouldn’t be used. This doesn’t stop you from just using AppArmor by itself to
provide a global policy.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-apache&#34; data-lang=&#34;apache&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;vhost&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;*:80&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
...

&lt;span class=&#34;nb&#34;&gt;AAHatName&lt;/span&gt; MY_HAT_NAME
&lt;span class=&#34;nt&#34;&gt;&amp;lt;/vhost&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See the following link for more information on using mod_apparmor and
configuring hats for it:
&lt;a href=&#34;http://www.mpipks-dresden.mpg.de/%7Emueller/docs/suse10.3/opensuse-manual_de/manual/bx5dh07.html&#34;&gt;5.2. Configuring Apache for mod_apparmor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned, mod_apparmor needs AppArmor to be compiled into the kernel, which
may rule out some Linux distributions. Distributions like Ubuntu have AppArmor
integrated into their kernel, so if compiling your kernel is not an option, you
could switch distribution.&lt;/p&gt;

&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;mod_apparmor may be the best option for a secure shared web server, as it would
seem the most secure whilst allowing shared cache modules to work correctly,
which give languages like PHP a huge boost in performance.&lt;/p&gt;</description>
    </item>

       <item>
      <title>Minimous – Posterous’ minimalist look in WordPress</title>
      <link>https://andytson.com/blog/2010/01/minimous-posterous-minimalist-look-in-wordpress/</link>
      <pubDate>Sun, 10 Jan 2010 13:30:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2010/01/minimous-posterous-minimalist-look-in-wordpress/</guid>
      <description>&lt;p&gt;If you’ve ever searched for a WordPress theme on WordPress.org, you’ve probably
found that none of them are suitable for your personal blog. Most tend to be
complex designs that you’re sure someone created with a specific look in mind,
but they don’t suit you.&lt;/p&gt;

&lt;p&gt;A friend from work mentioned something similar almost 6 months ago, so when she
tweeted a suggestion to design something like the Posterous look (it’s a very
nice simple but popular look), I offered to help, figuring it would take no time
at all to create something similar in WordPress.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;So I copied the Kubrick theme and stripped out the styles, adding new ones in
place, and 15 minutes later I had something beginning to take shape to show. In
the end it took me about 2 hours, having never written a WordPress theme before,
to get it to what it largely looks like now.&lt;/p&gt;

&lt;p&gt;I submitted it to the WordPress.org theme directory, and a couple of weeks later
it was &lt;a href=&#34;http://wordpress.org/extend/themes/minimous&#34;&gt;approved&lt;/a&gt; and many people
started downloading it. WordPress.org lists new and updated themes on the
&lt;a href=&#34;http://wordpress.org/extend/themes/&#34;&gt;theme portal&lt;/a&gt; front page, giving them a
much needed boost in promotion until they fall off those lists (“Newest Themes”
about 1.5 weeks at the time, and “Updated Themes” about a day or two).&lt;/p&gt;

&lt;p&gt;Since then, people have tweeted, blogged, and even contacted me on Facebook
about the theme. It has now had over 2000 downloads.&lt;/p&gt;

&lt;p&gt;One thing that I regret is not having put a link in the footer in the initial
release (missing almost 1000 of the first downloads). When I had added that, I
could easily see who’s using the theme.&lt;/p&gt;

&lt;p&gt;As for what the theme looks like, you’re looking at it right now. Unless of
course you are reading this in the future and I’ve changed the theme for some
reason, in which case you could
&lt;a href=&#34;http://wp-themes.com/minimous/&#34;&gt;preview the theme on WordPress.org&lt;/a&gt;.
I’ve written a web page describing how to sort out the sidebar
&lt;a href=&#34;https://webtatic.com/projects/minimous/&#34;&gt;over here&lt;/a&gt;, so be sure
to check that out if you are thinking of using the theme.&lt;/p&gt;</description>
    </item>

       <item>
      <title>Justifying your choice in web service infrastructure</title>
      <link>https://andytson.com/blog/2010/01/justifying-your-choice-in-web-service-infrastructure/</link>
      <pubDate>Sat, 09 Jan 2010 13:44:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2010/01/justifying-your-choice-in-web-service-infrastructure/</guid>
      <description>&lt;p&gt;First up, there is no silver bullet in building a web service infrastructure.
There are two prevailant types, however, that you should ideally be choosing
from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RPC (remote procedure call) – e.g. SOAP, XML-RPC&lt;/li&gt;
&lt;li&gt;REST (Representational state transfer) – e.g. umm? REST?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I strongly suggest is using one of these, and not designing your own
protocol, or proprietry XML straight-up. As for which you should choose…&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&#34;rest&#34;&gt;REST&lt;/h2&gt;

&lt;p&gt;One thing you’ll notice when developing a REST web service is that there isn’t
an exact specification of the protocol and structure, however the suggested way
is to use discrete urls as resources, and use HTTP (GET, POST, PUT, DELETE)
methods to determine the action to perform.&lt;/p&gt;

&lt;p&gt;Looking at the Twitter API, it instead forgoes the discrete resource urls and
HTTP methods in favour of using verbs in the url to determine the action to
perform on the resource, and just HTTP GET and POST to determine whether it gets
or sets data. This hasn’t stopped it from being successful however, and its use
of “REST” standards has attributed to the success of many of its third-party
sites.&lt;/p&gt;

&lt;p&gt;Would that have been true if they had used SOAP instead? Obviously not, as
Twitter can also be used in javascript mashups, which SOAP would be a big pain
to use.&lt;/p&gt;

&lt;p&gt;Since the idea in REST is to use the HTTP specification in designing the
implementation, there is only a small amount of error reporting that can be done
using HTTP status codes, the HTTP methods may not be enough to represent complex
actions, and the input protocol (application/www-form-urlencoded) is only a
simple key-value structure (sure PHP improves on it with the use of [] to
represent multi-dimensional data, but not all servers and clients are written in
PHP, so this should factor into your decision).&lt;/p&gt;

&lt;p&gt;However, the HTTP specification includes extra features such as caching that the
web service can be coded to benefit from.&lt;/p&gt;

&lt;h3 id=&#34;rpc&#34;&gt;RPC&lt;/h3&gt;

&lt;p&gt;As for RPC web services, I’ll stick to talking about SOAP as its better featured
than others. This instead entirely uses HTTP POST on a single url (endpoint),
and uses verbs that determine actions and parameters. Yes it can have multiple
endpoints, but for simplicity just consider them as other web services.&lt;/p&gt;

&lt;p&gt;This is a protocol with a fixed specification, which can be relied upon to be
the same. Both the request and response are simliarly structured with a header
and body. It even has a specification for error reporting. Once you’ve seen one
SOAP service, you’ve seen them all (well not exactly, different vendors sadly
sometimes have their own nuances).&lt;/p&gt;

&lt;h3 id=&#34;your-choice&#34;&gt;Your choice&lt;/h3&gt;

&lt;p&gt;So I’ve already mentioned that there is no silver bullet. Each may be better
suited depending on the situation. But what situtation?&lt;/p&gt;

&lt;p&gt;The simplist answer some may jump to conclusions is that SOAP should be used in
inter-application communication and REST for third-parties. That may be mostly true.&lt;/p&gt;

&lt;p&gt;Some points to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where a language has support, SOAP is easier to consume, with a standardised
interface that can allow a language to make calls via a proxy that acts as if it
were a local call.&lt;/li&gt;
&lt;li&gt;A language only supplies a HTTP client more often than SOAP (e.g. Javascript),
however a REST client which helps with resource locations and detecting and
decoding the response is rare.&lt;/li&gt;
&lt;li&gt;Any web service written in REST could also be written in SOAP, however the
reverse is not as easily done due to the restriction on request complexity of
resources and single-dimensional data&lt;/li&gt;
&lt;li&gt;REST is only suitable for sending key -&amp;gt; value pairs as input due to the
nature of its input protocol (application/www-form-urlencoded), and would need
additional resource urls to represent multi-dimensional and batch data, meaning
multiple calls to create, insert and commit as a single transaction, when SOAP
can do that all in one call.&lt;/li&gt;
&lt;li&gt;REST is tied to HTTP over the web, however SOAP can be used in different
transports. A bit moot however if you only ever need to create/consume web
services.&lt;/li&gt;
&lt;li&gt;REST has additional transport specifications that can be used for caching and
conditional gets. However SOAP can still code this into a RPC function, or a
SOAP header.&lt;/li&gt;
&lt;li&gt;SOAP has additional specification extensions such as WSDL and WS-* (too many to list)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;In all, I favour SOAP myself, but then all the web services I have coded so far
I believe to be necessarily complex enough to justify it over REST. In PHP it is
extremely easy to create and consume SOAP using SoapServer/SoapClient, and it
automatically throws SOAP faults as Exceptions, which I wouldn’t want to live
without.&lt;/p&gt;

&lt;p&gt;I can see the attraction of REST due to it’s language support and most services
using it support JSON. Zend Framework also makes it easy to reuse your
controllers, which should already be in resource structure, for serving REST views.&lt;/p&gt;</description>
    </item>

       <item>
      <title>Recovering a broken Subversion working copy</title>
      <link>https://andytson.com/blog/2009/12/recovering-a-broken-subversion-working-copy/</link>
      <pubDate>Wed, 02 Dec 2009 22:28:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2009/12/recovering-a-broken-subversion-working-copy/</guid>
      <description>&lt;p&gt;There are times when a Subversion working copy can mess up. This is usually due
to human error, for example due to permissions problems or moving files or
folders incorrectly&lt;/p&gt;

&lt;p&gt;These can usually be easily recoverable, although at times it can seem there&amp;rsquo;s
no solution. Here are a few examples and their solutions.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h3 id=&#34;incorrectly-deleting-files-folders-without-using-svn-rm&#34;&gt;Incorrectly deleting files/folders without using svn rm&lt;/h3&gt;

&lt;p&gt;This will usually result in subversion complaining when you attempt to commit.
The symptom of this is the svn status giving something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;!       path/to/missing/file
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To fix this, simply issue the svn rm command for the file, and Subversion will
fix and mark it as deleted.&lt;/p&gt;

&lt;h3 id=&#34;incorrectly-moving-files-folders-without-using-svn-mv&#34;&gt;Incorrectly moving files/folders without using svn mv&lt;/h3&gt;

&lt;p&gt;Sometimes someone may forget to run the subversion move command, and
move files/folders manually. If you attempt to add a file after this, you will
lose the history of the file. If you attempt with a folder, it will give an
error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;svn: warning: &#39;path/to/moved/folder&#39; is already under version control
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The symptom of this is an svn status of:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;?       path/to/moved/folder
!       path/to/old/folder
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The best solution for this is to simply move it back and run the svn mv command
instead.&lt;/p&gt;

&lt;h3 id=&#34;adding-a-folder-with-permission-problems&#34;&gt;Adding a folder with permission problems&lt;/h3&gt;

&lt;p&gt;Sometimes either the group or permissions of a folder will be incorrect. If you
add the folder, it will usually issue an error like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;svn: Can&#39;t create directory &#39;new/folder/.svn&#39;: Permission denied
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whats worse is that the working copy now registers the folder in a half-added
state. The parent folder metadata says the folder is added, but the child folder
is missing its .svn metadata. The symptom of this is an svn status of:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~       new/folder
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The solution is to first fix the permissions of the folder, then move the folder
to a temporary location, and revert the add:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# first fix the permissions&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ...&lt;/span&gt;
 
mv new/folder new/folder2
svn revert new/folder
 
mv new/folder2 new/folder
svn add new/folder
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;an-svn-metadata-transplant&#34;&gt;An .svn metadata transplant&lt;/h3&gt;

&lt;p&gt;There are sometimes some cases that can’t be explained. The best solution I’ve
found for this is to do a .svn folder lobotomy and restore with fresh
.svn folders. To do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# backup your project in case you run into trouble&lt;/span&gt;
cp -Rp /path/to/project /temporary/location
 
&lt;span class=&#34;c1&#34;&gt;# strip out the old .svn folders&lt;/span&gt;
find /path/to/project -name .svn -print0 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xargs -0 rm -rf
 
&lt;span class=&#34;c1&#34;&gt;# check out a clean copy&lt;/span&gt;
svn co http://repo/location /temporary/location2
 
&lt;span class=&#34;c1&#34;&gt;# move the .svn folders from the clean copy into the correct relative&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# place in the &amp;lt;strong&amp;gt;broken&amp;lt;/strong&amp;gt; copy&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /temporary/location2
find . -name .svn -print0 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xargs -0 -I &lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt; mv &lt;span class=&#34;s1&#34;&gt;&amp;#39;{}&amp;#39;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/path/to/project/{}&amp;#39;&lt;/span&gt;
 
&lt;span class=&#34;c1&#34;&gt;# remove the clean copy&lt;/span&gt;
rm -rf /temporary/location2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>

       <item>
      <title>Get an &#34;A&#34; in YSlow with Webtatic Optimizer</title>
      <link>https://andytson.com/blog/2009/08/get-an-a-in-yslow-with-webtatic-optimizer/</link>
      <pubDate>Sun, 09 Aug 2009 22:14:00 +0000</pubDate>
      
      <guid>https://andytson.com/blog/2009/08/get-an-a-in-yslow-with-webtatic-optimizer/</guid>
      <description>&lt;p&gt;The performance of a website is an important issue. Even fast responding dynamic
pages can be hit with problems with sub-optimal static content such as high
overhead on many HTTP requests and large javascript/css files. Tools like
&lt;a href=&#34;http://developer.yahoo.com/yslow/&#34;&gt;YSlow&lt;/a&gt;, and
&lt;a href=&#34;http://code.google.com/speed/page-speed/&#34;&gt;Google Page Speed&lt;/a&gt; help identify
these problem areas.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://webtatic.com/projects/optimizer/&#34;&gt;Webtatic Optimizer&lt;/a&gt; is a tool that
can be used to improve these areas, and can help get an almost perfect score.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h3 id=&#34;make-fewer-http-requests&#34;&gt;Make fewer HTTP requests&lt;/h3&gt;

&lt;p&gt;JavaScript and Css files are naturally loaded individually. Having multiples of
them being used across an entire site, e.g. including the JQuery library along
with your own javascript, adds to the time the user has to wait for the files to
download.&lt;/p&gt;

&lt;p&gt;The Optimizer can concatenate these files and store in a new static file, so
loading this instead will mean less requests, resulting in an “A” in this
category. (images may decrease the score if you use many of them, but I will add
in a future release the ability to easily create CSS sprites which rewrite the
css file to accomidate the position of an image within its sprite).&lt;/p&gt;

&lt;h3 id=&#34;add-expires-headers&#34;&gt;Add Expires headers&lt;/h3&gt;

&lt;p&gt;Whilst you can force an expiry of X hours in apache, this means that changes to
these files wont be reflected in the browser until the image has expired.
However, browsers cache files based on their entire request url (including query
string), so simply concatenating onto the referenced url a unique query string
that changes when the contents are modified, is enough to be able to set a
year’s expiry whilst changes are reflected immediately.&lt;/p&gt;

&lt;p&gt;The Optimizer does this by rewriting css url() urls, calculating the
last-modified date of the physical file, and appending this onto the url. There
is also a php function helper to do this for static files included in dynamic
pages. With this you can get an “A” in this section.&lt;/p&gt;

&lt;h3 id=&#34;compress-components-with-gzip&#34;&gt;Compress components with gzip&lt;/h3&gt;

&lt;p&gt;Text-based http requests can be reduced in size significantly using gzip when
the browser supports it as a content encoding. The Optimizer does this when
creating the concatenated files, also creating a gzipped version at the same
time.&lt;/p&gt;

&lt;p&gt;This will give an “A” in YSlow.&lt;/p&gt;

&lt;h3 id=&#34;minify-javascript-and-css&#34;&gt;Minify JavaScript and CSS&lt;/h3&gt;

&lt;p&gt;If a browser is not able to use the gzipped version of a file, optimized
versions of the original JavaScript or CSS can be used instead. This is done at
the same time as concatenating the files, using JsMin for JavaScript, and a
simple CSS minifier, giving you an “A” for this category in YSlow.&lt;/p&gt;

&lt;h3 id=&#34;example&#34;&gt;Example&lt;/h3&gt;

&lt;p&gt;Using a configuration such as below, enables the above optimizations to be
incorporated into the generated files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;k&#34;&gt;[config]&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;1.0.0&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;[javascript]&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;config.workingPath&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;http&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;defaults.output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;site.js&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;files&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&#34;s&#34;&gt;  + javascript/jquery.min.js&lt;/span&gt;
&lt;span class=&#34;s&#34;&gt;  + javascript/my-javascript.js&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;[css]&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;config.workingPath&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;http&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;defaults.output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;site.css&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;files&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&#34;s&#34;&gt;  + css/layout.css&lt;/span&gt;
&lt;span class=&#34;s&#34;&gt;  + css/global/**.css&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above configuration can passed to the optimizer command-line script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;optimizer-compile optimizer.ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will concatenate http/javascript/jquery.min.js and
http/javascript/my-javascript.js, minimise it, and store it in http/site.js and
a gzipped version in http/site.js.gz. It will also concatentate, minify, and
rewrite url()’s for http/css/layout.css and any CSS files in http/css/global and
sub-directories, and store it in http/site.css and a gzipped version in
http/site.css.gz.&lt;/p&gt;

&lt;h3 id=&#34;advanced-features&#34;&gt;Advanced features&lt;/h3&gt;

&lt;p&gt;There are much more advanced features that can be configured, which you can find
out more about in the documentation. The Webtatic Optimizer is a fully
extensible library, using plugins and filters to achieve the above. You can
enable/disable any features or can even write your own.&lt;/p&gt;

&lt;h3 id=&#34;an-example-in-use&#34;&gt;An example in use&lt;/h3&gt;

&lt;p&gt;Using each of the Webtatic Optimizer’s features above, I have managed to get the
&lt;a href=&#34;https://passport.fubra.com/&#34;&gt;Fubra Passport&lt;/a&gt;, an authentication gateway and
payment system for the sites &lt;a href=&#34;http://www.fubra.com/&#34;&gt;Fubra Limited&lt;/a&gt; runs/is
affiliated with, a score of “B”. It fails at getting an “A” as it doesn’t have
a CDN, and cookies are passed for static content.&lt;/p&gt;

&lt;p&gt;I will address the latter, along with making it easy to automatically rewrite
local static file urls to a CDN, in a future release.&lt;/p&gt;</description>
    </item>

    
  </channel>
</rss>
