<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>code_fu - Home</title>
  <id>tag:khamsouk.souvanlasy.com,2008:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.7.3">Mephisto Noh-Varr</generator>
  <link href="http://khamsouk.souvanlasy.com/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://khamsouk.souvanlasy.com/" rel="alternate" type="text/html"/>
  <updated>2007-05-12T08:30:41Z</updated>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2007-05-11:40</id>
    <published>2007-05-11T05:07:00Z</published>
    <updated>2007-05-12T08:30:41Z</updated>
    <category term="google"/>
    <category term="ripple"/>
    <link href="http://khamsouk.souvanlasy.com/2007/5/11/helping-people-one-click-or-search-at-a-time" rel="alternate" type="text/html"/>
    <title>Helping people, one click or search at a time</title>
<summary type="html">&lt;p&gt;A &lt;a href=&quot;//www.kutarna.net/k-notes.html&quot;&gt;friend of mine&lt;/a&gt; pointed this site out to me the other day, and I think it&#8217;s a great concept.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;//ripple.org&quot;&gt;ripple.org&lt;/a&gt; is a website that allows users to support several non-profits and charities by clicking to view an ad or conducting a search.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;A &lt;a href=&quot;//www.kutarna.net/k-notes.html&quot;&gt;friend of mine&lt;/a&gt; pointed this site out to me the other day, and I think it&#8217;s a great concept.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;//ripple.org&quot;&gt;ripple.org&lt;/a&gt; is a website that allows users to support several non-profits and charities by clicking to view an ad or conducting a search.&lt;/p&gt;
&lt;p&gt;From their information page:&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;ripple exists to harness the power of the internet advertising in the true spirit of the internet &#8211; providing a tool for people to help others. We are leveraging the market for internet advertising to generate revenue to help people rather than our pockets.&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;When you view an ad or conduct a search, 100% of all proftits go to one of several aid organisations. While the organisations are Australian based, they do help communities around the world.&lt;/p&gt;


	&lt;p&gt;Ripple uses google adsense and google search, so the search results should be the same as what you normally get through the google home page; albeit without the related info, cached and similar pages. It&#8217;s in Beta, so that&#8217;s a good enough start.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2007-05-01:39</id>
    <published>2007-05-01T13:27:00Z</published>
    <updated>2007-12-12T04:23:40Z</updated>
    <category term="Programming"/>
    <category term="ajax"/>
    <category term="file upload"/>
    <category term="freeimage"/>
    <category term="imagescience"/>
    <category term="minimagick"/>
    <category term="raiis"/>
    <category term="rmagick"/>
    <category term="ruby"/>
    <link href="http://khamsouk.souvanlasy.com/2007/5/1/ajax-file-uploads-in-rails-using-attachment_fu-and-responds_to_parent" rel="alternate" type="text/html"/>
    <title>AJAX file uploads in Rails using attachment_fu and responds_to_parent</title>
<summary type="html">&lt;p&gt;In this walkthrough, I go through the available options and an example using attachment_fu to handle file uploads and image thumbnailing, and responds_to_parent to implement the &lt;a href=&quot;//developer.apple.com/internet/webcontent/iframe.html&quot;&gt;iframe remoting pattern&lt;/a&gt; to work around javascript&#8217;s security restrictions on file system access.&lt;/p&gt;


	&lt;p&gt;You can also &lt;a href=&quot;//khamsouk.souvanlasy.com/assets/2007/5/26/attachment_example.zip&quot;&gt;download&lt;/a&gt; the complete example.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In this walkthrough, I go through the available options and an example using attachment_fu to handle file uploads and image thumbnailing, and responds_to_parent to implement the &lt;a href=&quot;//developer.apple.com/internet/webcontent/iframe.html&quot;&gt;iframe remoting pattern&lt;/a&gt; to work around javascript&#8217;s security restrictions on file system access.&lt;/p&gt;


	&lt;p&gt;You can also &lt;a href=&quot;//khamsouk.souvanlasy.com/assets/2007/5/26/attachment_example.zip&quot;&gt;download&lt;/a&gt; the complete example.&lt;/p&gt;
&lt;h3&gt;Step 1. Choose a file upload plugin&lt;/h3&gt;


	&lt;p&gt;Sure, you can write one yourself (or bake the code directly into your app), but unless you have specific requirements you should take a look at what&#8217;s already there. Even if you do have a good excuse, you can learn from the existing plugins or extend them. The three that I&#8217;ve used over the past two years are:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;&lt;a href=&quot;//www.kanthak.net/opensource/file_column/&quot;&gt;file_column&lt;/a&gt; &#8211; the first file upload plugin available for Rails that I know of, it handles saving files to the filesystem, resizing of images, creation of thumbnails, and integration with rmagick; however it doesn&#8217;t seem to be in active development.&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;//svn.techno-weenie.net/projects/plugins/acts_as_attachment/&quot;&gt;acts_as_attachment&lt;/a&gt; &#8211; written by &lt;a href=&quot;//techno-weenie.net/&quot;&gt;Rick Olson&lt;/a&gt;, it does everything that file_column can, but with a cleaner and extensible code base.&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;//svn.techno-weenie.net/projects/plugins/attachment_fu/&quot;&gt;attachment_fu&lt;/a&gt; &#8211; is a rewrite of acts_as_attachment adding a plugin architecture to extend it to add different image processors (image_science, mini_magick and rmagick are provided) and storage backends (database, file system, and Amazon S3). The only problem is you need Rails 1.2+&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; attachment_fu if you are using Rails 1.2+, otherwise acts_as_attachment.&lt;/p&gt;


	&lt;h3&gt;Step 2. Determine which Image Processor you want to use.&lt;/h3&gt;


attachment_fu supports three processors out of the box:
	&lt;ol&gt;
	&lt;li&gt;&lt;a href=&quot;//seattlerb.rubyforge.org/ImageScience.html&quot;&gt;image_science&lt;/a&gt; &#8211; a light ruby wrapper around the FreeImage library, it can only be  used to resize images. It used to have problems with image quality of thumbnails and &lt;span class=&quot;caps&quot;&gt;PNG&lt;/span&gt; color profiles but these have recently been fixed.&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;//rmagick.rubyforge.org/&quot;&gt;RMagick&lt;/a&gt; &#8211; a ruby wrapper around the ImageMagick/GraphicsMagick libraries, it provides a lot of advanced image processing features. It&#8217;s memory hungry though, and can max resource limits on some shared hosts causing your app to fail; it&#8217;s happened to me a few times on large images.&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;//rubyforge.org/projects/mini-magick/&quot;&gt;minimagick&lt;/a&gt; &#8211; another wrapper around ImageMagick, however it resizes images using imagemagick&#8217;s &lt;a href=&quot;//www.imagemagick.org/script/mogrify.php&quot;&gt;mogrify&lt;/a&gt; command. If you are hitting resource limits on your host, minimagick is preferred over rmagick.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; image_science if you only need image resizing and can handle the slightly inferior thumbnail quality, minimagick otherwise.&lt;/p&gt;


	&lt;h3&gt;Step 3. Install image processors and attachment_fu&lt;/h3&gt;


	&lt;p&gt;The installation process is quite long for the image processors, so I&#8217;ve just linked to them here:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;RMagick/ImageMagick: &lt;a href=&quot;//rmagick.rubyforge.org/install-osx.html&quot;&gt;Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;//rmagick.rubyforge.org/install-linux.html&quot;&gt;Linux&lt;/a&gt;, and &lt;a href=&quot;//rmagick.rubyforge.org/install-faq.html#win&quot;&gt;Windows&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;FreeImage/image_science: &lt;a href=&quot;//seattlerb.rubyforge.org/ImageScience.html&quot;&gt;Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;, Linux&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;To install minimagick: &lt;pre&gt;sudo gem install mini_magick&lt;/pre&gt;&lt;/li&gt;
		&lt;li&gt;To install attachment_fu:&lt;pre&gt;script/plugin install http://svn.techno-weenie.net/projects/plugins/attachment_fu/&lt;/pre&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Step 4. Add uploading to your code&lt;/h3&gt;


