<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US">
  <title>flame.org - Home</title>
  <id>tag:blog.flame.org,2009:mephisto/</id>
  <generator version="0.8.0" uri="http://mephistoblog.com">Mephisto Drax</generator>
  
  <link href="http://blog.flame.org/" rel="alternate" type="text/html" />
  <updated>2009-11-10T12:28:22Z</updated>
  <link rel="self" href="http://feeds.feedburner.com/flame_org" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-11-10:2798</id>
    <published>2009-11-10T12:23:00Z</published>
    <updated>2009-11-10T12:28:22Z</updated>
    <category term="Programming" />
    <category term="programming" />
    <category term="ruby-on-rails" />
    <link href="http://blog.flame.org/2009/11/10/attr_accessible-vs-accepts_nested_attributes_for" rel="alternate" type="text/html" />
    <title>attr_accessible vs accepts_nested_attributes_for</title>
<content type="html">
            &lt;p&gt;First, I just have to say that I never thought I’d be in Japan, let along blogging from here.&lt;/p&gt;

&lt;p&gt;Today I ran into a little gotcha with restricting access to models when trying out the Rails 2.3 method of nested models.  In my model, I have:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;  has_many &lt;span class="sy"&gt;:dnskeys&lt;/span&gt;, &lt;span class="sy"&gt;:dependent&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  accepts_nested_attributes_for &lt;span class="sy"&gt;:dnskeys&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sy"&gt;:allow_destroy&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;true&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sy"&gt;:reject_if&lt;/span&gt; =&amp;gt; proc { |attrs| attrs.all? { |k, v| v.blank? }}&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  attr_accessible &lt;span class="sy"&gt;:name&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;I was surprised, although I should not have been, that this prevented me from posting a zone and its dnskeys in the same action.  Adding the proper attr_accessible line made the magic happen again:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;  attr_accessible &lt;span class="sy"&gt;:dnskeys_attributes&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/GYfT8gAcZIuBbUJtp4qPO64IZ4o/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GYfT8gAcZIuBbUJtp4qPO64IZ4o/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/GYfT8gAcZIuBbUJtp4qPO64IZ4o/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GYfT8gAcZIuBbUJtp4qPO64IZ4o/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=GoUz0Kiubps:xsuJkaAv7vk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=GoUz0Kiubps:xsuJkaAv7vk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=GoUz0Kiubps:xsuJkaAv7vk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=GoUz0Kiubps:xsuJkaAv7vk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=GoUz0Kiubps:xsuJkaAv7vk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=GoUz0Kiubps:xsuJkaAv7vk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=GoUz0Kiubps:xsuJkaAv7vk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=GoUz0Kiubps:xsuJkaAv7vk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-11-05:2797</id>
    <published>2009-11-05T09:09:00Z</published>
    <updated>2009-11-05T09:43:45Z</updated>
    <category term="Programming" />
    <category term="programming" />
    <category term="ruby-on-rails" />
    <link href="http://blog.flame.org/2009/11/5/experiments-with-haml" rel="alternate" type="text/html" />
    <title>Experiments with HAML</title>
<content type="html">
            &lt;p&gt;I decided to try HAML today, rather than the standard ERB templates.  The jury is still out on if it is better or worse, but like many things Rails, it is better to just dive in and try it.&lt;/p&gt;

&lt;p&gt;I have a little project (not yet released) which I’m converting over to use HAML.  Since I also use rspec for testing, along with Cucumber and Webrat, I thought I had a long day ahead of me.&lt;/p&gt;

&lt;p&gt;It turns out most of it can be made close to automatic, with just a little cleanup afterwards.&lt;/p&gt;

&lt;p&gt;Using the rake task below, you can issue these two commands to convert your existing *.html.erb views into *.html.haml.  The second target will convert the rspec view tests to expect haml.  Renaming the spec tests is not required, but I like sanity.&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;  $ rake haml:convert:html&lt;tt&gt;
&lt;/tt&gt;  $ rake haml:convert:spec&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;If you use a SCM (I still like Subversion best) you’ll want to remove the old files and add the new ones.  For Subversion, I do:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;  $ svn rm app/views/*/*.html.erb spec/views/*/*.html.erb_spec.rb&lt;tt&gt;
&lt;/tt&gt;  $ svn add app/views/*/*.html.haml spec/views/*/*.html.haml_spec.rb&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;The main problems were that not all of the templates were properly indented, and “- end” lines appeared in the HAML templates.  Fixing this was fast, as I really don’t have much in my templates yet as this is a new project.  This step too could probably be done in an automated way.  However, the indentation is probably going to require a bit of manual work.&lt;/p&gt;

