Wednesday, July 31, 2013

Error: no candidate version available for postgresql-contrib-9.2

This is the error I got when I set up PostgreSQL using chef on ubuntu 13.04:

no candidate version available for postgresql-contrib-9.2

Where does the error come from


So ... it is obvious that there is no Postgresql 9.2 found in all the apt repository the system can see.

It turns out that latest postgresql packages are distributed else where:
https://wiki.postgresql.org/wiki/Apt


Solve in command line


To include the repository and update your packages in command line, do this:

echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > /etc/apt/sources.list.d/pgdg.list
wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update

Solve in chef


file "/etc/apt/sources.list.d/pgdg.list" do
  owner "root"
  group "root"
  mode 00644
  content "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main"
end

execute "include pgdg repository key" do
  command "wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -"
end

execute "update apt-get list" do
  command "sudo apt-get update"
end

Wednesday, July 17, 2013

Ways to define a class in Javascript

Developers who come from famous OO languages such as Java/C++, like myself, may often find defining class in JavaScript confusing. This article aims to provide a very basic "class definition" in JavaScript.

Few notes on JavaScript nature
  • there is no class actually,  usual class concept in Java/C++ can hardly apply
  • everything are basically object literal, simply key-value collection
  • value of an object can be accessed by notation ".key" or "[key]"

Let's begin with a simple example below.

var eddie = { name: "Eddie", age: 25 };
var steven = { name: "Steven", age: 72 };
var benny = { name: "Benny", age: 3 };

1. Object Literal

Above objects eddie, steven, benny are all defined by object literal notation. It doesn't define any class, everything is raw but simple.

  • you can access the fields (properties) in this object like this:
  • eddie.name prints Eddie
  • steven["age"] prints 72
  • you can add new property dynamically

eddie.gender = 'M';
benny.gender = 'M';

  • pros: simple, intuitive
  • cons: not reusable. Imagine when you want to define function (e.g. getName()) among all persons. >

You need a way to define a class.

2. Constructor Function

2.1 class definition
var Person = function(name, age) {
      this.name = name;
      this.age = age;
      this.getName = function() {
            return this.age;
      }
}

  • Person is called constructor function
  • constructor function will implicitly return this to caller 
  • use keyword new to invoke constructor function, as below

2.2 object creation

var eddie = new Person("Eddie", 25);
var steven = new Person("Steven", 72);
var benny = new Person("Benny", 3);

  • new will allocate new memory, and this in constructor function will reference to the new memory
  • "eddie.name" will print Eddie
  • "benny.getName()" will print Benny

2.3 syntax
  • var Person = function(name, age) { ... } is the equivalent to 
  • function Person(name, age) { ... }

2.4 memory concern
  • note that memory of function getName() is allocated in every instance. To solve this, move the function from constructor function to prototype.
Person.prototype.getName = function() {
      return this.name;
}

This way, only a single copy of getName would exist in memory.
  • "benny.getName()" will still print Benny

2.5 incorrect object creation

var john = Person("John", 11);
  • if "new" is missing (likely by mistake), you are NOT calling constructor function. 
  • "this" will reference to global context, window. Effectively, you are doing the following:
window.name = "Kalok";
window.age = 11;

  • "typeof john" will return undefined, because "implicit return this" would not apply without "new"

3. That vs This

To address the issue "this" may refer to global context, here's a possible solution.

var Person = function(name, age) {
      // define an empty object literal
      var that = {};

      // assign to that instead of this
      that.name = name;
      that.age = age;

      // return that explicit
     return that;
}

  • "that" is just a dummy word, use "self", "_this" or whatever meaningful to you
  • the disadvantage of this solution is it loses the link to prototype, not good enough in most cases.

4. Self-invoking Constructor

Now we go back to the class definition at the beginning, and check whether this is an instance of the constructor itself.

var Person = function(name, age) {
      if (!this instanceof Person)) {
            return new Person(name, age);
      }
      this.name = name;
      this.age = age;
      this.getName = function() {
            return this.age;
      }
}

Thursday, June 6, 2013

Getting your real IP inside Terminal

If you want to check you current public IP for you PC / Mac, sure you know when you visit whereismyip "http://whatismyipaddress.com/".

However, what to do if you are inside a Terminal, with just an internal IP?