I&#8217;ll use a restful model for our file uploads since it&#8217;s all the rage (here&#8217;s a good &lt;a href=&quot;//ueckerman.net/2007/04/24/the-basics-of-rest-in-rails/&quot;&gt;introduction&lt;/a&gt;). You can create a restful scaffold using the following command:
&lt;pre&gt;
ruby script/generate scaffold_resource asset filename:string content_type:string size:integer width:integer height:integer parent_id:integer thumbnail:string created_at:datetime
&lt;/pre&gt;

	&lt;p&gt;This will create the controllers, models, views and a migration. I&#8217;ve included support for saving image properties (&lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes) and thumbnailing (&lt;code&gt;parent_id&lt;/code&gt; and &lt;code&gt;thumbnail&lt;/code&gt; attributes).&lt;/p&gt;


Here is the resulting migration if you want to do it manually:
&lt;pre&gt;
class CreateAssets &amp;lt; ActiveRecord::Migration
  def self.up
    create_table :assets do |t|
      t.column :filename,     :string
      t.column :content_type, :string
      t.column :size,         :integer
      t.column :width,        :integer
      t.column :height,       :integer
      t.column :parent_id,    :integer
      t.column :thumbnail,    :string
      t.column :created_at,   :datetime
    end    
  end

  def self.down
    drop_table :assets
  end
end
&lt;/pre&gt;

	&lt;p&gt;In the model, it&#8217;s really a one liner to add file upload features.&lt;/p&gt;


&lt;pre&gt;
class Asset &amp;lt; ActiveRecord::Base

  has_attachment  :storage =&amp;gt; :file_system, 
                  :max_size =&amp;gt; 1.megabytes,
                  :thumbnails =&amp;gt; { :thumb =&amp;gt; '80x80&amp;gt;', :tiny =&amp;gt; '40x40&amp;gt;' },
                                    :processor =&amp;gt; :MiniMagick # attachment_fu looks in this order: ImageScience, Rmagick, MiniMagick

  validates_as_attachment # ok two lines if you want to do validation, and why wouldn't you?
end
&lt;/pre&gt;

	&lt;p&gt;The &lt;code&gt;has_attachment&lt;/code&gt; (or &lt;code&gt;acts_as_attachment&lt;/code&gt; method for those not using attachment_fu) adds a lot of useful methods such as &lt;code&gt;image?&lt;/code&gt; to determine if the file is an image, and &lt;code&gt;public_filename(thumbnail=nil)&lt;/code&gt; to retrieve the filename for the original or thumbnail. I usually add methods to determine other file types such as movies, music, and documents.&lt;/p&gt;


	&lt;p&gt;The options available are:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;content_type&lt;/code&gt; &#8211; Allowed content types. Allows all by default. Use &lt;code&gt;:image&lt;/code&gt; to allow all standard image types.&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;min_size&lt;/code&gt; &#8211; Minimum size allowed. 1 byte is the default.&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;max_size&lt;/code&gt; &#8211; Maximum size allowed. 1.megabyte&lt;code&gt;&lt;/code&gt; is the default.&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;size&lt;/code&gt; &#8211; Range of sizes allowed. (&lt;code&gt;1..1.megabyte&lt;/code&gt;) is the default. This overrides the &lt;code&gt;:min_size&lt;/code&gt; and &lt;code&gt;:max_size&lt;/code&gt; options.&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;resize_to&lt;/code&gt; &#8211; Used by RMagick to resize images. Pass either an array of width/height, or a geometry string.&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;thumbnails&lt;/code&gt; &#8211; Specifies a set of thumbnails to generate. This accepts a hash of filename suffixes and RMagick resizing options.&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;thumbnail_class&lt;/code&gt; &#8211; Set what class to use for thumbnails. This attachment class is used by default.&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;path_prefix&lt;/code&gt; &#8211; path to store the uploaded files. Uses &lt;code&gt;public/#{table_name}&lt;/code&gt; by default for the filesystem, and just &lt;code&gt;#{table_name}&lt;/code&gt;
   for the S3 backend. Setting this sets the &lt;code&gt;:storage&lt;/code&gt; to &lt;code&gt;:file_system&lt;/code&gt;.&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;storage&lt;/code&gt; &#8211; Use &lt;code&gt;:file_system&lt;/code&gt; to specify the attachment data is stored with the file system. Defaults to &lt;code&gt;:db_system&lt;/code&gt;.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;In the above we&#8217;re storing the files in the file system and are adding two thumbnails if it&#8217;s an image: one called &#8216;thumb&#8217; no bigger than 80&#215;80 pixels, and the other called &#8216;tiny&#8217;. By default, these will be stored in the same directory as the original: /public/assets/nnnn/mmmm/ with their thumbnail name as a suffix. To show them in the view, we just do the following: &lt;code&gt;&amp;lt;%= image_tag(image.public_filename(:thumb)) %&amp;gt;&lt;/code&gt;&lt;/p&gt;


&lt;p&gt;&lt;code&gt;validates_as_attachment&lt;/code&gt; ensures that &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;content_type&lt;/code&gt; and &lt;code&gt;filename&lt;/code&gt; are present and checks against the options given to &lt;code&gt;has_attachment&lt;/code&gt;; in our case the original should be no larger than 1 megabyte.&lt;/p&gt;

	&lt;p&gt;Next, we&#8217;ll work on the view code. To enable multipart file uploads, we need to set &lt;code&gt;multipart =&amp;gt; true&lt;/code&gt; as a form option in &lt;code&gt;new.rhtml&lt;/code&gt;. The &lt;code&gt;uploaded_data&lt;/code&gt; file input field is used by attachment_fu to store the file contents in an attribute so that attachment_fu can do its magic when the &lt;code&gt;uploaded_data=&lt;/code&gt; method is called.&lt;/p&gt;


&lt;pre&gt;
&amp;lt;%= error_messages_for :asset %&amp;gt;
&amp;lt;% form_for(:asset, :url =&amp;gt; assets_path, :html =&amp;gt; { :multipart =&amp;gt; true }) do |form| %&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;label for=&quot;uploaded_data&quot;&amp;gt;Upload a file:&amp;lt;/label&amp;gt;
    &amp;lt;%= form.file_field :uploaded_data %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= submit_tag &quot;Create&quot; %&amp;gt;
  &amp;lt;/p&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;We&#8217;ll also pretty up the index code. We want to show a thumbnail if the file is an image, otherwise just the name:&lt;/p&gt;


&lt;pre&gt;
&amp;lt;h1&amp;gt;Listing assets&amp;lt;/h1&amp;gt;

