<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description>rambling about the business of software development</description><title>blog.petersen.vg</title><generator>Tumblr (3.0; @cpetersen)</generator><link>http://blog.petersen.vg/</link><item><title>Life Scientists and Social Media</title><description>&lt;p&gt;I just got an email from &lt;a href="http://www.gene2drug.com/"&gt;BioInformatics LLC&lt;/a&gt; advertising their new &lt;a href="http://lifesciencesocialmedia.com/?dnum=11"&gt;new report, &lt;i&gt;The New Collaboration: Social Media and the Life Science Opportunity&lt;/i&gt;&lt;/a&gt;. It is a great report, and is closely related to what we are doing here at the Assay Depot. A few things jumped out at me while reading it.&lt;/p&gt;

&lt;h3&gt;Product Information&lt;/h3&gt;

&lt;p&gt;According to the report, third party online portals are the least trusted source of product information, while company websites are the most trusted. I can understand that, when I’m looking for a computer, I check out Apple’s website before I check Amazon. Now I wouldn’t characterize Amazon (or the Assay Depot for that matter) as online portals, but we are both marketplaces that act as third parties in transactions between customers and companies.&lt;/p&gt;

&lt;p&gt;To mitigate this trust issue, and to make things as easy as possible for our users, wherever possible, we will link the products on our website to the companies own web page about that product.&lt;/p&gt;

&lt;h3&gt;Objective Feedback&lt;/h3&gt;

&lt;p&gt;If social media isn’t the most trusted source of product information, it is the most trusted source for objective feedback. 45% of respondents said so. This complements our strategy of providing peer reviews of the services and products we offer.&lt;/p&gt;

&lt;h3&gt;Influence on Purchasing Decision&lt;/h3&gt;

&lt;p&gt;Section 8 of the report touches on how social media has influenced purchasing decisions. Interestingly it seems that social media has made them more informed regarding their purchasing decisions, but it hasn’t made purchasing faster, or changed the purchasing process.&lt;/p&gt;

&lt;p&gt;I strongly believe this is going to change. Currently their are no tools that combine social media and purchasing, it is a bit of a disjointed process. People search for information (often using social media) about what they are purchasing. Then they go back to the old system of calling to negotiate prices and legal contracts and faxing purchase orders back and forth. I’m trying not to make this post too much of a “sales pitch”, but that is what we are trying to do. Make the purchasing of research services easy by combining e-commerce with customer reviews, links to the actual supplier, and eventually more community and social media capabilities. We just want to make scientists lives easier.&lt;/p&gt;

&lt;h3&gt;Finally…&lt;/h3&gt;

&lt;p&gt;There are two more quotes in the report that I found interesting:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Social Media appeals to the fundamental values of science - communication
  contribution and collaborating.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I couldn’t agree more…&lt;/p&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In an environment where the average scientist buys products from a dozen or more 
  vendors, making it easier for them to open a dialog with you can can only strengthen
  their loyalty.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;right on again…&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237863335</link><guid>http://blog.petersen.vg/post/237863335</guid><pubDate>Thu, 27 Mar 2008 00:00:00 -0700</pubDate></item><item><title>Create Your Own EC2 Image</title><description>&lt;p&gt;We have been working day and night preparing for our beta launch in April, which is just one of the many excuses I have for not posting in so long. Part of preparing for that launch is setting up the platform that we are going to deploy to. For numerous reasons, we’ve chosen &lt;a href="http://aws.amazon.com/ec2"&gt;Amazon’s EC2&lt;/a&gt; for our production system. EC2 is a great service, and getting up and running with it isn’t hard at all. However, when it comes to creating your own image, I ran into some barriers, I thought I’d share how we overcame them. I hope you find it useful.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;(Side note: Deepak Singh over at business|byte|genes|molecules blogged about an &lt;a href="http://mndoci.com/blog/2008/03/03/jeff-barr-on-amazon-web-services/"&gt;interview with Jeff Barr, an Amazon Web Services Evangelist&lt;/a&gt; which I found interesting).&lt;/i&gt;&lt;/p&gt;

&lt;h3&gt;Assumptions&lt;/h3&gt;

&lt;p&gt;For the purpose of this post, I am assuming your have a working EC2 account, your rsa key is installed properly, and have the basic tools working, ie:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
ec2din
ec2dim
]]&gt;&lt;/script&gt;&lt;a href="http://docs.amazonwebservices.com/AWSEC2/2007-08-29/GettingStartedGuide/?ref=get-started"&gt;Here is a good tutorial on how to get up and running.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Starting with EC2 on Rails&lt;/h3&gt;

