55 comments Tuesday, October 9, 2007

Update Dec. 9, 2007: I decided to get my own domain and to use Wordpress instead of Blogger so this blog has moved. The new address is panscendo.com. Any new updates to this tutorial will be here

Update Nov. 29, 2007: Tutorial now current for Rails 2.0 RC2 and RubyAMF 1.5

RubyAMF is a flash remoting gateway that allows a Rails backend to communicate with a Flex frontend. The marriage allows rapid development of rich internet applications. This tutorial goes over the basic steps of creating a RESTful Rails project that has a HTML and Flex frontend and data persistence via MySQL database.

Rails

Setting up the Rails Project

Create a new rails project by first opening a command prompt and then changing the working directory to your rails project directory. Once there type the following command to create a rails project called "rubyamf"

> rails rubyamf

Now that we have a project created we need to install RubyAMF by using the rails installer. To do this you must first move into the rubyamf directory and then run the ruby plugin installer script


> cd rubyamf
rubyamf> ruby script/plugin install http://rubyamf.googlecode.com/svn/trunk/rubyamf

Note: If you receive a error like this: "Missing the Rails 1.99.0 gem. Please 'gem install -v=1.99.0 rails', update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed." then you just need to commet out the the line specified by the error. Since Rails 2.0 is still being developed it isn't actually 1.99.0 but 1.99.blah.

Connecting Rails to your Database

Since we want to be able to save our data we need to create a database to store said data. Open up a command prompt again and, assuming MySQL is already running, type:

> mysql -u root -p
Enter password:
mysql> create database rubyamf;

Good, now we need to tell Rails how to communicate with the database we just created. Open up the config/database.yml file and edit the text to look like this:

development:
adapter: mysql
endocing: utf8
database: rubyamf
username: root
password: yourpassword
host: localhost

Creating a REST controller

We now have a Rails project that is able to talk to a database. Cool! Now what we need to do is create a controller that issues the commands. Rails allows us to do this with a little beauty command called "scaffold_resource." When we run it we always follow it with an uppercase singular noun and a series of name value pairs. The noun is the name of the Rails model, or the database table, and the name:value pairs are the names of the column in the table and their datatype. Lets try it out; open up that command prompt once again, make the rubyamf directory the active dir and then issue the following command:

rubyamf> ruby script/generate scaffold Message text:string

Note: "scaffold_resource" has been changed to "resource" in Rails 2.0.

Among other things you now have two important files; messages_controller.rb which Flex and RubyAMF will communicate with, and a migrate file (called 001_create_messages.rb) that we will run to create the database table.

Lets do the latter right now. In the command prompt type this:

rubyamf> rake db:migrate

Making Sure it all Works

We're basically finished with rails for now. But before we call it good lets just make sure that it is running smoothly (and so we can look in awe of what we just did).

Boot up your rails server:

rubyamf> ruby script/server

Now open up your favorite browser and make sure that RubyAMF is running by going to http://localhost:3000/rubyamf/gateway. You should see something like the following image.

Screenshot of RubyAMF Gateway up and running

If you do not get the above image and instead get prompted to download an AMF file you need to edit the app/controllers/rubyamf_controller.rb file. Open it up and change:

amf_response = if request.env['CONTENT_TYPE'].to_s.match(/x-amf/) 
headers['Content-Type'] = "application/x-amf"
RailsGateway.new.service(request.raw_post) #send the raw data throught the rubyamf gateway and create the response
else
welcome_screen_html # load in some stub html
end
send_data(amf_response, :type => 'application/x-amf')

To:

amf_response = if request.env['CONTENT_TYPE'].to_s.match(/x-amf/) 
content_type = "application/x-amf"
RailsGateway.new.service(request.raw_post) #send the raw data throught the rubyamf gateway and create the response
else
content_type = "text/html"
welcome_screen_html # load in some stub html
end
send_data(amf_response, :type => content_type, :disposition=>'inline')

Note: If you use the rubyamf controller fix suggested on the RAMF blog it will brake your application (thanks goes to Quest4 for figuring this one out). The above code is not official so use it at your own risk.

Now make sure our Messages controller is working by pointing your browser to http://localhost:3000/messages and witnessing this:

Screenshot of message controller

So far so good. Now what we need to do is to add some data into the database so our Flex app has something to retrieve. Lets do that by clicking the "New Message" link at http://localhost:3000/messages, typing a short message (this tutorial uses "Hello World"), and press the "Create" button. *Bam* you just added a new Message to the database.