&amp;lt;ul id=&quot;assets&quot;&amp;gt;
&amp;lt;% @assets.each do |asset| %&amp;gt;
&amp;lt;li id=&quot;asset_&amp;lt;%= asset.id %&amp;gt;&quot;&amp;gt;
&amp;lt;% if asset.image? %&amp;gt;
&amp;lt;%= link_to(image_tag(asset.public_filename(:thumb))) %&amp;gt;&amp;lt;br /&amp;gt;
&amp;lt;% end %&amp;gt;
&amp;lt;%= link_to(asset.filename, asset_path(asset)) %&amp;gt; (&amp;lt;%= link_to &quot;Delete&quot;, asset_path(asset), :method =&amp;gt; :delete, :confirm =&amp;gt; &quot;are you sure?&quot;%&amp;gt;)
&amp;lt;/li&amp;gt;
&amp;lt;% end %&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;br /&amp;gt;

&amp;lt;%= link_to 'New asset', new_asset_path %&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;Don&#8217;t forget to do a &lt;code&gt;rake db:migrate&lt;/code&gt; to add the assets table. At this stage you can start your server and go to &lt;a&gt;http://localhost:3000/assets/new&lt;/a&gt; to add a new file. After being redirected back to the index page you&#8217;ll notice that thumbnails are showing in our index with the originals. To get rid of this, we can modify &lt;code&gt;assets_controller&lt;/code&gt; to only display originals by checking if the &lt;code&gt;parent_id&lt;/code&gt; attribute is &lt;code&gt;nil&lt;/code&gt;. attachment_fu also allows you to store thumbnails into a different model, which would make this step unnecessary.&lt;/p&gt;


&lt;pre&gt;
  def index
    @assets = Asset.find(:all, :conditions =&amp;gt; {:parent_id =&amp;gt; nil}, :order =&amp;gt; 'created_at DESC')
    respond_to do |format|
      format.html # index.rhtml
      format.xml  { render :xml =&amp;gt; @assets.to_xml }
    end
  end
&lt;/pre&gt;

	&lt;h3&gt;Step 5. &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; it&lt;/h3&gt;


	&lt;p&gt;Let&#8217;s try and &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; our file uploads. The current user flow is:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;go to index page&lt;/li&gt;
		&lt;li&gt;click on “new file” link&lt;/li&gt;
		&lt;li&gt;choose a file and submit the form&lt;/li&gt;
		&lt;li&gt;get redirected to index.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;What we want to happen is to have all that occur on the index page, with no page refreshes. Normally you would do the following:&lt;/p&gt;


	&lt;h4&gt;Add the Javascript prototype/scriptaculous libraries into your layout.&lt;/h4&gt;


&lt;pre&gt;&amp;lt;%= javascript_include_tag :defaults %&amp;gt;&lt;/pre&gt;

	&lt;h4&gt;Change the &lt;code&gt;form_for&lt;/code&gt; tag to a &lt;code&gt;remote_form_for&lt;/code&gt;&lt;/h4&gt;


&lt;pre&gt;&amp;lt;% remote_form_for(:asset, :url =&amp;gt; assets_path, :html =&amp;gt; { :multipart =&amp;gt; true }) do |f| %&amp;gt;&lt;/pre&gt;

	&lt;h4&gt;Add &lt;code&gt;format.js&lt;/code&gt; to the &lt;code&gt;create&lt;/code&gt; action in the controller to handle &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; requests:&lt;/h4&gt;


&lt;pre&gt;
  def create
    @asset = Asset.new(params[:asset])
    respond_to do |format|
      if @asset.save
        flash[:notice] = 'Asset was successfully created.'
        format.html { redirect_to asset_url(@asset) }
        format.xml  { head :created, :location =&amp;gt; asset_url(@asset) }
        format.js
      else
        format.html { render :action =&amp;gt; &quot;new&quot; }
        format.xml  { render :xml =&amp;gt; @asset.errors.to_xml }
        format.js
      end
    end
  end
&lt;/pre&gt;

	&lt;h4&gt;Make a &lt;code&gt;create.rjs&lt;/code&gt; file to insert the asset at the bottom of your list:&lt;/h4&gt;


&lt;pre&gt;
page.insert_html :bottom, &quot;assets&quot;, :partial =&amp;gt; 'assets/list_item', :object =&amp;gt; @asset
page.visual_effect :highlight, &quot;asset_#{@asset.id}&quot; 
&lt;/pre&gt;

	&lt;h4&gt;Create a partial to show the image in the list&lt;/h4&gt;


&lt;pre&gt;
&amp;lt;li id=&quot;asset_&amp;lt;%= list_item.id %&amp;gt;&quot;&amp;gt;
&amp;lt;% if list_item.image? %&amp;gt;
&amp;lt;%= link_to(image_tag(list_item.public_filename(:thumb))) %&amp;gt;&amp;lt;br /&amp;gt;
&amp;lt;% end %&amp;gt;
&amp;lt;%= link_to(list_item.filename, asset_path(list_item))%&amp;gt; (&amp;lt;%= link_to_remote(&quot;Delete&quot;, {:url =&amp;gt; asset_path(list_item), :method =&amp;gt; :delete, :confirm =&amp;gt; &quot;are you sure?&quot;}) %&amp;gt;)
&amp;lt;/li&amp;gt;
&lt;/pre&gt;

	&lt;h4&gt;Add &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; deletion (optional)&lt;/h4&gt;


	&lt;p&gt;If you&#8217;ve noticed the changes in the previous code, I&#8217;ve added &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; deletion of files as well. To enable this on the server we add a &lt;code&gt;destroy.rjs&lt;/code&gt; file to remove the deleted file form the list.&lt;/p&gt;


&lt;pre&gt;
page.remove &quot;asset_#{@asset.id}&quot; 
&lt;/pre&gt;

	&lt;p&gt;In the controller you also need to add &lt;code&gt;format.js&lt;/code&gt; to the &lt;code&gt;delete&lt;/code&gt; action.&lt;/p&gt;


	&lt;h4&gt;Keep our form views &lt;span class=&quot;caps&quot;&gt;DRY&lt;/span&gt; (optional)&lt;/h4&gt;


	&lt;p&gt;We should also make the file upload form contents into a partial and use it in &lt;code&gt;new.rhtml&lt;/code&gt; as well as &lt;code&gt;index.rhtml&lt;/code&gt;.&lt;/p&gt;


&lt;code&gt;_form.rhtml&lt;/code&gt;
&lt;pre&gt;
  &amp;lt;p&amp;gt;
    &amp;lt;label for=&quot;uploaded_data&quot;&amp;gt;Upload a file:&amp;lt;/label&amp;gt;
    &amp;lt;%= form.file_field :uploaded_data %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= submit_tag &quot;Create&quot; %&amp;gt;
  &amp;lt;/p&amp;gt;
&lt;/pre&gt;

&lt;code&gt;new.rhtml&lt;/code&gt;
&lt;pre&gt;
&amp;lt;% form_for(:asset, :url =&amp;gt; assets_path, :html =&amp;gt; { :multipart =&amp;gt; true }) do |form| %&amp;gt;
&amp;lt;%= render(:partial =&amp;gt; '/assets/form', :object =&amp;gt; form)%&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/pre&gt;

	&lt;h4&gt;Add the form to &lt;code&gt;index.rhtml&lt;/code&gt;&lt;/h4&gt;


