Casual Thoughts

Martin Schürrer's Blog. I'm working on letsannotate.com - easy collaborative review. Check it out.

May 18

Solving “bash: grep: command not found” on OS X

$ some script | grep something
bash: grep: command not found

If you are using a Mac with a German keyboard layout and your typing is as sloppy as mine, chances are you are familiar with this error. You probably also know that deleting the space before grep fixes it. Why is this?

Option 7 corresponds to the | character. Option Space corresponds to the non breaking space which looks just like the regular space but is - as far as the shell is concerned - totally different. And obviously there’s no ‘ grep’ command on your system. And if you still hold down Option while pressing space… Guess what will happen… Now how do we fix it?

Check out the documentation on Mac OS X Key Bindings or simply make your ~/Library/KeyBindings/DefaultKeyBinding.dict file look like this (if it doesn’t exist create it, if there are already bindings in it just add the one from below)

{
  "~ " = ("insertText:", " ");
}

What does this do? Every time you press Option Space instead of inserting a non breaking space OS X now inserts a regular space. Problem fixed.


May 4

File upload progress with Rails and nginx

At letsannotate.com users upload .pdf files and we convert them to images so that they work on every device. We wanted to show our users not only how far their upload had progressed, we also wanted to inform them about the status of the .pdf conversion.

We use Rails on nginx via Passenger, but there are solutions for both Apache and lighttpd.

nginx

First step: Install and configure nginx’s upload progress module.

Rails

Now we need to update our Rails controllers and views.

We use assaf’s great uuid gem to generate different identifiers for each upload.

  def new
    @document = Document.new
    @uuid = UUID.generate :compact
  end

When creating our form we use the hidden_field ‘progress_token’ to pass the job’s uuid back to the server. Now once the user clicks on submit some browsers will block intermittent AJAX requests. To work around that we need an iframe (:target => "uploadframe")

<% form_for(@document, :url => "/documents/?X-Progress-ID=#{@uuid}", :html => {:multipart => true, :target => "uploadframe", :onsubmit => "startUpload();"}) do |f| %>
    <%= f.hidden_field 'progress_token', :value => @uuid %>
    <%= f.file_field :pdf_file %>
    <%= f.submit 'Upload' %>
<% end %>

<div id="progress" style="width: 400px; background-color: silver;">
    <div id="progressbar" style="width: 1px; height: 10px; background-color: black;"></div>
</div>
<div id="message"></div>
<iframe id="uploadframe" name="uploadframe" width="100%" height="100%" frameborder="0" border="0" src="about:blank"></iframe>

Javascript

During the upload we query nginx every second how far along our file upload is. Once our file has been transfered completely we start querying our application how far the post-processing has come along.

You can find this code - which is a modified version of the nginx example at this gist where you’ll also find expanded example code.

Now once the upload and post-processing has finished we need a way to redirect not only the iframe but also its parent. We’ll need to use a hack since parent.document.location is read only.

<!-- iframe -->
<script>parent.changeParentUrl('<%= new_url %>');</script>
// parent frame
function changeParentUrl(url) { document.location = url; }

Enter redis

One thing’s left: While Rails (or a Resque/delayed_job worker) post-processes our document we have no way to get at its status. Redis to the rescue. We’ll simply update a key (e.g. pdf_progress:1234) every time the document’s status changes.

I hope this explains in detail how to create a seamless experience for file uploads. If there’s anything you’d like to know or if you believe I should create a complete example app, just leave a comment.


Sep 26

GWT Hosted Mode on 64 Bit Ubuntu

As far as I know this still works (for GWT 1.7) but has become obsolete with the release of GWT 2.0!

Here’s how I got GWT 1.7 Hosted Mode to work on my 64 bit Ubuntu Karmic Koala 9.10 laptop. These instructions should also work on Jaunty (9.04)

  1. Install ia32-sun-java6-bin:
    sudo apt-get install ia32-sun-java6-bin
  2. Make sure the default Java installation remains the 64 bit one
    sudo update-java-alternatives --set java-6-sun
  3. Download libstdc++5 for IA32 from Jaunty repos: http://archive.ubuntu.com/ubuntu/pool/universe/g/gcc-3.3/libstdc++5_3.3.6-17ubuntu1_i386.deb
  4. Extract the libstdc++.so.5 file
    dpkg-deb --fsys-tarfile libstdc++5_3.3.6-17ubuntu1_i386.deb  | tar -O --extract './usr/lib/libstdc++.so.5.0.7' > libstdc++.so.5
  5. Move the extracted file to /usr/lib32
    sudo mv libstdc++.so.5 /usr/lib32
  6. Run
    sudo ldconfig
  7. Start GWT:
    JAVA_HOME=/usr/lib/jvm/ia32-java-6-sun mvn gwt:run