<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>http://seconddrawer.com.au/</id>
  <title>Second Drawer</title>
  <updated>2010-07-03T14:00:00Z</updated>
  <link rel="alternate" href="http://seconddrawer.com.au/"/>
  <link rel="self" href="http://seconddrawer.com.au/atom.xml"/>
  <author>
    <name>Felix Hanley</name>
    <uri>http://seconddrawer.com.au</uri>
  </author>
  <entry>
    <id>tag:seconddrawer.com.au,2010-07-04:/blog/2010/07/rack-map-and-subdomains/</id>
    <title type="html">Rack map and subdomains</title>
    <published>2010-07-03T14:00:00Z</published>
    <updated>2010-07-03T14:00:00Z</updated>
    <link rel="alternate" href="http://seconddrawer.com.au/blog/2010/07/rack-map-and-subdomains/"/>
    <content type="html">&lt;h2 id='the_situation'&gt;The situation&lt;/h2&gt;

&lt;p&gt;You are using subdomains for locales such as &lt;em&gt;en.example.com&lt;/em&gt; and &lt;em&gt;th.example.com&lt;/em&gt;. Your app is Rack based and is behind Nginx with a &amp;#8216;wildcard&amp;#8217; &lt;em&gt;server_name&lt;/em&gt; directive such as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
  server_name .example.com;
  ...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You are also using Rack&amp;#8217;s map abilities to have two different applications mounted on different paths on your domain. This could be done like this in your &lt;em&gt;config.ru&lt;/em&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;map &amp;#39;/users&amp;#39; do
  run Example::Admin
end

map &amp;#39;/&amp;#39; do
  run Example::Public
end&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='the_problem'&gt;The problem&lt;/h2&gt;

&lt;p&gt;If the URL &lt;em&gt;http://th.example.com&lt;/em&gt; is hit, Nginx will set &amp;#8216;HTTP_HOST&amp;#8217; as &amp;#8216;th.example.com&amp;#8217; but &amp;#8216;SERVER_NAME&amp;#8217; will be &amp;#8216;example.com&amp;#8217;. What his means is that tests within Rack fail and result in neither of the above &amp;#8216;maps&amp;#8217; matching so a 404 is returned.&lt;/p&gt;

&lt;h2 id='a_solution'&gt;A solution&lt;/h2&gt;