&lt;pre&gt;
&amp;lt;% remote_form_for(:asset, :url =&amp;gt; assets_path, :html =&amp;gt; { :multipart =&amp;gt; true }) do |form| %&amp;gt;
&amp;lt;%= render(:partial =&amp;gt; '/assets/form', :object =&amp;gt; form) %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;Now that we have all our code in place, go back to the index page where you should be able to upload a new file using &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt;. The new file  should appear at the bottom of our list of files with a visual highlight!&lt;/p&gt;


	&lt;p&gt;Unfortunately there is only one problem. There is a security restriction with javascript to prevent access to the filesystem. If you used validations for your asset model you would have gotten an error complaining about missing attributes. This is because only the filename is sent to the server, not the file itself. How can we solve this issue?&lt;/p&gt;


	&lt;h3&gt;Step 6. Using iframes and responds_to_parent&lt;/h3&gt;


	&lt;p&gt;To get around the &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt;/file upload problem we make use of the &lt;a href=&quot;//developer.apple.com/internet/webcontent/iframe.html&quot;&gt;iframe remoting pattern&lt;/a&gt;. To do this we need a hidden iframe and target our form&#8217;s action to that iframe. First, we change the &lt;code&gt;index.rhtml&lt;/code&gt; to go back to using a &lt;code&gt;form_for&lt;/code&gt; tag. But how will we get rails to process our action like an &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; request you ask? We simply add a &#8221;.js&#8221; extension to the form&#8217;s action! We then set the iframe to a 1&#215;1 sized pixel so it doesn&#8217;t get shown. Don&#8217;t use &lt;code&gt;display:none&lt;/code&gt; otherwise your iframe will be hidden from your form depending on your browser you will end up opening a new window, loading the server response in the main window, or downloading the server response as a file.&lt;/p&gt;


&lt;pre&gt;
&amp;lt;% form_for(:asset, :url =&amp;gt;formatted_assets_path(:format =&amp;gt; 'js'), :html =&amp;gt; { :multipart =&amp;gt; true, :target =&amp;gt; 'upload_frame'}) do |form| %&amp;gt;
&amp;lt;%= render(:partial =&amp;gt; '/assets/form', :object =&amp;gt; form) %&amp;gt;
&amp;lt;% end %&amp;gt;
&amp;lt;iframe id='upload_frame' name=&quot;upload_frame&quot; style=&quot;width:1px;height:1px;border:0px&quot; src=&quot;about:blank&quot;&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/pre&gt;

To handle the form on the server, we can use Sean Treadway&#8217;s &lt;a href=&quot;//sean.treadway.info/responds-to-parent/&quot;&gt;responds_to_parent plugin&lt;/a&gt;.
&lt;pre&gt;
script/plugin install http://responds-to-parent.googlecode.com/svn/trunk/
&lt;/pre&gt;

	&lt;p&gt;This plugin makes it dead simple to send javascript back to the parent window, not the iframe itself. You need to restart your server to load the plugin.&lt;/p&gt;


	&lt;p&gt;Just add the following to your &lt;code&gt;create&lt;/code&gt; action in the controller:&lt;/p&gt;


&lt;pre&gt;
def create
  @asset = Asset.new(params[:asset])
  respond_to do |format|
    if @asset.save
      flash[:notice] = 'Asset was successfully created.'
      format.html { redirect_to asset_url(@asset) }
      format.xml  { head :created, :location =&amp;gt; asset_url(@asset) }
      format.js do
        responds_to_parent do
          render :update do |page|
            page.insert_html :bottom, &quot;assets&quot;, :partial =&amp;gt; 'assets/list_item', :object =&amp;gt; @asset
            page.visual_effect :highlight, &quot;asset_#{@asset.id}&quot; 
          end
        end          
      end
    else
      format.html { render :action =&amp;gt; &quot;new&quot; }
      format.xml  { render :xml =&amp;gt; @asset.errors.to_xml }
      format.js do
        responds_to_parent do
          render :update do |page|
              # update the page with an error message
          end
        end          
      end
    end
  end
end
&lt;/pre&gt;

	&lt;p&gt;At this point you no longer need the &lt;code&gt;create.rjs&lt;/code&gt; file.&lt;/p&gt;


	&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;NOW&lt;/span&gt; you should be able to get your index page and upload a file the &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; way!&lt;/p&gt;


	&lt;h3&gt;Step 7. Make it production ready&lt;/h3&gt;


	&lt;p&gt;There are some more changes you need to make it production ready:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;handling errors, &lt;/li&gt;
		&lt;li&gt;displaying error messages when uploading fails,&lt;/li&gt;
		&lt;li&gt;showing some feedback to the user &#8211; such as a spinner &#8211; while the file is uploading or being deleted&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;But most of the head scratching work is done. Hope that helps.&lt;/p&gt;


	&lt;h3&gt;Step 8. Bonus: making a file download by clicking on a link&lt;/h3&gt;


Just add the following action to your assets controller; don&#8217;t forget to add the route to your &lt;code&gt;routes.rb&lt;/code&gt; file.
&lt;pre&gt;
  def download
    @asset = Asset.find(params[:id])
    send_file(&quot;#{RAILS_ROOT}/public&quot;+@asset.public_filename, 
      :disposition =&amp;gt; 'attachment',
      :encoding =&amp;gt; 'utf8', 
      :type =&amp;gt; @asset.content_type,
      :filename =&amp;gt; URI.encode(@asset.filename)) 
  end
&lt;/pre&gt;

	&lt;p&gt;Update: 2007/05/23 Thanks to &lt;a href=&quot;//mad.ly/&quot;&gt;Geoff Buesing&lt;/a&gt; for pointing out that we can use formatted_routes.&lt;/p&gt;


	&lt;p&gt;Update: 2007/05/26 Updated a bug in the initial index.html example (thanks Benedikt!) and added a download link to the final example (see the first paragraph).&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2006-05-12:15</id>
    <published>2006-05-12T14:39:00Z</published>
    <updated>2006-12-16T13:39:54Z</updated>
    <category term="Travel"/>
    <link href="http://khamsouk.souvanlasy.com/2006/5/12/a-long-flight" rel="alternate" type="text/html"/>
    <title>A long flight</title>
