<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Alex Le's Blog</title>
	<atom:link href="http://alexle.net/feed" rel="self" type="application/rss+xml" />
	<link>http://alexle.net</link>
	<description>Personal View</description>
	<pubDate>Sun, 23 Aug 2009 14:25:01 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5</generator>
	<language>en</language>
			<item>
		<title>easy Rails configurations with external YML</title>
		<link>http://alexle.net/archives/298</link>
		<comments>http://alexle.net/archives/298#comments</comments>
		<pubDate>Sun, 23 Aug 2009 14:22:22 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Random Walk]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[configuration]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[yml configuration]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=298</guid>
		<description><![CDATA[<p>If you have to deal with multiple configuration values for different environments, this easy and very simple trick will let you put all these values to an external YML file and have a convenient global hash to access the values.  Another benefit of putting config values in a YML file is that you can re-factor shared values into a default block, and override values in environment-specific blocks.  You can keep your code DRY, now keep your config DRY as well, instead of littering your different environment config files.</p>
<p>In your environment.rb, add this one line between the Rails::Initializer.run do &#8230; end block</p>
<pre name="code" class="ruby">
Rails::Initializer.run do |config|
  # ... other config code

  SITE_CONFIG = YAML.load_file(  "#{RAILS_ROOT}/config/site_config.yml" )[ ENV['RAILS_ENV'] || RAILS_ENV ]
end
</pre>
<p>Create a new &#8220;site_config.yml&#8221; file the /config folder using the following skeleton:</p>
<pre name="code">
# config/site_config.yml

# the shared configurations.  Override values here in each individual environment.
defaults: &#038;defaults
  twitter_username: your_username
  twitter_password: your_password

  # Blog
  blog_url: http://alexle.net
  blog_feed: http://alexle.net/feed/
  blog_email: 

development:
  <<: *defaults
  # override
  twitter_username: dev_username
  twitter_password: dev_password

slicehost:
  <<: *defaults

test:
  <<: *defaults

staging:
  <<: *defaults

production:
  <<: *defaults
</pre>
<p>Restart your web server so that the environment.rb file is picked up.  Now within your code, you can access the values using</p>
<pre name="code" class='ruby'>
  logger.debug SITE_CONFIG["twitter_username"]
</pre>
<p>The only gotcha of this method is that we cannot override nested configuration blocks due to the way YML files are interpreted.</p>
<pre name="code">
# this sample won't work
defaults: &#038;defaults
  twitter:
    username:
    password:

development:
  <<: *defaults

  # this override doesn't work since it replaces the twitter hash in the defaults block with a new
  # hash containing only the "username" key (The "password" key-value is gone!)
  twitter:
    username: dev_username
</pre>
<p>cheers!</p>
]]></description>
			<content:encoded><![CDATA[<p>If you have to deal with multiple configuration values for different environments, this easy and very simple trick will let you put all these values to an external YML file and have a convenient global hash to access the values.  Another benefit of putting config values in a YML file is that you can re-factor shared values into a default block, and override values in environment-specific blocks.  You can keep your code DRY, now keep your config DRY as well, instead of littering your different environment config files.</p>
<p>In your environment.rb, add this one line between the Rails::Initializer.run do &#8230; end block</p>
<pre name="code" class="ruby">
Rails::Initializer.run do |config|
  # ... other config code

  SITE_CONFIG = YAML.load_file(  "#{RAILS_ROOT}/config/site_config.yml" )[ ENV['RAILS_ENV'] || RAILS_ENV ]
end
</pre>
<p>Create a new &#8220;site_config.yml&#8221; file the /config folder using the following skeleton:</p>
<pre name="code">
# config/site_config.yml

# the shared configurations.  Override values here in each individual environment.
defaults: &#038;defaults
  twitter_username: your_username
  twitter_password: your_password

  # Blog
  blog_url: http://alexle.net
  blog_feed: http://alexle.net/feed/
  blog_email: 

development:
  <<: *defaults
  # override
  twitter_username: dev_username
  twitter_password: dev_password

slicehost:
  <<: *defaults

test:
  <<: *defaults

staging:
  <<: *defaults

production:
  <<: *defaults
</pre>
<p>Restart your web server so that the environment.rb file is picked up.  Now within your code, you can access the values using</p>
<pre name="code" class='ruby'>
  logger.debug SITE_CONFIG["twitter_username"]
</pre>
<p>The only gotcha of this method is that we cannot override nested configuration blocks due to the way YML files are interpreted.</p>
<pre name="code">
# this sample won't work
defaults: &#038;defaults
  twitter:
    username:
    password:

development:
  <<: *defaults

  # this override doesn't work since it replaces the twitter hash in the defaults block with a new
  # hash containing only the "username" key (The "password" key-value is gone!)
  twitter:
    username: dev_username
</pre>
<p>cheers!</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/298/feed</wfw:commentRss>
		</item>
		<item>
		<title>vimtutor on CentOS</title>
		<link>http://alexle.net/archives/297</link>
		<comments>http://alexle.net/archives/297#comments</comments>
		<pubDate>Sat, 22 Aug 2009 22:54:14 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Random Walk]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[Server]]></category>

		<category><![CDATA[centos]]></category>

		<category><![CDATA[linux]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=297</guid>
		<description><![CDATA[<p>My good friend <a href="http://stephencelis.com/">Stephen Celis</a> convinced me to give Rails.vim a shot for Rails development.  My vi skill is not that great yet (e.g. beginner level), so Stephen recommended vimtutor, which does not come pre-installed on my CentOS server.  So here&#8217;s a quick recap of getting vimtutor installed:</p>
<p>1.  Installing &#8220;which&#8221;, which the vimtutor script uses to detect the vi version and copy the vimtutor script accordingly.</p>
<p><code>sudo yum install which</code></p>
<p>2.  Installing &#8220;vim-enhanced&#8221; package, which contains the vimtutor</p>
<p><code>sudo yum install vim-enhanced</code></p>
<p>Now you should be able to do &#8220;vimtutor&#8221; and start a new vimtutor session.  Happy h-j-k-l around and stops using the arrow keys <img src='http://alexle.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></description>
			<content:encoded><![CDATA[<p>My good friend <a href="http://stephencelis.com/">Stephen Celis</a> convinced me to give Rails.vim a shot for Rails development.  My vi skill is not that great yet (e.g. beginner level), so Stephen recommended vimtutor, which does not come pre-installed on my CentOS server.  So here&#8217;s a quick recap of getting vimtutor installed:</p>
<p>1.  Installing &#8220;which&#8221;, which the vimtutor script uses to detect the vi version and copy the vimtutor script accordingly.</p>
<p><code>sudo yum install which</code></p>
<p>2.  Installing &#8220;vim-enhanced&#8221; package, which contains the vimtutor</p>
<p><code>sudo yum install vim-enhanced</code></p>
<p>Now you should be able to do &#8220;vimtutor&#8221; and start a new vimtutor session.  Happy h-j-k-l around and stops using the arrow keys <img src='http://alexle.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/297/feed</wfw:commentRss>
		</item>
		<item>
		<title>ImageMagick on CentOS with all necessary delegates</title>
		<link>http://alexle.net/archives/296</link>
		<comments>http://alexle.net/archives/296#comments</comments>
		<pubDate>Fri, 31 Jul 2009 19:15:10 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[Server]]></category>

		<category><![CDATA[imagemagick]]></category>

		<category><![CDATA[jpeg2000]]></category>

		<category><![CDATA[jpg2000]]></category>

		<category><![CDATA[linux]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=296</guid>
		<description><![CDATA[<p>Here&#8217;s a quick summary to install ImageMagick from source and to handle all the common graphics files:</p>
<p>1)  Install necessary libraries for image processing.  ImageMagick will rely on these libraries to handle the images.</p>
<p><code>sudo yum install libjpeg-devel libpng-devel glib2-devel fontconfig-devel zlib-devel libwmf-devel freetype-devel libtiff-devel jasper jasper-devel ghostscript-fonts</code></p>
<p>jasper and jasper-devel is needed for Jpeg2000. Also ghostscrip-fonts is needed for some components (such as captcha generator).</p>
<p>2)  Download the lastest imagemagick from source and install (untar, run ./configure, sudo make, sudo make install)  The output of the ./configure command will show all supported file types</p>
<p>3)  To validate the supported files format, run </p>
<p><code>convert -list configure | grep DELEGATES</code></p>
<p>the result should be something like<br />
<code><br />
> convert -list configure | grep DELEGATES<br />
DELEGATES     bzlib fontconfig freetype jpeg jng jp2 lcms png tiff x11 xml wmf zlib<br />
</code></p>
<p><strong>References:</strong></p>
<p>* <a href="http://b.lesseverything.com/2007/6/24/setting-up-imagemagick-rmagick-on-redhat-centos">http://b.lesseverything.com/2007/6/24/setting-up-imagemagick-rmagick-on-redhat-centos</a></p>
<p>* <a href="http://forums.fedoraforum.org/archive/index.php/t-32148.html">http://forums.fedoraforum.org/archive/index.php/t-32148.html</a></p>
]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a quick summary to install ImageMagick from source and to handle all the common graphics files:</p>
<p>1)  Install necessary libraries for image processing.  ImageMagick will rely on these libraries to handle the images.</p>
<p><code>sudo yum install libjpeg-devel libpng-devel glib2-devel fontconfig-devel zlib-devel libwmf-devel freetype-devel libtiff-devel jasper jasper-devel ghostscript-fonts</code></p>
<p>jasper and jasper-devel is needed for Jpeg2000. Also ghostscrip-fonts is needed for some components (such as captcha generator).</p>
<p>2)  Download the lastest imagemagick from source and install (untar, run ./configure, sudo make, sudo make install)  The output of the ./configure command will show all supported file types</p>
<p>3)  To validate the supported files format, run </p>
<p><code>convert -list configure | grep DELEGATES</code></p>
<p>the result should be something like<br />
<code><br />
> convert -list configure | grep DELEGATES<br />
DELEGATES     bzlib fontconfig freetype jpeg jng jp2 lcms png tiff x11 xml wmf zlib<br />
</code></p>
<p><strong>References:</strong></p>
<p>* <a href="http://b.lesseverything.com/2007/6/24/setting-up-imagemagick-rmagick-on-redhat-centos">http://b.lesseverything.com/2007/6/24/setting-up-imagemagick-rmagick-on-redhat-centos</a></p>
<p>* <a href="http://forums.fedoraforum.org/archive/index.php/t-32148.html">http://forums.fedoraforum.org/archive/index.php/t-32148.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/296/feed</wfw:commentRss>
		</item>
		<item>
		<title>Mac-imized</title>
		<link>http://alexle.net/archives/295</link>
		<comments>http://alexle.net/archives/295#comments</comments>
		<pubDate>Mon, 16 Feb 2009 09:25:01 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Random Walk]]></category>

		<category><![CDATA[life]]></category>

		<category><![CDATA[rant]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=295</guid>
		<description><![CDATA[<p>It&#8217;s been a long time since my previous post.  There was a lot that has happened (and not happened). I switched my job from being a consultant at BridgePoint Technologies, a small consulting firm in Oak Brook, to being a lead developer at Designkitchen.com.  I love the team at BridgePoint, I learned and grew a lot during my time there, and of course I always remembered to have a good time wherever I go to.  I had a blast, and I still keep regular contacts with friends and colleagues there.  The new position at Designkitchen is also awesome in the sense that it offers new opportunities, new challenges, and a new environment.  And I find life is funny in its own way.  BridgePoint&#8217;s office is right across the street from the McDonald&#8217;s HQ.  I used to walked across the street to lunch with friends to the yellow McDonalds restaurant near by, which impressively has a timer to tell how fast each customer is served.  The average was about less than 40 seconds.  Joining us were also McDonalds corporate employees grabbing a quick bite.  Was it one more reason to get back to work faster to climb the corporate ladder?  Anyhow, I&#8217;m currently the lead developer for ClubBK.com, a Burger King&#8217;s effort to get their presence on the so-cool cyberspace for kids.  Never did I feel more like having burgers for lunch everyday.  Nonetheless, I&#8217;m having a blast working side by side with the different teams at Designkitchen.  Everyday is a learning experience.</p>
<p>I picked up a Canon Digital Rebel XSI with a 50mm f/1.4 prime lense.  I knew nothing about photography, and now is always a good time to start picking up a new hobby.  My grandfather is really good photographer, and I don&#8217;t want to see him disappointing that his grand kid is being ignorant of the art.  I&#8217;m not.  I just never had the budget ready for such a plunge.  But I&#8217;m glad I did it.  The XSI is an excellent camera &#8212; light, compact, good build, and cheap.  Coupled with the fast f/1.4 lense, I&#8217;ve had some good (or lucky) shots of people at really low light conditions.  Everybody was impressed with the photos, without knowing about my newbie status.</p>
<p>I also got a new Mac Book Air with 64GB SSD for rails and iPhone apps development.   Designkitchen is a heavy Mac environment.  Almost 100% of the creative team is on Mac (clubBK.com is 100% mac, that&#8217;s for sure), and most Rails guys I know are also on Mac.  Not that I&#8217;m being influenced by peer-pressure, but definitely that counts for something.  I&#8217;ve been using the Air for a straight 2 days, leaving my Dell D830 in the backpack.  Heck, I don&#8217;t need a backpack for the Air!  Performance wise, the machine is zippy and Rails 2.3.0 boots in merely seconds.  I managed to consume more than half the 64GB with the iPhone SDK and OS X updates, but I still have plenty of room left.  I have all my media on the main desktop, and for music, Last.FM and Pandora provide some awesome head-banging time when I&#8217;m not home (try some Disarmonia Mundi and you&#8217;ll know what I mean).  In other words, I&#8217;m getting macimized while staying anti-vista.   </p>
<p>I&#8217;m saving the best for last, but I&#8217;m finally free.  2.10, the day to remember.  I&#8217;m so ready to have my life back.  Time to make some changes and live life a bit, as I&#8217;ve been in the shadow for way too long.</p>
]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been a long time since my previous post.  There was a lot that has happened (and not happened). I switched my job from being a consultant at BridgePoint Technologies, a small consulting firm in Oak Brook, to being a lead developer at Designkitchen.com.  I love the team at BridgePoint, I learned and grew a lot during my time there, and of course I always remembered to have a good time wherever I go to.  I had a blast, and I still keep regular contacts with friends and colleagues there.  The new position at Designkitchen is also awesome in the sense that it offers new opportunities, new challenges, and a new environment.  And I find life is funny in its own way.  BridgePoint&#8217;s office is right across the street from the McDonald&#8217;s HQ.  I used to walked across the street to lunch with friends to the yellow McDonalds restaurant near by, which impressively has a timer to tell how fast each customer is served.  The average was about less than 40 seconds.  Joining us were also McDonalds corporate employees grabbing a quick bite.  Was it one more reason to get back to work faster to climb the corporate ladder?  Anyhow, I&#8217;m currently the lead developer for ClubBK.com, a Burger King&#8217;s effort to get their presence on the so-cool cyberspace for kids.  Never did I feel more like having burgers for lunch everyday.  Nonetheless, I&#8217;m having a blast working side by side with the different teams at Designkitchen.  Everyday is a learning experience.</p>
<p>I picked up a Canon Digital Rebel XSI with a 50mm f/1.4 prime lense.  I knew nothing about photography, and now is always a good time to start picking up a new hobby.  My grandfather is really good photographer, and I don&#8217;t want to see him disappointing that his grand kid is being ignorant of the art.  I&#8217;m not.  I just never had the budget ready for such a plunge.  But I&#8217;m glad I did it.  The XSI is an excellent camera &#8212; light, compact, good build, and cheap.  Coupled with the fast f/1.4 lense, I&#8217;ve had some good (or lucky) shots of people at really low light conditions.  Everybody was impressed with the photos, without knowing about my newbie status.</p>
<p>I also got a new Mac Book Air with 64GB SSD for rails and iPhone apps development.   Designkitchen is a heavy Mac environment.  Almost 100% of the creative team is on Mac (clubBK.com is 100% mac, that&#8217;s for sure), and most Rails guys I know are also on Mac.  Not that I&#8217;m being influenced by peer-pressure, but definitely that counts for something.  I&#8217;ve been using the Air for a straight 2 days, leaving my Dell D830 in the backpack.  Heck, I don&#8217;t need a backpack for the Air!  Performance wise, the machine is zippy and Rails 2.3.0 boots in merely seconds.  I managed to consume more than half the 64GB with the iPhone SDK and OS X updates, but I still have plenty of room left.  I have all my media on the main desktop, and for music, Last.FM and Pandora provide some awesome head-banging time when I&#8217;m not home (try some Disarmonia Mundi and you&#8217;ll know what I mean).  In other words, I&#8217;m getting macimized while staying anti-vista.   </p>
<p>I&#8217;m saving the best for last, but I&#8217;m finally free.  2.10, the day to remember.  I&#8217;m so ready to have my life back.  Time to make some changes and live life a bit, as I&#8217;ve been in the shadow for way too long.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/295/feed</wfw:commentRss>
		</item>
		<item>
		<title>Pick for Next US President</title>
		<link>http://alexle.net/archives/293</link>
		<comments>http://alexle.net/archives/293#comments</comments>
		<pubDate>Fri, 26 Sep 2008 19:39:51 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Observations]]></category>

		<category><![CDATA[Random Walk]]></category>

		<category><![CDATA[Server]]></category>

		<category><![CDATA[election]]></category>

		<category><![CDATA[presidential campaign]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=293</guid>
		<description><![CDATA[<p>I don&#8217;t like to get political on my blog, but a friend of mine sent me a link to a political quiz at ABCNews.</p>
<p><a href="http://abcnews.go.com/Politics/MatchoMatic/fullpage?id=5542139">http://abcnews.go.com/Politics/MatchoMatic/fullpage?id=5542139</a></p>
<p>Here are my answers:<br />
<center><br />
<a href='http://alexle.net/wp-content/uploads/2008/09/mccain-obama.png'><img src="http://alexle.net/wp-content/uploads/2008/09/mccain-obama-300x260.png" alt="mccain-obama" title="mccain-obama" width="300" height="260" class="aligncenter size-medium wp-image-294" /></a><br />
</center></p>
<p>I don&#8217;t disagree with some of the things that Obama is saying, but I strongly agree with McCain&#8217;s principles and leadership.  And as a foreign immigrant to this country, I&#8217;m strongly offended by Obama&#8217;s way of dealing with the issue:</p>
<blockquote><p>Obama: &#8220;We should require them to pay a fine, learn English, and go to the back of the line for citizenship behind those who came here legally.  But we cannot &#8212; and should not &#8212; deport 12 million people.&#8221;  (number #8)</p></blockquote>
<p>Who the hell is Obama to say &#8220;let&#8217;s fine these illegal immigrants because they just sneaked in the country?&#8221;  JERK, JERK, and JERK.  How about babies that were brought to the States by their parents, granted &#8220;illegally&#8221; according to US&#8217;s immigration laws.  Do these babies do anything wrong to get fined?  They speak English, pay taxes, go to school, and contribute to society as much as anyone else &#8212; while getting treated as a 2nd-class citizen.</p>
<p>McCain has a much clearer policy and it is towards an legalizing the integration of the immigrants (currently there&#8217;s no such thing!)</p>
<blockquote><p>&#8220;The program will &#8230; ensure that all undocumented aliens either leave of follow the path to legal residence.  American cannot permit a permanent category of individuals that do not have recognized status &#8212; a permanent second class&#8221;
</p></blockquote>
<p>McCain, I wish you the best of luck!</p>
]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t like to get political on my blog, but a friend of mine sent me a link to a political quiz at ABCNews.</p>
<p><a href="http://abcnews.go.com/Politics/MatchoMatic/fullpage?id=5542139">http://abcnews.go.com/Politics/MatchoMatic/fullpage?id=5542139</a></p>
<p>Here are my answers:<br />
<center><br />
<a href='http://alexle.net/wp-content/uploads/2008/09/mccain-obama.png'><img src="http://alexle.net/wp-content/uploads/2008/09/mccain-obama-300x260.png" alt="mccain-obama" title="mccain-obama" width="300" height="260" class="aligncenter size-medium wp-image-294" /></a><br />
</center></p>
<p>I don&#8217;t disagree with some of the things that Obama is saying, but I strongly agree with McCain&#8217;s principles and leadership.  And as a foreign immigrant to this country, I&#8217;m strongly offended by Obama&#8217;s way of dealing with the issue:</p>
<blockquote><p>Obama: &#8220;We should require them to pay a fine, learn English, and go to the back of the line for citizenship behind those who came here legally.  But we cannot &#8212; and should not &#8212; deport 12 million people.&#8221;  (number #8)</p></blockquote>
<p>Who the hell is Obama to say &#8220;let&#8217;s fine these illegal immigrants because they just sneaked in the country?&#8221;  JERK, JERK, and JERK.  How about babies that were brought to the States by their parents, granted &#8220;illegally&#8221; according to US&#8217;s immigration laws.  Do these babies do anything wrong to get fined?  They speak English, pay taxes, go to school, and contribute to society as much as anyone else &#8212; while getting treated as a 2nd-class citizen.</p>
<p>McCain has a much clearer policy and it is towards an legalizing the integration of the immigrants (currently there&#8217;s no such thing!)</p>
<blockquote><p>&#8220;The program will &#8230; ensure that all undocumented aliens either leave of follow the path to legal residence.  American cannot permit a permanent category of individuals that do not have recognized status &#8212; a permanent second class&#8221;
</p></blockquote>
<p>McCain, I wish you the best of luck!</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/293/feed</wfw:commentRss>
		</item>
		<item>
		<title>Ruby on Rails: SQL Server 2005 Pagination</title>
		<link>http://alexle.net/archives/292</link>
		<comments>http://alexle.net/archives/292#comments</comments>
		<pubDate>Fri, 26 Sep 2008 18:14:30 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Random Walk]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[Tutorials]]></category>

		<category><![CDATA[Web Technolgy]]></category>

		<category><![CDATA[mislav-will_paginate sqlserver 2005]]></category>

		<category><![CDATA[pagination]]></category>

		<category><![CDATA[rails sqladapter]]></category>

		<category><![CDATA[row_number()]]></category>

		<category><![CDATA[sql server 2005]]></category>

		<category><![CDATA[will_paginate]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=292</guid>
		<description><![CDATA[<p>For a Rails/SQLServer application I&#8217;m working on, I had to deal with pagination with custom queries because of the different joins.  The mislav-will_paginate plugin works great for MySQL, but for SQL Server, the paginated query generated by the current SQL Server Adapter (I&#8217;m using activerecord-sqlserver-adapter-1.0.0.9250) does not work very well.  The current implementation is targetted really for SQL Server 2000 and older versions since these versions do not have support for ROW_NUMBER() method.  It is a major pain in the butt to do pagination with these databases.  With the newer SQL Sever 2005, the job is a bit easier.  Microsoft implemented the ROW_NUMBER() method with a convoluted syntax to have better support for pagination, but it is still a drag because of the weird syntax.</p>
<p><strong><a href="http://www.semergence.com">Semergence</a></strong> wrote in his blog about <a href="http://www.semergence.com/2007/07/31/fixing-rails-pagination-for-sql-server/">patching the SQLServerAdapter to support pagination</a>.  Based on his post, I improved ActiveRecord::ConnectionAdapters::SQLServerAdapter::<strong>add_limit_offset!</strong> to make the query work in a more general way with free-form queries, e.g. queries ran with the <strong>paginate_by_sql()</strong> method provided by mislav-will_paginate</p>
<p>Include this script in your <strong>environment.rb</strong> file, or an external file and &#8220;require&#8221; the file within <strong>environment.rb</strong>.</p>
<pre name="code" class="ruby">
  # monkey-patching SQLServerAdapter to support SQL Server 2005-style pagination
  module ActiveRecord
    module ConnectionAdapters
      class SQLServerAdapter
        def add_limit_offset!(sql, options)
          puts sql
          options[:offset] ||= 0
          options_limit = options[:limit] ? "TOP #{options[:limit]}" : ""
          options[:order] ||= if order_by = sql.match(/ORDER BY(.*$)/i)
                                order_by[1]
                              else
                                sql.match('FROM (.+?)\b')[1] + '.id'
                              end
          sql.sub!(/ORDER BY.*$/i, '')
          sql.sub!(/SELECT/i, "SELECT #{options_limit} * FROM ( SELECT ROW_NUMBER() OVER( ORDER BY #{options[:order] } ) AS row_num, ")
          sql << ") AS t WHERE row_num > #{options[:offset]}&#8221;
          puts sql
          sql
        end
      end
    end
  end
</pre>
<p>The method above monkey-patches the SQLServerAdapter by overwriting the add_limit_offset! method.</p>
<p>Here&#8217;s a custom query that I used and the transformed result:</p>
<pre name="code" class="sql">
Resource.paginate_by_sql([
      %!SELECT  resources.*
        	,skills_count.skill_count
        FROM resources
        	,(
        		SELECT resource_id
        			, COUNT(*) AS skill_count
        		FROM resource_skills
            WHERE meta_skill_id IN (1,2,3,4,5,6,7,8,9,10)
        		GROUP BY resource_id
        	) AS skills_count
        WHERE resources.is_active = ?
          AND resources.id = skills_count.resource_id
        ORDER BY skill_count DESC
      !, true ], :page => page, :per_page => per_page
</pre>
<p>With :page = 1, :per_page = 2, the resulted SQL is:</p>
<pre name="code" class="sql">
SELECT TOP 2 * FROM ( SELECT ROW_NUMBER() OVER( ORDER BY skill_count DESC ) AS row_num, resources.*
 	,skills_count.skill_count
 FROM resources
 	,(
 		SELECT resource_id
 			, COUNT(*) AS skill_count
 		FROM resource_skills
 WHERE meta_skill_id IN (1,2,3,4,5,6,7,8,9,10)
 		GROUP BY resource_id
 	) AS skills_count
 WHERE resources.is_active = 1
 AND resources.id = skills_count.resource_id

 ) AS t WHERE row_num > 0
</pre>
<p>The will_pagination&#8217;s COUNT query is</p>
<pre name="code" class="sql">
SELECT COUNT(*) FROM (
 SELECT resources.*
 	,skills_count.skill_count
 FROM resources
 	,(
 		SELECT resource_id
 			, COUNT(*) AS skill_count
 		FROM resource_skills
 WHERE meta_skill_id IN (21,22)
 		GROUP BY resource_id
 	) AS skills_count
 WHERE resources.is_active = 1
 AND resources.id = skills_count.resource_id
 ) AS count_table
</pre>
<p>The ORDER BY part is automatically removed from the main query (which becomes a sub-select) by the plugin  to speed up the query.  This in turns sanatizes the sql so that SQL Server doesn&#8217;t not complain about nested &#8220;ORDER BY&#8221; within a sub-select.  Neat!</p>
<p>The only catch with the current add_limit_offset! is that it does not support ALIAS-ing, because the aliasing confuses the reqex to parse out the ORDER BY condition in the OVER() part of the query. </p>
<p>For regular find() queries, here&#8217;s a sample result</p>
<pre name="code" class="sql">
Resource.find(:first)
# original query:  SELECT * FROM resources
# transformed:   SELECT TOP 1 * FROM ( SELECT ROW_NUMBER() OVER( ORDER BY resources.id ) AS row_number, * FROM resources ) AS t WHERE row_num > 0
</pre>
<p>Hope this helps and cheers!</p>
]]></description>
			<content:encoded><![CDATA[<p>For a Rails/SQLServer application I&#8217;m working on, I had to deal with pagination with custom queries because of the different joins.  The mislav-will_paginate plugin works great for MySQL, but for SQL Server, the paginated query generated by the current SQL Server Adapter (I&#8217;m using activerecord-sqlserver-adapter-1.0.0.9250) does not work very well.  The current implementation is targetted really for SQL Server 2000 and older versions since these versions do not have support for ROW_NUMBER() method.  It is a major pain in the butt to do pagination with these databases.  With the newer SQL Sever 2005, the job is a bit easier.  Microsoft implemented the ROW_NUMBER() method with a convoluted syntax to have better support for pagination, but it is still a drag because of the weird syntax.</p>
<p><strong><a href="http://www.semergence.com">Semergence</a></strong> wrote in his blog about <a href="http://www.semergence.com/2007/07/31/fixing-rails-pagination-for-sql-server/">patching the SQLServerAdapter to support pagination</a>.  Based on his post, I improved ActiveRecord::ConnectionAdapters::SQLServerAdapter::<strong>add_limit_offset!</strong> to make the query work in a more general way with free-form queries, e.g. queries ran with the <strong>paginate_by_sql()</strong> method provided by mislav-will_paginate</p>
<p>Include this script in your <strong>environment.rb</strong> file, or an external file and &#8220;require&#8221; the file within <strong>environment.rb</strong>.</p>
<pre name="code" class="ruby">
  # monkey-patching SQLServerAdapter to support SQL Server 2005-style pagination
  module ActiveRecord
    module ConnectionAdapters
      class SQLServerAdapter
        def add_limit_offset!(sql, options)
          puts sql
          options[:offset] ||= 0
          options_limit = options[:limit] ? "TOP #{options[:limit]}" : ""
          options[:order] ||= if order_by = sql.match(/ORDER BY(.*$)/i)
                                order_by[1]
                              else
                                sql.match('FROM (.+?)\b')[1] + '.id'
                              end
          sql.sub!(/ORDER BY.*$/i, '')
          sql.sub!(/SELECT/i, "SELECT #{options_limit} * FROM ( SELECT ROW_NUMBER() OVER( ORDER BY #{options[:order] } ) AS row_num, ")
          sql << ") AS t WHERE row_num > #{options[:offset]}&#8221;
          puts sql
          sql
        end
      end
    end
  end
</pre>
<p>The method above monkey-patches the SQLServerAdapter by overwriting the add_limit_offset! method.</p>
<p>Here&#8217;s a custom query that I used and the transformed result:</p>
<pre name="code" class="sql">
Resource.paginate_by_sql([
      %!SELECT  resources.*
        	,skills_count.skill_count
        FROM resources
        	,(
        		SELECT resource_id
        			, COUNT(*) AS skill_count
        		FROM resource_skills
            WHERE meta_skill_id IN (1,2,3,4,5,6,7,8,9,10)
        		GROUP BY resource_id
        	) AS skills_count
        WHERE resources.is_active = ?
          AND resources.id = skills_count.resource_id
        ORDER BY skill_count DESC
      !, true ], :page => page, :per_page => per_page
</pre>
<p>With :page = 1, :per_page = 2, the resulted SQL is:</p>
<pre name="code" class="sql">
SELECT TOP 2 * FROM ( SELECT ROW_NUMBER() OVER( ORDER BY skill_count DESC ) AS row_num, resources.*
 	,skills_count.skill_count
 FROM resources
 	,(
 		SELECT resource_id
 			, COUNT(*) AS skill_count
 		FROM resource_skills
 WHERE meta_skill_id IN (1,2,3,4,5,6,7,8,9,10)
 		GROUP BY resource_id
 	) AS skills_count
 WHERE resources.is_active = 1
 AND resources.id = skills_count.resource_id

 ) AS t WHERE row_num > 0
</pre>
<p>The will_pagination&#8217;s COUNT query is</p>
<pre name="code" class="sql">
SELECT COUNT(*) FROM (
 SELECT resources.*
 	,skills_count.skill_count
 FROM resources
 	,(
 		SELECT resource_id
 			, COUNT(*) AS skill_count
 		FROM resource_skills
 WHERE meta_skill_id IN (21,22)
 		GROUP BY resource_id
 	) AS skills_count
 WHERE resources.is_active = 1
 AND resources.id = skills_count.resource_id
 ) AS count_table
</pre>
<p>The ORDER BY part is automatically removed from the main query (which becomes a sub-select) by the plugin  to speed up the query.  This in turns sanatizes the sql so that SQL Server doesn&#8217;t not complain about nested &#8220;ORDER BY&#8221; within a sub-select.  Neat!</p>
<p>The only catch with the current add_limit_offset! is that it does not support ALIAS-ing, because the aliasing confuses the reqex to parse out the ORDER BY condition in the OVER() part of the query. </p>
<p>For regular find() queries, here&#8217;s a sample result</p>
<pre name="code" class="sql">
Resource.find(:first)
# original query:  SELECT * FROM resources
# transformed:   SELECT TOP 1 * FROM ( SELECT ROW_NUMBER() OVER( ORDER BY resources.id ) AS row_number, * FROM resources ) AS t WHERE row_num > 0
</pre>
<p>Hope this helps and cheers!</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/292/feed</wfw:commentRss>
		</item>
		<item>
		<title>log4net for asp.net 2.0 and asp.net 3.5</title>
		<link>http://alexle.net/archives/289</link>
		<comments>http://alexle.net/archives/289#comments</comments>
		<pubDate>Mon, 22 Sep 2008 16:39:29 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Random Walk]]></category>

		<category><![CDATA[.net]]></category>

		<category><![CDATA[asp.net 2.0]]></category>

		<category><![CDATA[asp.net 3.5]]></category>

		<category><![CDATA[log4net]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=289</guid>
		<description><![CDATA[<p>Here is a quick guide to configure log4net for general asp.net 2.0 and asp.net 3.5 web projects.  While you can find general guides for setting up log4net, more advanced configuration will require further digging through Log4Net documentations.  My intention is to provide a quick, 5 minutes overview of configuring log4net for a web project with a more complicated, nested logging configuration.  </p>
<p>My goal is to have 2 independent loggers working in parallel. One logs application errors (such as exceptions or serious errors that need to be reviewed later) to the Event log of Windows, and the other will log all general messages to a text file.  The reason why 2 loggers are needed is because the Windows server is configured to send out email notifications on &#8220;Error&#8221; events to notify whoever in charge of maintaining the application.  The general logging file containing all logging messages will provide more application-level debugging info.</p>
<p><strong>Installing and Setting up Log4Net</strong><br />
Log4Net is a drop-in DLL file that you can download from the <a href="http://logging.apache.org/log4net/download.html"><strong>Apache project site</strong></a>.  The binary is compatible with ASP.NET 3.5 and ASP.NET 2.0, as well as the Mono platform.  After adding the reference to the DLL to your project, create the <strong>Global.asax</strong> file and add one line to the <strong>Application_Start</strong> method to initialize log4net at application start up.</p>
<pre name="code" class="c#">
void Application_Start(object sender, EventArgs e)
{
  log4net.Config.XmlConfigurator.Configure();
}
</pre>
<p>In the <strong>web.config</strong> file, add the log4net section handler to the <strong>configSections</strong> block</p>
<pre name="code" class="xml">
<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net">
    </section >
    <!-- your other config stuff show followed -->
  </configSections>
  <!-- Log4Net -->
  <log4net>
    <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="ERROR"></levelMin>
        <levelMax value="FATAL"></levelMax>
      </filter>
<mapping>
        <level value="ERROR"></level>
        <eventLogEntryType value="Error">
        </eventLogEntryType>
      </mapping>
<mapping>
        <level value="DEBUG"></level>
        <eventLogEntryType value="Information">
        </eventLogEntryType>
      </mapping>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline%date [%thread] %-5level %logger [%property] - %message%newline" />
      </layout>
    </appender>

    <!-- Regular Log Files -->
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
      <file value="log/log.log" ></file>
      <appendToFile value="true" ></appendToFile>
      <maximumFileSize value="1024KB"></maximumFileSize>
      <maxSizeRollBackups value="2"></maxSizeRollBackups>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline%date [%thread] %-5level %logger [%property] - %message%newline"></conversionPattern>
      </layout>
    </appender>

    <!-- Specifying the logger -->
    <root>
      <appender-ref ref="EventLogAppender"></appender-ref>
      <appender-ref ref="RollingFile"></appender-ref>
    </root>
  </log4net>
</configuration>
</pre>
<p>Basically we have 2 &#8220;appender&#8221; loggers and their above configurations are quite self-explanatory. The first appender, <strong>EventLogAppender</strong>, has a <strong>level range filter</strong>, which will filter out only FATAL or ERROR log entry.  Then it has 2 mappings to map the different log levels to the correct Window&#8217;s Event message type.  Finally, the layout section defines how the log text should look like.</p>
<p>For the 2nd logger, we use a <strong>RollingFile</strong> appender, which will automatically rotate the files based on the log file size.  We define where to log the files to, what the maximum size is, and how many files we would like to keep.  We don&#8217;t need to configure a filter for this logger since we are collecting all entries for debugging purposes, but you can add a range filter or a pattern filter without any problem.</p>
<p>Finally, we define the <strong>root</strong> logger.  This root-level logger is the one logger receiving our log message and it will distribute these messages to all of the configured referenced appenders.</p>
<p>To use log4net in the program, all you need to do is add &#8220;<strong>using log4net;</strong>&#8221; to the top of the file, and initilize a static logger as follow:</p>
<pre name="code" class="c#">
public class PageBase : System.Web.UI.Page
{
  public static readonly ILog log = LogManager.GetLogger("Logger");
  public PageBase()
  {
     log.Debug("This is a debug message");
     log.Info("This is an info message");
     log.Error("This is an error message");
  }
}
</pre>
<p><strong>Notes</strong></p>
<ul>
<li>Log4net is meant to be un-obtrusive and it won&#8217;t throw any error whatsoever, even in the case of invalid configuration.  This means that you won&#8217;t know why it fails if log4net happens to fail.  As the manual says, log4net is not meant to be a reliable logging mechanism.  So watch out there</li>
<li>For the file appender, if you log into a sub-folder within the web project, you should take extra precaution steps to protect the one folder from public eyes.  For example, denying all anonymous users from accessing the &#8220;log&#8221; folder by adding the following section into the web.config
</li>
</ul>
<pre name="code" class="xml">
<configuration>
  <location path="log">
    <system.web>
      <authorization>
        <deny users="?" />
      </authorization>
    </system.web>
  </location>
</configuration>
</pre>
<p><strong>References</strong></p>
<ul>
<li><a href="http://logging.apache.org/log4net/release/manual/configuration.html">Log4Net configuration manual page</a></li>
<li><a href="http://www.codeproject.com/KB/aspnet/Log4Net_Configuration.aspx">CodeProject&#8217;s Article on Log4Net Configuration</a>.  This is an introductory article just to get you up working with log4net.</li>
</ul>
]]></description>
			<content:encoded><![CDATA[<p>Here is a quick guide to configure log4net for general asp.net 2.0 and asp.net 3.5 web projects.  While you can find general guides for setting up log4net, more advanced configuration will require further digging through Log4Net documentations.  My intention is to provide a quick, 5 minutes overview of configuring log4net for a web project with a more complicated, nested logging configuration.  </p>
<p>My goal is to have 2 independent loggers working in parallel. One logs application errors (such as exceptions or serious errors that need to be reviewed later) to the Event log of Windows, and the other will log all general messages to a text file.  The reason why 2 loggers are needed is because the Windows server is configured to send out email notifications on &#8220;Error&#8221; events to notify whoever in charge of maintaining the application.  The general logging file containing all logging messages will provide more application-level debugging info.</p>
<p><strong>Installing and Setting up Log4Net</strong><br />
Log4Net is a drop-in DLL file that you can download from the <a href="http://logging.apache.org/log4net/download.html"><strong>Apache project site</strong></a>.  The binary is compatible with ASP.NET 3.5 and ASP.NET 2.0, as well as the Mono platform.  After adding the reference to the DLL to your project, create the <strong>Global.asax</strong> file and add one line to the <strong>Application_Start</strong> method to initialize log4net at application start up.</p>
<pre name="code" class="c#">
void Application_Start(object sender, EventArgs e)
{
  log4net.Config.XmlConfigurator.Configure();
}
</pre>
<p>In the <strong>web.config</strong> file, add the log4net section handler to the <strong>configSections</strong> block</p>
<pre name="code" class="xml">
<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net">
    </section >
    <!-- your other config stuff show followed -->
  </configSections>
  <!-- Log4Net -->
  <log4net>
    <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="ERROR"></levelMin>
        <levelMax value="FATAL"></levelMax>
      </filter>
<mapping>
        <level value="ERROR"></level>
        <eventLogEntryType value="Error">
        </eventLogEntryType>
      </mapping>
<mapping>
        <level value="DEBUG"></level>
        <eventLogEntryType value="Information">
        </eventLogEntryType>
      </mapping>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline%date [%thread] %-5level %logger [%property] - %message%newline" />
      </layout>
    </appender>

    <!-- Regular Log Files -->
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
      <file value="log/log.log" ></file>
      <appendToFile value="true" ></appendToFile>
      <maximumFileSize value="1024KB"></maximumFileSize>
      <maxSizeRollBackups value="2"></maxSizeRollBackups>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline%date [%thread] %-5level %logger [%property] - %message%newline"></conversionPattern>
      </layout>
    </appender>

    <!-- Specifying the logger -->
    <root>
      <appender-ref ref="EventLogAppender"></appender-ref>
      <appender-ref ref="RollingFile"></appender-ref>
    </root>
  </log4net>
</configuration>
</pre>
<p>Basically we have 2 &#8220;appender&#8221; loggers and their above configurations are quite self-explanatory. The first appender, <strong>EventLogAppender</strong>, has a <strong>level range filter</strong>, which will filter out only FATAL or ERROR log entry.  Then it has 2 mappings to map the different log levels to the correct Window&#8217;s Event message type.  Finally, the layout section defines how the log text should look like.</p>
<p>For the 2nd logger, we use a <strong>RollingFile</strong> appender, which will automatically rotate the files based on the log file size.  We define where to log the files to, what the maximum size is, and how many files we would like to keep.  We don&#8217;t need to configure a filter for this logger since we are collecting all entries for debugging purposes, but you can add a range filter or a pattern filter without any problem.</p>
<p>Finally, we define the <strong>root</strong> logger.  This root-level logger is the one logger receiving our log message and it will distribute these messages to all of the configured referenced appenders.</p>
<p>To use log4net in the program, all you need to do is add &#8220;<strong>using log4net;</strong>&#8221; to the top of the file, and initilize a static logger as follow:</p>
<pre name="code" class="c#">
public class PageBase : System.Web.UI.Page
{
  public static readonly ILog log = LogManager.GetLogger("Logger");
  public PageBase()
  {
     log.Debug("This is a debug message");
     log.Info("This is an info message");
     log.Error("This is an error message");
  }
}
</pre>
<p><strong>Notes</strong></p>
<ul>
<li>Log4net is meant to be un-obtrusive and it won&#8217;t throw any error whatsoever, even in the case of invalid configuration.  This means that you won&#8217;t know why it fails if log4net happens to fail.  As the manual says, log4net is not meant to be a reliable logging mechanism.  So watch out there</li>
<li>For the file appender, if you log into a sub-folder within the web project, you should take extra precaution steps to protect the one folder from public eyes.  For example, denying all anonymous users from accessing the &#8220;log&#8221; folder by adding the following section into the web.config
</li>
</ul>
<pre name="code" class="xml">
<configuration>
  <location path="log">
    <system.web>
      <authorization>
        <deny users="?" />
      </authorization>
    </system.web>
  </location>
</configuration>
</pre>
<p><strong>References</strong></p>
<ul>
<li><a href="http://logging.apache.org/log4net/release/manual/configuration.html">Log4Net configuration manual page</a></li>
<li><a href="http://www.codeproject.com/KB/aspnet/Log4Net_Configuration.aspx">CodeProject&#8217;s Article on Log4Net Configuration</a>.  This is an introductory article just to get you up working with log4net.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/289/feed</wfw:commentRss>
		</item>
		<item>
		<title>&#8220;safer&#8221; parseInt() for JavaScript with plus unary operator</title>
		<link>http://alexle.net/archives/290</link>
		<comments>http://alexle.net/archives/290#comments</comments>
		<pubDate>Mon, 22 Sep 2008 05:22:28 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Ajax &#038; Web 2.0]]></category>

		<category><![CDATA[Random Walk]]></category>

		<category><![CDATA[Tutorials]]></category>

		<category><![CDATA[Web Scripting]]></category>

		<category><![CDATA[Web Technolgy]]></category>

		<category><![CDATA[javascript]]></category>

		<category><![CDATA[parseInt]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=290</guid>
		<description><![CDATA[<p>I randomly ran into <a href="http://blog.stevenlevithan.com/">Steven Levithan&#8217;s blog</a> while searching to get an idea of how JavaScript handles Unicode.  Steven is a JavaScript - Unicode and Regular Expression expert.  He has a cool section called &#8220;Code Challenge&#8221; with some good food-for-thoughts challenges.  It&#8217;s really JavaScript being pushed to the max, in terms of brevity, creativity, and obscurity.  Check out Stephen&#8217;s &#8220;<a href="http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter">Roman Numeral Convert</a>&#8221; challenge for example.</p>
<p>Reading through the comments, I picked out a nugget explaining a JavaScript behavior which actually caused me some unexpected issues with TubeCaption&#8217;s Captionizer.  Steven explained best in his <a href="http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter#comment-16146">original comment </a></p>
<blockquote><p>&#8230; you might have already realized this, but the unary + operator and parseInt are not equivalent. + can convert strings to numbers, and returns NaN if the element cannot be converted. parseInt (which takes an optional second argument for the radix) does the same thing, but also extracts leading numbers from strings. E.g., parseInt(&#8221;12x&#8221;) returns 12, while +&#8221;12x&#8221; returns NaN. Additionally, parseInt and + make different assumptions about the radix when there’s a leading zero. +&#8221;012&#8243; returns 12, but parseInt(&#8221;012&#8243;) returns 10. The leading zero causes parseInt to treat it as an octal number in probably all browsers, despite octals being summarily deprecated in ES3. Of course, you can use parseInt(&#8221;012&#8243;,10) to get around that.</p></blockquote>
<p>Here is a quick demo of how parseInt() behaves.</p>
<p><a href='http://alexle.net/wp-content/uploads/2008/09/parseint.png'><img src="http://alexle.net/wp-content/uploads/2008/09/parseint.png" alt="" title="parseint" width="188" height="171" class="aligncenter size-full wp-image-291" /></a></p>
<p>For the SRT import feature of <a href="http://www.tubecaption.com">TubeCaption</a>&#8217;s <a href="http://www.tubecaption.com/captions/demo">Captionizer</a>, I heavily relied on parseInt() to get the different time values.  I was caught by surprise when a user notified me that his SRT file could not be imported into the timeline.  After some debugging, it turned out that some values had padding values and the parseInt() returned incorrect results in octal instead of decimal.  I wish I had known about the &#8220;+&#8221; trick and the subtlety of JavaScript at the time.</p>
]]></description>
			<content:encoded><![CDATA[<p>I randomly ran into <a href="http://blog.stevenlevithan.com/">Steven Levithan&#8217;s blog</a> while searching to get an idea of how JavaScript handles Unicode.  Steven is a JavaScript - Unicode and Regular Expression expert.  He has a cool section called &#8220;Code Challenge&#8221; with some good food-for-thoughts challenges.  It&#8217;s really JavaScript being pushed to the max, in terms of brevity, creativity, and obscurity.  Check out Stephen&#8217;s &#8220;<a href="http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter">Roman Numeral Convert</a>&#8221; challenge for example.</p>
<p>Reading through the comments, I picked out a nugget explaining a JavaScript behavior which actually caused me some unexpected issues with TubeCaption&#8217;s Captionizer.  Steven explained best in his <a href="http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter#comment-16146">original comment </a></p>
<blockquote><p>&#8230; you might have already realized this, but the unary + operator and parseInt are not equivalent. + can convert strings to numbers, and returns NaN if the element cannot be converted. parseInt (which takes an optional second argument for the radix) does the same thing, but also extracts leading numbers from strings. E.g., parseInt(&#8221;12x&#8221;) returns 12, while +&#8221;12x&#8221; returns NaN. Additionally, parseInt and + make different assumptions about the radix when there’s a leading zero. +&#8221;012&#8243; returns 12, but parseInt(&#8221;012&#8243;) returns 10. The leading zero causes parseInt to treat it as an octal number in probably all browsers, despite octals being summarily deprecated in ES3. Of course, you can use parseInt(&#8221;012&#8243;,10) to get around that.</p></blockquote>
<p>Here is a quick demo of how parseInt() behaves.</p>
<p><a href='http://alexle.net/wp-content/uploads/2008/09/parseint.png'><img src="http://alexle.net/wp-content/uploads/2008/09/parseint.png" alt="" title="parseint" width="188" height="171" class="aligncenter size-full wp-image-291" /></a></p>
<p>For the SRT import feature of <a href="http://www.tubecaption.com">TubeCaption</a>&#8217;s <a href="http://www.tubecaption.com/captions/demo">Captionizer</a>, I heavily relied on parseInt() to get the different time values.  I was caught by surprise when a user notified me that his SRT file could not be imported into the timeline.  After some debugging, it turned out that some values had padding values and the parseInt() returned incorrect results in octal instead of decimal.  I wish I had known about the &#8220;+&#8221; trick and the subtlety of JavaScript at the time.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/290/feed</wfw:commentRss>
		</item>
		<item>
		<title>Internet Explorer 8 Beta 2 Crashes Firefox by installing new WPF plugin</title>
		<link>http://alexle.net/archives/285</link>
		<comments>http://alexle.net/archives/285#comments</comments>
		<pubDate>Fri, 29 Aug 2008 16:57:57 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Random Walk]]></category>

		<category><![CDATA[Web Technolgy]]></category>

		<category><![CDATA[oops]]></category>

		<category><![CDATA[firefox crash]]></category>

		<category><![CDATA[internet explorer 8]]></category>

		<category><![CDATA[windows presentation foundation]]></category>

		<category><![CDATA[wpf firefox]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=285</guid>
		<description><![CDATA[<p>It&#8217;s a mouthful for the title, but it is true.  I just installed IE8 Beta 2 to try out the new features and see if IE&#8217;s javascipt engine gets any speed bump.  So far IE8 is running only as fast as IE7 in my tests, while Firefox 3 runs screamingly fast (read 500% faster, seriously).</p>
<p>I&#8217;m impressed with IE8b2&#8217;s new Developer tool, a Firebug-like tool.  Surprisingly, the JavaScript debugger actually WORKS!  And it feels much smoother to debug JavaScript than Firebug (Firebug still suffers from some reading/refreshing glitches and doesn&#8217;t feel as responsive).</p>
<p><a href="http://alexle.net/wp-content/uploads/2008/08/ie8b2_debugging.png"><img class="aligncenter size-full wp-image-286" title="ie8b2_debugging" src="http://alexle.net/wp-content/uploads/2008/08/ie8b2_debugging.png" alt="ie8b2 debugging" width="443" height="237" /></a></p>
<p>I was able to step into an object created using prototype&#8217;s Class.create() with no problem using F10 step over, F11 step-in keys work as expected.  Nice!  There is also a Profiler which would be totally awesome and for sure I&#8217;ll be using it extensively to optimize the JavaScript for my upcoming application.   Finally there&#8217;s some light at the end of the tunnel, which Microsoft actually give us developers what we&#8217;ve been dreaming for:  making IE sucks less.</p>
<p>I also managed to crash IE8b2.</p>
<p>I was actually running the debugger and stepping in my code.  Then I noticed and clicked clicked on &#8220;Browser Mode IE7&#8243;.  The entire application froze up.  My explanation is that the main browser process or thread is attached to the debugger, which is running in line-debugging.  Switching &#8220;Browser Mode&#8221; to a different setting requires the main browser to switch to a different view.  However, since the main process is stuck with the debugger, and the debugger is waiting for the main process to switch browsing mode, we have a deadlock situation.</p>
<p>I had to end-task the sucker.</p>
<p><span style="color: #ff0000;">And suddenly, my Firefox 3.1 started to constantly crash</span>, even in safe-mode (running Firefox.exe using -safe-mode flag).  I chose to permanently disable all add-ons and Firefox managed to get to my favorite homepage, the about:blank page.   However, whenever I went to Yahoo Mail, the browser just crashed without even a trace in the Windows Event Application log.  All I got is the Mozilla Crash Reporter to play with.   With all my add-ons disabled, I was determined to find out what was killing Firefox, in safemode.  Apparently, something was almost as determined as I to come get Firefox, even when it&#8217;s waving the &#8220;-safe-mode&#8221; flag.</p>
<p>First, I went to Firefox Options, trying to find out what happened.  Clicking on the &#8220;Applications&#8221; tab would automatically crashed Firefox, weird. I went into Options, then Managed Add-ons.  I disabled all plugins, then restarted Firefox and try Yahoo Mail.  It worked.</p>
<p><a href="http://alexle.net/wp-content/uploads/2008/08/firefox_plugins_list.png"><img class="aligncenter size-full wp-image-287" title="firefox_plugins_list" src="http://alexle.net/wp-content/uploads/2008/08/firefox_plugins_list.png" alt="" width="450" height="831" /></a></p>
<p>Since IE8 was the only application I installed before Firefox started to crash, I proceed to enable all plugins but Microsoft&#8217;s.  Yahoo Mail worked still.  I then enabled the Windows Presentation Foundation (WPF) plugin and, bam, Firefox crashed again.  The culprit is the new WPF plugin that IE8 beta 2 secretly installed into Firefox.  It&#8217;s very nice of you, IE8 installer.  Should I call you mal-ware now since you just make one of my main application mal-functioned?  You just make me almost lose anything trust (left) that I have for installing Microsoft&#8217;s stuff.  Good thing trying out the new IE8 (which proves IE7 is that horrible for developer still!) is compelling enough so I let you go easy this time.</p>
<p>So IE8 Beta 2 testers, disable Windows Presentation Foundation plug-in for Firefox will help you stop IE8 from sabotaging your Firefox browsing experience with blazingly fast javascript execution, which IE can only cry foul by crashing itself.</p>
]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s a mouthful for the title, but it is true.  I just installed IE8 Beta 2 to try out the new features and see if IE&#8217;s javascipt engine gets any speed bump.  So far IE8 is running only as fast as IE7 in my tests, while Firefox 3 runs screamingly fast (read 500% faster, seriously).</p>
<p>I&#8217;m impressed with IE8b2&#8217;s new Developer tool, a Firebug-like tool.  Surprisingly, the JavaScript debugger actually WORKS!  And it feels much smoother to debug JavaScript than Firebug (Firebug still suffers from some reading/refreshing glitches and doesn&#8217;t feel as responsive).</p>
<p><a href="http://alexle.net/wp-content/uploads/2008/08/ie8b2_debugging.png"><img class="aligncenter size-full wp-image-286" title="ie8b2_debugging" src="http://alexle.net/wp-content/uploads/2008/08/ie8b2_debugging.png" alt="ie8b2 debugging" width="443" height="237" /></a></p>
<p>I was able to step into an object created using prototype&#8217;s Class.create() with no problem using F10 step over, F11 step-in keys work as expected.  Nice!  There is also a Profiler which would be totally awesome and for sure I&#8217;ll be using it extensively to optimize the JavaScript for my upcoming application.   Finally there&#8217;s some light at the end of the tunnel, which Microsoft actually give us developers what we&#8217;ve been dreaming for:  making IE sucks less.</p>
<p>I also managed to crash IE8b2.</p>
<p>I was actually running the debugger and stepping in my code.  Then I noticed and clicked clicked on &#8220;Browser Mode IE7&#8243;.  The entire application froze up.  My explanation is that the main browser process or thread is attached to the debugger, which is running in line-debugging.  Switching &#8220;Browser Mode&#8221; to a different setting requires the main browser to switch to a different view.  However, since the main process is stuck with the debugger, and the debugger is waiting for the main process to switch browsing mode, we have a deadlock situation.</p>
<p>I had to end-task the sucker.</p>
<p><span style="color: #ff0000;">And suddenly, my Firefox 3.1 started to constantly crash</span>, even in safe-mode (running Firefox.exe using -safe-mode flag).  I chose to permanently disable all add-ons and Firefox managed to get to my favorite homepage, the about:blank page.   However, whenever I went to Yahoo Mail, the browser just crashed without even a trace in the Windows Event Application log.  All I got is the Mozilla Crash Reporter to play with.   With all my add-ons disabled, I was determined to find out what was killing Firefox, in safemode.  Apparently, something was almost as determined as I to come get Firefox, even when it&#8217;s waving the &#8220;-safe-mode&#8221; flag.</p>
<p>First, I went to Firefox Options, trying to find out what happened.  Clicking on the &#8220;Applications&#8221; tab would automatically crashed Firefox, weird. I went into Options, then Managed Add-ons.  I disabled all plugins, then restarted Firefox and try Yahoo Mail.  It worked.</p>
<p><a href="http://alexle.net/wp-content/uploads/2008/08/firefox_plugins_list.png"><img class="aligncenter size-full wp-image-287" title="firefox_plugins_list" src="http://alexle.net/wp-content/uploads/2008/08/firefox_plugins_list.png" alt="" width="450" height="831" /></a></p>
<p>Since IE8 was the only application I installed before Firefox started to crash, I proceed to enable all plugins but Microsoft&#8217;s.  Yahoo Mail worked still.  I then enabled the Windows Presentation Foundation (WPF) plugin and, bam, Firefox crashed again.  The culprit is the new WPF plugin that IE8 beta 2 secretly installed into Firefox.  It&#8217;s very nice of you, IE8 installer.  Should I call you mal-ware now since you just make one of my main application mal-functioned?  You just make me almost lose anything trust (left) that I have for installing Microsoft&#8217;s stuff.  Good thing trying out the new IE8 (which proves IE7 is that horrible for developer still!) is compelling enough so I let you go easy this time.</p>
<p>So IE8 Beta 2 testers, disable Windows Presentation Foundation plug-in for Firefox will help you stop IE8 from sabotaging your Firefox browsing experience with blazingly fast javascript execution, which IE can only cry foul by crashing itself.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/285/feed</wfw:commentRss>
		</item>
		<item>
		<title>Installing mechanize-0.7.7 on Windows</title>
		<link>http://alexle.net/archives/284</link>
		<comments>http://alexle.net/archives/284#comments</comments>
		<pubDate>Wed, 20 Aug 2008 04:33:01 +0000</pubDate>
		<dc:creator>Alex Le</dc:creator>
		
		<category><![CDATA[My Projects]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[TubeCaption.com]]></category>

		<category><![CDATA[gem]]></category>

		<category><![CDATA[hpricot]]></category>

		<category><![CDATA[mechanize]]></category>

		<category><![CDATA[tubecaption]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=284</guid>
		<description><![CDATA[<p>I wanted to give mechanize a shot for a small prototype I was building.  It&#8217;s been a while since I last ran the gem command so of course the first thing it would do was to update itself.  For some reason, it got stuck forever.  It turned out that the latest hpricot gem was trying to build itself from source (! - very strange!) and gem updater got stuck looking for a compatible compiler.</p>
<p>So I downloaded the mechanize gem from Rubyforge instead and ran</p>
<p><strong>gem install mechanize-0.7.7.gem</strong></p>
<p>However, the gem still tried to access the gem index and eventually got stuck somewhere.  The ruby runtime ballooned up to more than 600MB as showed in Task Manager.  I dug up the gem install command and it turns out the gem install can be forced to install without checking the dependencies and without updaing the local index.   So the final gem command is</p>
<p><strong>gem install mechanize-0.7.7.gem &#8211;no-ri &#8211;no-rdoc -f &#8211;no-update-sources</strong></p>
<p>With the &#8211;no-update-sources flag, the gem won&#8217;t try to go off to http://gems.rubyforge.org and get the latest repository info but expecting there is already a local gem file.</p>
<p>Hope this help someone <img src='http://alexle.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
]]></description>
			<content:encoded><![CDATA[<p>I wanted to give mechanize a shot for a small prototype I was building.  It&#8217;s been a while since I last ran the gem command so of course the first thing it would do was to update itself.  For some reason, it got stuck forever.  It turned out that the latest hpricot gem was trying to build itself from source (! - very strange!) and gem updater got stuck looking for a compatible compiler.</p>
<p>So I downloaded the mechanize gem from Rubyforge instead and ran</p>
<p><strong>gem install mechanize-0.7.7.gem</strong></p>
<p>However, the gem still tried to access the gem index and eventually got stuck somewhere.  The ruby runtime ballooned up to more than 600MB as showed in Task Manager.  I dug up the gem install command and it turns out the gem install can be forced to install without checking the dependencies and without updaing the local index.   So the final gem command is</p>
<p><strong>gem install mechanize-0.7.7.gem &#8211;no-ri &#8211;no-rdoc -f &#8211;no-update-sources</strong></p>
<p>With the &#8211;no-update-sources flag, the gem won&#8217;t try to go off to http://gems.rubyforge.org and get the latest repository info but expecting there is already a local gem file.</p>
<p>Hope this help someone <img src='http://alexle.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/284/feed</wfw:commentRss>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 1.406 seconds -->