&lt;p&gt;In Rack apps you are able to modify the environment. This means that &lt;em&gt;one&lt;/em&gt; way to fix this is to simply set the environment&amp;#8217;s&amp;#8217; SERVER_NAME&amp;#8217; to equal &amp;#8216;HTTP_HOST&amp;#8217; by including something like this in your &lt;em&gt;config.ru&lt;/em&gt; file, before your map calls:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module Rack
  class Blah
    def initialize app
      @app = app
    end

    def call env
      env[&amp;#39;SERVER_NAME&amp;#39;] = env[&amp;#39;HTTP_HOST&amp;#39;]
      @app.call env
    end
  end
end
use Rack::Blah

map &amp;#39;/users&amp;#39; do
...etc.&lt;/code&gt;&lt;/pre&gt;</content>
  </entry>
  <entry>
    <id>tag:seconddrawer.com.au,2010-05-21:/blog/2010/optimising-your-images/</id>
    <title type="html">Optimise your images for performance and consistency</title>
    <published>2010-05-20T14:00:00Z</published>
    <updated>2010-05-20T14:00:00Z</updated>
    <link rel="alternate" href="http://seconddrawer.com.au/blog/2010/optimising-your-images/"/>
    <content type="html">&lt;p&gt;In an effort to reduce your website&amp;#8217;s page size, whether it be to just provide a better experience for the user or to work inline with &lt;a href='http://googlewebmastercentral.blogspot.com/2010/04/using-site-speed-in-web-search-ranking.html'&gt;Google&amp;#8217;s plans to factor page speed into rankings&lt;/a&gt;, you will inevitably get to the point of dealing with your site&amp;#8217;s images.&lt;/p&gt;

&lt;p&gt;In many sites the images take up a large proportion of the site&amp;#8217;s weight (in bytes). So getting the most out of them is very important. One tool that is essential in this regard is &lt;a href='http://pmt.sourceforge.net/pngcrush/'&gt;pngcrush&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='pngcrush'&gt;pngcrush&lt;/h2&gt;

&lt;p&gt;Pngcrush is a tool that &lt;em&gt;lossless&lt;/em&gt; reduces the size of PNG files. PNG are used mainly for styling the website and so are vital to the look (and often the readability) of the site itself. JPEGs are great for photographs which need no restriction on the number of colours. Compression of JPEGs are dealt with differently. Few modern designers use GIFs anymore now that IE supports alpha transparency in PNGs, so we will assume that we are only dealing with PNGs.&lt;/p&gt;

&lt;p&gt;Pngcrush uses a number of techniques to reduce the size of your PNGs such as reducing the palette or applying different compression algorithms to the image data.&lt;/p&gt;

&lt;h2 id='an_example'&gt;An example&lt;/h2&gt;

&lt;p&gt;A good example of the size difference is the &lt;a href='/images/menu.png'&gt;menu image used on this site&lt;/a&gt;. An initial save of the PNG image was 159Kb. This same image when run through pngcrush resulted in a size of 14.5Kb, with no reduction in quality. It is a simple as this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pngcrush infile.png outfile.png&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or trying more methods to reduce size:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pngcrush -brute infile.png outfile.png&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For my site, I am already using the sprite technique to combine images for my main menu so together I am able to reduce, not only the total amount to be downloaded, but also the number of HTTP requests needed to create my menu.&lt;/p&gt;

&lt;h2 id='alternatives'&gt;Alternatives&lt;/h2&gt;

&lt;p&gt;There are several other alternatives to pngcrush such as its fork, &lt;a href='http://optipng.sourceforge.net/'&gt;optiPNG&lt;/a&gt;. This does pretty much the same job.&lt;/p&gt;

&lt;h2 id='colour_consistency'&gt;Colour consistency&lt;/h2&gt;

&lt;p&gt;One thing that pngcrush does that others do not yet seem to do is reduce the file size by removing the colour correction (or colour profile) data from the file. This can sometimes reduce the size by up to 40%. What this also means is that your images will appear more consistently across browsers. How so?&lt;/p&gt;

&lt;p&gt;Many image manipulation programs will place a colour profile within the image to enable different systems to display the image as close as possible to the original. Firefox, for instance, will use these profiles to adjust the colours before displaying them. Google Chrome, on the other hand, will not. What this means is that some images on your site will appear differently in Firefox and Chrome. It could also mean that colour values in CSS style sheets will not match those colours, while using identical codes, in PNG files.&lt;/p&gt;

&lt;p&gt;The command line to remove all colour profiles from your PNG is as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB infile.png outfile.png&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='conclusion'&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;By removing the colour profile data from your images, you not only reduce the file size but you force browsers (such as Firefox) to make do without the profile and so render them more consistently, with other systems &lt;em&gt;and&lt;/em&gt; with CSS colour values. A faster and more colour accurate site.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:seconddrawer.com.au,2010-04-23:/blog/2010/rack-locale-setter-middleware/</id>
    <title type="html">Rack locale setter middleware</title>
    <published>2010-04-22T14:00:00Z</published>
    <updated>2010-04-22T14:00:00Z</updated>
    <link rel="alternate" href="http://seconddrawer.com.au/blog/2010/rack-locale-setter-middleware/"/>
    <content type="html">&lt;p&gt;For a project I am currently working on I am using the nice i18n library &lt;em&gt;&lt;a href='http://github.com/ai/r18n'&gt;r18n&lt;/a&gt;&lt;/em&gt; which provides i18n for &lt;a href='http://rubyonrails.org/'&gt;Rails&lt;/a&gt;, &lt;a href='http://sinatrarb.org/'&gt;Sinatra&lt;/a&gt; and most general Ruby projects. It also is reasonably ORM agnostic and so I am using it quite easily with &lt;a href='http://datamapper.org/'&gt;DataMapper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have decided to use a subdomain to specify the locale rather than having it be part of the path. So instead of this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://example.com/en/foo/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I have this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://en.example.com/foo/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I find this makes it easier by being able to specify relative paths everywhere that don&amp;#8217;t need to have the locale played with. Switching the locale for the site is also just a matter of changing the domain.&lt;/p&gt;

&lt;p&gt;That said, r18n expects the locale to be placed in the &amp;#8216;params&amp;#8217; array for Sinatra and I thought a simple Rack middleware would do this well. So here it is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module Rack
  class LocaleSetter
    def initialize(app)
      @app = app
    end

    def call(env)
      req = Rack::Request.new(env)
      if m = req.host.match(/^(?:www\.)?([a-z]{2})\./)
        locale = m[1]
      else
        locale = &amp;#39;en&amp;#39;
      end
      req.params[&amp;#39;locale&amp;#39;] ||= locale
      @app.call env
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Due to many peoples&amp;#8217; habit of putting &amp;#8216;www&amp;#8217; at the start of the domain, this should account for &lt;em&gt;en.example.com&lt;/em&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;em&gt;www.en.example.com&lt;/em&gt;. It also allows for the locale to be specified in the query string. So &lt;em&gt;en.example.com/foo?locale=th&lt;/em&gt; will set the locale to &amp;#8216;th&amp;#8217;.&lt;/p&gt;

&lt;p&gt;There are probably others out there but due to the simplicity of Rack based apps it is very easy to write, and adjust, your own.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:seconddrawer.com.au,2010-03-11:/blog/2010/update-to-tinydnsdyn/</id>
    <title type="html">tinydnsdyn - Dynamic DNS for DJBDNSs tinydns</title>
    <published>2010-03-10T13:00:00Z</published>
    <updated>2010-03-10T13:00:00Z</updated>
    <link rel="alternate" href="http://seconddrawer.com.au/blog/2010/update-to-tinydnsdyn/"/>
    <content type="html">&lt;p&gt;It has been a while since I have touched tinydns-dynamic but some new updates and changes have been made.&lt;/p&gt;

&lt;h2 id='why_tinydnsdyn_previously_tinydnsdynamic'&gt;Why tinydnsdyn (previously tinydns-dynamic)&lt;/h2&gt;

&lt;p&gt;I have been using the &lt;a href='http://cr.yp.to/djbdns.html'&gt;djbdns&lt;/a&gt; DNS server package for many years and I seem to like the &amp;#8216;DJB way&amp;#8217; (although I use &amp;#8217;&lt;a href='http://smarden.org/runit/'&gt;runit&lt;/a&gt;&amp;#8217; instead of &amp;#8216;daemontools&amp;#8217;). I like knowing my services are monitored and restarted if they die. Almost all my services on each of my services are run this way and I have had no troubles whatsoever with their performance or uptime.&lt;/p&gt;

&lt;p&gt;&lt;a href='/projects/tinydnsdyn/'&gt;Tinydnsdyn&lt;/a&gt; is a simple script to enable dynamic DNS for the DNS server written by Dan Bernstein, tinydns. It filled a small hole that was missing on one of my previous jobs and was written quickly and roughly to fill that void. It has been some years since I have used it and now decided to clean it up and spit it out again.&lt;/p&gt;

&lt;h2 id='features'&gt;Features?!&lt;/h2&gt;

&lt;p&gt;It is pretty simple but here are some of its features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It uses Python which is available on most *nix servers.&lt;/li&gt;

&lt;li&gt;It is designed to be run using daemontools (or similar) which if you are running tinydns then you will most likely already have that up and running.&lt;/li&gt;

&lt;li&gt;Some basic security is built in. It uses a simple nonce digest authentication and you can restrict the hosts that can have dynamic IPs.&lt;/li&gt;

&lt;li&gt;Simple logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So see how it fits you.&lt;/p&gt;

&lt;h2 id='getting_it'&gt;Getting it&lt;/h2&gt;

&lt;p&gt;Code can be grabbed from the &lt;a href='http://git.seconddrawer.com.au/tinydnsdyn.git'&gt;tinydnsdyn Git repository&lt;/a&gt; and you can tell me about all the bugs and mistakes on the &lt;a href='http://support.seconddrawer.com.au/projects/tinydnsdyn/'&gt;tinydnsdyn ticket tracker&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:seconddrawer.com.au,2010-03-03:/blog/2010/magento-1-4-nginx-config/</id>
    <title type="html">Magento 1.4.0 Nginx configuration</title>
    <published>2010-03-02T13:00:00Z</published>
    <updated>2010-05-19T14:00:00Z</updated>
    <link rel="alternate" href="http://seconddrawer.com.au/blog/2010/magento-1-4-nginx-config/"/>
    <content type="html">&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; I have added my php5.conf file for completeness, by request.&lt;/p&gt;

&lt;p&gt;So after my &lt;a href='/blog/2010/simple-nginx-config-for-magento/'&gt;previous post regarding an Nginx configuration for Magento&lt;/a&gt;, they have released version 1.4 and are now up to 1.4.0.1 already. I have migrated my Magento installations to the new stable version and this is my current Nginx configuration. Again, comments welcome.&lt;/p&gt;

&lt;p&gt;This is in a configuration file called &lt;em&gt;conf.d/magento.conf&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# not sure if this is needed but if the file exists just serve it
if (-f $request_filename) {
  break;
}

# this should catch everything
# if not found then it directs to the named location
location / {
  index index.php;
  error_page 404 = @magento;
}

# this has the catcher for the downloader, the rest to the index
location @magento {
  rewrite ^/downloader/(.*)$ /downloader/index.php$1;
  rewrite ^(.*)$ /index.php$1;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I also have a separate configuration file for static domains called &lt;em&gt;conf.d/static_domain.conf&lt;/em&gt; that looks a little like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# no need to log
access_log  off;

# set a nice long expires for all content and enable caching
location / {
  expires max;
  add_header Cache-Control public;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This enables me to reuse the configuration settings nicely. These are then both combined into the virtual host configuration like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
  server_name example.com www.example.com;
  root /var/www/vhost/example.com/htdocs;
  access_log /var/log/nginx/example.com.access.log main;
  index index.php;

  include conf.d/magento.conf;

  location ~* ^(.+\.php)(.*) {
    include conf.d/php5.conf;
  }
}

server {
  listen 1.1.1.1:443 default ssl;
  server_name secure.example.com;
  root /var/www/vhost/example.com/htdocs;
  access_log /var/log/nginx/example.com.access.log main;
  index index.php;

  ssl_certificate conf.d/your-certificate.pem;
  ssl_certificate_key conf.d/your-certificate-key.pem;

  include conf.d/magento.conf;

  location ~* ^(.+\.php)(.*) {
    include conf.d/php5.conf;
    fastcgi_param HTTPS on;
  }
}

server {
  # have as many &amp;#39;static&amp;#39; servers as you need
  server_name static.example.com media.example.com;
  root /var/www/vhost/example.com/htdocs;

  include conf.d/static_domain.conf;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The included php5.conf file looks a little like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;include /etc/nginx/fastcgi_params;
fastcgi_index                index.php;
fastcgi_connect_timeout      60;
fastcgi_send_timeout         180;
fastcgi_read_timeout         180;
fastcgi_buffer_size          128k;
fastcgi_buffers              4 256k;
fastcgi_busy_buffers_size    256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors     on;
fastcgi_param                SCRIPT_FILENAME  $document_root$fastcgi_script_name;
fastcgi_split_path_info      ^(.+\.php)(.*)$;
fastcgi_param                PATH_INFO $fastcgi_path_info;
fastcgi_pass                 php5;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice the static domain&amp;#8217;s root is the same as the main domain but it will only serve files that actually exist, nothing is passed to PHP etc. This obviously then requires that you set up Magento&amp;#8217;s verious URL settings to serve your CSS, javascript and images from this static domain.&lt;/p&gt;

&lt;p&gt;This cut a couple of seconds off a default install&amp;#8217;s page loading time and can further be improved by combining javascript and CSS assets.&lt;/p&gt;</content>
  </entry>
</feed>