Enough of Rails, lets dive into Flex

Flex

Setting up the Flex Project

Boot up Adobe Flex and create a new project. I named mine rubyamf for consistency but you could name it something else (like planctomyces). Click the "Next" button, not the "Finish" button. Set the output folder to the "bin" dir (you'll probably have to create this) in the "public" dir of your rails project. That is, \rubyamf\public\bin. Press "Next." Now make sure that your output folder URL is set to: http://localhost:3000/bin. Press "Finish." You now have a shiny new Flex project.

Adding services-config.xml

We need to create an XML file that will point your Flex project in the direction of your Rails project. This is called the "services-config.xml" file and it needs to be placed in the same folder as your MXML file. Create a new file via File > New > File and name it "services-config.xml"

Now for the code. Open up "services-config.xml" and add this code:

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="rubyamf-flashremoting-service" class="flex.messaging.services.RemotingService" messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="rubyamf">
<channels>
<channel ref="rubyamf"/>
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition id="rubyamf" class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://localhost:3000/rubyamf/gateway" class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
</services-config>

Now we tell Flex to include "services-config.xml" when it compiles the application. To do this we need to add a command to the flex compiler. Do this by Project > Properties > Flex Compiler and adding -services "services-config.xml" to the "Additional compiler arguments" field.

Screenshot showing additional compiler arguments field

Creating the UI

Now the fun part. Here's the Flex UI code to paste into the MXML file:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:TextArea id="resultTxt"
width="80%" height="30%" />
<mx:Button id="getMessage"
label="Get Messages" />
<mx:TextArea id="createTxt"
width="80%" height="30%" />
<mx:Button id="createMessage"
label="Create Message" />
</mx:Application>

The above should look something like this:

Screenshot of flex ui

The above is pretty and all but it's like a mannequin; looks good but it has no function. Lets give it a purpose and turn it into a real live lady. We'll do this by adding the RemoteObject code.

Between the <mx:Application> and <mx:TextArea /> tags add this:

 <mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.rpc.Fault;

private function onFault(e:FaultEvent):void
{
resultTxt.text = e.fault.faultString;
}
private function onResult(e:ResultEvent):void
{
resultTxt.text = e.message.toString();
}
]]>
</mx:Script>

<mx:RemoteObject id="messageService" fault="onFault(event)"
source="MessagesController" destination="rubyamf">
<mx:method name="index" result="onResult(event)" />
<mx:method name="create" result="onResult(event)" />
</mx:RemoteObject>
  • RemoteObject is where the magic occurs. This particular instance we chose to call id="messageService"
  • source="MessagesController" is the name of the rails controller we want to communicate with. The actual name needs to be exactly the same as the ruby class name (open up app/controllers/messages_controller.rb)
  • destination="rubyamf" maps to the channel-definition in the services-config.xml file we created earlier (which then points Flex to the rubyamf remoting endpoint).
  • The two <mx:method /> tags map to two of the methods in the MessagesController class.

To call our methods we'll update the "click" event handlers of the two buttons in our UI. Add click="messageService.index.send();" to the "getMessage" button and click="messageService.create.send({text: createTxt.text});" to the "createMessage" button.

 <mx:Button id="getMessage"
label="Get Messages"
click="messageService.index.send();" />

<mx:Button id="createMessage"
label="Create Message"
click="messageService.create.send({text: createTxt.text});" />

Back to Rails

Tweaking messages_controller.rb

We're almost finished. All we have to do now is explain to our rails controller about AMF. We'll be polite and speak it's native language; ruby. Open up app/controllers/messages_controller.rb and add "format.amf { render :amf => @messages }" to the respond_to block of the index method.

 def index
@messages = Message.find(:all)

respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => @messages.to_xml }
format.amf { render :amf => @messages }
end
end

The respond_to block tells our controller to act differently when different mediums are attempting to work with it. If a browser calls the index method the controller will spit out HTML but now if the Flash Player requests something the controller will spit out AMF. Perfect!

Updating the create method is a bit trickier. We add an if statement to check if AMF was sent, and if so, do some tricky stuff.

 def create
if is_amf
@message = Message.new({:text => params[0][:text]})
else
@message = Message.new(params[:message])
end
...

Note: params[0][:text] was suggested by Peter Armstrong - thanks!

Then we add some code to the respond_to block that tells the controller to speak AMF if it's talking to the flash player.

 ...