<summary type="html">&lt;p&gt;Here I am writing from my cousin's apartment in the West Village, N.Y. Longest flight ever. Short version: cancelled flight, delays at every point of the trip, and lost luggage. Welcome to the America :D&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Here I am writing from my cousin's apartment in the West Village, N.Y. Longest flight ever. Short version: cancelled flight, delays at every point of the trip, and lost luggage. Welcome to the America :D&lt;/p&gt;
&lt;p&gt;The long story: The direct leg from Osaka to Chicago wasn't too bad, but it went all crazy from there. After being digitally finger printed and having our photos taken at immigration, we went to the domestic transit counter only to be told that our 6:00 pm flight from Chicago to LaGuardia had been cancelled due to bad weather! We were to wait for the next available flight at 7:00 pm, but when we got to the other gate, we were told to see customer service instead.
&lt;/p&gt;
&lt;p&gt;The name Customer Service Counter is probably a joke on their end. Normally you think of several people helping out customers with their problems, not a couple of staff directing you to a series of phone booths to wait for a customer service agent to call you! It's a bit jarring if you're used to the level of service at domestic Japanese airlines; it's times like these you realise the effect of all this cost cutting.
&lt;/p&gt;
&lt;p&gt;The process itself is not difficult if you can speak english, but my fellow Japanese travelers would have found it really difficult to go through the whole process of being on stand-by and dealing with the process over a phone.
&lt;/p&gt;
&lt;p&gt;Our customer service agent told us we were not on stand-by on the next flight as we were previously told, but the 6:00 am flight the next morning. I don't think so! Luckily, she gave us the option to use another airline, and we were booked on their next available flight. 
&lt;/p&gt;
&lt;p&gt;Just our luck, the flight was to leave in 30 minutes. We made a mad dash from Terminal 1 to Terminal 3 only to find out this flight was late by over one hour. After 30 minutes of waiting our gate then changed. When the flight got to New York, we were put into a holding pattern for 30 minutes and then when we landed we waited another 30 minutes to be towed into the gate. At this point were about 2 hours late.
&lt;/p&gt;
&lt;p&gt;Next was picking up our luggage. Only problem was, it wasn't there. In baggage claim, they were very nice about it all, and promised to deliver it to us the next day. On a whim, we decided to check our original airline. Apparently, they thought we were still on their flight at 7:00 pm and our bags popped out on conveyer belt just minutes after. *sigh*
&lt;/p&gt;
&lt;p&gt;We waited in line at the taxi stand and met a very nice woman from Connecticut 
who was, funnily enough, off to meet some Australian friends at the Marriot. After some small chat, she told us about some unscrupulous people who offered you the opportunity to skip the taxi line and use their service instead. What they don't tell you before hand is that it will cost $90 to get where you are going instead of the usual $25! Right on cue, they came and bugged us for a while before looking for the next group that looked like tourists.
&lt;/p&gt;
&lt;p&gt;After a 20 minute ride we got to my cousin's place safe, if a little tired, at 1:30 am in the morning, 3 hours late.
&lt;/p&gt;
&lt;p&gt;Today, we are heading off to the &lt;a href=&quot;http://www.moma.org/&quot;&gt;Museum of Modern Art (MoMA)&lt;/a&gt;. Too rainy to do anything else (I'm a rain man, but that's for another blog entry) but I've really been looking forward to checking it out, staring out things to buy at their &lt;a href=&quot;http://www.momastore.org/&quot;&gt;online shop&lt;/a&gt; the past few weeks :D&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2006-01-06:14</id>
    <published>2006-01-06T13:38:00Z</published>
    <updated>2007-10-11T21:55:08Z</updated>
    <category term="Australia"/>
    <category term="Japan"/>
    <link href="http://khamsouk.souvanlasy.com/2006/1/6/bluefire-grill-vs-barbacoa" rel="alternate" type="text/html"/>
    <title>Bluefire Grill vs Barbacoa</title>
<summary type="html">&lt;p&gt;On my trip to Oz over the festive season I tried out &lt;a href=&quot;http://www.bluefiregrill.com.au/newquay/newquay.htm&quot;&gt;Bluefire Grill&lt;/a&gt; at the Docklands in Melbourne. It's a &lt;a href=&quot;http://en.wikipedia.org/wiki/Churrascaria&quot;&gt;churrascaria&lt;/a&gt; style restaurant, offering seafood, calamari, chicken, lamb, beef &amp;amp; pork served on skewers and carved at the table for AU$50. It's fine in itself, but doesn't hold a candle to &lt;a href=&quot;http://metropolis.japantoday.com/tokyo/447/restaurants.asp&quot;&gt;Barbacoa&lt;/a&gt; in Omotesando, Tokyo (&lt;a href=&quot;http://www.tokyo.to/barbacoa/barbacoamap.html&quot;&gt;Map&lt;/a&gt;).&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;On my trip to Oz over the festive season I tried out &lt;a href=&quot;http://www.bluefiregrill.com.au/newquay/newquay.htm&quot;&gt;Bluefire Grill&lt;/a&gt; at the Docklands in Melbourne. It's a &lt;a href=&quot;http://en.wikipedia.org/wiki/Churrascaria&quot;&gt;churrascaria&lt;/a&gt; style restaurant, offering seafood, calamari, chicken, lamb, beef &amp;amp; pork served on skewers and carved at the table for AU$50. It's fine in itself, but doesn't hold a candle to &lt;a href=&quot;http://metropolis.japantoday.com/tokyo/447/restaurants.asp&quot;&gt;Barbacoa&lt;/a&gt; in Omotesando, Tokyo (&lt;a href=&quot;http://www.tokyo.to/barbacoa/barbacoamap.html&quot;&gt;Map&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For &amp;yen;3,300 (~ AU$40), you can get served skewers of 18 different cuts of beef - some cooked differently such as garlic or pepper - as well as roasted herb chicken, cheese bread (which is surprisingly tasty), roasted pineapple, and unlimited access to the salad bar. You can also opt for the &amp;yen;5,200 (~ AU$60) drink set which includes all you can drink house wine, beer, &lt;a href=&quot;http://en.wikipedia.org/wiki/Caipirinha&quot;&gt;caipirinha&lt;/a&gt;, coffee and tea. Vegetarians can opt for the salad bar only option for a measly &amp;yen;2,700 (~ AU$32). It's a damn good deal, especially for its location. It's one of the few restaurants where I go for the toilet break option in middle of a meal :). Usually I get so full that I often opt for a taxi fare home instead of taking the train!
&lt;/p&gt;
&lt;p&gt;
The service at Barbacoa is, as usual in Japan, great; but sometimes it's a bit hard to get the notice of the waiters as they move pretty quickly between tables to serve the overfed masses. An interesting way to help them determine who to serve is the use of a plastic coin. One side tells them at a glance whether you want more meat, while the other side tells them to stop serving you for the moment.
&lt;/p&gt;
&lt;p&gt;
Bluefire has great service as well, the staff are more friendly and talkative but there were some small exceptions to their service: the oil from skewers of beef dripped on my shoes while they were being cut (although I guess that's what you get when you don't sit down at the table properly!), and Sherri was served a cut of beef that had been unceremoniously retrieved from the table. Oh, and they really need to put a big sign advertising their restaurant out the front; we must have walked past it several times. After we were seated, three other groups complained about the difficulty in finding the place as well!
&lt;/p&gt;
&lt;p&gt;
Overall, they're both great places to eat, but I think I'll miss Barbacoa when I finally leave Japan.
&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2006-01-04:13</id>
    <published>2006-01-04T13:37:00Z</published>
    <updated>2006-12-16T13:38:16Z</updated>
    <category term="Australia"/>
    <link href="http://khamsouk.souvanlasy.com/2006/1/4/everyone-seems-to-be-a-wine-buff-these-days" rel="alternate" type="text/html"/>
    <title>Everyone seems to be a wine buff these days ...</title>
<summary type="html">Everyone seems to be a wine buff these days ...</summary><content type="html">
            Everyone seems to be a wine buff these days ...