Just try:
curl -s http://checkip.dyndns.org | sed 's/[a-zA-Z/<> :]//g'
or
wget http://ipecho.net/plain -O - -q ; echo

Then you can get your real IP. 

Coding for Fun

 :)


Wednesday, May 29, 2013

Clarifying about including json data in javascript file

Just received a beginner question about passing json data to the amchart.
A friend was confused about inline json object creation and loading external json file

All the following two versions work

Version 1:

    <!-- main.html -->
    <script src="js/amcharts.js" type="text/javascript"></script>
    <script src="js/your_formatted_data.js" type="text/javascript"></script>
    var chart = new AmCharts.AmSerialChart();
    chart.dataProvider = chartData;
    chart.categoryField = "country";
    <!-- js/your_formatted_data.js -->
    var chartData = [
                      {country: "USA", visits: 1234},
                      {country: "HK", visits: 5678},
                    ];


Version 2:

    <!-- main.html -->
    <script src="js/amcharts.js" type="text/javascript"></script>
    var chartData = [
                      {country: "USA", visits: 1234},
                      {country: "HK", visits: 5678},
                    ];
    var chart = new AmCharts.AmSerialChart();
    chart.dataProvider = chartData;
    chart.categoryField = "country";

I would suggest the version one because it is easier to maintain and more readable.
You can change the json data inside your_formatted_data.js without changing the main.html

Tuesday, May 28, 2013

Power Charging your Mac for development: Finder, Sublime Text, Zsh

Here are some tips I shared during my General Assembly Ruby On Rails class, to make your Mac better for coding development


1. Finder

1.1 Setting Finder shortcut to a "projects" folder


since we travel a lot between different project, download, application folders during our coding exercises, it is better to organize all our code in a coding folder (I call it "projects" with subfolders named after the project / organization names)
and to speed up the travelling even faster, I add my projects folder shortcut to the Finder favourites.

1.2 Use Path Finder


if you are willing to pay, there is one Finder alternative called "Path Finder" which provides more file management features and more friendly to users familiar with Windows operating system.



2. Personalize Sublime Text

2.1 Sublime Text Command Line shortcut


we always navigates between Terminal (or iTerm) and Finder (or Path Finder)
so, being able to open the current Terminal project in Sublime Text is a huge speedup

http://www.sublimetext.com/docs/2/osx_command_line.html

2.2 Sublime Text Package Control


There are lots of wonderful plugins being developed by other talented people, setting up Package Control enables you to search and install them with few keystrokes

http://wbond.net/sublime_packages/package_control/installation

2.3 Sublime Text Plugin: Sidebar Enhancement


After setting up Package Control, the first plugin I recommend you to install is Sidebar Enhancement
- Open up Command Palette by pressing Apple + Shift + P
- Open up Package Control by typing Install Package and click Enter
- type SidebarEnhancement and click Enter
- after installing successfully (status message at the bottom of Sublime Text), restart Sublime Text completely (Quit and Open, not just close the current window editor)

2.4 Format your code nicely with spaces


use 2 spaces instead of tab
http://www.sublimetext.com/docs/2/indentation.html

2.5 Remove trailing whitespace after save automatically


http://blog.nategood.com/sublime-text-strip-whitespace-save




3. use Zsh for terminal shell


You can type less characters to execute commands. Zsh is also smart enough to correct your typo and suggest correct commands and arguments

https://github.com/robbyrussell/oh-my-zsh



Happy Coding !


Wednesday, April 10, 2013

Managing Rails Environment Variables is the pain in the ass

Managing Rails Environment Variables is the pain in the ass


I have quite a few heroku apps that have sandbox, staging and production environment.
and I have to manage lots of environment variables, e.g. Facebook, AWS, TWILIO, octopus database URL etc.

figaro gem really help:
https://github.com/laserlemon/figaro


Environment variables in ONE place with figaro


figaro gives you a yaml file which stores all the environment variables for all environments:

    config/application.yml


Updating Heroku environment variables in one command


the powerful bit comes when you update your heroku instances environment variables

    rake figaro:heroku

this rake task save you time to run those heroku config:set xxx=yyy --app abc-staging


Not committing this file to public !


like handling other confidential data files in git repository, this file is ignored (included in .gitignore) and never being committed to git repository.
while sharing the file structure without sharing the secrets.
I recommend using a ".sample" approach.

