Sunday, March 20, 2011

A simple URL shortening algorithm

Shortening a URL is a convenient way to save long URL to make use of space when posting. It's especially popular on Twitter where message is limited to 140 words. Many websites provide this service such as tinyurl.com, bit.ly,...

There some gems or wrapper to use that service in your Rails app. But the shortened URLs belong to another domain (ex: http://bit.ly/ek8Hhe which belongs to bit.ly). If you want to make it belonged to your domain (ex: http://example.com/wfds7i), you must implement your own URLs shortener.

This is a simple way to do that.

Basically, the problem is:
given a URL, how to map it to a string which has pattern XXXXXX, where X belongs to {0..9a-zA-Z}. There would be 62^6 = 56800235584 such strings. That amount is almost enough.
Then the simple idea to solve that problem is:
map the URL to an integer in 1..62^6. That number must correspond to a string in space {XXXXXX} that could be calculated by using a 10-base to 62-base conversion algorithm (you can understand easily by figuring out how to convert a decimal number to hexa number). 

Here is an implementation of mine in Ruby:

class URLShortener
  CHARSET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  BASE = 62
  CODE_LENGTH = 6

  def self.encode(id)
    code = ""
    while (id > 0) do
      code = CHARSET[id % BASE].chr + code
      id = id / BASE
    end

    (code.length > CODE_LENGTH) ? "" : "0" * (CODE_LENGTH - code.length) + code 
  end

  def self.decode(code)
    return -1 if code.length != CODE_LENGTH
    id = 0
    for i in 0..(CODE_LENGTH-1) do
      n = CHARSET.index(code[i])
      return -1 if n.nil?
      id += n * (BASE ** (CODE_LENGTH - i - 1))
    end
    return id
  end
end

Making ajax form

Making an ajax form is a javascript code snippet that we see very frequently. So I've tried to write it as a pattern that could be easy to reuse when needed.

<form action="do_something" method="post" id="do_something_form"> 
  Field 1: <input type="text" name="field1" id="field1" /> 
  <br /> 
  Field 2: <input type="text" name="field2" id="field2"/> 
  <br /> 
  <input type="submit" value="Submit" /> 
</form> 

<script>
  jQuery('#do_something_form').submit(function(event){
    // stop normal form submitting
    event.preventDefault();
  
    // get form's fields
    var field1_val = jQuery('#field1').val(),
        field2_val = jQuery('#field2').val(),
        url        = jQuery(this).attr('action');

    // send request
    jQuery.post(url,                   // ajax url
                {
                  field1: field1_val,
                  field2: field2_val
                },                     // data passed to server side
                function(response){    // callback 
                  // do things with response data, ex:
                  alert(response["message"]);
                  if (response["success"] == true) {
                    // ... 
                  }
                },
                "json"                 // response's format 
    );
  });
</script>
 
Then at backend:
 
def create
  @form = params
  
  if some_condition
    @result = {
      :success    => true,
      :message    => "Resource has been created successfully!",
      :other_data => {}
    }
  else
    @result = {
      :success => false,
      :message => "Creation failed! Please try again!"
    }
  end

  render :text => @result.to_json
end
Reference:
http://api.jquery.com/jQuery.post/

Sunday, March 13, 2011

Tổng quan về kinh tế học #1




Nói đến kinh tế là nói đến quá trình sản xuất, trao đổi hàng hóa, của cải vật chất và tinh thần trong xã hội. Thông qua quá trình đó, con người tương tác với nhau để tạo ra của cải vật chất hay những giá trị mới, tái phân bổ chúng, phục vụ cho các nhu cầu trong cuộc sống, rồi lại lao động và lại tái tạo ra những giá trị mới khác,... Đó là tổng thể của cái gọi là nền kinh tế. Làm sao để nền kinh tế tạo ra thật nhiều giá trị? Làm sao để quá trình sản xuất và lưu thông hàng hóa hiệu quả hơn?... Đó là những vấn đề của kinh tế học.

Một trong những yếu tố cơ bản của nền kinh tế là thị trường và tiền tệ.

Nơi hàng hóa được đem ra trao đổi, mua bán được gọi là thị trường. Vd: thị trường bất động sản, thị trường chứng khoán, chợ,...

Hàng hóa có thể được trao đổi, mua bán trên thị trường dưới nhiều hình thức:
- Trao đổi trực tiếp:
   vd: 1 trâu đổi 100 thúng lúa
- Trao đổi gián tiếp (quy đổi sang một loại hàng hóa trung gian)
   vd: 1 trâu <-> 100 thúng lúa
         1 bò <-> 80 thúng lúa
         1 căn nhà <-> 1000 thúng lúa
   hoặc,
         1 trâu <-> 1 lượng vàng
         1 bò <-> 0.5 lượng vàng
         1 nhà <-> 100 lượng vàng

Yếu tố đóng vai trò trung gian trong trao đổi hàng hóa được gọi là tiền tệ. Thời xưa, tiền tệ cũng chính là hàng hóa (lúa, vàng, bạc,...), bản thân chúng có giá trị nội tại. Khi kinh tế ngày càng phát triển, nhiều hình thức tiền tệ khác ra đời làm cho quá trình trao đổi, lưu thông hàng hóa thuận tiện, nhanh chóng hơn như tiền đồng, tiền giấy, tiền điện tử,... Tiền tệ trở về với đúng bản chất của nó: làm trung gian trong trao đổi hàng hóa, bản thân nó không có hoặc có rất ít giá trị nội tại. Vai trò trung gian, đại diện cho giá trị thực đó của tiền tệ được đảm bảo bởi nhà nước và pháp luật.

Saturday, March 12, 2011

Be careful writing hooks to Rack layer (middle ware layer) in Rails

I've got this error from a Rails project:

ERROR NoMethodError: private method `split' called for 0:Fixnum


Following the link below gave me some clues:
http://rack.lighthouseapp.com/projects/22435/tickets/52-read-error-nomethoderror-private-method-split-called-for-0fixnum


1. something's wrong in Rack layer
2. someone wrote incorrect code that hooked to Rack layer 

Case #1: rarely happened
Case #2: may be 

I did some search and found this code in authentication module:
response.headers["Expires"] = 0

This must be the cause of the error. 

Though the correct code is just: 
response.headers["Expires"] = "0"

it still took me over a day to find out and fix that bug!!! 

Simple but not simple!


A case of "Broken Pipe" error in Rails

Have you ever seen "Broken PIPE" error in Rails?

It somehow like this:


*** Exception Errno::EPIPE in Passenger RequestHandler (Broken pipe) (process 22235):
    from /usr/lib/ruby/gems/1.8/gems/passenger-2.1.2/lib/phusion_passenger/rack/request_handler.rb:67:in `write'


This error seems appear when your program interacts improperly with external programs. In my case, it happened to me in a project that I used XMLRPC library to remotely communicate with some web services.

My implementation for that feature is as following:
- create a XMLRPC connection object
- use that XMLRPC object every time calling a webservice API

There some other guys had been headache with that error also:
http://gaveen.owain.org/2008/04/errnoepipe-broken-pipe-mysql-error-in.html
http://stackoverflow.com/questions/1082166/exception-errnoepipe-in-passenger-requesthandler-broken-pipe
http://stackoverflow.com/questions/4351624/ruby-on-rails-errnoepipe-broken-pipe

and the reasons they found come around Passenger or Mysql.

In my case, I've got the same thing even with upgrading Passenger or migrating to another web server.
After a lot of retries, I've found that if I call the API very often, "Broken pipe" doesn't appear, but if I stop doing anything for a while and then call the API, it does happen. That observation led me to a guess: XMLRPC connection object may be broken after a certain amount of time (timeout). Excellently, that's exactly right! I then changed my implementation so that every time calling a webservice API, I use a newly created XMLRPC connection object instead of using the same XMLRPC connection object for every API calls.

That solved my problem!