&lt;p&gt;While there, I also fixed up multi-line constructs generated with a much nicer compact format:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;  %h1&lt;tt&gt;
&lt;/tt&gt;    Title&lt;tt&gt;
&lt;/tt&gt;  %tr&lt;tt&gt;
&lt;/tt&gt;    %th&lt;tt&gt;
&lt;/tt&gt;      Heading&lt;tt&gt;
&lt;/tt&gt;    %th&lt;tt&gt;
&lt;/tt&gt;      Heading&lt;tt&gt;
&lt;/tt&gt;...&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Compare with this:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;  %h1 Title&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  %tr&lt;tt&gt;
&lt;/tt&gt;    %th Heading&lt;tt&gt;
&lt;/tt&gt;    %th Heading&lt;tt&gt;
&lt;/tt&gt;...&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;And now for the rake task:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# RAILS_ROOT/lib/tasks/haml_convert.rake&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;haml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;haml/exec&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; &lt;tt&gt;
&lt;/tt&gt;namespace &lt;span class="sy"&gt;:haml&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  namespace &lt;span class="sy"&gt;:convert&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Convert all *.html.erb files to *.html.haml&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    task &lt;span class="sy"&gt;:html&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="co"&gt;Dir&lt;/span&gt;.glob(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;app/views/**/*.html.erb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).each &lt;span class="r"&gt;do&lt;/span&gt; |html|&lt;tt&gt;
&lt;/tt&gt;        puts html + &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="co"&gt;Haml&lt;/span&gt;::&lt;span class="co"&gt;Exec&lt;/span&gt;::&lt;span class="co"&gt;HTML2Haml&lt;/span&gt;.new([html, html.gsub(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;.html.erb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;.html.haml&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)]).process_result&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="co"&gt;File&lt;/span&gt;.delete(html)&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Convert all *.html.erb_spec.rb files to *.html.haml_spec.rb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    task &lt;span class="sy"&gt;:spec&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="co"&gt;Dir&lt;/span&gt;.glob(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;spec/views/**/*.html.erb_spec.rb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).each &lt;span class="r"&gt;do&lt;/span&gt; |oldname|&lt;tt&gt;
&lt;/tt&gt;        puts oldname + &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        newname = oldname.gsub(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;.html.erb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;.html.haml&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;        nf = &lt;span class="co"&gt;File&lt;/span&gt;.open(newname, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;w&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="co"&gt;File&lt;/span&gt;.open(oldname) &lt;span class="r"&gt;do&lt;/span&gt; |of|&lt;tt&gt;
&lt;/tt&gt;          of.each_line &lt;span class="r"&gt;do&lt;/span&gt; |line|&lt;tt&gt;
&lt;/tt&gt;            nf.puts line.gsub(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;.html.erb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;.html.haml&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;          &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        nf.close&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="c"&gt;#File.delete(oldname)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/aTQdokzcVLu_pW_1Bn2ZudhObcI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/aTQdokzcVLu_pW_1Bn2ZudhObcI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/aTQdokzcVLu_pW_1Bn2ZudhObcI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/aTQdokzcVLu_pW_1Bn2ZudhObcI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MnFo9iC9W8s:gW-l20109sI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MnFo9iC9W8s:gW-l20109sI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=MnFo9iC9W8s:gW-l20109sI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MnFo9iC9W8s:gW-l20109sI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=MnFo9iC9W8s:gW-l20109sI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MnFo9iC9W8s:gW-l20109sI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=MnFo9iC9W8s:gW-l20109sI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MnFo9iC9W8s:gW-l20109sI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-11-04:2796</id>
    <published>2009-11-04T11:36:00Z</published>
    <updated>2009-11-05T09:43:52Z</updated>
    <category term="Programming" />
    <category term="programming" />
    <category term="ruby" />
    <category term="ruby-on-rails" />
    <link href="http://blog.flame.org/2009/11/4/activeresource-and-shallow-nested-routes" rel="alternate" type="text/html" />
    <title>ActiveResource and Shallow Nested Routes</title>
<content type="html">
            &lt;p&gt;I recently tried to dive into ActiveResource, which allows a Ruby (usually Ruby on Rails) application to connect to a remote RESTful API and treat it almost as if it were local.  There were some problems with my API from ActiveResource’s point of view.&lt;/p&gt;

&lt;p&gt;Firstly, I use nested routes.  This isn’t really a problem as it is possible to specify a prefix to add to the path, and even to substitution on this path.  However, Rails added the concept of a “shallow nested route” a while back.&lt;/p&gt;

&lt;p&gt;A shallow nested route is a short-hand notation which allows one to appear to scope out collections (that is, a list of things) from the actual thing itself.  For example, in my application (https://dlv.isc.org/) I have:&lt;/p&gt;

&lt;p&gt;/users/123  &amp;lt;– specific userid&lt;/p&gt;

&lt;p&gt;/users/123/zones &amp;lt;— list of all zones for user 123&lt;/p&gt;

&lt;p&gt;/zones/456  &amp;lt;— specific zone&lt;/p&gt;

&lt;p&gt;This allows me to look at a specific user’s zones (or them, their own zones) without having to do some sort of special back-end processing which relies on something not in the path, such as the @current_user instance variable.  After all, how would an admin list a user’s zones if /zones returned the current user’s zones only?  Through an admin interface probably, but that seems messy.  Shallow routes are seemingly more clean.&lt;/p&gt;

&lt;p&gt;However, they break ActiveResource’s concept of the world.&lt;/p&gt;

&lt;p&gt;With a little trickery, however, I managed to get shallow nested routes to work without having to do much additional work.  I did have to pass in an additional argument to the collection list(s) however.&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Zone&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="co"&gt;SITE&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.user = &lt;span class="co"&gt;USERNAME&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.password = &lt;span class="co"&gt;PASSWORD&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.collection_path(prefix_options = {}, query_options = &lt;span class="pc"&gt;nil&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    prefix_options, query_options = split_options(prefix_options) &lt;span class="r"&gt;if&lt;/span&gt; query_options.nil?&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/users/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;USERID&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;prefix(prefix_options)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;collection_name&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;format.extension&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;query_string(query_options)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Dnskey&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="co"&gt;SITE&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.user = &lt;span class="co"&gt;USERNAME&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.password = &lt;span class="co"&gt;PASSWORD&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.collection_path(prefix_options = {}, query_options = &lt;span class="pc"&gt;nil&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    prefix_options, query_options = split_options(prefix_options) &lt;span class="r"&gt;if&lt;/span&gt; query_options.nil?&lt;tt&gt;
&lt;/tt&gt;    z = &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; query_options.has_key?(&lt;span class="sy"&gt;:zone_id&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      z = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/zones/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;query_options[&lt;span class="sy"&gt;:zone_id&lt;/span&gt;]&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      query_options.delete(&lt;span class="sy"&gt;:zone_id&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;z&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;prefix(prefix_options)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;collection_name&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;format.extension&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;query_string(query_options)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;In my case, I used a constant USERID to the Zone’s collection, but left the specific item (aka “element&lt;em&gt;path”) alone.  For Dnskeys, where I needed to pass in different zone&lt;/em&gt;id values, I had to do a small trick.&lt;/p&gt;

&lt;p&gt;I call this as:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;all_zones = &lt;span class="co"&gt;Zones&lt;/span&gt;.find &lt;span class="sy"&gt;:all&lt;/span&gt; &lt;span class="c"&gt;# returns a list of all zones for the USERID&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;z = &lt;span class="co"&gt;Zone&lt;/span&gt;.find(&lt;span class="i"&gt;1&lt;/span&gt;) &lt;span class="c"&gt;# returns only Zone with the id of 1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;z.destroy &lt;span class="c"&gt;# destroys the zone, uses the element_path()&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;z = &lt;span class="co"&gt;Zone&lt;/span&gt;.find(&lt;span class="i"&gt;2&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;keys = &lt;span class="co"&gt;Dnskey&lt;/span&gt;.find(&lt;span class="sy"&gt;:all&lt;/span&gt;, { &lt;span class="sy"&gt;:zone_id&lt;/span&gt; =&amp;gt; z.id }) &lt;span class="c"&gt;# disgusting, but works&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# This is a hack.  I want to use Dnskey.create here, but it won't work since I cannot&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# pass the zone_id along, and there are no association hints so I can't use&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# zone.dnskeys.create() like I can with ActiveRecord.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;d = &lt;span class="co"&gt;Dnskey&lt;/span&gt;.new(&lt;span class="sy"&gt;:flags&lt;/span&gt; =&amp;gt; key.flags, &lt;span class="sy"&gt;:algorithm&lt;/span&gt; =&amp;gt; key.algorithm.to_i, ...)&lt;tt&gt;
&lt;/tt&gt;d.prefix_options[&lt;span class="sy"&gt;:zone_id&lt;/span&gt;] = zone.id&lt;tt&gt;
&lt;/tt&gt;d.save&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FNCxx2NY3XOmFtIzDp_DpUS2b6g/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FNCxx2NY3XOmFtIzDp_DpUS2b6g/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FNCxx2NY3XOmFtIzDp_DpUS2b6g/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FNCxx2NY3XOmFtIzDp_DpUS2b6g/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=NN_a0BPFPiU:rd0RjSNSh-8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=NN_a0BPFPiU:rd0RjSNSh-8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=NN_a0BPFPiU:rd0RjSNSh-8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=NN_a0BPFPiU:rd0RjSNSh-8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=NN_a0BPFPiU:rd0RjSNSh-8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=NN_a0BPFPiU:rd0RjSNSh-8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=NN_a0BPFPiU:rd0RjSNSh-8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=NN_a0BPFPiU:rd0RjSNSh-8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-08-14:2788</id>
    <published>2009-08-14T18:56:00Z</published>
    <updated>2009-10-19T22:59:53Z</updated>
    <category term="web-design" />
    <link href="http://blog.flame.org/2009/8/14/first-steps-at-real-web-bling" rel="alternate" type="text/html" />
    <title>First steps at "real" web bling</title>
<content type="html">
            &lt;p&gt;You’d not know it from the looks of this blog, but I’m starting to play with “real” web design stuff.  You know, fonts that aren’t available on the web for title bars, buttons, etc. Yea, image replacement.  Ahh well, I guess it’s time to stop thinking that purist views can be pretty too.&lt;/p&gt;

&lt;p&gt;Along these lines, I’ve cracked out Illustrator.  It pains me to do stuff in Photoshop for some reason – too limited, things don’t scale properly, etc.&lt;/p&gt;

&lt;p&gt;I’d love to hear about any open source tools that can do the steps of “make it pretty”, “edit it easily”, and end with “save slices out to individual files.”  Ideally with “write all the XHTML and css files for you in a sane and reliable way.”&lt;/p&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/iViP9WqfFuphOTQ7PCFCA1vkXo8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iViP9WqfFuphOTQ7PCFCA1vkXo8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/iViP9WqfFuphOTQ7PCFCA1vkXo8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iViP9WqfFuphOTQ7PCFCA1vkXo8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LUZwEnqJ4fY:6D0-Aw4TGdQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LUZwEnqJ4fY:6D0-Aw4TGdQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=LUZwEnqJ4fY:6D0-Aw4TGdQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LUZwEnqJ4fY:6D0-Aw4TGdQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=LUZwEnqJ4fY:6D0-Aw4TGdQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LUZwEnqJ4fY:6D0-Aw4TGdQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=LUZwEnqJ4fY:6D0-Aw4TGdQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LUZwEnqJ4fY:6D0-Aw4TGdQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-06-05:2787</id>
    <published>2009-06-05T06:11:00Z</published>
    <updated>2009-10-19T21:28:43Z</updated>
    <category term="asterisk" />
    <category term="voip" />
    <link href="http://blog.flame.org/2009/6/5/d-link-vta-vr-with-asterisk" rel="alternate" type="text/html" />
    <title>D-Link VTA-VR with Asterisk</title>
<content type="html">
            &lt;p&gt;While walking around a local store, I came upon the clearance isle and found a D-Link VTA-VR in an opened package.  Seeing the price was $25 (which read as $15 at the register) I thought I’d give it a try.  The goal is to rip it from its Vonage branding and make it speak to my Asterisk server.&lt;/p&gt;

&lt;p&gt;It worked, mostly.  There are many guides on the net on how to deal with this device, but it turns out the default password was already open, so perhaps someone had already cracked it for me.  Thanks, if so.&lt;/p&gt;

&lt;p&gt;The box has two phone jacks, but my first goal was to get just one of them working.  This turns out to be trivial – just configure the username, password, and the proxy and away it goes.&lt;/p&gt;

&lt;p&gt;The second line turned out to be a problem.  This client, like so many other cheap devices, seems to break the SIP protocol.  For one, both lines share a single UDP agent port (defaults to 10000, I set it to 5060 for packet capture filter sanity.)  This is ok but, when registering at least, Asterisk would often (but not always) report “expired nonce.”&lt;/p&gt;

&lt;p&gt;What is an “expired nonce” you ask?  It is part of the registration protocol.  Basically, the SIP device sends a REGISTER requeest without any login information, and it receives an UNAUTHORIZED response.  In that response, however, is some information which can be combined with a username and a password that the client and server know, to generate an authentication token.  Part of this is called a “nonce” which is really just a little bit of random data that prevents certain security attacks.&lt;/p&gt;

&lt;p&gt;What I was seeing is this:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;pre&gt;&lt;code&gt;VTA:  REGISTER for line 1
Asterisk:  UNAUTHORIZED retry with nonce [123456]
VTA:  REGISTER for line 2
Asterisk:  UNAUTHORIZED retry with nonce [abcdef]
VTA:  REGISTER for line 1 with nonce [123456]
Asterisk:  Expired nonce [123456] retry with [deadbeef]
VTA:  REGISTER for line 2 with nonce [abcdef]
Asterisk:  Expired nonce [abcdef] retry with [feedme]
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The VTA would never recover from this.  A bit of random jitter between registration attempts, or only attempting one at a time, would fix this.  Using different ports on the VTA device would fix this, but there is no configuration option for that.  If the VTA used a different Call-ID for each registration request, it would work.&lt;/p&gt;

&lt;p&gt;Unfortunately, there seems to be no way to get both lines working reliably with a single Asterisk server.&lt;/p&gt;

&lt;p&gt;There are several hacks I can think of, one is to install a SIP proxy that can register the second line, but would really just proxy the connection to the Asterisk server.  Another would be to cause Asterisk to listen on more than one port, and use different ports per line.  I don’t think that’s easy or even possible.&lt;/p&gt;

&lt;p&gt;Another option would be to hack Asterisk to make it understand that a very popular firmware is rather broken, and it should just expire a nonce based on more criteria than it uses now.  Right now, for a given Call-ID, there can be but one nonce.  If a new one is issued, the old goes away.  If Asterisk were to maintain a linked list of possible values and expire them all when one is found to be working, this might work.  It would delay line 2 registration, but that’s quite acceptable.&lt;/p&gt;

&lt;h3&gt;Myth Busting&lt;/h3&gt;

&lt;p&gt;I’d also like to dispel some myths that many VTA-VR hacking pages are saying, usually referring to each other in the process.&lt;/p&gt;

&lt;p&gt;The VTA-VR uses four UDP ports:  One for the shared “agent port”, one for each line’s SIP proxy (usually both are 5060, this is the port the Asterisk server listens on), and one for TLS (which I do not use, but it defaults to 5061.)  You cannot set the proxy port to something other than what the asterisk server is listening on, so any comments like “you need to use different ports” is just wrong, as unless your Asterisk server is accepting connections on more than one port, it won’t work.&lt;/p&gt;

&lt;p&gt;Setting the “user agent” port to 5060 is handy.  If you do this, you can set the defaultip=10.42.1.2 in sip.conf for that line, and even if the device is not registered, Asterisk will still send calls there.  This is somewhat scary, but it does seem to work.  Sometimes.&lt;/p&gt;

&lt;p&gt;Changing the timers does not help a great deal.  They are defaults, it’s best to leave them alone.&lt;/p&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Ssy5h7bkWOvIg68k5Lmcu4jfc1c/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Ssy5h7bkWOvIg68k5Lmcu4jfc1c/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Ssy5h7bkWOvIg68k5Lmcu4jfc1c/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Ssy5h7bkWOvIg68k5Lmcu4jfc1c/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=BoE4Vb1OaL4:uoUwGACNJuc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=BoE4Vb1OaL4:uoUwGACNJuc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=BoE4Vb1OaL4:uoUwGACNJuc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=BoE4Vb1OaL4:uoUwGACNJuc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=BoE4Vb1OaL4:uoUwGACNJuc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=BoE4Vb1OaL4:uoUwGACNJuc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=BoE4Vb1OaL4:uoUwGACNJuc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=BoE4Vb1OaL4:uoUwGACNJuc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-03-27:2786</id>
    <published>2009-03-27T03:19:00Z</published>
    <updated>2009-10-19T21:25:07Z</updated>
    <category term="bind" />
    <category term="dnssec" />
    <category term="security" />
    <link href="http://blog.flame.org/2009/3/27/dnssec-vs-firewall" rel="alternate" type="text/html" />
    <title>DNSSEC vs Firewall</title>
<content type="html">
            &lt;p&gt;A very common cause for DNSSEC validation failure under BIND 9 is firewall issues.  Specifically, a firewall that blocks fragments.&lt;/p&gt;

&lt;p&gt;To work around this, limiting the packet size one is willing to accept so to avoid fragmentation is a good, but temporary, solution.&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;pre&gt;&lt;code&gt;options {
  edns-udp-size 1460;
};&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This has the side-effect of causing TCP retries on large packets, which are often the DNSKEY responses.  However, it also causes DNSSEC to work, so overall it’s a good thing.&lt;/p&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/UOG5HbqBJNdKRH_C8QDs8Qb1mJI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UOG5HbqBJNdKRH_C8QDs8Qb1mJI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/UOG5HbqBJNdKRH_C8QDs8Qb1mJI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UOG5HbqBJNdKRH_C8QDs8Qb1mJI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=7YQSN0qNtac:BswgTrDvT4U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=7YQSN0qNtac:BswgTrDvT4U:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=7YQSN0qNtac:BswgTrDvT4U:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=7YQSN0qNtac:BswgTrDvT4U:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=7YQSN0qNtac:BswgTrDvT4U:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=7YQSN0qNtac:BswgTrDvT4U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=7YQSN0qNtac:BswgTrDvT4U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=7YQSN0qNtac:BswgTrDvT4U:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-03-06:2785</id>
    <published>2009-03-06T21:53:00Z</published>
    <updated>2009-11-05T09:40:02Z</updated>
    <category term="programming" />
    <category term="ruby-on-rails" />
    <link href="http://blog.flame.org/2009/3/6/a-real-xml-api-and-rails" rel="alternate" type="text/html" />
    <title>A Real XML API and Rails</title>
<content type="html">
            &lt;p&gt;I recently implemented an XML API that I intended to be used outside of a web browser.  Much of the words others have written on the topic are ways to get a Javascript framework to use the &lt;code&gt;authentication_token&lt;/code&gt; magic.  Some others show the &lt;code&gt;GET&lt;/code&gt; side and mention the &lt;code&gt;DELETE&lt;/code&gt; but omit the &lt;code&gt;PUT&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;Here are things I’ve learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To ensure XML data is returned, use the correct HTTP header:  &lt;code&gt;Accept: application/xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Rails assumes that multipart forms and url-encoded forms are from browsers.  You can’t use them in a default Rails setup if you want to avoid the &lt;code&gt;authentication_token&lt;/code&gt; check.&lt;/li&gt;
&lt;li&gt;To &lt;code&gt;POST&lt;/code&gt; or &lt;code&gt;PUT&lt;/code&gt;, use a header of &lt;code&gt;Content-Type: application/xml&lt;/code&gt; and include XML data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is rather unfortunate that Rails assumes that the encoding ties into a browser.  It should be possible to use any encoding so long as the XML data types in the headers are correct.  This is probably a bug, but it might be that if you receive XML through an API, you should &lt;b&gt;send&lt;/b&gt; XML too.&lt;/p&gt;

&lt;h3&gt;Example&lt;/h3&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;curl --user user:password -H 'Accept: application/xml' \&lt;tt&gt;
&lt;/tt&gt;  -H 'Content-Type: application/xml' \&lt;tt&gt;
&lt;/tt&gt;  -X POST -d '&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;item&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;name&amp;gt;foo&amp;lt;/name&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;description&amp;gt;bar&amp;lt;/description&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;price&amp;gt;100&amp;lt;/price&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;/item&amp;gt;' http://localhost:3000/items/create&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/5KOyI-3PqL1SIdBGGPxp--7ila4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5KOyI-3PqL1SIdBGGPxp--7ila4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/5KOyI-3PqL1SIdBGGPxp--7ila4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5KOyI-3PqL1SIdBGGPxp--7ila4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=W2G9hoEuM8I:61XrcHO80gM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=W2G9hoEuM8I:61XrcHO80gM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=W2G9hoEuM8I:61XrcHO80gM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=W2G9hoEuM8I:61XrcHO80gM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=W2G9hoEuM8I:61XrcHO80gM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=W2G9hoEuM8I:61XrcHO80gM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=W2G9hoEuM8I:61XrcHO80gM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=W2G9hoEuM8I:61XrcHO80gM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-03-03:2783</id>
    <published>2009-03-03T03:05:00Z</published>
    <updated>2009-10-19T21:09:20Z</updated>
    <category term="rant" />
    <link href="http://blog.flame.org/2009/3/3/dell-and-world-record-customer-support" rel="alternate" type="text/html" />
    <title>Dell and World Record Customer Support</title>
<content type="html">
            &lt;p&gt;Recently a message started appearing that told me my A/C adapter was not recognized by the system.  Knowing that the A/C adapter and laptop were covered by a next-day on-side warranty, I called Dell.  I carefully explained the problem: the batteries don’t charge any longer, the boot-time error message, and that the green LED on the adapter seems dimmer than it should be.&lt;/p&gt;

&lt;p&gt;The technician at Dell decided that, with this set of problems, the motherboard needs to be replaced.  I asked if perhaps an adapter should be tried first…  No, he assured me, that would not be the problem.&lt;/p&gt;

&lt;p&gt;Two days later (which is service contract for “next business day service”) a very friendly and helpful technician arrived, and replaced the motherboard.  Same problem.  He and I had a good old laugh at Dell for that, and he asked Dell to send a replacement A/C adapter.&lt;/p&gt;&lt;/p&gt;

&lt;p&gt;Two days later, it arrived.  No warning message! Success!  But wait…  now when I move the laptop it looses power for a brief moment.  If there is no battery, it turns off.  This was not happening before…&lt;/p&gt;&lt;/p&gt;

&lt;p&gt;Calling Dell resulted in a mess.  The first technician at Dell I spoke with was, to be as kind as possible, a moron.  He had me run hardware tests.  He had me set the brightness on the laptop LCD to full on and off battery, and since it didn’t flicker anymore was fully prepared to declare the problem resolved.  I slowly and carefully explained that this is a physical problem and that moving the computer at all causes it to turn off if the batteries are too low or removed.&lt;/p&gt;

&lt;p&gt;True to the incompetence that I have come to expect from nearly every computer company’s tech support, he declared that since no errors show up in the BIOS self-tests, it MUST be software.  I asked to speak to his manager.&lt;/p&gt;

&lt;p&gt;The manager declared that this was indeed a problem, part of the ongoing issue, but that I needed to ship the computer to Dell.  This is because, in the mean time, my service contract has expired.  They admit that while this was an on-going problem, and they will fix it, it won’t be done with on-site, and that I have to ship the laptop.  I called bullsh*t.&lt;/p&gt;

&lt;p&gt;After about 20 minutes of hold-time, two agents, and over 45 minutes of on-the-phone time they finally decided that it was indeed still covered under the same warranty replacement terms as when the problem started, and they will ship another motherboard out and have it replaced again, next-day (in service-contract terms), which means to the rest of us 3 days.&lt;/p&gt;

&lt;p&gt;So, so far, to replace a $100 A/C adapter, Dell has wasted five hours of my time and probably two to three times what the laptop is worth in service calls.&lt;/p&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/c-1Pa55lUjmvocKrnYenq3dvyhs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/c-1Pa55lUjmvocKrnYenq3dvyhs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/c-1Pa55lUjmvocKrnYenq3dvyhs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/c-1Pa55lUjmvocKrnYenq3dvyhs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MtkAMWL0i2Y:9REtMubneV4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MtkAMWL0i2Y:9REtMubneV4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=MtkAMWL0i2Y:9REtMubneV4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MtkAMWL0i2Y:9REtMubneV4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=MtkAMWL0i2Y:9REtMubneV4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MtkAMWL0i2Y:9REtMubneV4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=MtkAMWL0i2Y:9REtMubneV4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=MtkAMWL0i2Y:9REtMubneV4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-02-28:2782</id>
    <published>2009-02-28T21:56:00Z</published>
    <updated>2009-10-19T20:56:34Z</updated>
    <category term="cryptography" />
    <category term="programming" />
    <category term="ruby" />
    <category term="security" />
    <link href="http://blog.flame.org/2009/2/28/ruby-and-openssl" rel="alternate" type="text/html" />
    <title>Ruby and OpenSSL</title>
<content type="html">
            &lt;p&gt;I recently had to do some DNSSEC-type (somewhat low-level) cryptography work, and found the
seeming lack of Ruby OpenSSL documentation a big pain.  I found numerous examples of how OpenSSL is commonly used with PEM-encoded keys, but precious little information on low-level key loading.  To save others the trouble of having to dig up some of this, I’ve collected some short examples of how to do low-level RSA and DSA building from a lower level than most use.&lt;/p&gt;

&lt;p&gt;This table summarizes the variables which need to be set to use an RSA public and private key.&lt;/p&gt;

&lt;h3&gt;RSA Keys&lt;/h3&gt;

&lt;table&gt;
  &lt;tr&gt;
    Key TypeItemDescription
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;RSA Public&lt;/td&gt;&lt;td&gt;e&lt;/td&gt;&lt;td&gt;Public Exponent&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;RSA&lt;/td&gt;&lt;td&gt;n&lt;/td&gt;&lt;td&gt;Modulus&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;RSA Private&lt;/td&gt;&lt;td&gt;d&lt;/td&gt;&lt;td&gt;Private Exponent&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;RSA Private&lt;/td&gt;&lt;td&gt;p&lt;/td&gt;&lt;td&gt;Prime 1&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;RSA Private&lt;/td&gt;&lt;td&gt;q&lt;/td&gt;&lt;td&gt;Prime 2&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;RSA Private&lt;/td&gt;&lt;td&gt;dmq1&lt;/td&gt;&lt;td&gt;Exponent 1&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;RSA Private&lt;/td&gt;&lt;td&gt;dmp1&lt;/td&gt;&lt;td&gt;Exponent 2&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;RSA Private&lt;/td&gt;&lt;td&gt;iqmp&lt;/td&gt;&lt;td&gt;Coefficient&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Thus, in order to make a working RSA public key (so the method &lt;code&gt;key.public&lt;em&gt;encrypt()&lt;/code&gt; or &lt;code&gt;key.public&lt;/em&gt;decrypt()&lt;/code&gt; work) you must set at least &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;e&lt;/code&gt;.  For a working private key, you would need to load all of the items.  Exposing any of the items marked as “RSA Private” above will cause a key compromise.&lt;/p&gt;

&lt;h3&gt;RSA Example&lt;/h3&gt;

&lt;p&gt;In this example, a 128-bit RSA key is loaded from numerical values.  In DNSSEC, the public key is stored in the DNSKEY record for the zones.  Don’t use these numbers for real crypto; the short key length is used only to make the numbers short enough to fit in the screen width.  For real work, 1024 is probably a reasonable minimum length for short-lived uses, and 2048 for longer-term use.&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;openssl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Build a RSA public key.  We only need to load two things&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# here in order to use the public key to use it to encrypt,&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# sign, or verify.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;pub = &lt;span class="co"&gt;OpenSSL&lt;/span&gt;::&lt;span class="co"&gt;PKey&lt;/span&gt;::&lt;span class="co"&gt;RSA&lt;/span&gt;::new&lt;tt&gt;
&lt;/tt&gt;pub.e = &lt;span class="i"&gt;65537&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;pub.n = &lt;span class="i"&gt;216457604585180710748301099018726389113&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# At this point, this will work:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;crypted = pub.public_encrypt(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Build an RSA private key.  For the private key to work, we need&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# to load the entire key, private and public components.  As we&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# should have access to both, this is not really a problem.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv = &lt;span class="co"&gt;OpenSSL&lt;/span&gt;::&lt;span class="co"&gt;PKey&lt;/span&gt;::&lt;span class="co"&gt;RSA&lt;/span&gt;::new&lt;tt&gt;
&lt;/tt&gt;prv.e = &lt;span class="i"&gt;65537&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv.d = &lt;span class="i"&gt;178210827022942698143906513631075003381&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv.n = &lt;span class="i"&gt;216457604585180710748301099018726389113&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv.p = &lt;span class="i"&gt;15294921647876231099&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv.q = &lt;span class="i"&gt;14152253249053866587&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv.dmp1 = &lt;span class="i"&gt;6806715058393856237&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv.dmq1 = &lt;span class="i"&gt;637679537428568107&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv.iqmp = &lt;span class="i"&gt;6672106206837437412&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Now we have a working private key.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;puts prv.private_decrypt(crypted) &lt;span class="c"&gt;# prints &amp;quot;test&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;h3&gt;DSA keys&lt;/h3&gt;

&lt;p&gt;A DSA key is more or less the same, just with different variable names.  It is also split into a public and private part, and the key can be loaded from individual components just as easily.&lt;/p&gt;

&lt;table&gt;
  &lt;tr&gt;
    Key TypeItemDescription
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;DSA Public&lt;/td&gt;&lt;td&gt;pub_key&lt;/td&gt;&lt;td&gt;Public Key&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;DSA&lt;/td&gt;&lt;td&gt;q&lt;/td&gt;&lt;td&gt;Prime 1&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;DSA&lt;/td&gt;&lt;td&gt;p&lt;/td&gt;&lt;td&gt;Prime 2&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;DSA&lt;/td&gt;&lt;td&gt;g&lt;/td&gt;&lt;td&gt;Multiplicative order modulo p is q&lt;/td&gt;
  &lt;/tr&gt;&lt;tr&gt;
    &lt;td&gt;DSA Private&lt;/td&gt;&lt;td&gt;priv_key&lt;/td&gt;&lt;td&gt;Private Key&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;h3&gt;DSA Example&lt;/h3&gt;

&lt;p&gt;Unfortunately, this example has some numbers which are too long to display nicely.
I have used a trick to convert them from strings into integers so they
will fit here.  Normally you would not need to do this.&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;openssl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Build an DSA private key.  For the private key to work, we need&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# to load the entire key, private and public components.  As we&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# should have access to both, this is not really a problem.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv = &lt;span class="co"&gt;OpenSSL&lt;/span&gt;::&lt;span class="co"&gt;PKey&lt;/span&gt;::&lt;span class="co"&gt;DSA&lt;/span&gt;::new&lt;tt&gt;
&lt;/tt&gt;prv.pub_key = (&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;899167044393666062859565588228279347268072456516837337&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;               &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;963353916587148226144760114643916732975837345856985656&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;               &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;3340384802383806137452386519280693373122367959&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).to_i&lt;tt&gt;
&lt;/tt&gt;prv.p = (&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;952649509730281181203079535805855260554748337655197352471196&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;869232197576949258404031665397657842790773780623545384978542&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;6685417827665656974405272756289291&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).to_i&lt;tt&gt;
&lt;/tt&gt;prv.q = &lt;span class="i"&gt;903197981571669745498020976355730183999507610553&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;prv.g = (&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;535694721480531756072717909769318961974692885092552247120424&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;749877864650255208980198391972633196543370921493242375015765&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;755160911031468160738717891191998&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).to_i&lt;tt&gt;
&lt;/tt&gt;prv.priv_key = &lt;span class="i"&gt;557886499717422048101097620625259920363848888840&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# At this point, this will work:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;signature = prv.sign(&lt;span class="co"&gt;OpenSSL&lt;/span&gt;::&lt;span class="co"&gt;Digest&lt;/span&gt;::&lt;span class="co"&gt;DSS1&lt;/span&gt;.new, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Build a DSA public key.  We only need to load two things&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# here in order to use the public key to use it to encrypt,&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# sign, or verify.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;pub = &lt;span class="co"&gt;OpenSSL&lt;/span&gt;::&lt;span class="co"&gt;PKey&lt;/span&gt;::&lt;span class="co"&gt;DSA&lt;/span&gt;::new&lt;tt&gt;
&lt;/tt&gt;pub.pub_key = (&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;899167044393666062859565588228279347268072456516837337&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;               &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;963353916587148226144760114643916732975837345856985656&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;               &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;3340384802383806137452386519280693373122367959&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).to_i&lt;tt&gt;
&lt;/tt&gt;pub.p = (&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;952649509730281181203079535805855260554748337655197352471196&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;869232197576949258404031665397657842790773780623545384978542&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;6685417827665656974405272756289291&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).to_i&lt;tt&gt;
&lt;/tt&gt;pub.q = &lt;span class="i"&gt;903197981571669745498020976355730183999507610553&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;pub.g = (&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;535694721480531756072717909769318961974692885092552247120424&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;749877864650255208980198391972633196543370921493242375015765&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;755160911031468160738717891191998&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).to_i&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Now we have a working private key.  Verify the signature&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;if&lt;/span&gt; pub.verify(&lt;span class="co"&gt;OpenSSL&lt;/span&gt;::&lt;span class="co"&gt;Digest&lt;/span&gt;::&lt;span class="co"&gt;DSS1&lt;/span&gt;.new, signature, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Signature verified.&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Signature verification failed.&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/QWhxQPQYYtaDToT4VOEYRvrSH6E/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/QWhxQPQYYtaDToT4VOEYRvrSH6E/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/QWhxQPQYYtaDToT4VOEYRvrSH6E/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/QWhxQPQYYtaDToT4VOEYRvrSH6E/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=SpkPg7HNMu8:X8S_G2dtRYw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=SpkPg7HNMu8:X8S_G2dtRYw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=SpkPg7HNMu8:X8S_G2dtRYw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=SpkPg7HNMu8:X8S_G2dtRYw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=SpkPg7HNMu8:X8S_G2dtRYw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=SpkPg7HNMu8:X8S_G2dtRYw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=SpkPg7HNMu8:X8S_G2dtRYw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=SpkPg7HNMu8:X8S_G2dtRYw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-02-28:2781</id>
    <published>2009-02-28T20:05:00Z</published>
    <updated>2009-11-05T09:44:04Z</updated>
    <category term="programming" />
    <category term="ruby" />
    <category term="ruby-on-rails" />
    <link href="http://blog.flame.org/2009/2/28/find-conditions-from-params" rel="alternate" type="text/html" />
    <title>Find conditions from params[]</title>
<content type="html">
            &lt;p&gt;I have often wished to add a trivial search capability to my controllers which would allow searching on different fields.  Without getting into a mess of many different &lt;code&gt;if&lt;/code&gt; statements each of which has a different set of conditions, I use something much like the following:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  cond_hash = {}&lt;tt&gt;
&lt;/tt&gt;  cond_strings = []&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; params[&lt;span class="sy"&gt;:search&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;    cond_hash[&lt;span class="sy"&gt;:login&lt;/span&gt;] = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;%&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;params[&lt;span class="sy"&gt;:search&lt;/span&gt;]&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    cond_hash[&lt;span class="sy"&gt;:email&lt;/span&gt;] = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;%&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;params[&lt;span class="sy"&gt;:search&lt;/span&gt;]&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    cond_strings &amp;lt;&amp;lt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;(login ILIKE :login OR email ILIKE :email)&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; params[&lt;span class="sy"&gt;:search_address&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;    cond_hash[&lt;span class="sy"&gt;:address&lt;/span&gt;] = params[&lt;span class="sy"&gt;:search_address&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;    cond_strings &amp;lt;&amp;lt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;(address == :address)&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  conditions = cond_strings.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt; AND &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="iv"&gt;@users&lt;/span&gt; = &lt;span class="co"&gt;User&lt;/span&gt;.all &lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; [ conditions, cond_hash ]&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;It may be safer to use &lt;code&gt;users.login&lt;/code&gt;, &lt;code&gt;users.email&lt;/code&gt;, and
&lt;code&gt;users.address&lt;/code&gt; in the SQL-like strings above.&lt;/p&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Xrll9qsV2Z9C9lF3e0bbH9ozvcw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Xrll9qsV2Z9C9lF3e0bbH9ozvcw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Xrll9qsV2Z9C9lF3e0bbH9ozvcw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Xrll9qsV2Z9C9lF3e0bbH9ozvcw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DqN4EwlIQSA:ga83sNFt1Js:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DqN4EwlIQSA:ga83sNFt1Js:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=DqN4EwlIQSA:ga83sNFt1Js:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DqN4EwlIQSA:ga83sNFt1Js:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=DqN4EwlIQSA:ga83sNFt1Js:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DqN4EwlIQSA:ga83sNFt1Js:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=DqN4EwlIQSA:ga83sNFt1Js:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DqN4EwlIQSA:ga83sNFt1Js:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-02-28:2780</id>
    <published>2009-02-28T05:09:00Z</published>
    <updated>2009-11-05T09:40:32Z</updated>
    <category term="programming" />
    <category term="ruby-on-rails" />
    <link href="http://blog.flame.org/2009/2/28/rails-2-0-and-cool-error-handling" rel="alternate" type="text/html" />
    <title>Rails 2.0 and cool error handling</title>
<content type="html">
            &lt;p&gt;Rails is a great framework, but it has gained something of a bad reputation in terms of error reporting.  Everyone has seen them – those ugly 500-status “we’re sorry, but something has gone wrong” messages.&lt;/p&gt;

&lt;p&gt;In a finished application, this just doesn’t cut it.  It used to be necessary to trap
the error using something like this:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;rescue_action_in_public&lt;/span&gt;(exception)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;case&lt;/span&gt; exception&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;when&lt;/span&gt; ::&lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;RecordNotFound&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class="sy"&gt;:file&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;Rails&lt;/span&gt;.public_path&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;/404.html&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;404&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class="sy"&gt;:file&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;Rails&lt;/span&gt;.public_path&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;/500.html&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;500&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;The problem is that, as error causes begin to pile up, this method gets messy.  Plus,
you might want to render something different in one controller than in another, and
would either need to duplicate all the logic, put controller-specific cases in the ApplicationController, or call ApplicationController::rescue&lt;em&gt;action&lt;/em&gt;in_public directly.&lt;/p&gt;

&lt;p&gt;Enter Rails 2.x error handling.  Drop this in your controller or ApplicationController.&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;rescue_from(&lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;RecordNotFound&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |e|&lt;tt&gt;
&lt;/tt&gt;  render &lt;span class="sy"&gt;:file&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;Rails&lt;/span&gt;.public_path&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;/404_record_not_found.html&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;404&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;By building up a rich set of rescue_from handlers in the ApplicationController, and only
overriding the ones you wish to make per-controller, you have fine-grained control.  And they
work exactly the same in development and testing as they do in production.&lt;/p&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Ch0OOLyee5XDJIZxduTZUyb9NMs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Ch0OOLyee5XDJIZxduTZUyb9NMs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Ch0OOLyee5XDJIZxduTZUyb9NMs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Ch0OOLyee5XDJIZxduTZUyb9NMs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LBYJ8xavjr0:l5LFDm_nSmk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LBYJ8xavjr0:l5LFDm_nSmk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=LBYJ8xavjr0:l5LFDm_nSmk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LBYJ8xavjr0:l5LFDm_nSmk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=LBYJ8xavjr0:l5LFDm_nSmk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LBYJ8xavjr0:l5LFDm_nSmk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=LBYJ8xavjr0:l5LFDm_nSmk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=LBYJ8xavjr0:l5LFDm_nSmk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-02-26:2778</id>
    <published>2009-02-26T06:05:00Z</published>
    <updated>2009-11-05T09:40:48Z</updated>
    <category term="programming" />
    <category term="ruby" />
    <category term="ruby-on-rails" />
    <category term="security" />
    <link href="http://blog.flame.org/2009/2/26/ruby-regular-expression-gotchas" rel="alternate" type="text/html" />
    <title>Ruby Regular Expression Gotchas</title>
<content type="html">
            &lt;p&gt;I love Ruby.  I love Ruby on Rails.  Rarely have I found a language or a framework that just works.&lt;/p&gt;

&lt;p&gt;However, you still have to know the finer details sometimes.  I recently made a model for a DNS zone.  The name in the model is the “front part” of a fully qualified domain name.  For instance, if zone.name = “foo” then I would write the name into my name server’s configuration files as “foo.example.com.”&lt;/p&gt;

&lt;p&gt;Knowing that people were evil, I saw that if a user put a string in like “example.com. NS hackerz-will-someday-rule-the-earth.ru.\nfoo” I would happily write out two strings, one being rather bad.&lt;/p&gt;

&lt;p&gt;Knowing how easy this sort of data validation is in Rails, I made my model look like:&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Zone&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  validates_presence_of &lt;span class="sy"&gt;:name&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  validates_uniqueness_of &lt;span class="sy"&gt;:name&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  validates_format_of &lt;span class="sy"&gt;:name&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sy"&gt;:with&lt;/span&gt; =&amp;gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;^[a-zA-Z0-9&lt;/span&gt;&lt;span class="ch"&gt;\-&lt;/span&gt;&lt;span class="ch"&gt;\_&lt;/span&gt;&lt;span class="ch"&gt;\.&lt;/span&gt;&lt;span class="k"&gt;]+$&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sy"&gt;:message&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;contains invalid characters.&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Happy, I ran a few tests using my browser and found that I could not insert names with spaces, colons, tabs, etc.  Then, several days later, I decided it was time to write tests for this.&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;test_helper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ZoneTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveSupport&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;test_name_with_newline_fails&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    z = &lt;span class="co"&gt;Zone&lt;/span&gt;.new(&lt;span class="sy"&gt;:name&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="k"&gt;zone&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    assert !z.valid?&lt;tt&gt;
&lt;/tt&gt;    assert z.errors.on(&lt;span class="sy"&gt;:name&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;test_name_with_space_fails&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    z = &lt;span class="co"&gt;Zone&lt;/span&gt;.new(&lt;span class="sy"&gt;:name&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;test zone&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    assert !z.valid?&lt;tt&gt;
&lt;/tt&gt;    assert z.errors.on(&lt;span class="sy"&gt;:name&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Imagine my surprise when test&lt;em&gt;name&lt;/em&gt;with&lt;em&gt;space&lt;/em&gt;fails() passed, and the one I was most worried about, test&lt;em&gt;name&lt;/em&gt;with&lt;em&gt;newline&lt;/em&gt;fails(), did not!&lt;/p&gt;

&lt;h2&gt;Not all regular expressions are alike.&lt;/h2&gt;

&lt;p&gt;The problem is in what I thought ^ and $ actually matched.  I thought these meant “match the beginning and ending of the string.”  However, it turns out it means “match the beginning and ending of each line contained in the string,” where lines are divided by newlines.  Ooops.&lt;/p&gt;

&lt;p&gt;Changing ^ into \A and $ into \Z fixed this problem.  Now I’m auditing all the code in this application to see if there are other problems like this.&lt;/p&gt;

&lt;p&gt;This is just one thing to add to an ever-growing security checklist for my Rails work.  It’s also a very typical security hole: programmer error.&lt;/p&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/PurYx4_TBRSGlendWexnmSJK9u0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PurYx4_TBRSGlendWexnmSJK9u0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/PurYx4_TBRSGlendWexnmSJK9u0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PurYx4_TBRSGlendWexnmSJK9u0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DcwlPvSWfrU:bSsks01Nvjg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DcwlPvSWfrU:bSsks01Nvjg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=DcwlPvSWfrU:bSsks01Nvjg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DcwlPvSWfrU:bSsks01Nvjg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=DcwlPvSWfrU:bSsks01Nvjg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DcwlPvSWfrU:bSsks01Nvjg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=DcwlPvSWfrU:bSsks01Nvjg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=DcwlPvSWfrU:bSsks01Nvjg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-02-24:2777</id>
    <published>2009-02-24T18:35:00Z</published>
    <updated>2009-10-19T23:00:25Z</updated>
    <category term="cooking" />
    <category term="sharp-things" />
    <category term="tools" />
    <link href="http://blog.flame.org/2009/2/24/mmm-sharp-knives" rel="alternate" type="text/html" />
    <title>Mmm, sharp knives...</title>
<content type="html">
            &lt;p&gt;&lt;/p&gt;

&lt;p&gt;OK, so I admit it.  I love sharp knives.  Well, more exactly I love my knives to be sharp.&lt;/p&gt;

&lt;p&gt;So, I bought a &lt;a href="http://www.amazon.com/Wusthof-2-Stage-Knife-Sharpener/dp/B0009NMVRI"&gt;Wüsthof knife sharpener&lt;/a&gt;, fully expecting it to suck.&lt;/p&gt;

&lt;p&gt;I am now happily using my knives to chop and cut, not saw, through things again.&lt;/p&gt;

&lt;p&gt;Oh, and my knives are J.A.Henckels professional “S” series.&lt;/p&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/qvYc0olGx2-d8ypSOwjSSmu0OK0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qvYc0olGx2-d8ypSOwjSSmu0OK0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/qvYc0olGx2-d8ypSOwjSSmu0OK0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qvYc0olGx2-d8ypSOwjSSmu0OK0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=VzH52s7FHK8:2vF2yQ9PRU4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=VzH52s7FHK8:2vF2yQ9PRU4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=VzH52s7FHK8:2vF2yQ9PRU4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=VzH52s7FHK8:2vF2yQ9PRU4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=VzH52s7FHK8:2vF2yQ9PRU4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=VzH52s7FHK8:2vF2yQ9PRU4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=VzH52s7FHK8:2vF2yQ9PRU4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=VzH52s7FHK8:2vF2yQ9PRU4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2009-02-21:2776</id>
    <published>2009-02-21T19:09:00Z</published>
    <updated>2009-10-19T21:04:44Z</updated>
    <category term="Programming" />
    <category term="programming" />
    <category term="ruby" />
    <link href="http://blog.flame.org/2009/2/21/string-bitruncate" rel="alternate" type="text/html" />
    <title>String#bitruncate</title>
<content type="html">
            &lt;p&gt;And that’s ‘“bi-truncate” not “bit-uncate”.&lt;/p&gt;

&lt;p&gt;What’s it do?&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;This is a test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.bitruncate(&lt;span class="sy"&gt;:length&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;6&lt;/span&gt;) ==&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Thi...est&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;This is a test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.bitruncate(&lt;span class="sy"&gt;:elength&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;6&lt;/span&gt;) ==&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;...a test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;The default options are { :length =&gt; 30 } which will produce 15 characters from the front and 15 from the end, putting … marks in the middle.&lt;/p&gt;

&lt;p&gt;For rails, I put this in my &lt;code&gt;lib/core_extensions.rb&lt;/code&gt; file.&lt;/p&gt;

&lt;div class="CodeMacro"&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;65&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;69&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;71&lt;tt&gt;
&lt;/tt&gt;72&lt;tt&gt;
&lt;/tt&gt;73&lt;tt&gt;
&lt;/tt&gt;74&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Copyright (c) 2009 Michael Graff.  All rights reserved.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Redistribution and use in source and binary forms, with or&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# without modification, are permitted provided that the following&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# conditions are met:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# 1. Redistributions of source code must retain the above copyright&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#    notice, this list of conditions and the following disclaimer.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# 2. Redistributions in binary form must reproduce the above&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#    copyright notice, this list of conditions and the following&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#    disclaimer in the documentation and/or other materials provided&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#    with the distribution.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# 3. The name of Michael Graff may not be used to endorse or promote&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#    products derived from this software without specific prior&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#    written permission.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# THIS SOFTWARE IS PROVIDED BY Michael Graff ``AS IS'' AND ANY&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL Micahel Graff&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# OF SUCH DAMAGE.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;String&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Truncate from both ends of a string.  The :length parameter, which defaults&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# to 30, will return the first 15 and the last 15 characters from a string&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# if it is longer than 30 characters.  If it is shorter, the entire string&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# is returned.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Another way to specify the front and back portions are with :flength and&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# :elength.  If you specify one of these but not the other then you will&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# not get the missing part.  e.g., :flength =&amp;gt; 10 alone will return only&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# the first 10 charcters of the string.  This is the same as the standard&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# truncate(s, :length =&amp;gt; 10) helper.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# If a :length parameter is provided it will override any other lengths&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# specified.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;bitruncate&lt;/span&gt;(options = {})&lt;tt&gt;
&lt;/tt&gt;    maxlength = options[&lt;span class="sy"&gt;:length&lt;/span&gt;] || &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    flength = options[&lt;span class="sy"&gt;:flength&lt;/span&gt;] || &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    elength = options[&lt;span class="sy"&gt;:elength&lt;/span&gt;] || &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    omission = options[&lt;span class="sy"&gt;:omission&lt;/span&gt;] || &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; maxlength == &lt;span class="i"&gt;0&lt;/span&gt; &amp;amp;&amp;amp; flength == &lt;span class="i"&gt;0&lt;/span&gt; &amp;amp;&amp;amp; elength == &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      maxlength = &lt;span class="i"&gt;30&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; maxlength != &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      flength = maxlength / &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      elength = maxlength / &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;return&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; length &amp;lt;= (flength + elength)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    front = &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    back = &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; flength &amp;gt; &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      front = &lt;span class="pc"&gt;self&lt;/span&gt;[&lt;span class="i"&gt;0&lt;/span&gt;..(flength - &lt;span class="i"&gt;1&lt;/span&gt;)]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; elength &amp;gt; &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      back = &lt;span class="pc"&gt;self&lt;/span&gt;[(length - elength)..(length)]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    front + omission + back&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/JMxkKwzYKw3oCTBl_PK15O5faHA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JMxkKwzYKw3oCTBl_PK15O5faHA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/JMxkKwzYKw3oCTBl_PK15O5faHA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JMxkKwzYKw3oCTBl_PK15O5faHA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=H1PO4-yi4AM:DDoCcy51BSw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=H1PO4-yi4AM:DDoCcy51BSw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=H1PO4-yi4AM:DDoCcy51BSw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=H1PO4-yi4AM:DDoCcy51BSw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=H1PO4-yi4AM:DDoCcy51BSw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=H1PO4-yi4AM:DDoCcy51BSw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=H1PO4-yi4AM:DDoCcy51BSw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=H1PO4-yi4AM:DDoCcy51BSw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
  <entry xml:base="http://blog.flame.org/">
    <author>
      <name>michael</name>
    </author>
    <id>tag:blog.flame.org,2008-05-20:395</id>
    <published>2008-05-20T02:30:00Z</published>
    <updated>2008-05-20T03:15:00Z</updated>
    <category term="Technology" />
    <link href="http://blog.flame.org/2008/5/20/vmware-server-and-xen" rel="alternate" type="text/html" />
    <title>Vmware Server and Xen</title>
<content type="html">
            &lt;p&gt;In the past, I’ve played with VMware (as a “workstation” “server”, not the bare-metal one we have access to now) but was never quite happy with it.  Some of the problems I had might have been that I ran it on windows Vista, not Linux.  However, from a VM point of view, the VM itself should be more or less identical.&lt;/p&gt;

&lt;p&gt;Recently I tried out Xen on the same hardware, but using NetBSD/amd64 as the “host” OS.&lt;/p&gt;

&lt;h3&gt;Hardware&lt;/h3&gt;

&lt;p&gt;The machine is Gateway GM5446E with a dual core Intel Core 2 Duo with 3 GB of ram.  The machine has three SATA hard drives, connected via an Intel AHCI controller running in native AHCI mode.&lt;/p&gt;

&lt;h3&gt;Bare Hardware Baseline&lt;/h3&gt;

&lt;p&gt;I booted a standard NetBSD-current/amd64 kernel and ran some speed tests, which gives a baseline for dom0 and guest OS disk I/O speed tests.  See below.&lt;/p&gt;

&lt;h3&gt;VMware&lt;/h3&gt;

&lt;p&gt;In my VMware install, I used the machine running “Windows Vista Media Center” – it was what came pre-installed on the machine.&lt;/p&gt;

&lt;p&gt;Host OS:  Windows Vista Media Center&lt;/p&gt;

&lt;p&gt;Guest OSs tried:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NetBSD-4.0/i386&lt;/li&gt;
&lt;li&gt;NetBSD-4.0/amd64&lt;/li&gt;
&lt;li&gt;NetBSD-current/i386&lt;/li&gt;
&lt;li&gt;NetBSD-current/amd64&lt;/li&gt;
&lt;li&gt;Linux Ubuntu (server, then-current version)&lt;/li&gt;
&lt;li&gt;Linux Debian (then-current version)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Linux booted in 64-bit mode, but would crap out at some later point with similar issues that NetBSD had.&lt;/p&gt;

&lt;p&gt;One machine, named “nfsd”, was dedicated to serving out home directories and source trees of NetBSD.  The other host OSs mounted /home or /netbsd-src from nfsd.&lt;/p&gt;

&lt;p&gt;Each machine had a “local” disk to store object files from pkgsrc, src, and other OS-related builds.&lt;/p&gt;

&lt;h4&gt;General VMware Problems&lt;/h4&gt;

&lt;p&gt;I could not get netbsd/amd64 (current or 4.0 release) to “self host” – build /usr/src and kernels – reliably.  They would either silently lock up without reason, or they would crash with an odd CPU exception.&lt;/p&gt;

&lt;p&gt;Timekeeping was whacky.  Without running the VMware-supplied (closed source) tools on a client, time was off, and apparently in uncorrectable ways.  Running ntp made things seriously whacky as the time would drift wildly as ntp tried to correct a guest.&lt;/p&gt;

&lt;p&gt;The VMware closed-source tools are only available on a small, limited number of OS types, and then specific versions of many of them.  They do supply a .so that is, in theory, linkable on many versions of Linux, but the install procedure warns loudly of warnings pertaining to compatibility.&lt;/p&gt;

&lt;p&gt;VMware running on anything but Intel chips with synchronized cycle
counters (which most OSs use for high-res timekeeping these days) was a
disaster.&lt;/p&gt;

&lt;h4&gt;VMware Strengths&lt;/h4&gt;

&lt;p&gt;If the problems above are solved, VMware is a true virtual machine architecture that will run any OS without modification.  VMware could run windows guests, right along with unmodified NetBSD, FreeBSD, Linux, and Solaris/x86 guests.&lt;/p&gt;

&lt;h3&gt;Xen&lt;/h3&gt;

&lt;p&gt;I tried Xen 3.1.3.&lt;/p&gt;

&lt;p&gt;Xen is a different architecture than vmware in that it prefers to use “paravirtualization” rather than a full virtual machine.  It has a host machine (called “domain 0” or “dom0”) which attaches to the physical hardware and acts as a conduit between the xen hypervisor and hardware.&lt;/p&gt;

&lt;p&gt;The boot process is that the xen kernel is booted first, which then boots the dom0 host.  Multiple domains can be created, serving different hardware, but in practice this is rarely done.&lt;/p&gt;

&lt;p&gt;Each host OS has a config file, and is stated with “xm create /path/to/file.conf”.  This boots the guest OS and connects a serial console, which can be used with “xm console ”.&lt;/p&gt;

&lt;p&gt;Since the “dom0” is a fully functional OS in its own rights, I have it serve NFS to the guest OSs.&lt;/p&gt;

&lt;p&gt;I created the following guest OSs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NetBSD-current/i386&lt;/li&gt;
&lt;li&gt;NetBSD-current/amd64&lt;/li&gt;
&lt;li&gt;Windows XP Pro (32-bit)&lt;/li&gt;
&lt;li&gt;Windows Server 2003 (32-bit)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes, I managed to install Windows XP Pro and Server 2003.  They run in a “vnc” console, and for all practical purposes looks like windows.  This is using Xen’s “hvm” – which is a full hardware emulated virtual machine, and allows running unmodified guest OSs.  People have Vista running in a virual machine under Xen, but I do not have “real” Vista install media or licenses, just the ones that came with and is tied to my hardware.&lt;/p&gt;

&lt;p&gt;Xen also supports both realtime and offline “migration.”  As I have only one machine of the same type, I have not yet read up on how this works.  The basics:  A realtime copy is made of the guest’s ram, device state, and other data.  It is transmitted to the new destination, and synced up until a very small switchover time can be used to swap where that guest is running.  Xen claims 100 ms switchover time is possible, but there are restrictions:  The disks are NOT migrated, so must reside on a shared volume.  The physical network each dom0 is on is also shared, in order to avoid disruption of TCP connections.  I also believe fairly identical CPU and dom0 operating systems should be used.&lt;/p&gt;

&lt;p&gt;Offline migration involves shutting the guest down, copying the disks over, and restarting it on a new dom0.  This will, of course, interrupt service.&lt;/p&gt;

&lt;h4&gt;Xen Problems&lt;/h4&gt;

&lt;p&gt;It is difficult to configure for the fist time.  The documentation is… lacking.  It is also only as solid as the host OS is, but vmware has the same issue in “server” or “workstation” incarnations.&lt;/p&gt;

&lt;p&gt;Xen is also very, very “linux” specific in documentation and examples. Most of these can be translated – I certainly did so easily enough – but this is being corrected in their documentation as more OSs are able to boot as dom0.&lt;/p&gt;

&lt;h4&gt;Xen Strengths&lt;/h4&gt;

&lt;p&gt;Timekeeping in Xen, since it is paravirtualized, is almost perfect.  Small drifts will occur without running ntp, but all guests (and the host) can run ntp and obtain sanity.&lt;/p&gt;

&lt;p&gt;It also appears that all guests and the dom0 “drift” identically, so this is probably related to hardware timekeeping issues.  The measured drift of an uncorrected NetBSD guest was 4 seconds in two weeks.  ntp correction kept the others in perfect real-world sync.&lt;/p&gt;

&lt;p&gt;It is as free as you want it to be.  Support and commercial versions exist, but the free stuff works amazingly well.&lt;/p&gt;

&lt;h3&gt;Performance&lt;/h3&gt;

&lt;p&gt;On Xen, all tests were performed with the domu’s running but idle, and no hvm guests running (windows is just too unpredictable.)  On VMware, only one VM was active at once, and the Vista host was as idle as it could be made.&lt;/p&gt;

&lt;p&gt;I measured three main things here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Boot speed:  How fast a kernel gets from loading to the first /etc/rc message.&lt;/li&gt;
&lt;li&gt;Disk speed:  read/write speed.&lt;/li&gt;
&lt;li&gt;CPU Performance:&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Boot Speed&lt;/h4&gt;

&lt;p&gt;The dom0 boots as fast as any other kernel boots; it must probe the hardware, wait for hardware to change state, etc.  No measured difference between a standard NetBSD-current/amd64 kernel and the dom0 kernel.&lt;/p&gt;

&lt;p&gt;The domUs (guests) boot so fast it is nearly impossible to measure. This is because the devices they have access to are known – all are on a virtual bus, and are directly enumerable, so there is no need to probe for devices, wait for them to change state, or time out when not present.  As best I can measure, just under 2 seconds is a fair estimate.&lt;/p&gt;

&lt;p&gt;The hvm (windows) guest seems to be about as fast as windows is.  I did not analyze this one much.&lt;/p&gt;

&lt;p&gt;On VMware, the host OSs boot at about the same speed as a “real” machine boots unless a custom kernel is built with just “known present” devices.  Even then, boot times are 15-20 seconds.&lt;/p&gt;

&lt;h4&gt;Disk Speed&lt;/h4&gt;

&lt;p&gt;In all host/dom0 tests, “iozone” version 3.263 was used, with a 1 GB file on the same disk.  Each test was performed only once; for real comparison data we’d want to run it more than once, but this is just a first-pass test.&lt;/p&gt;

&lt;p&gt;For native NetBSD/amd64, I had to increase the file size to 4 GB to avoid the cache, as the machine has 3 GB of ram.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wd0 is a 500 GB SATA 3.0Gb/sec disk.&lt;/li&gt;
&lt;li&gt;wd1 is present but unused.&lt;/li&gt;
&lt;li&gt;wd2 is a 320 GB SATA 1.5Gb/sec disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All are on different channels of an Intel AHCI controller running in native SATA mode.&lt;/p&gt;

&lt;p&gt;For the Xen tests, all disks were mounted as files on the dom0 host. From dom0’s point of view, the file is mounted on a “vnd” virtual disk, and that virtual disk is exported to the host.&lt;/p&gt;

&lt;p&gt;For the VMware test, all disks were mounted as files in the Windows filesystem.&lt;/p&gt;

&lt;table&gt;
  &lt;tr&gt;
    OS
    Disk
    Block Size
    Read
    Write
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/amd64 native&lt;/td&gt;
    &lt;td&gt;wd0&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;60762&lt;/td&gt;
    &lt;td&gt;59949&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;60545&lt;/td&gt;
    &lt;td&gt;60141&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;wd2&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;78342&lt;/td&gt;
    &lt;td&gt;76342&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;78311&lt;/td&gt;
    &lt;td&gt;75252&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/amd64 dom0&lt;/td&gt;
    &lt;td&gt;wd0&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;60641&lt;/td&gt;
    &lt;td&gt;60109&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;60459&lt;/td&gt;
    &lt;td&gt;61919&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;wd2&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;80258&lt;/td&gt;
    &lt;td&gt;79102&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;80187&lt;/td&gt;
    &lt;td&gt;80295&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/amd64 domu&lt;/td&gt;
    &lt;td&gt;wd0&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;51205&lt;/td&gt;
    &lt;td&gt;24004&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;51714&lt;/td&gt;
    &lt;td&gt;27971&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;wd2&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;77990&lt;/td&gt;
    &lt;td&gt;23997&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;77282&lt;/td&gt;
    &lt;td&gt;22496&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/i386 domu&lt;/td&gt;
    &lt;td&gt;wd0&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;41730&lt;/td&gt;
    &lt;td&gt;25012&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;42008&lt;/td&gt;
    &lt;td&gt;24543&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;wd2&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;66401&lt;/td&gt;
    &lt;td&gt;26048&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;66201&lt;/td&gt;
    &lt;td&gt;28910&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/i386 vmware&lt;/td&gt;
    &lt;td&gt;wd0&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;25014&lt;/td&gt;
    &lt;td&gt;13912&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;25417&lt;/td&gt;
    &lt;td&gt;13771&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;wd2&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;38831&lt;/td&gt;
    &lt;td&gt;16100&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;38994&lt;/td&gt;
    &lt;td&gt;16332&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;I also repeated one test with a raw, physical partition mounted in the netbsd-current/amd64 domU, which bypasses the “double filesystem” issue:&lt;/p&gt;

&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/amd64 domu&lt;/td&gt;
    &lt;td&gt;wd2&lt;/td&gt;
    &lt;td&gt;8192&lt;/td&gt;
    &lt;td&gt;79915&lt;/td&gt;
    &lt;td&gt;76992&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Physical mount&lt;/td&gt;
    &lt;td&gt;wd2&lt;/td&gt;
    &lt;td&gt;16384&lt;/td&gt;
    &lt;td&gt;79744&lt;/td&gt;
     &lt;td&gt;77102&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;h4&gt;CPU Performance&lt;/h4&gt;

&lt;p&gt;Each CPU speed test was run with:  Dhrystone Benchmark, Version 2.1 (Language: C)  Program compiled without ‘register’ attribute.&lt;/p&gt;

&lt;p&gt;I used an iteration count of 1,000,000,000 for each test.&lt;/p&gt;

&lt;table&gt;
  &lt;tr&gt;
    Operating System
    Dhrystones per second
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/amd64 native&lt;/td&gt;
    &lt;td&gt;11,013,216&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/amd64 dom0&lt;/td&gt;
    &lt;td&gt;10,365,917&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/amd64 domu&lt;/td&gt;
    &lt;td&gt;11,130,899&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/i386 domu&lt;/td&gt;
    &lt;td&gt;4,935,347&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;netbsd-current/i386 vmware&lt;/td&gt;
    &lt;td&gt;5,012,123&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Just for grins, I ran the following tests, one dhrystone on one guest and another on a different one.  Since each guest is uniprocessor in my configuration, I did not run two benchmarks on the same host.&lt;/p&gt;

&lt;table&gt;
  &lt;tr&gt;
    Operating Systems
    Speed 1
    Speed 2
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Running both domu/i386 and domu/amd64&lt;/td&gt;
    &lt;td&gt;4916421.0&lt;/td&gt;
    &lt;td&gt;11135857.0&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Running both dom0/amd64 and domu/amd64&lt;/td&gt;
    &lt;td&gt;10298661.0&lt;/td&gt;
    &lt;td&gt;11135857.0&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Running both dom0/amd64 and domu/i386&lt;/td&gt;
    &lt;td&gt;10373444.0&lt;/td&gt;
    &lt;td&gt;4921260.0&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;h3&gt;Conclusions&lt;/h3&gt;

&lt;p&gt;Xen is production ready.&lt;/p&gt;

&lt;p&gt;When the host OS can be modified, much higher performance numbers are obtained vs. the low-end VMware server I ran.&lt;/p&gt;

&lt;p&gt;While it might be extremely tempting to build one guest that does one very specific function, this probably does not scale:  memory is pre-allocated and dedicated to a guest, and while some swapping is allowed, it will slow the guest at seemingly random times; disk can be overcommitted, but the OS sees failure to allocate a block as a hardware failure; the more hosts, the more maintenance costs are present: maintaining packages on each guest, upgrading, etc.&lt;/p&gt;

&lt;p&gt;VMware “hmx” or whatever the name of the run-on-bare-metal product should be tested.&lt;/p&gt;

&lt;p&gt;I’d love to install Xen on a huge machine with lots of ram and many, many CPUs as a test.  Would someone like to ship me a 4 CPU quad core with 64 GB?&lt;/p&gt;
          
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/CsNEjz7gokNi_c_rCyCTQl8ZcpE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CsNEjz7gokNi_c_rCyCTQl8ZcpE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/CsNEjz7gokNi_c_rCyCTQl8ZcpE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CsNEjz7gokNi_c_rCyCTQl8ZcpE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=bEPTKsBHzSc:g4YmsqTqlGk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=bEPTKsBHzSc:g4YmsqTqlGk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=bEPTKsBHzSc:g4YmsqTqlGk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=bEPTKsBHzSc:g4YmsqTqlGk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=bEPTKsBHzSc:g4YmsqTqlGk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=bEPTKsBHzSc:g4YmsqTqlGk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?i=bEPTKsBHzSc:g4YmsqTqlGk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flame_org?a=bEPTKsBHzSc:g4YmsqTqlGk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flame_org?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>  </entry>
</feed>