copy the config/application.yml to config/application.yml.sample
and then commit this .sample file to git repository for your teammates to follow


Thanks laser lemon and thanks figaro !

Sunday, March 24, 2013

Pronunciation of "route"

Occasionally, I often heard two different versions for the pronunciation of "route"("root" vs "rowt"), mostly from computer networking context. It got me to google which one is "correct".

Firstly, "root" +1 from Hong Kong Yahoo dictionary...
http://hk.dictionary.yahoo.com/dictionary?p=route

Then, it appears a typical pronunciation difference between British and American...
http://www.howjsay.com/index.php?word=route&submit=Submit

While some people suggest that there is a little historical factor... one more party French... hmm...
http://ph.answers.yahoo.com/question/index?qid=20100511082156AAuZ6VL

Interesting responses:
"I say root. Personally, I cringe when I hear someone pronounce it rowt."
"I say root. I hate when people say rowt. They all must die."

Conclusion: 

Monday, March 18, 2013

iphone Personal Hotspot suddenly disappeared and I fixed it accidentally

Suddenly Gone

I had been using the Personal Hotspot on my iPhone since day one. But just now, the Personal Hotspot was gone ! disappeared ! missing !


I suspected that it was some changes on firmware update ... but the version stayed the same. version 6.1.2

I tried the following:
- Switch it off and on again
- "Settings" > "General" > "Reset" > "Reset Network Settings"

didn't work.

Fix

then at last I found the settings in 
- "Settings" > "General" > "Cellular" > "Personal Hotspot"
after I switched it on, the "Settings" > "Personal Hotspot" appeared again.

WEIRD!

Sunday, March 3, 2013

hotcocoa/mappings/appkit/box.rb:3:in `block': uninitialized constant CGRectZero (NameError)

Where does this error coming from?

So... after playing with RubyMotion, I start picking up MacRuby !
my goal was to build up some desktop utility apps and interactive desktop application taking various of gesture capturing input devices.

First, I tried out the hello world in XCode and it works fine. Then I tried writing Macruby apps without XCode. After I install macruby on rvm and run the Macruby apps generated by hotcoca, I saw this error:

hotcocoa/mappings/appkit/box.rb:3:in `block': uninitialized constant CGRectZero (NameError)


Troubleshooting in irb ?

Spent quite a lot of time checking documentation and setup instructions. When I tested the missing dependencies in irb, I found out that only those related to Cocoa UI are missing. So I load the cocoa framework explicitly and it works:

framework 'CocoaGraphic'
CRRectZero

Solve that in hotcocoa project

inside my application.rb, I load the framework explicitly before loading the hotcocoa gem:

begin
  # for OSX 10.8
  framework 'CoreGraphics'
rescue
end
framework 'Cocoa'

require 'rubygems' # disable this for a deployed application
require 'hotcocoa'



Tuesday, January 29, 2013

Refactoring "if nil?"

Very often we have checking against nil value like this:

if products.nil?
  products.first.total_amount
else
  0.0
end


There is a cleaner way to achieve the same result:

products.first.try(:total_amount) || 0.0

Wednesday, December 19, 2012

Possible reasons that your apn_on_rails may not work

There were several times that user reported that the Push Notification not working. That's always my first response: "It should be working. No way it is not working. I just fixed it few days ago, and it was working !"

I found the need to share all the errors I saw, and also as a checklist reference for my future projects.

1. I was using the wrong fork of http://github.com/XXX/apn_on_rails 

  There are bugs in the master github repository PRX/apn_on_rails. And in some forks, you should put the .pem file path as the configatron.apn.cert, while in some other branches, configatron.apn.cert is actually asking for file content:

    configatron.apn.cert = File.join(Rails.root, 'config', 'certs', 'apn_dev.pem')
    configatron.apn.cert = File.read(File.join(Rails.root, 'config', 'certs', 'apn_dev.pem'))

  There are some more other fixes loosely exist in some forks and I have no idea which one is the best, so ... I forked one more for myself. https://github.com/3dd13/apn_on_rails


2. apn push token I collected from 2 mobile apps are the same