&lt;p&gt;Being somewhat of a guest I didn't have to fork out too much, except for one night which my wallet doesn't want to remember (tip: don't go out drinking in a group where there is an inordinate imbalance of Singaporean girls to men). A curse I have is that when I drink a lot I still have a good head on my shoulders and what I noticed this time round was that a lot more people had become wine buffs.
&lt;/p&gt;&lt;p&gt;
Now, don't get me wrong, I like my wine, especially a red. After my few years of drinking I can tell what I like and don't like. I even know I should usually swirl my glass to let an old wine breathe. But nowadays, there seems to be an expectation that if you drink it, you should have a long conversation about it. That's fine, but don't put on an act (hint: your wine glass is not a washing machine!). Just enjoy it. You're not at a wine tasting but having a few good drinks with friends. I read this article on waiterrant.net today on &lt;a href=&quot;http://waiterrant.net/?p=250&quot;&gt;How to order wine without looking like an asshole&lt;/a&gt; which I found really funny, and reminded me of some of the stuff I saw.
&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2006-01-03:12</id>
    <published>2006-01-03T13:37:00Z</published>
    <updated>2006-12-16T13:37:40Z</updated>
    <link href="http://khamsouk.souvanlasy.com/2006/1/3/a-time-for-reflection-and-growth" rel="alternate" type="text/html"/>
    <title>A time for reflection and growth</title>
<summary type="html">&lt;p&gt;
When each year ends, it begins a time of reflection; on past accomplishments and positive life changing events, as well as failures and loss. Hopefully for most of us it was more of the former, and less of the latter.
&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;
When each year ends, it begins a time of reflection; on past accomplishments and positive life changing events, as well as failures and loss. Hopefully for most of us it was more of the former, and less of the latter.
&lt;/p&gt;
&lt;p&gt;
This time I've also realized that I'm stuck in a rut. Looking in from outside of my little box, a lot of things have happened. However, when living it day by day, everything seems to be one long repetitive blur. So my New Year's resolution is to break this cycle of monotony by taking on the various ideas that have been floating around my head the last few months.
&lt;/p&gt;&lt;p&gt;
Without change, there's no growth, only stagnation.
&lt;/p&gt;&lt;p&gt;
I hope this year brings much joy and happiness to you and your loved ones.
&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2005-09-07:11</id>
    <published>2005-09-07T14:36:00Z</published>
    <updated>2006-12-16T13:37:01Z</updated>
    <category term="Mac"/>
    <link href="http://khamsouk.souvanlasy.com/2005/9/7/so-my-birthday-is-coming-up" rel="alternate" type="text/html"/>
    <title>So my birthday is coming up ...</title>
<summary type="html">&lt;p&gt;And just when I was wondering what some kind person could get me, at a special media event Apple released a new version of the iPod. The &lt;a href=&quot;http://www.apple.com/ipodnano/&quot;&gt;iPod Nano&lt;/a&gt;. It's a replacement for the iPod mini and has a color screen and is apparently as thin as a pencil according to Apple's marketing materials ;). It comes in 2GB and 4GB versions.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;And just when I was wondering what some kind person could get me, at a special media event Apple released a new version of the iPod. The &lt;a href=&quot;http://www.apple.com/ipodnano/&quot;&gt;iPod Nano&lt;/a&gt;. It's a replacement for the iPod mini and has a color screen and is apparently as thin as a pencil according to Apple's marketing materials ;). It comes in 2GB and 4GB versions.&lt;/p&gt;
&lt;p&gt;At the same event, Motorola and Apple announced an iTunes compatible mobile phone, the &lt;a href=&quot;http://www.apple.com/itunes/mobile/&quot;&gt;ROKR&lt;/a&gt;. It can store up to 100 songs. However it is only available in the USA for now.&lt;/p&gt;&lt;p&gt;There is also a new version of &lt;a href=&quot;http://www.apple.com/quicktime/mac.html&quot;&gt;Quicktime&lt;/a&gt; and &lt;a href=&quot;http://www.apple.com/itunes/download/&quot;&gt;iTunes 5&lt;/a&gt; to download.&lt;/p&gt;&lt;p&gt;So about my birthday on the 13th, 4GB anyone? Hello? ... is anyone there? Where'd you all go?&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2005-09-06:10</id>
    <published>2005-09-06T14:35:00Z</published>
    <updated>2006-12-16T13:36:16Z</updated>
    <category term="Programming"/>
    <link href="http://khamsouk.souvanlasy.com/2005/9/6/debugging-javascript-no-longer-a-complete-pain-now-only-a-little" rel="alternate" type="text/html"/>
    <title>Debugging JavaScript no longer a complete pain (now only a little).</title>
<summary type="html">&lt;p&gt;I used to hate coding JavaScript. Not because of the language (well maybe a bit) but the many countless hours littering code with alert() messages to see where things were going wrong. Sure, Mozilla has &lt;a href=&quot;http://www.mozilla.org/projects/venkman/&quot;&gt;Venkman&lt;/a&gt;, but what happens when the error occurs in Safari, Opera or Internet Explorer? I really don't want to go through Message Box hell again now that I'm getting my feet wet with AJAX. Enter fvloggger by David F. Miller.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I used to hate coding JavaScript. Not because of the language (well maybe a bit) but the many countless hours littering code with alert() messages to see where things were going wrong. Sure, Mozilla has &lt;a href=&quot;http://www.mozilla.org/projects/venkman/&quot;&gt;Venkman&lt;/a&gt;, but what happens when the error occurs in Safari, Opera or Internet Explorer? I really don't want to go through Message Box hell again now that I'm getting my feet wet with AJAX. Enter fvloggger by David F. Miller.&lt;/p&gt;
&lt;p&gt;Based on (almost) everyone's favorite free logging tool &lt;a href=&quot;http://logging.apache.org/log4j/&quot;&gt;Log4J&lt;/a&gt;; it allows you to add logging messages to an element in the DOM tree, so there's no more need to create annoying alert() messages to see what's going on. An introduction to fvlogger can be found in this &lt;a href=&quot;http://www.alistapart.com:80/articles/jslogging&quot;&gt;article&lt;/a&gt; on &lt;a href=&quot;http://www.alistapart.com&quot;&gt;A List Apart&lt;/a&gt;. Happy AJAXing.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2005-07-06:9</id>
    <published>2005-07-06T14:34:00Z</published>
    <updated>2006-12-16T13:35:29Z</updated>
    <category term="Japan"/>
    <link href="http://khamsouk.souvanlasy.com/2005/7/6/fukuoka-and-star-wars-iii-at-last" rel="alternate" type="text/html"/>
    <title>Fukuoka and Star Wars III (at last!)</title>
<summary type="html">&lt;p&gt;As usual with my last few trips I brought the rain with me to Fukuoka, the main city of Kyushu island. It was my first time there but we didn't really have a lot of time to do the tourist thing, since we were there to meet Uzuki's relatives and visit her family's cemetery on Sunday.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;As usual with my last few trips I brought the rain with me to Fukuoka, the main city of Kyushu island. It was my first time there but we didn't really have a lot of time to do the tourist thing, since we were there to meet Uzuki's relatives and visit her family's cemetery on Sunday.&lt;/p&gt;

&lt;p&gt;On Saturday we did manage to try some Hakata ramen and ate gyoza at the yatai (food stalls) along the river. We also did a bit of shopping at Canal City where I bought a couple of T-shirts for the impending hot and humid summer. Not much sight seeing because of the rain though :/&lt;/p&gt;
&lt;p&gt;I also caught a late night &quot;premiere&quot; of Star Wars III which will be in full release this weekend in Japan. There are some really fantastic scenes but I felt the dialogue really needed some work; most lines and scenes - especially towards the end - seemed to be there to tie up loose ends or to explain away inconsitencies brought about  due to events in Episodes I and II e.g. Senator Organa off-hand request to wipe C3PO's memory (why not R2D2 as well?). I think the worst scene of all was Darth Vader shouting out after being told &lt;strong&gt;&amp;lt;spoiler&amp;gt;&lt;/strong&gt;he was the one who killed Padme&lt;strong&gt;&amp;lt;/spoiler&amp;gt;&lt;/strong&gt;; it looked like a scene from a bad B-Movie. When I returned to Tokyo Sunday night, Episode IV was shown on TV and it was really interesting to compare the two.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2005-06-27:8</id>
    <published>2005-06-27T14:34:00Z</published>
    <updated>2006-12-16T13:34:44Z</updated>
    <link href="http://khamsouk.souvanlasy.com/2005/6/27/the-future-now-with-only-one-thing-certain-in-life-taxes" rel="alternate" type="text/html"/>
    <title>The future, now with only one thing certain in life ... Taxes!</title>
<summary type="html">&lt;p&gt;&lt;a href=&quot;http://www.news.com.au/story/0,10117,15739502-13762,00.html&quot;&gt;http://www.news.com.au/story/0,10117,15739502-13762,00.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Now that scientists in the U.S. have managed to revive dogs that have been clinically dead for three hours it won't be long until tests start on humans.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;a href=&quot;http://www.news.com.au/story/0,10117,15739502-13762,00.html&quot;&gt;http://www.news.com.au/story/0,10117,15739502-13762,00.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Now that scientists in the U.S. have managed to revive dogs that have been clinically dead for three hours it won't be long until tests start on humans.&lt;/p&gt;
&lt;p&gt;The process of revival seems like something out of a horror movie: drain the blood while replacing it with a cold saline solution keeping the body temperature at around 7&#730;C, then replace the blood and give your subject 100% oxygen and an electric shock to restart the heart.
&lt;/p&gt;&lt;p&gt;I think this'll be useful to preserve bodies during transport when they are reaching clinical death or to &quot;stabilise&quot; the body after massive blood loss; allowing doctors to attempt to repair whatever is wrong in a stable condition.&lt;/p&gt;&lt;p&gt;I can imagine in the future we'll have &quot;rejuvenation&quot; surgery to replace old organs. Body parts can be cloned before the surgery, or in rare cases while we are in suspended animation, and doctors can repair whatever is needed in this suspended state.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2005-06-16:7</id>
    <published>2005-06-16T14:33:00Z</published>
    <updated>2006-12-16T13:34:00Z</updated>
    <category term="Japan"/>
    <link href="http://khamsouk.souvanlasy.com/2005/6/16/mmmm-beer" rel="alternate" type="text/html"/>
    <title>Mmmm....Beer?</title>
<summary type="html">&lt;p&gt;Usually I don't drink beer when I go out since I'm more partial to a drop of red wine; however, one of my favorite places to go out for a meal and drinks is &lt;a href=&quot;http://www.brussels.co.jp/STORES/hydropathes.html&quot;&gt;Les Hydropathes&lt;/a&gt; in Shibuya (usually as a regular meet up joint with my good friend Mikihiro).
&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Usually I don't drink beer when I go out since I'm more partial to a drop of red wine; however, one of my favorite places to go out for a meal and drinks is &lt;a href=&quot;http://www.brussels.co.jp/STORES/hydropathes.html&quot;&gt;Les Hydropathes&lt;/a&gt; in Shibuya (usually as a regular meet up joint with my good friend Mikihiro).
&lt;/p&gt;
&lt;p&gt;It's a belgian beer bar with a nice beer menu (of course!) from White beer all the way to Trappist beer, probably over 50 in all, with 3 types of beer on tap as specials of the day. I would guess I've gone through over 15 beers so far, my favorites for now are Chimay Blue and Rocheford Number 10; yes, I like my dark beer!&lt;/p&gt;&lt;p&gt;The food there is also great; they serve a Mussel soup there which is fantastic and after you've finished with the mussels you can ask them to make a pasta with the rest of it. They also have some of the best &#29983;&#12495;&#12512; (raw ham) in town as well as chips with mayonnaise.&lt;/p&gt;&lt;p&gt;I took Simon (an old pal of Annie's) along to the last meetup on Friday. He's working in Japan for the next couple of months, I had not seen him in  ages, hopefully he enjoyed it. We were supposed to go to the Aegean greek restaurant but I didn't read the map properly and we spent 10 minutes in the rain looking for it on the wrong side of the station. Luckily, Les Hyrdropathes was close by!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2005-05-30:6</id>
    <published>2005-05-30T14:32:00Z</published>
    <updated>2007-05-04T05:27:48Z</updated>
    <category term="Programming"/>
    <link href="http://khamsouk.souvanlasy.com/2005/5/30/what-kind-of-developer-are-you" rel="alternate" type="text/html"/>
    <title>What kind of developer are you?</title>