respond_to do |format|
if @message.save
flash[:notice] = 'Message was successfully created.'
format.html { redirect_to message_url(@message) }
format.xml { head :created, :location => message_url(@message) }
format.amf { render :amf => "Message Saved" }
else
format.html { render :action => "new" }
format.xml { render :xml => @message.errors.to_xml }
format.amf { render :amf => @message.errors }
end
end
end

Whew! That's it. We can test the app now.

Testing... (in awe)

First we need to start our server (or restart it).

rubyamf> ruby script/server

Compile and run your Flex project. It should be running from the URL "http://localhost:3000/bin/rubyamf.html." Click on "Get Messages" and you should see something like this:

checking if get-messages works

Type a message into the second text area ("We received data from RubyAMF, can we send data to it?"). Press the button and you should see:

checking if create-message works

Finished!


Yee-haw! By using the powers of RubyAMF we have just grabbed data from a database and written some right back at speeds much faster than XML or JSON. Plus, we still get a HTML front end for those types that fear flash.

0 comments Sunday, October 7, 2007

DNA Painter is a small application that reads a nucleotide sequence and outputs an image. The logic behind it is pretty simple. I coded it while being influenced by ideas of cellular automata although it, technically, is not implementing those ideas.

The program works by reading a nucleotide string (A, T, C, or G) and applying logic to the current character. Each nucleotide gives the program a different and simple instruction.

  • A: Move one pixel down and add some red to the current color
  • T: Move one pixel right and add some green to the current color
  • C: Move one pixel up and add some blue to the current color
  • G: Move one pixel left and do something wacky (I think the current build right now just darkens the pixel)
In Actionscript 3.0 a pixel is a 32 bit number with 8 bits corresponding to the Alpha (transparency), Red, Green, and Blue values respectively. By mapping the RGB values to certain nucleotides I'll get at least 3 colors per image. Since chances are good that certain pixels will be painted on more than once the combination of two or more RGB values will result in a different color (red + blue = magenta, etc). This means that any image, given a long enough nucleotide sequence, will result in a multitude of color.

Application


Although I created DNA Painter as an expression of art through computation and science one use of DNA Painter is the creation of visual representations of genes. The application can output an image based off of, say, the aldolase gene of three different mammalian species so the relative divergence of the gene can be seen. Yes, I realize that using some sort of bioinformatic statistical analysis on the actual DNA string will be much better. But it's not cool you see, and in this world we need cooo-oool.

Notes on usage

Some things to think about while playing around with the program:
  • A long red line in an image means the mapped gene has a long series of A (adenine) and a long green horizontal line means T (thymine) and so on.
  • A stair step in the image is a sequence of alternating nucleotides
  • Increasing the bitmap size will show a more accurate picture of the gene. This is because the drawing wraps when it reaches an edge of the bitmap. So a larger bitmap means less overlap so less "noise".
  • The five available genes that are embedded in the application are all human genes


More Info on the genes

Further Development


Although I would like to make the images prettier by applying filters and other effects I think I would like to focus more on the application of the program rather than the aesthetics. It would be nice to remove the wrap effect so each gene or sequence will be a consistent image no matter the bitmap size. This will allow the user to zoom in and out (and pan). It'll allow the visualization of repeating sections of nucleotides that can be shown to exist across related genes. Furthermore, by applying the application to mRNA we could break down each image to a series of codons.

Now that I think about it we could create a catalog of common DNA sequences. Whoa!

1 comments Friday, October 5, 2007

Crow cam


The Behavioural Ecology Research Group of Oxford has recently published a paper in Science detailing tool use by New Caledonian crows, Corvus moneduloides, by attaching miniature cameras to their tail feathers.

Both Sciam and BBC News cover the story. BBC News links to the videos but if you want to avoid the 30 sec advertisements I suggest you go straight to the source.

0 comments Thursday, October 4, 2007

Ah yes, get your quality learnings right here - all for free. UC Berkeley has uploaded a series of lectures to youtube on various topics including biology, physics, and chemistry. There will be more to come.

So far, in the biology realm, there is only Integrative Biology 131. The lectures I browsed are very good and I look forward to more. Be a lobbyist and help get some lectures on evolution and/or ecology up.

This page lists the lectures by class: http://youtube.com/profile?user=ucberkeley

Update: I found out that Berkeley has been uploading webcasts and podcasts of their lectures since 2005. This semester they have a total of 45 classes. Here is the class list. To watch or listen to achieved lectures change the number following "semesterid=" in the URL to a previous semester (changing it to "1" will give you Spring 2005's class list). There are some semesters with no classes and others with only a few.