I was setting up two mobile apps push notification by one backend server, and user is using both mobile apps. I knew that I had to use two different .pem cert file to push to the two different apps, but sometimes one of them was not working and sometimes it pushed messages to the wrong mobile apps.

After tracing all the code, finally, I found out that the apn_token from the 2 mobile apps I collected are actually the same. And the APN::Device instance did not create with the correct app:

    device = APN::Device.find_or_create_by_token(apn_token)

so this is my fix:

    device = APN::Device.find_or_create_by_token_and_app_id(self.apn_token, apn_app.id)


3. I submitted the apn token with incorrect format

I solved this issue few months ago, but recently after I rewrite some code and this bug dragged me crazy ... once again.

the apn push token you collected from mobile is in this format:

    00ea74e76a873e8e9c14c2dd2afe3b42abb35148e94042811e2b6985072641f2

but actually, apn_on_rails is expecting this:

    00ea74e7 6a873e8e 9c14c2dd 2afe3b42 abb35148 e9404281 1e2b6985 072641f2

I wrote a method to convert that:

4. I setup the staging with production push cert with sandbox apn host

One of my early chore was setting up apn push cert, so to do it quick (and dirty), I was using development .pem cert file on both my dev machine and so-called production. But later when I was switching the production cert to the real production cert, It did not work.

At that moment of time, what drove me crazy was that no error was thrown and the "sent_at" attribute of the APN::Notification is correctly updated.

So, we keep checking everything again and again, generating certs for several times, restarting servers, clearing up database records. AND ... the real bug is actually the incorrect configatron.apn.host

gateway.push.apple.com should be used for production, and gateway.sandbox.push.apple.com should be used for development


5. Used production for staging (on heroku) Procfile

Push messages are sent out in worker threads (by sidekiq), and workers are started using Procfile:

    worker: bundle exec sidekiq -e production -C config/sidekiq.yml

obviously, this Procfile won't work for staging or development machine, the correct one should be:

    worker: bundle exec sidekiq -e $RACK_ENV -C config/sidekiq.yml


6. Errno::ENAMETOOLONG File name too long

There were something like that in the log

    Errno::ENAMETOOLONG
    WARN: File name too long - Bag Attributes

actually, this is not an error, just a warning. However, it fills up my logentries page which makes it hard to debug.