<summary type="html">&lt;p&gt;After seeing an overhanging brace that looks at you funny in someone else's code, do you:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Spend several hours methodically reformatting (and rewriting) their code using vi/emacs/NOTEPAD.EXE only to have it changed back on your next check-out.&lt;/li&gt;&lt;li&gt;Start a &quot;reformat code&quot; war using your favorite IDE with the other developer, impressing your peers with the amount of commits the both of you do everyday.&lt;/li&gt;&lt;li&gt;Say fugeddaboutit (one of the guys will change it anyway) and leave work early for a beer at the local.&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">
            &lt;p&gt;After seeing an overhanging brace that looks at you funny in someone else's code, do you:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Spend several hours methodically reformatting (and rewriting) their code using vi/emacs/NOTEPAD.EXE only to have it changed back on your next check-out.&lt;/li&gt;&lt;li&gt;Start a &quot;reformat code&quot; war using your favorite IDE with the other developer, impressing your peers with the amount of commits the both of you do everyday.&lt;/li&gt;&lt;li&gt;Say fugeddaboutit (one of the guys will change it anyway) and leave work early for a beer at the local.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;After encountering an empty commit message when investigating a problem caused by a merge, do you:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Lecture the other developer on the reasons for good software practices and procedures, and how it saves time when chasing bugs after merging code branches.&lt;/li&gt;&lt;li&gt;Drive them up the wall by adding empty commit messages to your insignificant changes to their code.&lt;/li&gt;&lt;li&gt;Blame it on the other developer and convince them to solve the problem for you.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;When you create a simple java bean do you:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Hand-code the whole class including corresponding hashcode() and equals() methods.&lt;/li&gt;&lt;li&gt;Create a suite of test cases using your favorite unit test tools and then start coding.&lt;/li&gt;&lt;li&gt;Use an IDE wizard to create the class, its attributes and helper methods without checking the code it produces.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;When asked to write a program to convert a text file into HTML do you:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Write a single line of obfuscated, unmaintainable PERL code that you'll forget about after writing that lengthy commit message.&lt;/li&gt;&lt;li&gt;Import a 200kb Jar file to convert the text into XML (since you read a benchmark showing it's faster than what ships with the JDK) and then apply XSL to change it into strict XHTML; requiring all your clients to upgrade to the latest standards compliant web browser.&lt;/li&gt;&lt;li&gt;Find a program on the internet that you can download and configure, but get stumped at that .tar.gz file extension.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;After reading blogs such as this do you:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Think to yourself you should write your own blog and set this young whippersnapper straight.&lt;/li&gt;&lt;li&gt;Write a trackback on your own blog about this blog to create extra hits for ad revenue.&lt;/li&gt;&lt;li&gt;Bookmark it for future reference. That bit about using XSL might come in handy later.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you answered mostly A you're a hardcore UNIX geek still in love with the command line who likes to view pr0n in 24 lines of black and green ASCII. If you answered mostly B, you're with the &lt;em&gt;&lt;strong&gt;in&lt;/strong&gt;&lt;/em&gt; crowd, continually heaping praise on each other for solving problems that have been solved before in a slightly different and probably better way. If you answered C you know just enough to get things done but actually remember nothing since whatever technology you learn today will not be needed tomorrow. Thought about a successful career in Project Management? ;)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2005-05-25:5</id>
    <published>2005-05-25T14:31:00Z</published>
    <updated>2006-12-16T13:32:30Z</updated>
    <category term="Mac"/>
    <category term="Programming"/>
    <link href="http://khamsouk.souvanlasy.com/2005/5/25/mac-os-x-tiger-and-case-sensitivity" rel="alternate" type="text/html"/>
    <title>Mac OS X Tiger and Case Sensitivity</title>
<summary type="html">&lt;p&gt;Ever since I joined the &lt;a href=&quot;http://developer.apple.com/macosx/tigerkit.html?ht&quot;&gt;Apple seed developer&lt;/a&gt; program earlier in the year, I've been going through a constant cycle of reinstalls trying out new developer seeds of &lt;a href=&quot;http://www.apple.com/macosx/&quot;&gt;Mac OS X Tiger&lt;/a&gt;. At one point, being an inquisitive - and some say masochistic - fellow, I decided to try out a HFS+ Case-Sensitive file system instead of plain HFS+. Case sensitivity is useful when interacting with different UNIX operating systems or when compiling and using some UNIX applications ported to the Mac.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Ever since I joined the &lt;a href=&quot;http://developer.apple.com/macosx/tigerkit.html?ht&quot;&gt;Apple seed developer&lt;/a&gt; program earlier in the year, I've been going through a constant cycle of reinstalls trying out new developer seeds of &lt;a href=&quot;http://www.apple.com/macosx/&quot;&gt;Mac OS X Tiger&lt;/a&gt;. At one point, being an inquisitive - and some say masochistic - fellow, I decided to try out a HFS+ Case-Sensitive file system instead of plain HFS+. Case sensitivity is useful when interacting with different UNIX operating systems or when compiling and using some UNIX applications ported to the Mac.&lt;/p&gt;
&lt;p&gt;What this mumbo-jumbo means is that on a case sensitive file system two documents: Document.txt and DOCUMENT.TXT are treated as unique files and can exist in the same folder. Plain HFS+ - while not case sensitive - is case preserving. This means if you name a file DoCuMeNt.TXT the case is remembered by the filesystem but you can't create another file called Document.txt in the same folder.&lt;/p&gt;&lt;p&gt;After a couple of weeks happily using my powerbook as a development environment, I encountered several problems when installing third-party applications. The first was a groupware client called &lt;a href=&quot;http://www.softarc.com/&quot;&gt;FirstClass&lt;/a&gt; that I use to read posts in the Tokyo &lt;a href=&quot;http://www.ringo.net/&quot;&gt;Ringo&lt;/a&gt; Mac User's Group. FirstClass tries to open a directory: /Library/FirstClass/fcp instead of /Library/FirstClass/FCP. After creating a  symbolic link (like a shortcut for you windows folks) from fcp to FCP, all was fine. Then I tried installing Civilization III and Neverwinter Nights. Civ III did not even start. Neverwinter Nights went through the splash screen and died soon after. Since they were games, I didn't mind too much. Well okay, just a little bit.&lt;/p&gt;&lt;p&gt;I tried Macromedia Dreamweaver which seemed to work for a while; but when doing anything serious it would pop up with all these error messages saying it can't find several script files. Since I use it a lot I was not a happy camper. Adobe CS 2 is also reported not to work or even install (although there is a &lt;a href=&quot;http://www.macosxhints.com/article.php?story=20050505184714699&quot;&gt;workaround&lt;/a&gt;). Imagine the chaos that would occur when applying patches that get the case for file names wrong. You might have multiple versions of the same file being loaded at the same time! I guess this is the reason why case sensitivity is supported for Macs OS X 10.4 Server and not for Client :)&lt;/p&gt;&lt;p&gt;So if you are planning to use a case sensitive filesystem, be prepared for a lot of sym linking drudgery. Personally, I settled with plain HFS+ for my system partition where I keep my Mac Applications and created a separate case sensitive partition for running and compiling UNIX applications.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2005-05-25:4</id>
    <published>2005-05-25T14:30:00Z</published>
    <updated>2006-12-16T13:31:42Z</updated>
    <category term="Japan"/>
    <link href="http://khamsouk.souvanlasy.com/2005/5/25/visa-finally-extended" rel="alternate" type="text/html"/>
    <title>Visa finally extended</title>
<summary type="html">&lt;p&gt;I got a postcard from Tokyo Immigration telling me to go to there within a week to receive my Working Visa extension. I ended up popping down there this morning to be safe since my current one ends this Saturday! It definitely took less time than the last visit.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I got a postcard from Tokyo Immigration telling me to go to there within a week to receive my Working Visa extension. I ended up popping down there this morning to be safe since my current one ends this Saturday! It definitely took less time than the last visit.&lt;/p&gt;
&lt;p&gt;At a cost of 4000&#20870; it's a lot cheaper than what Visas cost in Australia; and as an Australian citizen, my Engineer visa has been extended another 3 years. I believe some other nationalities might have to renew every 12 months.
&lt;/p&gt;&lt;p&gt;But it's not over yet! I now have to get my &quot;Alien Registration Card&quot; updated within the next 14 days at Shibuya city hall to reflect the change.
&lt;/p&gt;&lt;p&gt;
While waiting to be processed I watched the end of season 4 of 24 on the PSP. It was a fitting end even if it felt a bit anti-climactic and rushed. It'll be interesting to see how they handle the repercussions of the 2005 season finale next year.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://khamsouk.souvanlasy.com/">
    <author>
      <name>kam</name>
    </author>
    <id>tag:khamsouk.souvanlasy.com,2005-05-24:3</id>
    <published>2005-05-24T14:29:00Z</published>
    <updated>2006-12-16T13:30:05Z</updated>
    <category term="Programming"/>
    <link href="http://khamsouk.souvanlasy.com/2005/5/24/feed-me-widgets" rel="alternate" type="text/html"/>
    <title>Feed me widgets</title>
<summary type="html">&lt;p&gt;I've been downloading and trying out several dashboard widgets for Mac OS X Tiger and one of the most useful has been &lt;a href=&quot;http://www.apple.com/downloads/macosx/dashboard/hulagirl.html&quot;&gt;Hula girl&lt;/a&gt;.
&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I've been downloading and trying out several dashboard widgets for Mac OS X Tiger and one of the most useful has been &lt;a href=&quot;http://www.apple.com/downloads/macosx/dashboard/hulagirl.html&quot;&gt;Hula girl&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Just kidding (altho' early on it was the number 3 download in the dashboard category! Scary stuff). Andrew pointed me to one called &lt;a href=&quot;http://www.apple.com/downloads/macosx/dashboard/nixmanual.html&quot;&gt;*NIX Manual&lt;/a&gt;; it allows you view UNIX man pages as a dashboard widget. You can customise the color scheme and font sizes. Very nice. No more paging up and down using man in the terminal!&lt;/p&gt;&lt;p&gt;Another nice one is the &lt;a href=&quot;http://www.apple.com/downloads/macosx/dashboard/wikipedia.html&quot;&gt;wikipedia&lt;/a&gt; widget, which allows you to search and view articles on &lt;a href=&quot;http://www.wikipedia.org&quot;&gt;wikipedia&lt;/a&gt; complete with pictures and in multiple languages. You can even resize the widget for those wide articles.
&lt;/p&gt;&lt;p&gt;
If you're annoyed at dashboard's weather widget because it only adds the city name that's set in your &quot;Date and Time&quot; System Preferences while defaulting to USA for the country, join the club! Meanwhile, you can get a list of countries for a city by typing in the city name and pressing enter in the info panel for the weather widget. If you know what country the city is in, type in something like &quot;Melbourne, Australia&quot; and press enter. For the geeks out there, use a formatted string: &quot;CountryCode;RegionCode;CityName&quot; e.g. &quot;AU;VT;Melbourne&quot; without the need for enter.&lt;/p&gt;
          </content>  </entry>
</feed>