&lt;p&gt;In my search for a deployment platform, I came across the &lt;a href="http://ec2onrails.rubyforge.org/"&gt;EC2 on Rails project&lt;/a&gt;. It has a bunch of nice things built in, but for various reasons, their standard image wouldn’t work for us. Nevertheless, we decided to use their image as our starting point. You can get their current AMI’s by running the following command (assuming you have the ec2onrails gem installed):
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
cap ec2onrails:ami_ids
]]&gt;&lt;/script&gt;
Currently, the 32-bit AMI is ami-e620c58f. Next we start an instance and login:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
ec2run ami-e620c58f --instance-type m1.small -k gsg-keypair
ec2din
ssh -i ~/.ssh/id_rsa-gsg-keypair admin@ec2-XXX-XXX-XXX-XXX.compute-1.amazonaws.com
]]&gt;&lt;/script&gt;
In order to rebundle the image, you will need your pk and cert on the server. I store mine in the /mnt/aws-config directory, so lets create that directory. From &lt;i&gt;the server&lt;/i&gt; run:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
sudo mkdir /mnt/aws-config
sudo chown admin.admin /mnt/aws-config
]]&gt;&lt;/script&gt;
Next, upload the files from your &lt;i&gt;local computer&lt;/i&gt;
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
scp -i ~/.ssh/id_rsa-gsg-keypair ~/.ec2/*.pem admin@ec2-XXX-XXX-XXX-XXX.compute-1.amazonaws.com:/mnt/aws-config
]]&gt;&lt;/script&gt;
To make things easier in the coming steps, I add the pk and cert filenames to my environment. On the server, edit your .profile to include the following lines (I add them before ./usr/local/ec2onrails/config, but I’m not sure it matters):
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
KEY_FILE_NAME=pk-[your pk filename].pem
CERT_FILE_NAME=cert-[your cert filename].pem
AWS_ACCOUNT_ID=[your account id]
]]&gt;&lt;/script&gt;
Next we have to prepare to rebundle. The EC2 on Rails image comes with a rebundle script. However, I was never able to make it work, so I broke out the necessary steps here:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
curl http://s3.amazonaws.com/ec2-downloads/ec2-api-tools.zip &gt; /tmp/ec2-api-tools.zip
sudo unzip /tmp/ec2-api-tools.zip -d /usr/local
sudo chmod -R go-w /usr/local/ec2-api-tools*
sudo ln -sf /usr/local/ec2-api-tools-* /usr/local/ec2-api-tools
sudo aptitude install -y sun-java6-jre
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h3&gt;Insert your configuration here&lt;/h3&gt;

&lt;p&gt;At this point, you are ready to configure the sever however you see fit. For us it was installing some support software, etc. Although you may want to complete the tutorial first and make sure you can rebundle properly before investing too much time!&lt;/p&gt;

&lt;h3&gt;The /mnt directory&lt;/h3&gt;

&lt;p&gt;So at this point you have your perfect server, all you need to do is store the image so you can preserve it forever. There is one last item to deal with, the mnt directory. Whenever you ec2kill an instance and start a new one from the image, the /mnt directory get cleared, which makes sense. You need some place to store all the transient data (like logfiles and deployment versions) that don’t belong in the image. However, somethings in there (like directories for log files) need to exists for the image to start properly. So what’s a person to do? Well I decided on a scheme where I tar up a skeleton on the mnt directory, and wrote an install script for it. That way when I start a new instance, I log in, run ./install.sh and I’m up and running.&lt;/p&gt;

&lt;h3&gt;Create your mnt directory skeleton&lt;/h3&gt;

&lt;p&gt;Next I copy the /mnt directory to my home directory and get it just the way I like it (at least get rid of the openssh_id.pub and lost+found).
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
sudo cp -R /mnt ~
cd ~/mnt
sudo rm lost+found
sudo rm openssh_id.pub
]]&gt;&lt;/script&gt;
Now tar up your directory:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
sudo tar cvfz ~/mnt.tgz ~/mnt
]]&gt;&lt;/script&gt;
Next we need to write the install script. Mine looks something like (don’t forget to make it executable):
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
#!/bin/sh

sudo tar xvfz mnt.tgz
cd mnt
sudo chown app.app -R app
sudo chown mysql.mysql -R mysql_data
cd log
sudo chown syslog.adm *
sudo chown www-data.www-data -R apache2
sudo chown mysql.mysql -R mysql
sudo chown root.root -R fsck
cd ..
sudo mv * /mnt

sudo /etc/init.d/mysql start
sudo /etc/init.d/apache2 start
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;That’s it, your instance is now configured and ready, now for the good stuff.&lt;/p&gt;

&lt;h3&gt;Finally, its time to bundle&lt;/h3&gt;

&lt;p&gt;First we create the image:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
sudo ec2-bundle-vol -u $AWS_ACCOUNT_ID -c /mnt/aws-config/$CERT_FILE_NAME -k /mnt/aws-config/$KEY_FILE_NAME
]]&gt;&lt;/script&gt;
Next, we need to upload the image to S3, (you must create an S3 bucket prior to this step):
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
ec2-upload-bundle -b [your-bucket] -m /tmp/image.manifest.xml -a [your access key] -s [your secret access key]
]]&gt;&lt;/script&gt;
The final step is to register your image with Amazon and get your AMI:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
ec2-register -K /mnt/aws-config/$KEY_FILE_NAME -C /mnt/aws-config/$CERT_FILE_NAME [your-bucket]/image.manifest.xml
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h3&gt;Putting it all together (AKA, the test)&lt;/h3&gt;

&lt;p&gt;So you’ve now created your bundle. The true test is, can you start it, login, run your install script, and have a fully functional server. From your &lt;i&gt;local machine&lt;/i&gt;:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
ec2dim # You should see your new AMI
ec2run [AMI from previous command] --instance-type m1.small -k gsg-keypair
ec2din
ssh -i ~/.ssh/id_rsa-gsg-keypair admin@ec2-XXX-XXX-XXX-XXX.compute-1.amazonaws.com
]]&gt;&lt;/script&gt;
Now run the install script from the &lt;i&gt;remote machine&lt;/i&gt;:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
./install.sh
]]&gt;&lt;/script&gt;
You should now have a fully functional server.&lt;/p&gt;

&lt;h3&gt;Bonus&lt;/h3&gt;

&lt;p&gt;I created two aliases on my local machine that i found very helpful, maybe you will too:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
alias ec2ssh="ssh -i ~/.ssh/id_rsa-gsg-keypair"
alias ec2scp="scp -i ~/.ssh/id_rsa-gsg-keypair"
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h3&gt;Coming Attractions&lt;/h3&gt;

&lt;p&gt;Like I said earlier, we are launching our beta in April, so expect to see a lot of changes to the site shortly. One of those changes will include moving from WordPress to &lt;a href="http://mephistoblog.com/"&gt;Mephisto&lt;/a&gt;. if your feed reader resets, I apologize in advance.&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237859581</link><guid>http://blog.petersen.vg/post/237859581</guid><pubDate>Mon, 10 Mar 2008 00:00:00 -0700</pubDate></item><item><title>Geocoding in Ruby</title><description>&lt;h2&gt;The Geocode Module&lt;/h2&gt;

&lt;p&gt;Have you ever needed to turn a partial address into a full one? Have you ever wanted to get the latitude or longitude for a particular address? Maybe you want to plot addresses on a Google Map, or maybe, like a colleague of mine, you find it redundant to ask for city, state AND zip when creating a form. If any of these apply to you, you might be interested in geocoding.&lt;/p&gt;

&lt;p&gt;Geocoding is the process of turning an address (or in some cases a partial address) into latitude and longitude. Often times during the process you get more information about the address. For instance if you geocode “1000 5th Ave, 92101”, not only with you get the latitude and longitude (32.715714, -117.160158), you also find out that it’s in San Diego, CA.&lt;/p&gt;

&lt;p&gt;There are many services out there that will geocode addresses for you. For instance the &lt;a href="http://cartographer.rubyforge.org/"&gt;Cartographer plugin&lt;/a&gt; provides a couple of nice Geocoding modules. One for &lt;a href="http://geocoder.us/"&gt;Geocoder.us&lt;/a&gt; and one for &lt;a href="http://www.ontok.com/geocode/"&gt;Ontok&lt;/a&gt;. Both are great alternatives for geocoding. However, I wanted to use Google, and I didn’t want to use the full &lt;a href="http://cartographer.rubyforge.org/"&gt;Cartographer plugin&lt;/a&gt;. So I wrote the following module that allows you to geocode addresses in Ruby using Google’s service.&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
module Geocode
  def geocode(input)

    uri = "/maps/geo?q=#{input.gsub(/\s/, "%20")}&amp;output=xml&amp;key=&lt;your google map's key&gt;"
    res = Net::HTTP.start("maps.google.com") {|http|
      http.get(uri)
    }

    begin
      doc = REXML::Document.new(res.body)

      if doc &amp;&amp; doc.root
        coordinateNode = doc.root.get_elements("//coordinates").first
        addressNode = doc.root.get_elements("//ThoroughfareName").first
        stateNode = doc.root.get_elements("//AdministrativeAreaName").first
        cityNode = doc.root.get_elements("//SubAdministrativeAreaName").first
        cityNode = doc.root.get_elements("//LocalityName").first unless cityNode
        zipcodeNode = doc.root.get_elements("//PostalCodeNumber").first
  
        longitude,latitude = coordinateNode.text.split(",") if coordinateNode
        address = addressNode.text if addressNode
        state = stateNode.text if stateNode
        city = cityNode.text if cityNode
        zipcode = zipcodeNode.text if zipcodeNode

        return {
          :latitude =&gt; latitude.to_f,
          :longitude =&gt; longitude.to_f,
          :description =&gt; nil,
          :original_address =&gt; input,
          :score =&gt; nil,
          :street_number =&gt; nil,
          :prefix =&gt; nil,
          :street_name =&gt; nil,
          :street_type =&gt; nil,
          :suffix =&gt; nil,
          :address1 =&gt; address,
          :city =&gt; city,
          :state =&gt; state,
          :zipcode =&gt; zipcode
        }
      end
    rescue
      # Do something useful...
    end
    # if nothing has returned yet, then return nil
    return nil
  end
end
]]&gt;&lt;/script&gt;&lt;p&gt;You’ll notice a few returned items that are always nil, that’s because it is a drop in replacement for the Geocoding modules in Cartographer. So even if you use the Cartographer plugin, you can still use this module.&lt;/p&gt;

&lt;h2&gt;Using the Geocode Module&lt;/h2&gt;

&lt;p&gt;To use the Geocode module, simply include it, and pass it an address or partial address.
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
include Geocode
result = geocode("92121")
puts "#{result[:address1]}, #{result[:city]}, #{result[:state]}, #{result[:zipcode]}"
puts "#{result[:latitude]}, #{result[:longitude]}"
]]&gt;&lt;/script&gt;&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237850819</link><guid>http://blog.petersen.vg/post/237850819</guid><pubDate>Wed, 21 Nov 2007 00:00:00 -0800</pubDate></item><item><title>Stats on Rails</title><description>&lt;h2&gt;The Stats Module&lt;/h2&gt;

&lt;p&gt;Have you ever had an array of numbers and needed to know if one was a statistical outlier? Ever needed the standard deviation of those numbers? Well, I was recently working on an app, where I did. I packaged up the functionality as the following Module.
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
module Stats
  def mean_stdev_n(numbers)
    sum = 0
    sumsq = 0
    n = 0
    numbers.each do |num|
      if num
        sum += num
        sumsq += (num*num)
        n = n+1
      end
    end

    if n==0
      return nil,nil,0
    else
      mean = sum/n
      stddev = Math::sqrt(sumsq/n - mean * mean)
      return mean, stddev, n
    end
  end
 
  def outlier?(value, mean, stddev, n)
    grubbs = grubbs_outlier_test(value, mean, stddev)
    z = critical_z(n)
    return grubbs &gt; z
  end
 
  def grubbs_outlier_test(value, mean, stddev)
    ((mean - value)/stddev).abs
  end
 
  def critical_z(n)
    case(n)
    when 3
      1.15
    when 4
      1.48
    when 5
      1.71
    when 6
      1.89
    when 7
      2.02
    when 8
      2.13
    when 9
      2.21
    when 10
      2.29
    when 11
      2.34
    when 12
      2.41
    when 13
      2.46
    when 14
      2.51
    when 15
      2.55
    when 16
      2.59
    when 17
      2.62
    when 18
      2.65
    when 19
      2.68
    when 20
      2.71
    when 21
      2.73
    when 22
      2.76
    when 23
      2.78
    when 24
      2.80
    when 25
      2.82
    when 26
      2.84
    when 27
      2.86
    when 28
      2.88
    when 29
      2.89
    when 30
      2.91
    when 31
      2.92
    when 32
      2.94
    when 33
      2.95
    when 34
      2.97
    when 35
      2.98
    when 36
      2.99
    when 37
      3.00
    when 38
      3.01
    when 39
      3.03
    when 40..49
      3.04
    when 50..59
      3.13
    when 60..69
      3.20
    when 70..79
      3.26
    when 80..89
      3.31
    when 90..99
      3.35
    when 100..109
      3.38
    when 110..119
      3.42
    when 120..129
      3.44
    when 130..139
      3.47
    else
      3.49
    end
  end
end
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;If you are unfamiliar with the grubbs test… well you’re not alone, neither was I. I found &lt;a href="http://www.graphpad.com/articles/outlier.htm"&gt;this page&lt;/a&gt; to be especially helpful.&lt;/p&gt;

&lt;h2&gt;Usage&lt;/h2&gt;

&lt;p&gt;To use the module, simply include it, calculate mean, stddev and n, then use the outlier? funtion.
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
include(Stats)
numbers = # some array of numbers
mean, stddev, n = mean_stdev_n(numbers)
if outlier?(5, mean, stddev, n)
  puts "5 is an outlier"
else
  puts "5 is not an outlier"
end
]]&gt;&lt;/script&gt;&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237849048</link><guid>http://blog.petersen.vg/post/237849048</guid><pubDate>Sun, 18 Nov 2007 00:00:00 -0800</pubDate></item><item><title>Instantly add wiki functionality to your Rails app</title><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Its been a while since we’ve posted. That’s because we’ve been busy preparing for our beta launch. Toward that end, we’ve hired Rob Kaufman of &lt;a href="http://www.notch8.com"&gt;Notch8&lt;/a&gt; to strengthen our development effort. This post is about one of the plugins that has come out of that work, &lt;a href="http://code.google.com/p/wiki-column/"&gt;wiki_column&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://code.google.com/p/wiki-column/"&gt;wiki_column&lt;/a&gt;, allows you to add wiki functionality to any (textual) attribute of any model. Wiki links in that text will then refer to the model that you define as your wiki, the wiki model defaults to WikiPage. Any attribute you define as a wiki_column, will also get &lt;a href="http://textism.com/tools/textile/"&gt;textile&lt;/a&gt; formatting automatically, for this reason &lt;a href="http://code.google.com/p/wiki-column/"&gt;wiki_column&lt;/a&gt; requires the &lt;a href="http://whytheluckystiff.net/ruby/redcloth/"&gt;RedCloth&lt;/a&gt; gem.&lt;/p&gt;

&lt;h2&gt;How to install it&lt;/h2&gt;

&lt;p&gt;Let’s assume you want to add a wiki to your Rails app (why else would you be here?). Let’s also assume that you have a Product model that has a description attribute that would like wiki enabled. Given those assumptions, we’ll start at the beginning. First install the &lt;a href="http://whytheluckystiff.net/ruby/redcloth/"&gt;RedCloth&lt;/a&gt; gem:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo gem install RedCloth
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Next install the &lt;a href="http://code.google.com/p/wiki-column/"&gt;wiki_column&lt;/a&gt; plugin.
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
./script/plugin install http://wiki-column.googlecode.com/svn/trunk/wiki_column
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Next generate your WikiPage model and your Product model.
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
./script/generate scaffold_resource WikiPage slug:string body:text created_at:datetime updated_at:datetime
./script/generate scaffold_resource Product name:string description:text price:decimal created_at:datetime updated_at:datetime
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Don’t forget to migrate.
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
rake db:migrate
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Now we add the wiki functionality to your models, and validate that our slugs are unique. In your WikiPage model, add the following lines.
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
validates_uniqueness_of :slug
wiki_column :body
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Similarly, add the following line to your Product model.
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
wiki_column :description
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Next we need to change the show views. &lt;a href="http://code.google.com/p/wiki-column/"&gt;wiki_column&lt;/a&gt; adds a new method to your model called wiki_#{column}. So in your show.rhtml for WikiPage, change:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
&lt;%=h @wiki_page.body %&gt;
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;to
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
&lt;%= @wiki_page.wiki_body %&gt;
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Do the same for Product descriptions so they will link directly to your new wiki.&lt;/p&gt;

&lt;p&gt;Lastly, want our url to make sense to users. Our scaffold resource is called WikiPage, because we are adding/editing and viewing individual pages. However, to a user viewing our site, the following url would make more sense.
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
http://company.com/wiki/1
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Thus, the last step is to add a new resource to the routes.rb file
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
map.resources :wiki, :controller =&gt; 'wiki_pages'
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;That’s it, you should now have a functioning wiki and your products should integrate with it nicely.&lt;/p&gt;

&lt;h2&gt;How to use it&lt;/h2&gt;

&lt;p&gt;Now that your application is wiki enabled, how do you make use of this new found functionality?&lt;/p&gt;

&lt;p&gt;You already know you can use the full range of &lt;a href="http://textism.com/tools/textile/"&gt;textile&lt;/a&gt; commands, &lt;a href="http://hobix.com/textile/"&gt;they do a better job of explaining their syntax than I could.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What &lt;a href="http://code.google.com/p/wiki-column/"&gt;wiki_column&lt;/a&gt; adds is the ability to specify wiki words. Those wiki words should be surrounded by square braces. For example, if you wanted to link to a page with the slug ProductionInformation, your code would look like 
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
[ProductInformation]
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We designed &lt;a href="http://code.google.com/p/wiki-column/"&gt;wiki_column&lt;/a&gt; to be easily integrated into new or existing Ruby on Rails applications, as well as to be easy for your customers to use. As alway your comments, critiques, suggestions, and especially patches are welcome. Please post below.&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237845544</link><guid>http://blog.petersen.vg/post/237845544</guid><pubDate>Sun, 07 Oct 2007 00:00:00 -0700</pubDate></item><item><title>ActiveCalendar Update, Validators and added Flexibility</title><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;We posted the &lt;a href="http://code.google.com/p/activecalendar/"&gt;ActiveCalendar&lt;/a&gt; project a couple of months ago (incidentally it was the first post on this blog as well). Since then, the response has been great. It seems like people are actually using it. For that, thank you, we’re very happy people have found this code useful. Some of you have been kind enough to post comments and questions. In response, we’ve been making incremental changes (hopefully improvements) to the code base. Rather than continue to detail them in the comments of &lt;a href="http://developer.assaydepot.com/?p=5"&gt;the original post&lt;/a&gt;, I decided roll them up and describe them here.&lt;/p&gt;

&lt;h2&gt;validates_as_date&lt;/h2&gt;

&lt;p&gt;The plugin originally left the text fields uneditable, so the only way to edit the date was through the calendar. It became clear that this wasn’t ideal. Not only is it sometimes quicker to type your date out, as Art pointed out, once you selected a date, there was no way to blank it out. To alleviate this problem, we simply made the text fields editable. However, this create another potential problem, invalid dates. This is where validates_as_date was born.&lt;/p&gt;

&lt;p&gt;To validate your dates, add the following code to your model:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
  validates_as_date :date_field
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;That’s it! validates_as_date is a slight adaptation of the code snippet by Stuart Rackham found &lt;a href="http://snippets.dzone.com/posts/show/1548"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Add Dynarch Parameters&lt;/h2&gt;

&lt;p&gt;The &lt;a href="http://www.dynarch.com"&gt;Dynarch&lt;/a&gt; &lt;a href="http://www.dynarch.com/projects/calendar/"&gt;Calendar&lt;/a&gt; is very flexible… up until recently our plugin was not. Many of you wanted to access the flexibility, but were unable to. We recently checked in some code that allows you to pass options to the date_select and datetime_select methods and have the options passed into Dynarch’s Calendar.&lt;/p&gt;

&lt;p&gt;For instance, Mike Figley wanted to use the date status function, which allows you to specify some dates as special. Now you can, so using the example from Dynarch’s documentation, you could now use ActiveCalendar to highlight certain dates
&lt;script type="syntaxhighlighter" class="brush: html"&gt;&lt;![CDATA[
&lt;style&gt;
.special { background-color: #000; color: #fff; }


&lt;script&gt;
// this table holds your special days, so that we can automatize
// things a bit:
var SPECIAL_DAYS = {
        0 : [ 13, 24 ], // special days in January
        2 : [ 1, 6, 8, 12, 18 ], // special days in March
        8 : [ 21, 11 ], // special days in September
        11 : [ 25, 28 ] // special days in December
};

// this function returns true if the passed date is special
function dateIsSpecial(year, month, day) {
        var m = SPECIAL_DAYS[month];
        if (!m) return false;
        for (var i in m) if (m[i] == day) return true;
        return false;
}
// this is the actual date status handler. Note that it receives the
// date object as well as separate values of year, month and date, for
// your confort.
function dateStatusHandler(date, y, m, d) {
        if (dateIsSpecial(y, m, d)) return "special"
        else return false;
        // return true above if you want to disable other dates
}
&lt;/script&gt;

&lt;%= f.date_select :arrived_on, :dateStatusFunc =&gt; "dateStatusHandler" %&gt;

]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Notice the last line, now any extra options are passed directly to the Calendar.setup method.&lt;/p&gt;

&lt;p&gt;Included in the list of possible options you can pass is ifFormat, which is the date format ActiveCalendar uses. Uma Shankar Ladha wanted to be able to just select a month and year, I’m not sure if ActiveCalendar is the best way to do that, but you could use the following code to make sure that no matter what date the user selects, your program would only get the month and year:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
&lt;%= f.date_select :arrived_on, :ifFormat =&gt; "%m/%Y" %&gt;
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;That format is used by both Ruby and Javascript for displaying dates, so you have to make sure that your format is parsable by both Ruby and the Calendar Javascript. Luckily their formats are extremely similar. The following list contains all the tags recognizable by both:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
%a abbreviated weekday name
%A full weekday name
%b abbreviated month name
%B full month name
%d the day of the month ( 00 .. 31 )
%H hour ( 00 .. 23 )
%I hour ( 01 .. 12 )
%j day of the year ( 000 .. 366 )
%m month ( 01 .. 12 )
%M minute ( 00 .. 59 )
%n a newline character
%p ï¿½PMï¿½ or ï¿½AMï¿½
%S second ( 00 .. 59 )
%U, %W the week number
%w the day of the week ( 0 .. 6, 0 = SUN )
%y year without the century ( 00 .. 99 )
%Y year including the century ( ex. 1979 )
%% a literal % character
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;In case you are interested the Ruby formats you &lt;b&gt;can’t&lt;/b&gt; use are:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
%x - Preferred representation for the date alone, no time
%X - Preferred representation for the time alone, no date
%Z - Time zone name
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;And the Dynarch codes you &lt;b&gt;can’t&lt;/b&gt; use are:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
%C century number
%e the day of the month ( 0 .. 31 )
%k hour ( 0 .. 23 )
%l hour ( 1 .. 12 )
%P ï¿½pmï¿½ or ï¿½amï¿½
%s number of seconds since Epoch (since Jan 01 1970 00:00:00 UTC)
%t a tab character
%V the week number5
%u the day of the week ( 1 .. 7, 1 = MON )
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Also note that if you change the formatting, validates_as_date will not work properly. I plan on fixing that in the future.&lt;/p&gt;

&lt;h2&gt;Overridable IDs&lt;/h2&gt;

&lt;p&gt;The last change worth mentioning (there have been others) was contributed by Peer Allen. He was using ActiveCalendar in conjunction with AJAX and needed to override the id property. His code allows the programmer to specify the name and id of the html entries used by ActiveCalendar. Thanks Peer!&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Thank you all for using and contributing to ActiveCalendar. Please let us know how you’re using it and what problems you’ve encountered.&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237827819</link><guid>http://blog.petersen.vg/post/237827819</guid><pubDate>Sat, 11 Aug 2007 00:00:00 -0700</pubDate></item><item><title>IE PNG Fix in Rails</title><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;PNGs are great, having a full 8 bits of alpha transparency makes designing web pages so much easier. That being said, I’m sure anyone reading this post is well aware of the gross inadequacies of Internet Explorer 6  in terms to the rendering of PNGs. IE7 has remedied the situation, however, according to Google Analytics, 6% of the visitors to this website still use IE6, and the situation is much worse for &lt;a href="http://www.assaydepot.com"&gt;our company website&lt;/a&gt; where a full 37% of visitors still use IE6. My point is, if we want to take advantage of the features PNGs give us, we have to account for the IE6 users.&lt;/p&gt;

&lt;p&gt;We are in luck, &lt;a href="http://koivi.com/ie-png-transparency/"&gt;koivi.com&lt;/a&gt; has a write up on how we can use the Microsoft specific “DXImageTransform.Microsoft.AlphaImageLoader” css filter to load PNGs properly. The short version is, our image tags that used to look like:
&lt;script type="syntaxhighlighter" class="brush: html"&gt;&lt;![CDATA[
&lt;img width="128" height="128" src="example.png" alt="Example"/&gt;
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;must now look like (for IE6 only):
&lt;script type="syntaxhighlighter" class="brush: html"&gt;&lt;![CDATA[
&lt;img  alt="Example" width="128" height="128" src="spacer.gif" style="filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='example.png', sizingMethod='scale');" /&gt;
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;To make this process easier, I’ve written a Ruby on Rails method that handles the details for us.&lt;/p&gt;

&lt;h2&gt;png_tag&lt;/h2&gt;

&lt;p&gt;png_tag is the little brother of image_tag. It is actually two functions, first a function (ie?) to determine if the client is using IE, and if so what version. The second function (png_tag) acts just like image_tag, except when passed a png it will automatically use the DXImageTransform.Microsoft.AlphaImageLoader filter if the client is using IE6.&lt;/p&gt;

&lt;p&gt;The first function is as follows:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
  def ie?
    m = /MSIE\s+([0-9, \.]+)/.match(request.user_agent)
    unless m.nil?
      m[1].to_f
    end
  end
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;This is a pretty rudimentary check, it just looks for “MSIE” in the user agent, if it finds it it returns the number after it (the version) otherwise it returns nil. Now that we have the ability to see if our user is using IE, we can tackle the second function:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
  def png_tag(source, options = {})
    options.symbolize_keys!

    options[:src] = image_path(source)
    options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize

    if options[:size]
      options[:width], options[:height] = options[:size].split("x") if options[:size] =~ %r{^\d+x\d+$}
      options.delete(:size)
    end

    if ie? &amp;&amp; ie? &lt; 7 &amp;&amp; options[:src] =~ /png$/i
      src = options[:src]
      options[:style] = "filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='#{src}', sizingMethod='scale');"
      options[:src] = image_path('spacer.gif')
    end

    "&lt;img #{tag_options(options) if options} /&gt;"
  end
]]&gt;&lt;/script&gt;&lt;p&gt;If this code looks a lot like the code for “image_tag” that because it basically is “image_tag” with the IE6 check. If we find IE6, we simply change out the image source for a spacer and add the filter code. Since it also checks that the source image is a PNG before adding the filter, you can use png_tag everywhere you would have used image_tag.&lt;/p&gt;

&lt;h2&gt;My Image Doesn’t Show Up in IE?!?&lt;/h2&gt;

&lt;p&gt;I forgot to mention, there is one caveat. The “DXImageTransform.Microsoft.AlphaImageLoader” doesn’t automatically size your “img” tag. So your image is showing up, it just happens to be 1 pixel by 1 pixel (the size of our spacer). This just means you have to specify to the size of your image ahead of time (a good practice anyway).&lt;/p&gt;

&lt;p&gt;In the case where the programmer doesn’t specify the size, you could use &lt;a href="http://snippets.dzone.com/posts/show/805"&gt;this code&lt;/a&gt; to determine it at run time. I decided not to for my code, but keep that in mind if it is a feature you really need.&lt;/p&gt;

&lt;h2&gt;Using png_tag&lt;/h2&gt;

&lt;p&gt;I thought about bundling this as a plugin, but it just seemed like overkill. If you want to use png_tag, simply copy the two functions above into your application_helper.rb file, and copy the following spacer into your images directory:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://developer.assaydepot.com/wp-content/uploads/2007/08/spacer.gif" title="Spacer Image"&gt;right click here to save the 1x1 pixel spacer image.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you find this code useful!&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237824555</link><guid>http://blog.petersen.vg/post/237824555</guid><pubDate>Thu, 02 Aug 2007 00:00:00 -0700</pubDate></item><item><title>Setup a Central Logging Server using Splunk, syslog-ng and named pipes on Ubuntu</title><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;As you may already know, that I love Virtual Computing. My program of choice is VMWare, but regardless of what you use, I just love the concept. Virtual computing allows a small company like the &lt;a href="http://www.assaydepot.com"&gt;Assay Depot&lt;/a&gt; to create many virtual computers, each handling a different aspect of the business. However, nothing is free in this world, and Virtual Computing comes with its own set of challenges. In this post, I hope to show how you can use &lt;a href="http://www.splunk.com"&gt;Splunk&lt;/a&gt;, sysnlog-ng and named pipes to keep you informed as to what is happening on each of those virtual computers (it works just as well for physical computers). I use Ubuntu, so this post assumes you do too. You may have to do some interpreting if this is not the case.&lt;/p&gt;

&lt;p&gt;During this project I found this post informative: &lt;a href="http://mysfitt.net/tutorials/splunk_fifo.php"&gt;&lt;a href="http://mysfitt.net/tutorials/splunk_fifo.php"&gt;http://mysfitt.net/tutorials/splunk_fifo.php&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Design&lt;/h2&gt;

&lt;p&gt;I have many Ubuntu machines, database servers, development servers, mail relays, application servers, etc. I want to monitor them using Splunk. Splunk is a program that reads log files, makes them searchable and generally more manageable. Splunk can read log files from many different sources, for this post, I chose to to tail files from the local file system.&lt;/p&gt;

&lt;p&gt;Since I want to manage all my machines with one instance of Splunk, my next challenge was to continuously feed log files from those machines onto one central logging server. This is where syslog-ng comes in. On one end, syslog-ng can be configured to send all system log statements to a network port. On the other end, it can be configured to receive those statements and write them to a file. In this way, our central logging server can handle all the system log files of all the Ubuntu machines on our network and Splunk can index them all.&lt;/p&gt;

&lt;p&gt;Finally, I want to monitor services that don’t write directly to the system log. I would like to have syslog-ng simply tail those log files that I’m interested, however, either syslog-ng can’t do that, or I couldn’t figure it out (probably the latter). Instead it wrote a Ruby daemon that will tail a file and pipe the results to a named pipe. Syslog-ng then reads from that named pipe and sends the information over a network port to the central logging server that writes the statement to a file for indexing.&lt;/p&gt;

&lt;p&gt;Simple enough, lets get to it.&lt;/p&gt;

&lt;h2&gt;Install Splunk&lt;/h2&gt;

&lt;p&gt;For this post, I’ve chosen the Splunk 3.0 beta. If you choose to use version 2.2.6, you can download the deb file. For the beta, I downloaded the tgz version.&lt;/p&gt;

&lt;p&gt;The following code should be executed on the machine you plan to use as your central logging server.
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
wget 'http://www.splunk.com/index.php/download_track?file=/3.0b2/linux32/splunk-3.0b2-19829-Linux-i686.tgz&amp;ac=ostg-lb&amp;wget=true&amp;name=wget'
tar xvfz splunk-3.0b2-19829-Linux-i686.tgz
sudo mv splunk /opt
sudo cp /opt/splunk/etc/init.d/debian/splunk /etc/init.d
sudo chmod 755 /etc/init.d/splunk
sudo update-rc.d splunk start 50 2 .
/etc/init.d/splunk start
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;That’s it, we downloaded the package, expanded it to /opt, copied the init script to /etc/init.d and made it executable, told the server to start it when the machine starts, and finally started the server. Since we used the defaults (installed /opt/splunk) we didn’t have to change anything. If you want to install to a different location, their README is very informative.&lt;/p&gt;

&lt;h2&gt;Install syslog-ng (Server)&lt;/h2&gt;

&lt;p&gt;Next we need to syslog-ng on the central logging server and configure it to accept logging statements from the clients.&lt;/p&gt;

&lt;p&gt;First, install syslog-ng using apt-get:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo apt-get install syslog-ng
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;by default, syslog-ng doesn’t use dns names for performance reasons, but we want to turn it on so our logs are stored in directories named by server name, rather than by IP address. To turn it on, edit /etc/syslog-ng/syslog-ng.conf and change the line that says:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
        use_dns(no)
]]&gt;&lt;/script&gt;
to
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
        use_dns(yes)
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Next, you have to set up some sources and destinations. Sources are where syslog-ng will read from and are typically named with a leading “s_”. Destinations are where syslog-ng will write to and are typically named with a leading “d_”. Log statements connect sources and destinations. I added the following to my /etc/syslog-ng/syslog-ng.conf file.
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
source s_remote {
        tcp(port(5140) keep-alive(yes));
};

destination d_hosts {
        file(
                "/u01/log/hosts/$HOST/$YEAR/$MONTH/$DAY/$FACILITY"
                owner(root)
                group(root)
                perm(0644)
                dir_perm(0755)
                create_dirs(yes)
        );
};

log {
        source(s_remote);
        destination(d_hosts);
};
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;The source reads logging statements from port 5140. The destination writes those logging statements to files in /u01/log/hosts based on the host name, date and which service published the logging statement. Lastly, the log statement connects the two.&lt;/p&gt;

&lt;p&gt;Once you restart the syslog-ng service, your central logging server is ready to go:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo /etc/init.d/syslog-ng restart
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h2&gt;Install syslog-ng (Client)&lt;/h2&gt;

&lt;p&gt;Now that you have completed your central logging server, its time to setup some clients. First (just like with the server) you need to install syslog-ng:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo apt-get install syslog-ng
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Now setup some sources and destinations in /etc/syslog-ng/syslog-ng.conf, except this time, you will be reading log statements from the system and writing them to a network port:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
destination d_splunk {
        tcp("splunk01" port(5140));
};

log {
        source(s_all);
        destination(d_splunk);
};
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;The destination statement sets up syslog-ng to write to port 5140 on the server splunk01 (that’s the name of my central logging server). The log statement connects s_all, which is the default source for syslog-ng, to your logging server.&lt;/p&gt;

&lt;p&gt;Your logging server which should now be collecting all kernel log messages from all the servers you’ve configured.&lt;/p&gt;

&lt;h2&gt;Log Custom Services&lt;/h2&gt;

&lt;p&gt;Ok, so far we are logging all kernel log statements to your logging server. That’s great, but we really want to log our custom services which write to standard log files. Services such as postgres or Rails. Now, I’m certainly not a syslog-ng expert, but I couldn’t figure out how to get syslog-ng to tail a file, I could get it to read a file once, but that didn’t help much. I did however get syslog-ng to read from a named pipe. So I took it upon myself to write a program that would tail a file to a named pipe. (BTW, a named pipe, aka a FIFO, is tool for interprocess communication, one process can write to it like a file, while another reads from it like a file).&lt;/p&gt;

&lt;p&gt;First, we create our named pipe:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo mkdir /var/syslog-ng
cd /var/syslog-ng
sudo mkfifo syslog_fifo
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;I called mine, /var/syslog-ng/syslog_fifo. Now lets make syslog-ng read from that fifo and write to our network port. First we add a new source to /etc/syslog-ng/syslog-ng.conf
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
source s_pipe {
        pipe( "/var/syslog-ng/syslog_fifo" );
};
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Next we update the log statement from the previous section, it should now look like:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
log {
        source(s_all);
        source(s_pipe);
        destination(d_splunk);
};
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Now, it is reading from the s_all source as well as our new s_pipe source and writing everything to d_splunk, our logging server.&lt;/p&gt;

&lt;p&gt;You must restart syslog-ng for the changes to take effect:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
/etc/init.d/syslog-ng restart
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Finally, we need to tail the files we are interested in and pipe them to our new fifo. To accomplish this I wrote the following daemon using Ruby:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
#!/usr/bin/ruby

APP_NAME = "rlogd"

@configFilename = "/etc/rlogd.conf"
@pidFilename = "/etc/rlogd.pid"
@pipe = "/var/syslog-ng/syslog_fifo"

def getChildPid(pid)
  cPid = `ps -ef | awk '$3 == #{pid} {print $2}'`
  cPid.chomp!
end

def status
  return File.exists?(@pidFilename)
end

def start
  if status
    puts "#{APP_NAME} is already running... stopping"
    stop
  end
  pidFile = File.new(@pidFilename, "w")
  configFile = File.open(@configFilename, "r")
  configFile.each_line do |file|
    file.chomp!
    unless file.empty? or file.match('^#')
      puts "tail -f #{file} &gt; #{@pipe}"
      pid = fork do
        `tail -f #{file} &gt; #{@pipe}`
      end
      Process.detach(pid)
      pidFile.puts(pid)
    end
  end
  pidFile.close
end

def stop
  if status
    pidFile = File.open(@pidFilename, "r")
    pidFile.each_line do |pid|
      pid.chomp!
      begin
        # STUPID HACK TO GET THE GRANDCHILD PROCESS ID
        # PID =&gt; RUBY
        #   CHILD PID =&gt; SH
        #     GRANDCHILD PID =&gt; TAIL
        cPid = getChildPid(pid)
        unless cPid.empty?
          gcPid = getChildPid(cPid)
          unless gcPid.empty?
            Process.kill("TERM", gcPid.to_i)
          end
        end
      rescue
        puts "Unable to kill #{pid}"
      end
    end
    pidFile.close
    File.delete(@pidFilename)
  else
    puts "#{APP_NAME} is not started"
  end
end

case ARGV.first
  when 'start':
    start
  when 'stop':
    stop
  when 'restart':
    stop
    start
  when 'status':
    if status
      puts "started"
    else
      puts "stopped"
    end
  else
    puts "Usage: #{APP_NAME} {start|stop|restart|status}"
end
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;The daemon reads from /etc/rlogd.conf. The config file consists of the filenames of any file that you want to be tailed separated by newlines. For instance, if you wanted to monitor your postgres server, your rlogd.conf file would look something like:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
#
# rlogd.rb config file
# Files added here will be tailed into /var/syslog-ng/syslog_fifo
# where they can be controlled via syslog-ng
#
/etc/postgresql/8.2/main/log
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Now start the rlogd server:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
/etc/init.d/rlogd start
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;At this point, your client is setup. It should be sending all kernel log messages, as well as messages from log files you’ve configured to your logging server where they are stored and indexed.&lt;/p&gt;

&lt;p&gt;Since I will be performing this on all of my servers, I went ahead and packaged it up as a deb file, so setting up my clients is as easy as:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo apt-get install syslog-ng
sudo apt-get install rlogd
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href="http://developer.assaydepot.com/wp-content/uploads/2007/07/rlogd.zip" title="rlogd"&gt;Source for the deb file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.assaydepot.com/?p=10"&gt;How to create a deb file and deploy it using a repository server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Configure Splunk&lt;/h2&gt;

&lt;p&gt;Your Splunk server should already be running and your clients should be logging to it. The last step is to configure Splunk to read the log files. First, visit http://splunk01:8000/admin, where splunk01 is the name of your logging server. Next, click on “Data Inputs”, then on “Files and Directories”. From there you can “Add Input”; Set the path to /u01/log (or whatever directory you are using) and change the host to “Regex on path”. I use the following regex:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
/u01/log/hosts/([a-z,A-Z,0-9]*)/


which tells Splunk to use the path to determine the host name.

## Conclusion
That's it. You can now use Splunk to monitor the log files on all of your Ubuntu machines (virtual or otherwise). Additionally, once you set up the server, it is quite easy to setup the clients using the &lt;a href='http://developer.assaydepot.com/wp-content/uploads/2007/07/rlogd.zip' title='rlogd'&gt;the deb file. You could even deploy the deb file on your &lt;a href="http://developer.assaydepot.com/?p=10"&gt;repository server and make deploying even easier.&lt;/script&gt;&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237821145</link><guid>http://blog.petersen.vg/post/237821145</guid><pubDate>Sun, 29 Jul 2007 00:00:00 -0700</pubDate></item><item><title>Build Your Own Deb File and Repository Server</title><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;How do you install software on an Ubuntu machine? How do you create a deb file? How does apt-get work? These are the questions I will try to answer in this post, but first a little background.&lt;/p&gt;

&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;I love Virtual Computing. I can run tons of virtual servers on a very limited number of physical machines. This allows me to segregate applications exactly as I choose. I can have subversion and Trac running on one and nothing but an email gateway on another, it also gives me a way to try new applications like Splunk without jeopardizing a system and with investing in another box.&lt;/p&gt;

&lt;p&gt;The drawback to being able to create new virtual machines on a whim is administering them once they are created. I’ve written a couple of applications that would like to install on all my virtual machines and that is where packaging them as deb files and creating a repository server that apt-get is aware of comes in very handy.&lt;/p&gt;

&lt;h2&gt;Create a DEB file&lt;/h2&gt;

&lt;p&gt;The ultimate goal is to be able to type
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo apt-get install myapp
]]&gt;&lt;/script&gt;
from any of my VMs and have it install properly. All apt-get really does is check all its repository servers for a deb file that contains the “myapp” package, downloads the deb file and installs it. So before we build our repository server (also a VM BTW) we have to create the deb file.&lt;/p&gt;

&lt;p&gt;To create the deb file, you need to:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Create the directory structure&lt;/li&gt;
&lt;li&gt;Create the control file&lt;/li&gt;
&lt;li&gt;Write the install and uninstall scripts&lt;/li&gt;
&lt;li&gt;Build the package&lt;/li&gt;
&lt;/ul&gt;&lt;h3&gt;Create the Directory Structure&lt;/h3&gt;

&lt;p&gt;The directory structure of your package will directly mimic the directory structure of the system, with the files in place. For example, if my application requires placing the script A.sh in /usr/sbin and B in /etc/init.d, my directory structure would like:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_kstxnsYIRe1qa5jnl.png" alt=""/&gt;&lt;/p&gt;

&lt;h3&gt;Create the Control File&lt;/h3&gt;

&lt;p&gt;Next, we need to create the control file. The control file is placed in a special directory called DEBIAN. After you create that directory your directory structure should look like:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_kstxo1b2Ob1qa5jnl.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Inside of the DEBIAN directory, create a file named control. Mine looks like:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
Package: package
Version: 1.0
Section: web
Priority: optional
Architecture: all
Essential: no
Depends: ruby, sed, xinetd
Installed-Size: 1
Maintainer: Chris Petersen [christopher dot petersen at gmail dot com]
Provides: package
Description: A short description of your package
 This should be a longer description of your package,
 it can span multiple lines, and should indented with 
 spaces
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Most of the entries are self explanatory, but the one you will want to pay close attention to is the “depends” statement. When a user installs your package, if they haven’t installed any of the dependencies, apt-get will allow them to automatically install them.&lt;/p&gt;

&lt;h3&gt;Install and Uninstall&lt;/h3&gt;

&lt;p&gt;The next step is to write the install and uninstall scripts. The files in your package will automatically be copied to their corresponding location on disk, but if you need more configuration that has to be performed in your script, you can add that code to a script called “postinst” in the DEBIAN directory. Conversely, you must reverse any changes made during installation in a script called “prerm” which will be called during uninstallation.&lt;/p&gt;

&lt;p&gt;For instance, my package contains an xinetd service, so I am going to add lines to “/etc/services”. My “postinst” file will look like:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
#!/bin/sh

echo "package          1789/tcp" &gt;&gt; /etc/services
echo "package          1789/udp" &gt;&gt; /etc/services
/etc/init.d/xinetd reload
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;And my “prerm” file will look like:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
#!/bin/sh

sed '/package/d' /etc/services &gt; /tmp/services
mv /tmp/services /etc/services
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h4&gt;Side Note About postinst and prerm&lt;/h4&gt;

&lt;p&gt;I find sed to be a very useful tool when editing configuration files from a script. This &lt;a href="http://www.student.northpark.edu/pemente/sed/sed1line.txt"&gt;page&lt;/a&gt; contains many useful one sed script that may help you write your install/uninstall scripts.&lt;/p&gt;

&lt;h3&gt;Build the Package&lt;/h3&gt;

&lt;p&gt;Now our package is complete, we’ve placed our files in the appropriate places and written our control file, install and uninstall scripts. The last step is to package the results into a deb file. To do this, navigate to one level above your package. So if your package is in &lt;span class="code"&gt;~cpetersen/projects/pacakge&lt;/span&gt;, navigate to &lt;span class="code"&gt;~cpetersen/projects&lt;/span&gt;. From there execute the following command.
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
dpkg-deb --build package
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;That will create the file &lt;span class="code"&gt;~cpetersen/projects/package.deb&lt;/span&gt;. You now have a fully functioning deb file. You could install it using &lt;span class="code"&gt;dpkg&lt;/span&gt;, but we want to use apt-get, so next we’ll look at creating a repository server.&lt;/p&gt;

&lt;h2&gt;Setup a Repository Server&lt;/h2&gt;

&lt;p&gt;The repository server is a simple web server (apache in our case) that happens to store the deb files and some meta-data about them. The first step in getting it up and running is installing apache and the &lt;span class="code"&gt;dpkg-dev&lt;/span&gt; kit which will allows us to create the index.
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo apt-get install ssh
sudo apt-get install apache2
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Next, create the directory where the repository will live. I created a virtual machine to serve as the repository server. Since this is a dedicated machine, I will create my directory directly at the &lt;span class="code"&gt;www-root&lt;/span&gt;. This would work as well in an apache virtual server. My &lt;span class="code"&gt;www-root&lt;/span&gt; is &lt;span class="code"&gt;/var/www&lt;/span&gt; so my deb files will go into &lt;span class="code"&gt;/var/www/repository&lt;/span&gt;. Finally, you must index the deb files meta data. You can do this with a program called &lt;span class="code"&gt;dpkg-scanpackage&lt;/span&gt; that comes with the &lt;span class="code"&gt;dpkg-dev&lt;/span&gt; package. From the directory that you want to server as your repository (for me it is the root &lt;span class="code"&gt;/var/www&lt;/span&gt;) execute the following commands:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo su
dpkg-scanpackages . /dev/null | gzip -9c &gt; Packages.gz
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Your repository server is done. If you want more information, I found &lt;a href="http://odzangba.wordpress.com/2006/10/13/how-to-build-local-apt-repositories/"&gt;this page&lt;/a&gt; very helpful. Now make sure apache is running and we can move on to the final step, making your clients aware of the server.&lt;/p&gt;

&lt;h2&gt;Using Your Server&lt;/h2&gt;

&lt;p&gt;So now you have your deb file, and you have your repository server. How do your client machines know to you use it? &lt;span class="code"&gt;apt-get&lt;/span&gt; configures its servers using the &lt;span class="code"&gt;/etc/apt/sources.list&lt;/span&gt; file. So you need to add your new server to that file. I named my server repo01, and I placed my repository in the www-root directory, so I added the following line to all of my clients &lt;span class="code"&gt;/etc/apt/sources.list&lt;/span&gt; files:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
deb http://repo01 /
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Don’t forget the trailing ” /” (there is a space there). Now update your clients:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo apt-get update
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;And finally you should be able to install your package:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo apt-get install package
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h2&gt;A Note About Adding Packages&lt;/h2&gt;

&lt;p&gt;Once your server is up and running and your clients are configured to look for it, it is very easy to add or update packages.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Copy the deb file to your repository directory&lt;/li&gt;
&lt;li&gt;Re-execute the &lt;span class="code"&gt;dpkg-scanpackages&lt;/span&gt; command to update the index&lt;/li&gt;
&lt;li&gt;Update your clients with &lt;span class="code"&gt;sudo apt-get update&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Setting up your own repository server and distributing your internal applications as deb files can simplify administration of numberous machines. There are three basic steps, each of which we outlined in this post:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Create the deb file&lt;/li&gt;
&lt;li&gt;Setup the repository server&lt;/li&gt;
&lt;li&gt;Configure the clients to use your repository&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;You should now have a working deb file that you can install using apt-get.&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237815372</link><guid>http://blog.petersen.vg/post/237815372</guid><pubDate>Mon, 09 Jul 2007 00:00:00 -0700</pubDate></item><item><title>ActiveUpload - Easy File Uploads in Rails</title><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Our goal was to create a Rails plugin that allows the user to upload multiple files to a website, quickly and easily. This plugin should also give the developer control over what is uploaded, such as maximum filesize allowed, and what filetypes are acceptable. To accomplish this goal, we created the &lt;a href="http://code.google.com/p/activeupload/"&gt;ActiveUpload&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;After researching some alternatives, we settled on a Flash application called &lt;a href="http://swfupload.mammon.se/"&gt;SWFUpload&lt;/a&gt;. SWFUpload is a Flash movie that was written using &lt;a href="http://www.flashdevelop.org/community/"&gt;FlashDevelop&lt;/a&gt;. It is a Flash movie that runs on the client, and handles the client end of the uploads. However, the movie itself is invisible, it is styled with HTML and works via a series of JavaScript callbacks. It is simple yet flexible for the developer, and the user interface has all the functionality we require.&lt;/p&gt;

&lt;p&gt;SWFUpload is licensed under the MIT license and Flash Develop is free. For a demonstration of SWFUpload, visit their &lt;a href="http://swfupload.mammon.se/"&gt;site&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Design&lt;/h2&gt;

&lt;p&gt;We need to design a Rails plugin that integrates SWFUpload with a Rails application. Our plugin will consist of three parts.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;A Model for storing the files meta data in the database.&lt;/li&gt;
&lt;li&gt;A Controller for accepting the uploaded files and manipulating the model.&lt;/li&gt;
&lt;li&gt;A FormBuilder extension for rendering the User Interface.&lt;/li&gt;
&lt;/ul&gt;&lt;h3&gt;The Model&lt;/h3&gt;

&lt;p&gt;We started with the model. We knew we would need to store basic information about the file, such as filename and size. We also knew that we would want to attach this model to other models. We decided on a single table, single model design, which stores the filename and size, and attaches to other models using a &lt;a href="http://wiki.rubyonrails.org/rails/pages/UnderstandingPolymorphicAssociations"&gt;Polymorphic Association&lt;/a&gt;. The migration script looks like:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
class CreateAttachments &lt; ActiveRecord::Migration
  def self.up
    create_table :attachments, :force =&gt; true do |t|
      t.column :filename,        :string
      t.column :size,            :integer
      t.column :attachable_id,   :integer
      t.column :attachable_type, :string
      t.column :created_at,      :datetime
    end
  end

  def self.down
    drop_table :attachments
  end
end
]]&gt;&lt;/script&gt;&lt;p&gt;and the model looks like:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
class Attachment &lt; ActiveRecord::Base
  belongs_to :attachable, :polymorphic =&gt; true

  def dirname
    padded_id = sprintf("%6.6d", id)
    dirnames = padded_id.match("(...)(...)")
    dirname = "public/attachments/#{dirnames[1]}/#{dirnames[2]}"
  end

  def path
    "#{dirname}/#{filename}"
  end
end
]]&gt;&lt;/script&gt;&lt;h3&gt;The Controller&lt;/h3&gt;

&lt;p&gt;Next we decided to tackle the controller. The attachments controller has to do three things:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Upload the file&lt;/li&gt;
&lt;li&gt;Create the associated entry in the database&lt;/li&gt;
&lt;li&gt;Allow a user to download the file&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;After many attempts at getting the controller to do this, we settled on a controller with three methods.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;create&lt;/li&gt;
&lt;li&gt;upload&lt;/li&gt;
&lt;li&gt;show&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;You are probably wondering why create and upload are separate methods. The short answer is, if you create the attachment model inside of upload, there is no way to get the newly created id back out to the web page where you will be creating (or updating) one of your models that has attachments. The long answer, well if you want the long answer, read the “Modifying SWFUpload” section.&lt;/p&gt;

&lt;p&gt;It is remarkably easy to accept a file upload inside of rails, all you have to do is:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
file = File.new(filename, "wb")
file.write(params[:Filedata].read)
file.close
]]&gt;&lt;/script&gt;&lt;p&gt;The full controller looks like:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
require 'fileutils'

class AttachmentsController &lt; ApplicationController
  def create
    @f = Attachment.new()
    if @f.save
      render :text =&gt; "#{@f.id}"
    end
  end

  def upload
    @f = Attachment.find(params[:id])
    @f.filename = params[:Filename]
    @f.size = params[:Filedata].size

    if @f.save
      dirname = @f.dirname
      FileUtils.mkdir_p(dirname)
      file = File.new(@f.path, "wb")
      file.write(params[:Filedata].read)
      file.close
      render :text =&gt; "#{@f.id}"
    end
  end

  def show
    attachment = Attachment.find(params[:id])
    send_file attachment.path
  end
end
]]&gt;&lt;/script&gt;&lt;h2&gt;The FormBuilder&lt;/h2&gt;

&lt;p&gt;So now we have a model to store the uploaded files meta data and we have a controller to accept the uploaded file and manage the model. Now we need a way of displaying the UI, that is the job of the FormBuilder.&lt;/p&gt;

&lt;p&gt;The FormBuilder is a little too big to show here, but I encourage you to look it over, you can find it &lt;a href="http://activeupload.googlecode.com/svn/trunk/activeupload/lib/assay_depot/attachable.rb"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Basically the FormBuilder write the HTML for you, that HTML includes:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;The hidden input containing all the ids of the attachment models associated with this model&lt;/li&gt;
&lt;li&gt;The visible list of uploaded files (with delete javascript)&lt;/li&gt;
&lt;li&gt;The JavaScript to display SWFUpload&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The most complicated part of the helper is the JavaScript to display the Flash application, it looks like:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: javascript"&gt;&lt;![CDATA[
&lt;script&gt;
&lt;!--
  var swfu;
  var result;
  window.onload = function() {
    swfu = new SWFUpload({
      upload_script : "/attachments/upload",
      target : "SWFUploadTarget",
      flash_path : "/flash/SWFUpload.swf",
      allowed_filesize : 30720, // 30 MB
      allowed_filetypes : "*.*",
      allowed_filetypes_description : "All files...",
      browse_link_innerhtml : "Browse",
      upload_link_innerhtml : "Upload queue",
      browse_link_class : "swfuploadbtn browsebtn",
      upload_link_class : "swfuploadbtn uploadbtn",
      flash_loaded_callback : 'swfu.flashLoaded',
      upload_file_queued_callback : "fileQueued",
      upload_file_start_callback : 'uploadFileStart',
      upload_progress_callback : 'uploadProgress',
      upload_file_complete_callback : 'uploadFileComplete',
      upload_file_cancel_callback : 'uploadFileCancelled',
      upload_queue_complete_callback : 'uploadQueueComplete',
      upload_error_callback : 'uploadError',
      upload_cancel_callback : 'uploadCancel',
      auto_upload : true
    });
  };
--&gt;
&lt;/script&gt;
]]&gt;&lt;/script&gt;&lt;p&gt;That’s it, we now have all the pieces we need to accept uploaded files and attach them to any model. Normally I would jump directly into how you use it however, this project had a particularly interesting side note that I want to delve into. Please feel free to skip to the “Using ActiveUpload” section if you just want to get moving.&lt;/p&gt;

&lt;h2&gt;Modifying SWFUpload&lt;/h2&gt;

&lt;p&gt;As I alluded to in “The Controller” there are some limitation within SWFUpload. Ideally, SWFUpload would call its upload script and that would be it, that script would take care of creating the model, uploading the file and associating the file to the model you are actually working on. However, since the files are uploaded before you save the model that is impossible. The next best thing would be for the upload script to create the model and upload the file, then return the newly created id to the web page for associating when you save your model. Unfortunately, there is no way to get information from the upload script back into the page.&lt;/p&gt;

&lt;p&gt;Luckily, SWFUpload has numerous callbacks. We settled on a method by which we create the model in the call back that is called directly before you upload the file, the function is called uploadFileStart. This works great, except there is no way (that I could find) to get information from that callback into the upload script. Essentially, we could either associate the file with the attachment model, or the attachment model with your model, but not both.&lt;/p&gt;

&lt;p&gt;The solution was to modify the way SWFUpload works. As I mentioned in the Introduction, SWFUpload is open source and FlashDevelop is free, so anyone can modify the source.&lt;/p&gt;

&lt;p&gt;We examined the code and found where the call back was called:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: c"&gt;&lt;![CDATA[
// Call home E.T. - file obj, file count &amp; file queue length
if(uploadFileStartCallback.length &gt; 0)
        ExternalInterface.call(uploadFileStartCallback, getFileObject(currentFileId, currentFile), position, fileQueueLength);

// Add listener
currentFile.addListener(listener);

// Start upload
currentFile.upload(uploadScript);

]]&gt;&lt;/script&gt;&lt;p&gt;You can see the ExternalInterface is what allows SWFUpload to call JavaScript functions. We changed it to the following:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: c"&gt;&lt;![CDATA[
// Call home E.T. - file obj, file count &amp; file queue length
if(uploadFileStartCallback.length &gt; 0)
        callbackReturnValue = ExternalInterface.call(uploadFileStartCallback, getFileObject(currentFileId, currentFile), position, fileQueueLength);

// If there was a return value, append it to the uploadScript
if (callbackReturnValue != null)
        uploadScript = uploadScript + callbackReturnValue;

// Add listener
currentFile.addListener(listener);

// Start upload
currentFile.upload(uploadScript);

]]&gt;&lt;/script&gt;&lt;p&gt;We wanted to keep the solution as generic as possible, so we simply took the result of the callback (if any) and appended it to upload script. So we created a JavaScript call back that returned “?id=XXX” and we were able to get the id of the attachment model that was created in the call back into the upload script. The call back looks like:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: javascript"&gt;&lt;![CDATA[
function uploadFileStart(file, position, queuelength) {
  var div = document.getElementById("queueinfo");
  div.innerHTML = "Uploading file " + position + " of " + queuelength;

  var li = document.getElementById(file.id);
  li.className += " fileUploading";

  var id;
  var url = '/attachments/create';
  new Ajax.Request(url, {
    asynchronous: false,
    onComplete: function(transport) {
      id = transport.responseText;
    }
  });

  $('_object_attachment_id').value += ","+id;
}

]]&gt;&lt;/script&gt;&lt;h1&gt;Using ActiveUpload&lt;/h1&gt;

&lt;p&gt;There are six fast and easy steps to using ActiveUpload.&lt;/p&gt;

&lt;p&gt;First install the plugin:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
./script/plugin install http://activeupload.googlecode.com/svn/trunk/activeupload/
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Second, generate the migration, model and controller, and migrate your database:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
./script/generate activeupload
rake db:migrate

]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Third, add the following lines to any model you wish to attach files to:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
  has_many :attachments, :as =&gt; :attachable

  def attachment_id=(attachment_id)
    unless attachment_id.blank?
      attachment_ids = attachment_id.split(",")
      attachment_ids.each do |a_id|
        unless a_id.blank?
          attachment = Attachment.find(a_id)
          attachments &lt;&lt; attachment
        end
      end
    end
  end

  def attachment_id
    result = ""
    if attachments
      attachments.each do |attachment|
        result &lt;&lt; ",#{attachment.id}"
      end
    end
    result
  end

]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Fourth, add the form helpers to your new and edit views:
&lt;script type="syntaxhighlighter" class="brush: html"&gt;&lt;![CDATA[
  &lt;p&gt;
    &lt;b&gt;Attachments&lt;br /&gt;
    &lt;%= f.attachments_field :attachment_id, { :add =&gt; "true", :edit =&gt;"true", :filesize =&gt; 30720, :filetypes =&gt; [ "*.gif", "*.jpg", "*.png" ] } %&gt;
  &lt;/script&gt;&lt;/p&gt;

]]&gt;

&lt;p&gt;Fifth, add the view helper to your show view:
&lt;script type="syntaxhighlighter" class="brush: html"&gt;&lt;![CDATA[
  &lt;p&gt;
    &lt;b&gt;Attachments
    &lt;%= view_attachments_field(@model_name, {})  %&gt;
  &lt;/script&gt;&lt;/p&gt;

]]&gt;

&lt;p&gt;Sixth and lastly, add the JavaScript and Stylesheets to your layout:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
  &lt;%= javascript_include_tag :defaults %&gt;
  &lt;%= stylesheet_link_tag 'swfupload_theme' %&gt;
  &lt;%= javascript_include_tag "swfupload_callbacks.js" %&gt;
  &lt;%= javascript_include_tag "SWFUpload.js" %&gt;

]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;You should now be able to upload files to your Rails application.&lt;/p&gt;

&lt;h2&gt;ActiveScaffold&lt;/h2&gt;

&lt;p&gt;ActiveUpload works well with ActiveScaffold. To get ActiveScaffold to render the correct upload forms you must create a partial form override. Luckily, ActiveUpload comes with one. In the plugin’s public directory ($PROJECT/vendor/plugins/activeupload/public/) you will find a file named _attachment_id_form_column.rhtml. Copy that file to your models views directory ($PROJECT/app/views/$MODEL/). 
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
cp vendor/plugins/activeupload/public/_attachment_id_form_column.rhtml app/views/model
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Since attachment_id is a virtual column, you will need to tell ActiveScaffold to use it, you can do that by adding the following code to your model’s controller:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
active_scaffold :model_name do |config|
  config.create.columns = [:column1, :column2, :attachment_id]
  config.update.columns = [:column1, :column2, :attachment_id]
end
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Finally, you should add the following lines to your attachments_controller.rb:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
  active_scaffold
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h2&gt;Notes&lt;/h2&gt;

&lt;p&gt;You will want to periodically cleanse your Attachments table and the associated files. There are two different ways entries can get stuck in there.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;A user adds attachments, then fails to save thier model&lt;/li&gt;
&lt;li&gt;A user disassociates an attachment with a model&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;In both these cases entries are made in the table and files are uploaded. Unfortunately, they are completely inaccessible. You can delete any entries from your attachments table that have a empty attachable_id and attachable_type columns. Don’t forget to delete the associated files!&lt;/p&gt;

&lt;p&gt;Additionally, since create and upload are seperate methods, it is theoretically possible to create an entry in the table and not upload the corresponding file. I’ve set SWFUpload to automatically upload (as opposed to creating a queue) so I’ve never seen it happen, but it is possible.&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237799706</link><guid>http://blog.petersen.vg/post/237799706</guid><pubDate>Fri, 06 Jul 2007 00:00:00 -0700</pubDate></item><item><title>ActiveAuthentication - Active Directory Authentication in Rails</title><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In addition to managing our public presence on the web, we spend a considerable amount of time developing internal applications and services.  Ruby on Rails makes creating generic webapps a snap; however, for any practical application you need more than just simple CRUD.&lt;/p&gt;

&lt;h3&gt;How about Authentication?&lt;/h3&gt;

&lt;p&gt;Most businesses out there, in no small part due to the inflexibility of Windows authentication schemes, reluctantly use Active Directory to manage their user database.  Ill conceived parallel authentication schemes that do not fully integrate with AD risk a host of problems: multiple points of failure, more complex security testing, user confusion, complex password management, etc…  Instead, wouldn’t it be great if your Rails webapp played nice with AD?&lt;/p&gt;

&lt;h2&gt;Development&lt;/h2&gt;

&lt;p&gt;To solve these probles, we created &lt;a href="http://code.google.com/p/activeauthentication/"&gt;ActiveAuthentication&lt;/a&gt;. &lt;a href="http://code.google.com/p/activeauthentication/"&gt;ActiveAuthentication&lt;/a&gt; is a Rails plugin that allows users to authenticate against Active Directory&lt;/p&gt;

&lt;h3&gt;Requirements&lt;/h3&gt;

&lt;ul&gt;&lt;li&gt;Use same username as password as AD account&lt;/li&gt;
&lt;li&gt;Transparently manage the creation of new users to your webapp&lt;/li&gt;
&lt;li&gt;Respect the suspension/deletion of users from the AD domain&lt;/li&gt;
&lt;/ul&gt;&lt;h3&gt;What’s Out There&lt;/h3&gt;

&lt;p&gt;Search first, code second.  There are a lot of existing authentication plugins for Ruby on Rails.  We didn’t want to rewrite what was already working, so after a brief review we elected to build on &lt;a href="http://wiki.rubyonrails.org/rails/pages/Acts_as_authenticated"&gt;acts_as_authenticated&lt;/a&gt; for our Active Directory authentication system.&lt;/p&gt;

&lt;h3&gt;Development&lt;/h3&gt;

&lt;p&gt;With the majority of the work done by others, we made as few modifications as possible.  We modified an the Authenticator object by adding and initializing the attributes we need to connect to the Domain Controller.  Next we created a new authenticate method.&lt;/p&gt;

&lt;p&gt;The authenticate method does the following:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Search the database for a user with the same username as the person trying to login.&lt;/li&gt;
&lt;li&gt;Connect to the domain controller with the given username and password.&lt;/li&gt;
&lt;li&gt;If step 2 failed, reject the login request, otherwise proceed.&lt;/li&gt;
&lt;li&gt;Load the userï¿½s information from active directory.&lt;/li&gt;
&lt;li&gt;If you found a user in step one, proceed, otherwise create a new user.&lt;/li&gt;
&lt;li&gt;Populate your user model with the information from Active Directory.&lt;/li&gt;
&lt;li&gt;Save the new or updated user.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The actual code is as follows:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
class Authenticator
  connection = nil
  host = nil
  port = nil
  domain = nil
  dn = nil

  def initialization()
    config = YAML::load(File.open("#{RAILS_ROOT}/config/active_directory.yml"))
    @host = config["host"]
    @port = config["port"]
    @domain = config["domain"]
    @dn = config["dn"]
  end

  def authenticate(login, password)
    db_user = &lt;%= class_name %&gt;.find_by_login(login)
    begin
      email = login + "@" + @domain
      connection = LDAP::Conn.new(@host, @port)
      connection.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 )
      connection.bind( email, password )
      connection.search( @dn, LDAP::LDAP_SCOPE_SUBTREE, "sAMAccountName=#{login}") do |ad_user|
        if db_user == nil
          db_user = User.new
        end
        db_user.login = login
        db_user.email = email
        db_user.display_name = ad_user.vals("displayName").to_s
        db_user.given_name = ad_user.vals("givenName").to_s
        db_user.last_login_at = Time.new
        db_user.save
      end
      @connection = connection
      db_user
    rescue =&gt; e
      puts e
      nil
    end
  end

  def close
    @connection.unbind unless @connection == nil
    @connection = nil
  end
end
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;If you read the code carefully, you probably noticed the active_directory.yml file that is loaded in the initialization method. This file contains all the information necessary to connect to your domain controller. The file looks like:
&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
host: domaincontroller.yourcompany.com
port: 389
domain: yourcompany.com
dn: cn=users,dc=yourcompany,dc=com
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Simply replace domaincontroller with the name of your domain controller, and yourcompany with your domain name, and you should be good to go. Depending on how your directory is setup, you may have to experiment with the dn, but this setup worked for us.&lt;/p&gt;

&lt;h3&gt;Installation&lt;/h3&gt;

&lt;p&gt;The instructions for using the plugin are the same as they were for the acts_as_authenticated plugin.&lt;/p&gt;

&lt;h3&gt;Update&lt;/h3&gt;

&lt;p&gt;You also need to install the ruby ldap libraries. On Ubuntu you can do this with the following command:
&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
sudo apt-get install libldap-ruby1.8
]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Then you install the plugin:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
./script/plugin install http://activeauthentication.googlecode.com/svn/trunk/activeauthentication
]]&gt;&lt;/script&gt;&lt;p&gt;Next, generate your user model and update the database:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
./script/generate authenticated user account
rake db:migrate
]]&gt;&lt;/script&gt;&lt;p&gt;Now include the system in your application.rb file by adding the following code:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
include AuthenticatedSystem
]]&gt;&lt;/script&gt;&lt;p&gt;Add the before filter to any controllers you want to secure:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
before_filter :login_required
]]&gt;&lt;/script&gt;&lt;p&gt;Lastly, make sure you edit the active_directory.yml file in the config directory to match your environment.&lt;/p&gt;

&lt;p&gt;That’s it, now you can forget about administering users in your internal applications.&lt;/p&gt;</description><link>http://blog.petersen.vg/post/237810504</link><guid>http://blog.petersen.vg/post/237810504</guid><pubDate>Mon, 18 Jun 2007 00:00:00 -0700</pubDate></item><item><title>ActiveCalendar - Javascript Calendar on Rails</title><description>&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;When I first started with Rails I was amazed at how quickly you can get a project up and running. Coming from a Java background I was used to configuring either Hibernate, then Spring or spending my days tweaking EJB interfaces. The scaffolding in Rails blew me away. However, the basic date and date time renderer, as I’m sure you will agree, left a little something to be desired. It’s easy to change them after the scaffold was created, but that gets old quick. To solve these problems and others, I created &lt;a href="http://code.google.com/p/activecalendar/"&gt;ActiveCalendar&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Development&lt;/h2&gt;

&lt;p&gt;The first part of the process entailed choosing the look of the date renderer. I’ve always liked &lt;a href="http://www.dynarch.com/projects/calendar/"&gt;the DHTML / JavaScript Calendar&lt;/a&gt; from &lt;a href="http://www.dynarch.com/"&gt;Dynarch&lt;/a&gt;. Since it is licensed under the LGPL, it was a suitable choice.&lt;/p&gt;

&lt;p&gt;Next, I had to write the plugin. I didn’t want a generator because this plugin is designed to be a drop in replacement for the date renderer. It’s not something that has to be generated per scaffold, or configured per field, so I used rails to generate a basic plugin.&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
./script/generate plugin calendar
]]&gt;&lt;/script&gt;&lt;p&gt;Next, I added a public directory where I stored the necessary images and JavaScript and removed all the unused directories and files. In the end I had the following directory structure:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_kss8gy4Pr71qa5jnl.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;After creating the directory structure, it was time to open the hood and have a look at how rails renders fields. After a little digging, I found the FormHelper module in the following file:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/form_helper.rb
]]&gt;&lt;/script&gt;&lt;p&gt;This quickly led me to the DateHelper in:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/date_helper.rb
]]&gt;&lt;/script&gt;&lt;p&gt;Inside of the DateHelper module are methods called date_select and datetime_select, which correspond the methods used in the generated new.rhtml and edit.rhtml files. It should be noted that in the first iteration of the plugin, this is where the digging stopped. I overloaded the methods above with my own that rendered the Dynarch calendar. It worked wonderfully, until I discovered &lt;a href="http://activescaffold.com"&gt;ActiveScaffold&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ActiveScaffold is a great plugin that replaces the standard rails CRUD pages with a set of sexy AJAX powered pages. However, it uses a different method to render dates, so it was back to drop downs for me. Since I wanted a drop in replacement that would work with both standard Rails and ActiveScaffold, I was forced to dig deeper into the DateHelper.&lt;/p&gt;

&lt;p&gt;It turns out that the DateHelper, like the other FormHelpers, delegates calls to the InstanceTag class. In the final version of the plugin, I overloaded the to_date_select_tag and to_datetime_select_tag methods in InstanceTag and had them call my own DepotDateHelper class. ActiveScaffold must use the same InstanceTag class because once I did that, the calendar began rendering in ActiveScaffold as well.&lt;/p&gt;

&lt;p&gt;For good measure, I overloaded the date_select and datetime_select methods of DateHelper and continued to delegate to InstanceTag, but I added a couple of my own options.&lt;/p&gt;

&lt;h2&gt;Installation&lt;/h2&gt;

&lt;p&gt;You can install the plugin with the following command:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: bash"&gt;&lt;![CDATA[
./script/plugin install http://activecalendar.googlecode.com/svn/trunk/activecalendar
]]&gt;&lt;/script&gt;&lt;p&gt;Next add the appropriate javascript and stylesheets to your layout:&lt;/p&gt;

&lt;script type="syntaxhighlighter" class="brush: ruby"&gt;&lt;![CDATA[
&lt;%= stylesheet_link_tag "/javascripts/jscalendar-1.0/calendar-win2k-cold-1.css" %&gt;
&lt;%= javascript_include_tag "jscalendar-1.0/calendar.js" %&gt;
&lt;%= javascript_include_tag "jscalendar-1.0/lang/calendar-en.js" %&gt;
&lt;%= javascript_include_tag "jscalendar-1.0/calendar-setup.js" %&gt;
]]&gt;&lt;/script&gt;&lt;p&gt;That’s it, your dates should now render as JavaScript calendars.&lt;/p&gt;

&lt;h2&gt;Screen Shot&lt;/h2&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_kss8i2zaV01qa5jnl.png" alt=""/&gt;&lt;/p&gt;</description><link>http://blog.petersen.vg/post/236830000</link><guid>http://blog.petersen.vg/post/236830000</guid><pubDate>Sat, 16 Jun 2007 00:50:00 -0700</pubDate></item></channel></rss>