This one was caused by some strange bug (perhaps not a bug, but I don't understand why). It is related to the configatron.apn.cert path issue I was talking about.

In the same function, configatron.apn.cert was treated as both path and file content. If you want to know the details, check out the commit I made to fix it:
https://github.com/3dd13/apn_on_rails/commit/0b60b26b38540d0c59a6cd21068d6b2f9a6cf139


Tuesday, November 27, 2012

Deploying single ruby script to heroku


I need a simple ping service which notifies me (via email) when my web application is down. I can write a simple ruby script to achieve that without much problem.


However, I also want this script to be run regularly and hosted on the internet for FREE. the following is my attempt on using Heroku and Heroku's Scheduler add-on.
(Heroku's scheduler can run every 10mins, 1 hour or 1 day)


only 2 files are needed: health_check.rb and Gemfile.
Source Code:
https://gist.github.com/4153156

Directory Structure:


OK, actually 3 files.
- health_check.rb is a ruby script which calls Net::HTTP and sends email using Net::SMTP
- Gemfile is an file which tells Heroku that this is a ruby application
- Gemfile.lock is the file being generated after running bundle install

that's it. go ahead and push it to heroku:
git push heroku master


and then add Heroku Scheduler to your project.
you can do it by logging in to heroku.com or via command line


add a scheduler job with ruby command line:


DONE.




Tuesday, August 21, 2012

invalid DATABASE_URL error when I deploy padrino + mongoid to heroku

Problem


I deployed my padrino apps to heroku but could not be started. and I saw "invalid DATABASE_URL" when I run "heroku run padrino console"

the exception was thrown at this line

Padrino.before_load do
  Mongoid.load!(File.join(Padrino.root,"config/database.yml"))
end

Troubleshooting


I suspected that something wrong with my database configuration file, so I double checked all the configuration files, everything's fine. All the env and (list by running 'heroku config') looks fine. Then I tried run the remote console and try to repeat the problem by requiring and executing the Mongoid methods directly.


Real Cause


I found out that the program keep reading from database.yml and the content was totally different from my database.yml. It was something like erb script reconstructing the login credential for a PostgreSQL connection.
It turned out that, although the postgreSQL shared database add-on was no longer activated on heroku be default, heroku still tried to generate the config/database.yml which OVERWRITTEN my config/database.yml.

Solution


simple.
just rename my database.yml to mongoid.yml and then change the Mongoid.load! to

Mongoid.load!(File.join(Padrino.root,"config/mongoid.yml"))

Wednesday, July 11, 2012

Keyboard shortcuts for Android emulator (for Windows and Mac keyboard)

We are working on several Android projects recently, that's why we have to interact with emulator a lot.

Here is a handy keyboard shortcut list to perform Android phone physical button actions (i.e. Back and Home button):
http://www.shortcutworld.com/en/win/Android-Emulator.html


if you are using Mac magic keyboard, or Mac book pro, you may wonder where is the "Home" button on your keyboard. It is actually ... "Command + Fn + Left"

Thursday, June 14, 2012

Codeaholics June 2012 Meetup: .Net on MVC4, Scala on Play and Ruby Queue

.Net and MVC4

yesterday Thomas shared about MVC4 (beta) at Codeaholics
he did a demonstration on generating a new CRUD web application and a set of HTTP web API.

it was nice !
it just copied most of the tools/design from Ruby On Rails and the IDE is even better than those for Rails.
although the controller code is still too verbose
and the community to build library (gems) is not as active as Ruby one

but it is really a good move for Microsoft developers (most of them get stuck in the big enterprisy company, learning nothing new except politics) to know more about the best practices to develop Web application

Play on Scala

Another funny thing was that ... Jacob was sharing about Play and the code base turned out to be so similar to those written by Thomas !
yes ! the syntax of Scala on Play and .Net on MVC4 was so similar

It is good !

Both framework picked a lots of popular features/design from Ruby On Rails and it is good ! more and more best practices being found and recognized by all the coding community. It makes software better and coders are easier to pick up another tech stack.

Thanks all the speakers !
special thanks to Jacob who was just visiting Hong Kong and spent some time sharing coding things with our local community !

Sunday, April 1, 2012

Segmentation Fault when you run ruby / rake / rails / gem install commands

this post is based on
http://www.christopherirish.com/2011/09/02/ruby-1-9-2-segmentation-fault-and-openssl/


every ruby developer must have seen "Segmentation fault" when they run rake tasks, install gems or updating gems. The usual reason is because of the depending libraries are not updated or using the wrong one during the setup of ruby runtime.


very often it is because of openssl or iconv. To fix that error, you have to re-install your ruby runtime. If you are using rvm, these are the commands to uninstall and reinstall everything with correct libraries:


rvm remove 1.9.3
rvm pkg install iconv
rvm pkg install openssl
rvm install ruby-1.9.3 --with-openssl-dir=$rvm_path/usr --with-iconv-dir=$rvm_path/usr

Thursday, March 15, 2012

Compile Coffeescript to Javascript

Many friends not familiar with coffeescript yet, but Rails 3.2 is already generating coffee script by default when you do scaffold. So far it is OK for them to achieve something by "copy and paste" from internet. However, it is hard for them to modify the script they got.


So, one way is ... use Javascript by changing the extension from .js.coffee to .js. But human has to learn, right? Here is the second way: learn by comparing coffee script and javascript implemtation.


Compile CoffeeScript to Javascript inside Aptana Studio

[Commands] -> [CoffeeScript] -> [Run] -> [Compile and Display JS]

a corresponding .js file will be generated and then you can see how each line of coffee script is compiled into javascript.



if there is error saying coffee command not found, just go ahead and install coffee-script library for your OS.

e.g. in MacOSX, brew install coffee-script


Wednesday, February 15, 2012

Internship Program to recruit Hong Kong university student

Here I consolidate all the website and resources for recruiting internship. Hopefully, it lower your resistance to recruit internship students.

(It is really frustrated to find out the correct form to fill in in all these not user-friendly website. Most of them are not SEO-friendly. Some departments have their own internship webpage too.)


Every university will ask for your Business Registration document, so, prepare a soft copy.



Joint U


There is one online job posting system which is supposed to reach all the students. However, not many students go there and keep an eye on the job there.

http://www.jijis.org.hk/

HKUST


  1. complete this form: Form.doc
  2. email it to sails@ust.hk

Career Center

contact Irene Tsui:(852)23586695


HKU


post your job here: Employer Corner

you can also see some students' resume here: Net Match


Cedars

CU


Register and post your job here: OSA


Recruitment Service

Email: cpdc@cuhk.edu.hk

Contact: 39437202


PolyU


fill in the online form here: Online Form



Poly U Recruit

Email: Poly U Career

Contact: 27666789


BU


register an account and post job here: BU Career



Email: bucareer@hkbu.edu.hk

Contact:3411 7440


City U


  1. Fill in the form:
    Recruit Form
  2. Email Business Registration Certificate BR to CAIO
  3. Complete your email request by specifying subject title:
    Summer Jobs Advertisement -- [your company name]



Providing Internship


LingNan


Register and post the job here: For Employer

you can search for CV inside the system too



For Employers

Email: career@LN.edu.hk

Tel: 2616-7406 / 2616-7446

Fax: 2891-4516 / 2891-9603

Monday, November 7, 2011

Android Kitchen - Setting Up Eclipse and Android SDK

Actually following the official android setup guide should work already:
http://developer.android.com/sdk/installing.html


But we found several issues during the workshop:



1. Android SDK Path inside eclipse


Double check, make sure the Android SDK path inside eclipse is pointing to the correctly directory.



2. Use eclipse's Android manager plugin but not command line

In step 4, please use the ADT plugin to open the Android SDK and AVD Manager
From within Eclipse, select Window > Android SDK and AVD Manager.


there are problems, when not using the eclipse plugin, that even some SDK are downloaded, they cannot not be selected as Build Target inside eclipse. (We were using Indigo)



3. Always Clean and Re-build


Sometimes, an error message popup when we start the application saying "Force Close".

Very likely, it is because some generated files are cached which are not updated after changing the xml files (probably a bug in the Android plugin). For example, after changing the Android layout file (i.e. main.xml).

What you have to do is to "Project -> Clean...". This function clean up all the generated files.

If you have the "Project -> Build Automatically" option selected, Eclipse will compile all the files again. If not, click "Project -> Build Project".



4.if you use Java 1.7


We were using Java 1.7, and found out an error when we override (using @Override annotation) the onClick method of OnClickListener.

With Java 1.7, you can no longer override an interface method.

View.OnClickListener is an interface. Overriding an interface method still works in 1.6, but no longer valid in 1.7. So, "No Need to use @Override for onClick(View view) method".

Monday, October 24, 2011

Download Youtube clip, Convert to MP4 and OGG for HTML 5 video tag

I am working with Mac. One of my tasks was ... "36613, put this youtube video on our website !! using latest fancy portable HTML 5 !!"


"Yes. My Lord! " ... HTML 5 is not really being supported by all latest browser yet. and some of them only support some particular encoding schemes. So, what I had to do for this task was ...

  1. Download the video from youtube
  2. Convert the video to .mp4
  3. Convert the video to .ogg
  4. Write little HTML(5) code

I am going to talk about the freeware converters I used on Mac only. They are all real free, no watermark, no limited functions, no trial expiry date.

If you want to write a video tag that support all browsers, visit the following post: http://henriksjokvist.net/archive/2009/2/using-the-html5-video-tag-with-a-flash-fallback. It talked about including .mp4, .ogg and also .flv in order to support all browsers.



1. Download the .flv video from youtube

"Firefox" and Firefox Add-on "Ant Video Downloader": https://addons.mozilla.org/en-US/firefox/addon/video-downloader-player/

Usage:
  1. Use Firefox, go to the youtube video page you want to download.
  2. click the Ant video button next to the address bar.
  3. select the video name in the dropdown list.


2. Convert the .flv to .mp4

MPEG Streamclip: http://www.squared5.com/

Usage:
  1. Open the downloaded .flv file using MPEG Streamclip
  2. Choose Export to MPEG-4 in the menu
  3. Select the resolutions you want (usually defaults are alright).


3. Convert the .flv to .ogg

ffmpeg2theora: http://v2v.cc/~j/ffmpeg2theora

Usage:
  1. run the following command to convert the .flv file:
  2. ffmpeg2theora DownloadedYoutubeVideo.flv