<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Will writes</title>
	<atom:link href="http://blog.willj.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.willj.net</link>
	<description>It&#039;s all good</description>
	<lastBuildDate>Thu, 09 May 2013 10:13:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='blog.willj.net' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Will writes</title>
		<link>http://blog.willj.net</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.willj.net/osd.xml" title="Will writes" />
	<atom:link rel='hub' href='http://blog.willj.net/?pushpress=hub'/>
		<item>
		<title>Creating BERT dicts in Go</title>
		<link>http://blog.willj.net/2013/02/10/creating-bert-dicts-in-go/</link>
		<comments>http://blog.willj.net/2013/02/10/creating-bert-dicts-in-go/#comments</comments>
		<pubDate>Sun, 10 Feb 2013 02:09:06 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Golang]]></category>

		<guid isPermaLink="false">http://blog.willj.net/?p=1020</guid>
		<description><![CDATA[Creating BERT dicts in Go I’ve been learning Go recently and have written a program to connect to an existing service (written in Ruby) that sends and receives messages serialised as BERT terms. I’m posting this partly because I had quite a lot of fun figuring it out and partly to document creating BERT dicts [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=1020&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<div id="wrapper">
<h1 id="creatingbertdictsingo">Creating BERT dicts in Go</h1>
<p>I’ve been learning Go recently and have written a program to connect to an existing service (written in Ruby) that sends and receives messages serialised as <a href="http://bert-rpc.org/">BERT</a> terms.</p>
<p>I’m posting this partly because I had quite a lot of fun figuring it out and partly to document creating BERT dicts in Go should anyone else need to do this in the future and hit the same issues I did.</p>
<h2 id="whybert">Why BERT?</h2>
<p>I&#8217;m a big fan of BERT. It’s compact, flexible, and there are good libs available for serialisation/de-serialisation. So far I’ve exclusively been using the <a href="https://github.com/mojombo/bert">bert gem</a> (written by Tom Preston-Werner, author of the BERT spec).</p>
<h2 id="creatingbertdicts">Creating BERT dicts</h2>
<p>One of the great features of BERT is the complex types it supports, including dicts. The equivalent to a dict in Ruby would be a hash, in Go a map. They are really simple to create in Ruby:</p>
<pre><code>require 'bert'
BERT.encode({"key" =&gt; "val"})
=&gt; "\x83h\x03d\x00\x04bertd\x00\x04dictl\x00\x00\x00\x01h\x02m\x00\x00\x00\x03keym\x00\x00\x00\x03valj"
</code></pre>
<p>We can pull this apart and see exactly what the bert gem did to our data. Let&#8217;s dump the string to an array of 8-bit unsigned integers:</p>
<pre><code>BERT.encode({"key" =&gt; "val"}).unpack("C*")
=&gt; [131, 104, 3, 100, 0, 4, 98, 101, 114, 116, 100, 0, 4, 100, 105, 99, 116, 108, 0, 0, 0, 1, 104, 2, 109, 0, 0, 0, 3, 107, 101, 121, 109, 0, 0, 0, 3, 118, 97, 108, 106]
</code></pre>
<p>It’s hard to see exactly what happened, but with the BERT docs and the <a href="http://erlang.org/doc/apps/erts/erl_ext_dist.html">erlang External Term Format docs</a> we can see how the hash got encoded.</p>
<pre><code>magic| tuple |  atom   |       bert     |            |    dict        |  list 1 elem    |      list      |   atom  |      key      |   atom  |      |  val       | nil | nil
131, 104, 3, 100, 0, 4, 98, 101, 114, 116, 100, 0, 4, 100, 105, 99, 116, 108, 0, 0, 0, 1, 108, 0, 0, 0, 2, 100, 0, 3, 107, 101, 121, 100, 0, 3,       118, 97, 108, 106, 106
</code></pre>
<p>If the formatting of that breakdown is messed up <a href="https://gist.github.com/wjessop/4747914/raw/a7cea5f08b87add27c677145fa49815ed0c98faf/gistfile1.txt">here’s a raw gist</a> that may be clearer.</p>
<p>What you can see here are what the bytes represent (you can see the breakdown of each data type on the External Term Format <a href="http://erlang.org/doc/apps/erts/erl_ext_dist.html">docs</a>). This is great, but why write a blog post just about dicts? Well, they’re easy to create in Ruby:</p>
<pre><code>BERT.encode(:complex =&gt; {"key" =&gt; [:data, {:structures =&gt; "are easy to serialise"}]})
=&gt; "\x83h\x03d\x00\x04bertd\x00\x04dictl\x00\x00\x00\x01h\x02d\x00\acomplexh\x03d\x00\x04bertd\x00\x04dictl\x00\x00\x00\x01h\x02m\x00\x00\x00\x03keyl\x00\x00\x00\x02d\x00\x04datah\x03d\x00\x04bertd\x00\x04dictl\x00\x00\x00\x01h\x02d\x00\nstructuresm\x00\x00\x00\x15are easy to serialisejjjj"
</code></pre>
<p>but it’s not so obvious in Go, and I hit some issues when trying to create them.</p>
<h2 id="serialisingtobertingolang">Serialising to BERT in Golang</h2>
<p>Serialising data to BERT/BERP in Go is pretty easy for simple cases using the <a href="https://github.com/sethwklein/gobert">gobert</a> lib:</p>
<pre><code>package main

import (
    "fmt"
    "bytes"
    "github.com/sethwklein/gobert"
)

func main() {
    var buf = new(bytes.Buffer)
    bert.MarshalResponse(buf, bert.Atom("foo"))
    for _, b := range(buf.Bytes()) {
        fmt.Printf("%d ", b)
    }
    fmt.Println()
}
</code></pre>
<p>This gives us:</p>
<pre><code>0 0 0 7 131 100 0 3 102 111 111
</code></pre>
<p>If we run that through the Ruby lib decoder we get:</p>
<pre><code>&gt; BERT.decode([131, 100, 0, 3, 102, 111, 111].pack("C*"))
 =&gt; :foo
</code></pre>
<p>(The Ruby bert lib decodes atoms to symbols).</p>
<h2 id="serialisingtobertdictsingolang">Serialising to BERT dicts in Golang</h2>
<p>However, there is a little more effort involved serialising more complex data structures, in particular dicts, as I found out.</p>
<p>You might have thought that you could just pass in a map:</p>
<pre><code>package main

import (
    "fmt"
    "bytes"
    "github.com/sethwklein/gobert"
)

func main() {
    message := map[string]string{"key1": "val1", "key2": "val2"}

    var buf = new(bytes.Buffer)
    bert.MarshalResponse(buf, message)
    for _, b := range(buf.Bytes()) {
        fmt.Printf("%d ", b)
    }
    fmt.Println()
}
</code></pre>
<p>We get the output:</p>
<pre><code>0 0 0 1 131
</code></pre>
<p>Well, that doesn’t work. What you end up with is a one byte long BERP. It seems that gobert doesn’t automatically serialise maps. No problem, we’ll build one up manually. A quick look at the BERT documentation shows the format of a dict:</p>
<blockquote><p>“Dictionaries (hash tables) are expressed via an array of 2-tuples representing the key/value pairs. The KeysAndValues array is mandatory, such that an empty dict is expressed as {bert, dict, []}. Keys and values may be any term. For example, {bert, dict, [{name, &lt;&lt;“Tom”&gt;&gt;}, {age, 30}]}.”</p></blockquote>
<p>So let&#8217;s create this special structure manually.</p>
<pre><code>package main

import (
    "fmt"
    "bytes"
    "github.com/sethwklein/gobert"
)

func main() {
    message1 := []bert.Term{bert.Atom("key1"), bert.Atom("val1")}
    message2 := []bert.Term{bert.Atom("key2"), bert.Atom("val3")}
    keys_and_values := []bert.Term{message1, message2}

    dict := []bert.Term{bert.BertAtom, bert.Atom("dict"), keys_and_values}

    var buf = new(bytes.Buffer)
    bert.MarshalResponse(buf, dict)
    for _, b := range(buf.Bytes()) {
        fmt.Printf("%d ", b)
    }
    fmt.Println()
}
</code></pre>
<p>The result:</p>
<pre><code>0 0 0 51 131 104 3 100 0 4 98 101 114 116 100 0 4 100 105 99 116 104 2 104 2 100 0 4 107 101 121 49 100 0 4 118 97 108 49 104 2 100 0 4 107 101 121 50 100 0 4 118 97 108 51
</code></pre>
<p>It looks better, but it doesn’t decode, using Ruby:</p>
<pre><code>&gt; BERT.decode([131, 104, 3, 100, 0, 4, 98, 101, 114, 116, 100, 0, 4, 100, 105, 99, 116, 104, 2, 104, 2, 100, 0, 4, 107, 101, 121, 49, 100, 0, 4, 118, 97, 108, 49, 104, 2, 100, 0, 4, 107, 101, 121, 50, 100, 0, 4, 118, 97, 108, 51].pack("C*"))
TypeError: Invalid dict spec, not an erlang list
</code></pre>
<p>We’re still missing something. Let&#8217;s compare the output of the Ruby bert lib to the output of gobert for the same data structure:</p>
<pre><code>&gt; BERT.encode({:key1 =&gt; :val1, :key2 =&gt; :val2}).unpack("C*")
 =&gt; [131, 104, 3, 100, 0, 4, 98, 101, 114, 116, 100, 0, 4, 100, 105, 99, 116, 108, 0, 0, 0, 2, 104, 2, 100, 0, 4, 107, 101, 121, 49, 100, 0, 4, 118, 97, 108, 49, 104, 2, 100, 0, 4, 107, 101, 121, 50, 100, 0, 4, 118, 97, 108, 50, 106]
</code></pre>
<p>We’re definitely missing some data in the gobert output.</p>
<p>If you follow along the byte sequences you can see that they start off the same until the 18th byte. In the Ruby output this is ‘108’, or LIST_EXT. In the gobert output it’s 104, a SMALL_TUPLE_EXT. We can see where this difference happens in encode.go in the gobert lib (in the writeTag func):</p>
<pre><code>case reflect.Slice:
    writeSmallTuple(w, v)
case reflect.Array:
    writeList(w, v)
</code></pre>
<p>Let&#8217;s decode the BERT data to see where the diversion happens in the underlying data structures:</p>
<pre><code>magic| tuple  |  atom   |       bert       |   atom   |    dict
  131, 104, 3, 100, 0, 4, 98, 101, 114, 116, 100, 0, 4, 100, 105, 99, 116
</code></pre>
<p>We can see that the “bert” and “dict” atoms are encoded the same, but the keys_and_values array is getting encoded as a SMALL_TUPLE_EXT by gobert when we wanted a LIST_EXT. If we look back at the gobert code we can see that the decision to use SMALL_TUPLE_EXT over LIST_EXT is dependent on a slice or array being present. We can use the go “reflect” package to look at the arrays/slices we are creating and see what they are:</p>
<pre><code>package main

import (
    "fmt"
    "reflect"
    "github.com/sethwklein/gobert"
)

func main() {
    array := [2]bert.Term{}
    slice := []bert.Term{}

    array_val := reflect.ValueOf(array)
    slice_val := reflect.ValueOf(slice)
    fmt.Printf("array is a: %v\n", array_val.Kind())
    fmt.Printf("slice is a: %v\n", slice_val.Kind())
}

array is a: array
slice is a: slice
</code></pre>
<h2 id="thefix">The fix</h2>
<p>So, in order to fix our data structure to get gobert to correctly encode the dict we need to change the keys_and_values slice to an array:</p>
<pre><code>package main

import (
    "fmt"
    "bytes"
    "github.com/sethwklein/gobert"
)

func main() {
    message1 := []bert.Term{bert.Atom("key1"), bert.Atom("val1")}
    message2 := []bert.Term{bert.Atom("key2"), bert.Atom("val3")}
    keys_and_values := [2]bert.Term{message1, message2} // Now an array

    dict := []bert.Term{bert.BertAtom, bert.Atom("dict"), keys_and_values}

    var buf = new(bytes.Buffer)
    bert.MarshalResponse(buf, dict)
    for _, b := range(buf.Bytes()) {
        fmt.Printf("%d ", b)
    }
    fmt.Println()
}
</code></pre>
<p>The result:</p>
<pre><code>0 0 0 55 131 104 3 100 0 4 98 101 114 116 100 0 4 100 105 99 116 108 0 0 0 2 104 2 100 0 4 107 101 121 49 100 0 4 118 97 108 49 104 2 100 0 4 107 101 121 50 100 0 4 118 97 108 51 106
</code></pre>
<p>But more importantly, can we decode the data we encoded?</p>
<pre><code>&gt; BERT.decode([131, 104, 3, 100, 0, 4, 98, 101, 114, 116, 100, 0, 4, 100, 105, 99, 116, 108, 0, 0, 0, 2, 104, 2, 100, 0, 4, 107, 101, 121, 49, 100, 0, 4, 118, 97, 108, 49, 104, 2, 100, 0, 4, 107, 101, 121, 50, 100, 0, 4, 118, 97, 108, 51, 106].pack("C*"))
 =&gt; {:key1=&gt;:val1, :key2=&gt;:val3}
</code></pre>
<p>Yes!</p>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/1020/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/1020/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=1020&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2013/02/10/creating-bert-dicts-in-go/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>
	</item>
		<item>
		<title>Fixing the chef &#8220;Error Syncing Cookbooks &#8211; EOFError: end of file reached&#8221; error</title>
		<link>http://blog.willj.net/2013/01/21/fixing-the-chef-error-syncing-cookbooks-eoferror-end-of-file-reached-error/</link>
		<comments>http://blog.willj.net/2013/01/21/fixing-the-chef-error-syncing-cookbooks-eoferror-end-of-file-reached-error/#comments</comments>
		<pubDate>Mon, 21 Jan 2013 18:44:04 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[chef]]></category>

		<guid isPermaLink="false">http://blog.willj.net/?p=1016</guid>
		<description><![CDATA[I ran into a problem recently with some corrupt chef cookbooks after a recent chef upgrade, I was getting an &#8220;Error Syncing Cookbooks &#8211; EOFError: end of file reached&#8221; error on every chef run on all nodes: ================================================================================ Error Syncing Cookbooks: ================================================================================ Unexpected Error: ----------------- EOFError: end of file reached [2013-01-21T18:17:27+00:00] ERROR: Running exception handlers [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=1016&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>I ran into a problem recently with some corrupt chef cookbooks after a recent chef upgrade, I was getting an &#8220;Error Syncing Cookbooks &#8211; EOFError: end of file reached&#8221; error on every chef run on all nodes:</p>
<p><code>================================================================================</p>
<p>Error Syncing Cookbooks:<br />
================================================================================</p>
<p>Unexpected Error:<br />
-----------------<br />
EOFError: end of file reached</p>
<p>[2013-01-21T18:17:27+00:00] ERROR: Running exception handlers<br />
[2013-01-21T18:17:27+00:00] FATAL: Saving node information to /var/cache/chef/failed-run-data.json<br />
[2013-01-21T18:17:27+00:00] ERROR: Exception handlers complete<br />
[2013-01-21T18:17:27+00:00] FATAL: Stacktrace dumped to /var/cache/chef/chef-stacktrace.out<br />
[2013-01-21T18:17:27+00:00] FATAL: EOFError: end of file reached</code></p>
<p>I&#8217;d already deleted the cookbooks:</p>
<p><code>knife cookbook delete cookbook_name</code></p>
<p>and re-uploaded them, but this didn&#8217;t work. It took a purge to completely delete the cookbook from the chef server:</p>
<p><code>knife cookbook delete --purge cookbook_name</code></p>
<p>In the end I had so many cookbooks that were somehow corrupt that I bulk purged them and re-uploaded them all:</p>
<p><code>knife cookbook bulk delete --purge '.+'</code></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/1016/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/1016/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=1016&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2013/01/21/fixing-the-chef-error-syncing-cookbooks-eoferror-end-of-file-reached-error/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>
	</item>
		<item>
		<title>Downloadable plot hole filler</title>
		<link>http://blog.willj.net/2013/01/16/downloadable-plot-hole-filler/</link>
		<comments>http://blog.willj.net/2013/01/16/downloadable-plot-hole-filler/#comments</comments>
		<pubDate>Wed, 16 Jan 2013 10:21:29 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Apple]]></category>

		<guid isPermaLink="false">http://blog.willj.net/?p=1010</guid>
		<description><![CDATA[A response I got from Apple: Dear Will, I understand that you have questions about downloading filler for the plot-holes in [the movie] Battleship. My name is Pauline and I will be more than happy to help you resolve this. I am very glad that you have been able to view the rental &#8220;Battleship&#8221;, I [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=1010&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>A response I got from Apple:</p>
<blockquote><p>Dear Will,</p>
<p>I understand that you have questions about downloading filler for the plot-holes in [the movie] Battleship. My name is Pauline and I will be more than happy to help you resolve this.</p>
<p>I am very glad that you have been able to view the rental &#8220;Battleship&#8221;, I hope you enjoyed this film and had fun watching it. While I cannot comment or assist with filter for the content of the movie, I would be more than happy to look in to any other account issues you may be experiencing.</p>
<p>It has been a pleasure assisting you today. Should you have any other concerns you wish to raise, please let me know. Have a nice day!</p>
<p>Sincerely,</p></blockquote>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/1010/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/1010/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=1010&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2013/01/16/downloadable-plot-hole-filler/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>
	</item>
		<item>
		<title>Creating animated gifs with imagemagick</title>
		<link>http://blog.willj.net/2012/04/24/creating-animated-gifs-with-imagemagick/</link>
		<comments>http://blog.willj.net/2012/04/24/creating-animated-gifs-with-imagemagick/#comments</comments>
		<pubDate>Tue, 24 Apr 2012 10:49:42 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.willj.net/?p=1006</guid>
		<description><![CDATA[In my last post I linked to some animated gifs I made on my mac. It&#8217;s pretty easy if you have imagemagick installed. Simply get a bunch of images together and use the convert command: convert -resize 900x -loop 0 -delay 10 DSC_8264.JPG DSC_8265.JPG DSC_8266.JPG DSC_8267.JPG DSC_8268.JPG DSC_8269.JPG DSC_8270.JPG jon_walk.gif The last argument is the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=1006&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>In <a href="http://blog.willj.net/2012/04/23/railsberry-animated-gifs/" title="Railsberry animated gifs">my last post</a> I linked to some animated gifs I made on my mac. It&#8217;s pretty easy if you have imagemagick installed.</p>
<p>Simply get a bunch of images together and use the convert command:</p>
<p><code>convert -resize 900x -loop 0 -delay 10 DSC_8264.JPG DSC_8265.JPG DSC_8266.JPG DSC_8267.JPG DSC_8268.JPG DSC_8269.JPG DSC_8270.JPG jon_walk.gif</code></p>
<p>The last argument is the output filename. The options should be self explanatory, but you can check them up in the man page if you want to tweak the values.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/1006/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/1006/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=1006&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2012/04/24/creating-animated-gifs-with-imagemagick/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>
	</item>
		<item>
		<title>Railsberry animated gifs</title>
		<link>http://blog.willj.net/2012/04/23/railsberry-animated-gifs/</link>
		<comments>http://blog.willj.net/2012/04/23/railsberry-animated-gifs/#comments</comments>
		<pubDate>Mon, 23 Apr 2012 16:05:30 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[railsberry]]></category>

		<guid isPermaLink="false">http://blog.willj.net/?p=996</guid>
		<description><![CDATA[I put up some photos of Railsberry here, but Flickr doesn&#8217;t work with animated gifs, so here they are. Click the images to get the animated versions. Riding the Railsberry Unicorn: Jon Leighton getting closer: Josh Kalderimis misbehaving:<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=996&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>I put up some <a title="Railsberry" href="http://www.flickr.com/photos/will_j/sets/72157629881298443/">photos of Railsberry here</a>, but Flickr doesn&#8217;t work with animated gifs, so here they are. Click the images to get the animated versions.</p>
<h4>Riding the Railsberry Unicorn:</h4>
<p><a href="http://willjessop4.files.wordpress.com/2012/04/riding_unicorn.gif"><img class="alignnone size-full wp-image-997" title="Riding the Railsberry Unicorn" src="http://willjessop4.files.wordpress.com/2012/04/riding_unicorn.gif?w=580" /></a></p>
<h4>Jon Leighton getting closer:</h4>
<p><a href="http://willjessop4.files.wordpress.com/2012/04/jon_walk.gif"><img class="alignnone size-full wp-image-999" title="Jon Leighton" src="http://willjessop4.files.wordpress.com/2012/04/jon_walk.gif?w=580" /></a></p>
<h4>Josh Kalderimis misbehaving:</h4>
<p><a href="http://willjessop4.files.wordpress.com/2012/04/jk.gif"><img class="alignnone size-full wp-image-998" title="Josh Kalderimis" src="http://willjessop4.files.wordpress.com/2012/04/jk.gif?w=580" /></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/996/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/996/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=996&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2012/04/23/railsberry-animated-gifs/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>

		<media:content url="http://willjessop4.files.wordpress.com/2012/04/riding_unicorn.gif" medium="image">
			<media:title type="html">Riding the Railsberry Unicorn</media:title>
		</media:content>

		<media:content url="http://willjessop4.files.wordpress.com/2012/04/jon_walk.gif" medium="image">
			<media:title type="html">Jon Leighton</media:title>
		</media:content>

		<media:content url="http://willjessop4.files.wordpress.com/2012/04/jk.gif" medium="image">
			<media:title type="html">Josh Kalderimis</media:title>
		</media:content>
	</item>
		<item>
		<title>Error installing the pg gem on Lion</title>
		<link>http://blog.willj.net/2012/02/12/error-installing-the-pg-gem-on-lion/</link>
		<comments>http://blog.willj.net/2012/02/12/error-installing-the-pg-gem-on-lion/#comments</comments>
		<pubDate>Sun, 12 Feb 2012 16:53:39 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[Postgres]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.willj.net/?p=986</guid>
		<description><![CDATA[I got the following error installing the latest pg gem on Lion: Installing pg (0.12.2) with native extensions Unfortunately, a fatal error has occurred. Please report this error to the Bundler issue tracker at https://github.com/carlhuda/bundler/issues so that we can fix it. Thanks! /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/installer.rb:482:in `build_extensions': ERROR: Failed to build gem native extension. (Gem::Installer::ExtensionBuildError) /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb checking [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=986&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>I got the following error installing the latest pg gem on Lion:</p>
<p><code>
<pre>Installing pg (0.12.2) with native extensions Unfortunately, a fatal error has occurred. Please report this error to the Bundler issue tracker at https://github.com/carlhuda/bundler/issues so that we can fix it. Thanks!
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/installer.rb:482:in `build_extensions': ERROR: Failed to build gem native extension. (Gem::Installer::ExtensionBuildError)

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb 
checking for pg_config... yes
Using config values from /usr/local/bin/pg_config
checking for libpq-fe.h... yes
checking for libpq/libpq-fs.h... yes
checking for PQconnectdb() in -lpq... no
checking for PQconnectdb() in -llibpq... no
checking for PQconnectdb() in -lms/libpq... no
Can't find the PostgreSQL client library (libpq)
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
	--with-opt-dir
	--without-opt-dir
	--with-opt-include
	--without-opt-include=${opt-dir}/include
	--with-opt-lib
	--without-opt-lib=${opt-dir}/lib
	--with-make-prog
	--without-make-prog
	--srcdir=.
	--curdir
	--ruby=/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
	--with-pg
	--without-pg
	--with-pg-dir
	--without-pg-dir
	--with-pg-include
	--without-pg-include=${pg-dir}/include
	--with-pg-lib
	--without-pg-lib=${pg-dir}/lib
	--with-pg-config
	--without-pg-config
	--with-pg_config
	--without-pg_config
	--with-pqlib
	--without-pqlib
	--with-libpqlib
	--without-libpqlib
	--with-ms/libpqlib
	--without-ms/libpqlib


Gem files will remain installed in /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/pg-0.12.2 for inspection.
Results logged to /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/pg-0.12.2/ext/gem_make.out
	from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/installer.rb:445:in `each'
	from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/installer.rb:445:in `build_extensions'
	from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/installer.rb:197:in `install'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/source.rb:90:in `install'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/rubygems_integration.rb:82:in `preserve_paths'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/source.rb:89:in `install'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/installer.rb:73:in `install_gem_from_spec'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/rubygems_integration.rb:97:in `with_build_args'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/installer.rb:72:in `install_gem_from_spec'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/installer.rb:56:in `run'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/installer.rb:55:in `run'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/installer.rb:12:in `install'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/cli.rb:220:in `install'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/vendor/thor/task.rb:22:in `send'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/vendor/thor/task.rb:22:in `run'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/vendor/thor/invocation.rb:118:in `invoke_task'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/vendor/thor.rb:263:in `dispatch'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/lib/bundler/vendor/thor/base.rb:386:in `start'
	from /Users/will/.rvm/gems/ruby-1.9.3-p0@status/gems/bundler-1.1.rc.7/bin/bundle:13
	from /usr/bin/bundle:19:in `load'
	from /usr/bin/bundle:19
</code></pre>
<p>I fixed it by passing in a build option to the gem install command:</p>
<p><code>
<pre>env ARCHFLAGS="-arch x86_64" gem install --no-ri --no-rdoc pg -- --with-pg-config=/usr/local/Cellar/postgresql/9.1.2/bin/pg_config</code></pre>
<p>To make bundler use this option whenever it's installing a gem you can do:</p>
<p><code>
<pre>bundle config build.pg --with-pg-config=/usr/local/Cellar/postgresql/9.1.2/bin/pg_config</code></pre>
<p>See <a href="http://gembundler.com/man/bundle-config.1.html" title="Bundler build options">build options in the bundler docs</a> for a description of this.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/986/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/986/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=986&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2012/02/12/error-installing-the-pg-gem-on-lion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>
	</item>
		<item>
		<title>Announcing the (Unofficial) Yahoo groups public data API</title>
		<link>http://blog.willj.net/2012/02/06/announcing-the-unofficial-yahoo-groups-public-data-api/</link>
		<comments>http://blog.willj.net/2012/02/06/announcing-the-unofficial-yahoo-groups-public-data-api/#comments</comments>
		<pubDate>Mon, 06 Feb 2012 01:27:00 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[finder]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.willj.net/?p=974</guid>
		<description><![CDATA[The what? All Yahoo groups have public metadata. The number of members, the category, various email addresses etc. Yahoo doesn&#8217;t provide an API to this publicly available data (you can see it by visiting one of the group pages). Getting information about any particular group in your programs is hard. I&#8217;ve filled this gap by [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=974&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<h2>The what?</h2>
<p>All Yahoo groups have public metadata. The number of members, the category, various email addresses etc.</p>
<p>Yahoo doesn&#8217;t provide an API to this publicly available data (you can see it by visiting one of the <a href="http://tech.groups.yahoo.com/group/OneStopCOBOL/">group pages</a>). Getting information about any particular group in your programs is hard.</p>
<p>I&#8217;ve filled this gap by releasing a <a title="Yahoo groups API" href="http://yahoo-group-data.herokuapp.com/">third-party API to get the publicly available Yahoo groups metadata</a>.</p>
<h2>JSON API</h2>
<p>The API itself provides a really simple interface for getting group data in JSON format, just stick the urlencoded URL of the Yahoo group you are interested in on the end of the (Unofficial) Yahoo groups public data API URL and request it. You get JSON back.</p>
<p>The URL you request looks like this:</p>
<pre>http://yahoo-group-data.herokuapp.com/api/v1/group/http%3A%2F%2Ftech.groups.yahoo.com%2Fgroup%2FOneStopCOBOL%2F</pre>
<p>…and the JSON you get back looks like this:</p>
<pre>
{
    &quot;private&quot;: false,
    &quot;not_found&quot;: false,
    &quot;age_restricted&quot;: false,
    &quot;name&quot;: &quot;OneStopCOBOL&quot;,
    &quot;description&quot;: &quot;OneStopCOBOL - Official COBOL group&quot;,
    &quot;post_email&quot;: &quot;OneStopCOBOL@yahoogroups.com&quot;,
    &quot;subscribe_email&quot;: &quot;OneStopCOBOL-subscribe@yahoogroups.com&quot;,
    &quot;owner_email&quot;: &quot;OneStopCOBOL-owner@yahoogroups.com&quot;,
    &quot;unsubscribe_email&quot;: &quot;OneStopCOBOL-unsubscribe@yahoogroups.com&quot;,
    &quot;language&quot;: &quot;English&quot;,
    &quot;num_members&quot;: 151,
    &quot;category&quot;: &quot;COBOL&quot;,
    &quot;founded&quot;: &quot;2008-06-24&quot;
}
</pre>
<p>You can try it out and get sample code over at the homepage of the <a title="Yahoo groups API" href="http://yahoo-group-data.herokuapp.com/">(Unofficial) Yahoo groups public data API</a>.</p>
<h2>Motivation</h2>
<p>I run the <a title="Find recycling groups in your area" href="http://recyclinggroupfinder.com/">Recycling Group Finder</a>, a site that makes extensive use of Yahoo Groups data. The (Unofficial) Yahoo groups public data API is an abstraction of the functionality I wrote to get group data for that site. I just figured it might be useful to other people.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/974/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/974/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=974&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2012/02/06/announcing-the-unofficial-yahoo-groups-public-data-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>
	</item>
		<item>
		<title>Paula Deen riding things</title>
		<link>http://blog.willj.net/2012/02/02/paula-deen-riding-things/</link>
		<comments>http://blog.willj.net/2012/02/02/paula-deen-riding-things/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 22:00:10 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.willj.net/?p=967</guid>
		<description><![CDATA[I made some Paula Deen riding… pictures. Because I can. Find more here.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=967&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>I made some Paula Deen riding… pictures. Because I can. Find <a href="http://pauladeenridingthings.com/">more here</a>.</p>
<p><a href="http://willjessop4.files.wordpress.com/2012/02/paula-deen-sausuage.jpeg"><img class="alignnone size-full wp-image-969" title="Paula Deen riding a sausuage" src="http://willjessop4.files.wordpress.com/2012/02/paula-deen-sausuage.jpeg?w=580&#038;h=362" alt="" width="580" height="362" /></a></p>
<p><a href="http://willjessop4.files.wordpress.com/2012/02/paula-deen-riding-kitten.jpeg"><img class="alignnone size-full wp-image-968" title="Paula Deen riding a kitten" src="http://willjessop4.files.wordpress.com/2012/02/paula-deen-riding-kitten.jpeg?w=580&#038;h=326" alt="" width="580" height="326" /></a></p>
<p><a href="http://willjessop4.files.wordpress.com/2012/02/original.jpeg"><img class="alignnone size-full wp-image-970" title="Paula Deen riding a scientist" src="http://willjessop4.files.wordpress.com/2012/02/original.jpeg?w=580&#038;h=558" alt="" width="580" height="558" /></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/967/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/967/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=967&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2012/02/02/paula-deen-riding-things/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>

		<media:content url="http://willjessop4.files.wordpress.com/2012/02/paula-deen-sausuage.jpeg" medium="image">
			<media:title type="html">Paula Deen riding a sausuage</media:title>
		</media:content>

		<media:content url="http://willjessop4.files.wordpress.com/2012/02/paula-deen-riding-kitten.jpeg" medium="image">
			<media:title type="html">Paula Deen riding a kitten</media:title>
		</media:content>

		<media:content url="http://willjessop4.files.wordpress.com/2012/02/original.jpeg" medium="image">
			<media:title type="html">Paula Deen riding a scientist</media:title>
		</media:content>
	</item>
		<item>
		<title>Testing http over socket connections with socat</title>
		<link>http://blog.willj.net/2011/12/02/testing-http-over-socket-connections-with-socat/</link>
		<comments>http://blog.willj.net/2011/12/02/testing-http-over-socket-connections-with-socat/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 22:00:55 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[socat]]></category>

		<guid isPermaLink="false">http://willj.net/?p=942</guid>
		<description><![CDATA[Sometimes I need to test an http server that is listening on a unix socket. It&#8217;s really easy to do this using socat, but the socat man page is pretty long. Here it is for anyone who needs it in the future, and me when I inevitably forget. In this case the server is unicorn, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=942&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Sometimes I need to test an http server that is listening on a unix socket. It&#8217;s really easy to do this using socat, but the socat man page is pretty long. Here it is for anyone who needs it in the future, and me when I inevitably forget.</p>
<p>In this case the server is unicorn, but this will work for any http server listening on a socket, for instance thin. The lines beginning with &#8220;&#8211;&gt;&#8221; are lines I typed (the 4 lines at the start), remove the &#8220;&#8211;&gt;&#8221; when you try this.</p>
<pre>$ socat - UNIX-CONNECT:/u/apps/app/shared/sockets/unicorn.sock,crnl
--&gt;GET /session/new HTTP/1.1
--&gt;Host: thehostname.com
--&gt;X-Forwarded-Proto: https
--&gt;
HTTP/1.1 200 OK
Date: Fri, 02 Dec 2011 14:37:23 GMT
Status: 200 OK
Connection: close
Strict-Transport-Security: max-age=31536000
Content-Type: text/html; charset=utf-8
X-UA-Compatible: IE=Edge,chrome=1
ETag: "2346c47c7cb3bc37729e42fc8b20c821"
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: _x_session=blablabla; path=/; HttpOnly; secure
X-Request-Id: c0a374f460d1b1205df450ab77dd2328
X-Runtime: 0.159219

&lt;!DOCTYPE html&gt;
&lt;html lang="en" data-behavior="wallpaper"&gt;
&lt;head&gt;
etc.</pre>
<p>For those interested in the relevance of the crnl option at the end of the socket path, this from the man page:</p>
<blockquote><p>Converts  the  default  line  termination character NL (&#8216;n&#8217;, 0x0a)<br />
to/from CRNL (&#8220;rn&#8221;, 0x0d0a) when writing/reading on this<br />
channel (example).  Note: socat simply strips all CR characters.</p></blockquote>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/942/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/942/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=942&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2011/12/02/testing-http-over-socket-connections-with-socat/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>
	</item>
		<item>
		<title>Cloud email service price comparison</title>
		<link>http://blog.willj.net/2011/11/30/email-provider-price-comparison/</link>
		<comments>http://blog.willj.net/2011/11/30/email-provider-price-comparison/#comments</comments>
		<pubDate>Wed, 30 Nov 2011 21:27:42 +0000</pubDate>
		<dc:creator>Will Jessop</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[postmark]]></category>
		<category><![CDATA[price comparison]]></category>
		<category><![CDATA[sendgrid]]></category>
		<category><![CDATA[ses]]></category>

		<guid isPermaLink="false">http://willj.net/?p=922</guid>
		<description><![CDATA[Larger interactive versions of all the graphs on this page are available here. Update: Added Mailgun to the graphs. Earlier this year I posted a price comparison between Sendgrid, and the then newly available Amazon SES. Tim Falls commented on the post saying that Sendgrid had updated their pricing: Since this post was published, we [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=922&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p><strong>Larger interactive versions of all the graphs on this page are available <a href="http://willj.net/static/cloud_email_provider_price_comparison.html">here</a>.</strong></p>
<p><strong>Update:</strong> Added <a title="Mailgun" href="http://mailgun.net/">Mailgun</a> to the <a href="http://willj.net/static/cloud_email_provider_price_comparison.html">graphs</a>.</p>
<p>Earlier this year I posted a <a title="Sendgrid and Amazone SES price comparison" href="http://willj.net/2011/01/25/should-i-switch-from-sendgrid-to-amazon-ses/">price comparison</a> between <a title="Sendgrid" href="http://sendgrid.com/">Sendgrid</a>, and the then newly available <a title="Amazon SES" href="http://aws.amazon.com/ses/">Amazon SES</a>.</p>
<p><a title="Tim Falls" href="http://about.me/timfalls">Tim Falls</a> commented on the post saying that Sendgrid had updated their pricing:</p>
<blockquote><p>Since this post was published, we have released a new pricing structure *and* a new service tier that offers more email for less + a feature set and pricing model that you will find very competitive with SES.</p></blockquote>
<p>That was back in June, so it&#8217;s about time I produced an updated comparison. First, lets look at the difference between the old and new Sendgrid prices:</p>
<div id="attachment_928" class="wp-caption alignnone" style="width: 612px"><a href="http://willj.net/static/cloud_email_provider_price_comparison.html#sendgrid"><img class="size-full wp-image-928 " title="Comparison of old and new Sendgrid prices" src="http://willjessop4.files.wordpress.com/2011/11/screen-shot-2011-11-30-at-22-20-15.png?w=580" alt=""   /></a><p class="wp-caption-text">Comparison of old and new Sendgrid prices, click for a larger version</p></div>
<p>Overall the up-front plan prices, and prices for email over allowance have remained the same, but email allowance within each plan has increased. The exception is the Silver plan where email over allowance has increased by $0.0001/email. New to the lineup is the Lite plan.</p>
<p>More interesting is how these new prices compare to the competitors. I&#8217;ve added in Amazon SES, and Postmark too:</p>
<div id="attachment_938" class="wp-caption alignnone" style="width: 566px"><a href="http://willj.net/static/cloud_email_provider_price_comparison.html#comparison"><img class="size-full wp-image-938 " title="Sendgrid, Postmark and Amazon SES price comparison" src="http://willjessop4.files.wordpress.com/2011/11/screen-shot-2011-12-01-at-00-42-52.png?w=580" alt=""   /></a><p class="wp-caption-text">Sendgrid, Postmark and Amazon SES price comparison, click for a larger version</p></div>
<p>The most notable differences here are the inclusion of <a title="Postmark" href="http://postmarkapp.com/">Postmark</a>, and the the Sendgrid Lite plan that shadows Amazon SES. I&#8217;d guess this was added purely to compete with Amazon. As in my last post it is hard to see what is going on with smaller numbers of emails being sent, here&#8217;s a zoom on the origin:</p>
<div id="attachment_939" class="wp-caption alignnone" style="width: 601px"><a href="http://willj.net/static/cloud_email_provider_price_comparison.html#zoom"><img class="size-full wp-image-939 " title="Price comparison for small numbers of emails sent" src="http://willjessop4.files.wordpress.com/2011/11/screen-shot-2011-12-01-at-00-42-57.png?w=580" alt=""   /></a><p class="wp-caption-text">Price comparison for small numbers of emails sent, click for a larger version</p></div>
<p>Here you can see the Sendgrid Lite plan shadowing Amazon and the Postmark costs heading up rapidly.</p>
<h2>Conclusion</h2>
<p>It seems Sendgrid have just added an &#8216;Amazon SES&#8217; plan to pull back any customers that would have chosen SES based on price. It&#8217;s probably a good move, and it will allow easy transition into their more &#8216;premium&#8217; plans if you sign up and later decide to change plan.</p>
<p>Given the advertised features of Postmark compared to the price it seems hard to consider using them. They seem to have some fairly well known customers though, so if anyone has used Postmark leave a comment with how that is working out for you.</p>
<p>So which email cloud provider should you use? Use the graphs I made, but price is only going to be one factor, so check what each provider offers. I&#8217;ve linked to all the pricing pages below.</p>
<h3>Price sources</h3>
<ul>
<li><a href="http://sendgrid.com/pricing.html">Sendgrid prices</a></li>
<li><a href="http://postmarkapp.com/pricing">Postmark prices</a></li>
<li><a href="http://aws.amazon.com/ses/pricing/">Amazon SES prices</a></li>
<li><a title="Mailgun prices" href="http://mailgun.net/pricing">Mailgun prices</a></li>
</ul>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/willjessop4.wordpress.com/922/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/willjessop4.wordpress.com/922/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.willj.net&#038;blog=31097282&#038;post=922&#038;subd=willjessop4&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.willj.net/2011/11/30/email-provider-price-comparison/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6d29c38e7b917eee3139d16d16d58ab7?s=96&#38;d=identicon&#38;r=X" medium="image">
			<media:title type="html">willjessop4</media:title>
		</media:content>

		<media:content url="http://willjessop4.files.wordpress.com/2011/11/screen-shot-2011-11-30-at-22-20-15.png" medium="image">
			<media:title type="html">Comparison of old and new Sendgrid prices</media:title>
		</media:content>

		<media:content url="http://willjessop4.files.wordpress.com/2011/11/screen-shot-2011-12-01-at-00-42-52.png" medium="image">
			<media:title type="html">Sendgrid, Postmark and Amazon SES price comparison</media:title>
		</media:content>

		<media:content url="http://willjessop4.files.wordpress.com/2011/11/screen-shot-2011-12-01-at-00-42-57.png" medium="image">
			<media:title type="html">Price comparison for small numbers of emails sent</media:title>
		</media:content>
	</item>
	</channel>
</rss>
